エージェントへのタスクの書き方
コーディングエージェントは、モデルを使ってコードを読み、ファイルを変え、コマンドを動かすプログラムです。エージェントは、あなたが書いたタスクをもとに働きます。だから、返ってくるものはタスクで決まります。
「売店のコードをよくして」と頼むと、四十のファイルが変わって返ってくることがあります。はっきりしたタスクなら、確かめられる小さな変更が返ります。前に学んだのは、アシスタントに一つの質問をうまく聞くことでした。このレッスンでは、エージェントのためにタスクを丸ごと書きます。
このレッスンのゴール
メモ
エージェントが終えられ、自分で確かめられるタスクの仕様を書くことができる。
キーワード
| ことば | いみ | れい |
|---|---|---|
| コーディングエージェント | モデルを使ってコードを読み、ファイルを変え、コマンドを動かすプログラム | |
| タスクの仕様 | 一つの仕事のために書いた指示 | |
| 範囲 | 仕事に含まれる部分 | |
| 完了条件 | 仕事が終わったと示す確認 | node --test が通る |
| 範囲外 | 仕事で触ってはいけないもの |
学生が入力するセルは、このプレビューでは空白です。
タスクには五つの部分がある
目的は、何が変わるかを一文で言います。範囲は、仕事に含まれる部分を言います。ファイルの一覧は、エージェントが書いてよい場所を言います。
完了条件は、テストのコマンドのように、動かせる確認の名前を言います。範囲外は、そのままにするものを言います。エージェントは止まって聞くことがほとんどありません。だから、どの部分も、エージェントが推測しそうな問いに答えます。
例: あいまいなタスクと、はっきりしたタスク
| 部分 | あいまいなタスク | はっきりしたタスク |
|---|---|---|
| 目的 | 売店のコードをよくする | total に学生割引 10 パーセントを入れる |
| 範囲 | 書いていない | total だけ |
| ファイル | 書いていない | shop.js と shop.test.js |
| 完了条件 | 書いていない | node --test が通り、新しいテストが 2 つある |
| 範囲外 | 書いていない | 値段と表示のしかた |
学生が入力するセルは、このプレビューでは空白です。
よくある間違い
注意
タスクがあいまいなら、エージェントが聞いてくれると考える人が多いです。たいていのエージェントは、推測して先へ進みます。すると、すき間は、あなたが選んでいない選択になります。エージェントを動かす前に、範囲外と完了条件を書きましょう。
先にスクリプトでタスクを調べる
確認の一覧を使えば、よくあるすき間が一瞬で見つかります。このスクリプトは、記録した三つの仕様 A、B、C を持っています。欠けた部分、「改善」のようなあいまいな言葉、四つ以上のファイル、テストのない完了条件を探します。
ここでは、エージェントを動かしません。Run は言葉だけを調べるので、最初の三行は全員で同じです。
助っ人 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\");' 'const VAGUE = [\"いい感じ\", \"改善\", \"きれいに\", \"整理\", \"ちゃんと\", \"もっと\"];' 'const PARTS = [\"goal\", \"scope\", \"files\", \"done_when\", \"out_of_scope\"];' 'const NAMES = { goal: \"目的\", scope: \"範囲\", files: \"ファイル\", done_when: \"完了条件\", out_of_scope: \"範囲外\" };' 'const specs = {' ' \"A\": { goal: \"売店のコードを改善して、整理してください\" },' ' \"B\": { goal: \"total に学生割引 10 パーセントを入れる\", scope: \"total だけ\",' ' files: [\"shop.js\", \"shop.test.js\", \"prices.js\", \"README.md\"], done_when: \"node --test が通る\",' ' out_of_scope: \"値段\" },' ' \"C\": { goal: \"total に学生割引 10 パーセントを入れる\", scope: \"total だけ\",' ' files: [\"shop.js\", \"shop.test.js\"], done_when: \"node --test が通り、新しいテストが 2 つある\",' ' out_of_scope: \"値段と表示のしかた\" },' '};' > spec.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
仕様の確認を書く(2)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function problems(s) {' ' const out = PARTS.filter(function (p) { return s[p] === undefined || s[p].length === 0; })' ' .map(function (p) { return NAMES[p] + \"がない\"; });' ' // 日本語には単語の間の空白がないので、部分一致で探す。' ' if (s.goal) VAGUE.forEach(function (v) { if (s.goal.indexOf(v) >= 0) out.push(\"あいまい: \" + v); });' ' if (s.files && s.files.length > 3) out.push(\"ファイルが多すぎる\");' ' const d = s.done_when ? s.done_when.toLowerCase() : \"\";' ' if (s.done_when && d.indexOf(\"test\") < 0 && d.indexOf(\"テスト\") < 0) out.push(\"完了条件にテストがない\");' ' return out;' '}' >> spec.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
仕様の確認を書く(3)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' Object.keys(specs).forEach(function (name) {' ' const found = problems(specs[name]);' ' console.log(\"仕様 \" + name + \": \" + (found.length === 0 ? \"準備完了\" : \"直しが必要 \" + JSON.stringify(found)));' ' });' ' const q = \"短く一文で答えてください。コーディングエージェントへのタスクに完了条件が要るのは、なぜですか。\";' ' const sample = \"確かめる方法がないと、エージェントはいつ止めるか分からず、人もうまくいったか分からないからです。\";' ' const reply = await ask([{ role: \"user\", content: q }], sample, 80);' ' console.log(\"モデル: \" + reply.text);' '}' 'main();' >> spec.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
仕様の確認を動かす
docker exec -w /home/node/project agent node spec.jsここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
Run の出力
| 行 | 意味 |
|---|---|
| 仕様 A: 直しが必要 [...] | 四つの部分が欠け、あいまいな言葉が二つある |
| 仕様 B: 直しが必要 ["ファイルが多すぎる"] | 一つのタスクに四つのファイルは広すぎる |
| 仕様 C: 準備完了 | すべての部分があり、確認はテストである |
| モデル: ... | ラボからの一文。モデルが答えなければ記録済みサンプル |
学生が入力するセルは、このプレビューでは空白です。