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

無料レッスン

サブエージェントとコンテキストの分離

このレッスンのあとで: 副次的な作業に自分のウィンドウを与え、短い答えだけを受け取れる。

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

副次的な作業に自分のウィンドウを与える

サブエージェントは、副次的な作業を一つ受け持ち、新しいウィンドウで作業して、短い答えを返す、二回目のモデル呼び出しです。親は作業を見ず、結果だけを見ます。

ここが肝心です。四十個のファイルを読む検索は、親のウィンドウを埋めてしまいます。サブエージェントで行えば、親には数行の費用で済みます。

このレッスンのゴール

メモ

副次的な作業に自分のウィンドウを与え、短い答えだけを受け取れる。

キーワード

ことばいみ
サブエージェント副次的な作業を一人で行うモデル呼び出し
分離副次的な作業が自分のウィンドウを持つこと
指示書サブエージェントを始める短いメッセージ
契約結果が持つべきフィールドと大きさ
結果サブエージェントが返すもの
親副次的な作業を頼んだエージェント

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

サブエージェントは引き継ぎではない

引き継ぎは、仕事の全体を別のエージェントに渡し、そちらが続けます。サブエージェントは違います。親が責任を持ち続け、質問を一つだけ頼みます。

サブエージェントは、空の状態で始まります。親の履歴は見えません。見えるのは指示書だけです。

まず指示書、次に契約

良い指示書には、目的、大事な事実、見るファイル、答えの大きさが入っています。サブエージェントに必要なものは、すべてそこにあります。ほかに情報源がないからです。

契約は、返るものを決めます。名前の付いたフィールドと、語数の上限です。親が読む前に、ハーネスが結果を契約に合わせて切ります。長い答えが良い答えとは限りません。

指示書と結果の形

部分入れるもの理由
目的質問を一つ終わりが分かる
事実すでに分かっていること作業を繰り返さない
ファイル探す場所さまよわない
大きさ語数の上限結果が短く済む
契約フィールドと上限親は決まった形を読む

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

よくある間違い

注意

多くの人は、念のため親の履歴をすべてサブエージェントに渡します。すると何も分離されず、費用が倍になります。副次的な作業に必要なものだけで、指示書を書きます。

モデル用の補助を書く(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"

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

モデル用の補助を書く(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 d = await res.json();' '    return { text: d.choices[0].message.content, inTokens: count(d, \"prompt_tokens\"), outTokens: count(d, \"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\");' '// 1 文字を 1 トークンと数える。レッスン 1 と同じ。' 'function words(text) { return Array.from(text).length; }' 'const parent = \"利用者は失敗するテストを直したがっています。app.py を読み、テストを二回実行し、readme を確認し、しばらくスタイルの話をしました。変更は小さくしてほしいとのことです。\";' 'const work = [' '  \"ls: app.py readme tests notes.txt old.py\",' '  \"grep total: app.py 4 行目 def total items return sum items\",' '  \"grep total: tests 9 行目 assert items 3 件の total は 12\",' '  \"tests を読む: かごのテストコード 40 行\",' '  \"app.py を読む: かごの値段を計算して税を足す 22 行\",' '];' > sub4.js"

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

サブエージェントの実行を書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function makeBrief(goal, facts, files, max) {' '  const lines = [\"目的: \" + goal];' '  for (const f of facts) lines.push(\"事実: \" + f);' '  for (const f of files) lines.push(\"ファイル: \" + f);' '  lines.push(\"答えは \" + max + \" 文字以内にしてください。\");' '  return lines.join(\" | \");' '}' 'function cut(text, max) { return Array.from(text).slice(0, max).join(\"\"); }' 'function sum(list) { return list.reduce(function (a, b) { return a + b; }, 0); }' >> sub4.js"

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

サブエージェントの実行を書く(3)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  const brief = makeBrief(\"かごの合計を計算している場所を探す\", [\"3 件のテストが間違っている\"], [\"app.py\", \"tests\"], 60);' '  const sample = \"合計は app.py の 4 行目で計算しています。税を足さずに合計しています。tests の 9 行目も見てください。\";' '  const own = brief + \" | \" + work.join(\" ; \");' '  const reply = await ask([{ role: \"user\", content: own }], sample, 80);' '  const result = cut(reply.text, 60);' '  console.log(\"親のウィンドウ: \" + words(parent) + \" 文字\");' '  console.log(\"副次的な作業のウィンドウ: \" + words(own) + \" 文字、うちツールの結果は \" + sum(work.map(words)) + \" 文字\");' '  console.log(\"残した結果: \" + result);' '  console.log(\"親が払うのは \" + (words(brief) + words(result)) + \" 文字\");' '}' 'main();' >> sub4.js"

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

サブエージェントを実行する

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

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

ツールの結果は記録したもの

五つのツールの結果は、本物のサブエージェントが読むものの代わりに、作って記録したものです。短い呼び出しには指示書とこの結果を渡し、Run は答えを六十文字に切ります。

モデルがなければ、記録済みサンプルを表示し、記録した答えを使います。

出力の一例

行示すこと
親のウィンドウ: 89 文字親がすでに持っているもの
副次的な作業のウィンドウ: 311 文字、うちツールの結果は 203 文字作業が行われた場所
残した結果: 合計は app.py の ...六十文字まで
親が払うのは 153 文字指示書と結果で、203 文字は払わない

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

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

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