クリーム色の背景、色付き表示、高コントラスト、大きな文字のほうが読みやすいですか?配色と文字を選ぶと、すべてのページに一度で反映されます。

無料レッスン

コンテキストの予算を決める

このレッスンのあとで: 窓に何が入り、何を先に捨てるかを、決めることができる。

65分のレッスンコマンド6件AI コーディングエージェントのラボ:opencode でコードを説明・修正し、その結果を確かめる

プロンプトに入れる量には限りがある

コンテキストの予算とは、プロンプトの各部分が使えるトークンの数です。モデルは一度に読める量が決まっているので、部分を足して多すぎるときは、何かを諦めます。

コスト、トレース、信頼性のモジュールでは、お金と呼び出しの予算を扱いました。このレッスンは、窓そのものを予算立てし、さらに、何を先に捨てるか、何が抜けたかを利用者にどう伝えるかまで進みます。

このレッスンのゴール

メモ

窓に何が入り、何を先に捨てるかを、決めることができる。

キーワード

ことばいみれい
トークンモデルが数える、文章の小さな単位日本語では、ここで 2 文字を 1 と数える
窓モデルが一回で読み書きできる最大のトークン数
予算プロンプトの一部分が使えるトークン数
優先度部分の大切さ。0 は決して捨てない
切り詰める収まるように短くすること
余地返答のために空けておく分

学生が入力するセルは、このプレビューでは空白です。

返答にも、余地がいる

窓は、プロンプトと返答で分け合います。プロンプトが窓をいっぱいにすると、返答が途中で切れるか、呼び出しが失敗します。

そこで、まず返答の余地を空けます。次に、数え方は目安なので、少し余裕を引きます。残りがプロンプトの予算です。

例: プロンプトの予算

手順トークン理由
窓4000モデルが扱える最大
返答の余地500返答にも場所がいる
余裕 5 パーセント2004000 の 5 パーセント。数え違いに備える
プロンプトの予算33004000 引く 500 引く 200

学生が入力するセルは、このプレビューでは空白です。

よくある間違い

注意

窓はプロンプトのためだけにあると考える人が多いです。実は返答もその窓に入ります。プロンプトが窓をすべて使うと、答える場所が残りません。

どの部分を先に残すか

各部分に優先度をつけます。規則と利用者の質問は優先度 0 で、決して捨てません。これが収まらないなら、プロンプトは壊れているので、そう伝えます。

ほかは大切な順に取ります。収まれば残し、収まらなければ捨てます。ただし、あとに続く小さい部分は、入ることがあります。

例: 予算 3300 の場合

部分トークン優先度ここまでの合計結果
規則3000300残す
質問1000400残す
資料A90011300残す
資料B80022100残す
資料C70022800残す
履歴140034200 で超える捨てる

学生が入力するセルは、このプレビューでは空白です。

履歴は、全部ではなく切り詰める

履歴を丸ごと捨てると、会話がすべて消えます。よい方法は、収まる新しい発言だけを残すことです。

新しい発言から古いほうへ進み、収まらない最初の発言で止まります。会話の真ん中に穴があくと、意味が通らなくなるからです。

例: 残りが 500 トークンのとき

発言トークン合計結果
いちばん新しい200200残す
その前250450残す
さらに前300750 で超えるここで止める
いちばん古い40見ない450 に足して 490 なら入る大きさでも、捨てる

学生が入力するセルは、このプレビューでは空白です。

助っ人 model.js を書く(1)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '// 応答のトークン数。なければ null。' 'function count(data, name) {' '  return data.usage && typeof data.usage[name] === \"number\" ? data.usage[name] : null;' '}' > model.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

助っ人 model.js を書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function ask(messages, sample, max) {' '  try {' '    const res = await fetch(base + \"/v1/chat/completions\", {' '      method: \"POST\",' '      headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' '      body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 100 }),' '      signal: AbortSignal.timeout(30000),' '    });' '    if (res.ok === false) throw new Error(\"status \" + res.status);' '    const data = await res.json();' '    const text = data.choices[0].message.content;' '    return { text, inTokens: count(data, \"prompt_tokens\"), outTokens: count(data, \"completion_tokens\"), recorded: false };' '  } catch (error) {' '    console.log(\"記録済みサンプル: モデルが答えませんでした (\" + error.message + \")。\");' '    return { text: sample, inTokens: null, outTokens: null, recorded: true };' '  }' '}' 'module.exports = { ask };' >> model.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

予算のスクリプトを書く(1)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'function tokens(text) { return Math.ceil(text.length / 2); }' 'const parts = [' '  { name: \"規則\", tokens: 60, priority: 0 },' '  { name: \"質問\", tokens: 25, priority: 0 },' '  { name: \"資料A\", tokens: 120, priority: 1 },' '  { name: \"資料B\", tokens: 90, priority: 2 },' '  { name: \"履歴\", tokens: 150, priority: 3 },' '  { name: \"資料C\", tokens: 80, priority: 2 },' '];' > budget.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

予算のスクリプトを書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function assemble(parts, budget) {' '  const order = parts.slice().sort(function (a, b) { return a.priority - b.priority; });' '  const kept = [];' '  let used = 0;' '  for (const p of order) {' '    if (p.priority === 0 || used + p.tokens <= budget) { kept.push(p.name); used = used + p.tokens; }' '  }' '  return { kept: kept, used: used };' '}' >> budget.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

予算のスクリプトを書く(3)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  const names = parts.map(function (p) { return p.name; });' '  for (const budget of [350, 600]) {' '    const r = assemble(parts, budget);' '    const lost = names.filter(function (n) { return r.kept.includes(n) === false; });' '    console.log(\"予算 \" + budget + \": 残した \" + names.filter(function (n) { return r.kept.includes(n); }).join(\", \"));' '    console.log(\"  捨てた \" + (lost.join(\", \") || \"なし\") + \"、使用 \" + r.used);' '  }' '  const q = \"短く一文で答えてください。長すぎるプロンプトは、まず何を捨てますか。\";' '  const sample = \"古い履歴や役に立たない部分から先に捨て、規則と質問は残します。\";' '  const reply = await ask([{ role: \"user\", content: q }], sample, 80);' '  console.log(\"モデル: \" + reply.text);' '  console.log(\"私の数 \" + tokens(q) + \"、モデルの数 \" + (reply.inTokens === null ? \"報告なし\" : reply.inTokens));' '}' 'main();' >> budget.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

予算を動かす

コマンド
docker exec -w /home/node/project agent node budget.js

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

Run の出力

行意味
予算 350: 残した 規則, 質問, 資料A, 資料B収まった部分を、元の順で表示
捨てた 履歴, 資料C、使用 295捨てた部分と、使ったトークン
予算 600: ... 捨てた なし余裕があれば、全部入る
モデル: ...ラボからの一文。モデルが答えなければ記録済みサンプル
私の数 17、モデルの数 ...自分の数え方と、モデルの数。なければ報告なし

学生が入力するセルは、このプレビューでは空白です。

このラボとソースについて: AI コーディングエージェントのラボ:opencode でコードを説明・修正し、その結果を確かめる

授業で使いますか?このモジュールを学生に割り当てると、教員用ガイド、自動採点つきの課題、学生ごとのラボを使えます。