終わらなかったエージェント
AI エージェントとは、モデルが次のステップを自分で選ぶ繰り返しです。いつやめるかを教えるものがないので、計画と停止のルールが必要です。
サポート用のエージェントが、失敗する検索を一晩中繰り返しました。1回ごとにお金がかかり、成功する見込みはありません。繰り返しは正しく、止めるルールがなかったのです。
このレッスンのゴール
メモ
エージェントにステップを計画させ、ルールで止められる。
キーワード
| ことば | いみ | れい |
|---|---|---|
| エージェント | モデルが次のステップを選ぶ繰り返し | |
| 計画 | エージェントがとるつもりのステップを、データにしたもの | |
| ステップの予算 | 1回の実行で使えるステップの最大数 | 3 |
| 停止ルール | 繰り返しを終わらせる判定 | |
| 結果 | 実行が終わった理由 |
学生が入力するセルは、このプレビューでは空白です。
計画は感覚ではなくデータ
モデルに計画を JSON のリストで頼み、データとして扱います。プログラムは、数える、各ステップを確かめる、実行前に人に見せる、ができます。
計画は提案にすぎません。形が違うリストや、どのツールにもできないステップが返ることがあります。従う前に、計画を確かめます。
例: 計画とその実行
| ステップ | 計画の内容 | ツールの結果 | 実行の状態 |
|---|---|---|---|
| 1 | おにぎりを調べる | おにぎりは 150 円 | ok |
| 2 | お茶を調べる | お茶は 140 円 | ok |
| 3 | キウイを調べる | 合う道具がない | fail |
| 4 | 値段を伝える | 届かない | 予算か行き詰まりで決まる |
学生が入力するセルは、このプレビューでは空白です。
モデル用の補助を書く(1)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '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 || 200 }),' ' signal: AbortSignal.timeout(30000),' ' });' ' if (res.ok === false) throw new Error(\"status \" + res.status);' ' return (await res.json()).choices[0].message.content;' > model.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
モデル用の補助を書く(2)
docker exec -w /home/node/project agent sh -c "printf '%s\n' ' } catch (error) {' ' console.log(\"記録済みサンプル: モデルが答えませんでした (\" + error.message + \")。\");' ' const list = [].concat(sample);' ' const turn = messages.filter(function (m) { return m.role === \"assistant\"; }).length;' ' return list[Math.min(turn, list.length - 1)];' ' }' '}' 'module.exports = { ask };' >> model.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
計画するエージェントを書く(1)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'const PRICES = { \"おにぎり\": 150, \"お茶\": 140, \"パン\": 180 };' 'const messages = [' ' { role: \"system\", content: \"あなたは JSON だけで答えます。\" },' ' { role: \"user\", content: \"おにぎり、お茶、キウイの値段を調べる手順を計画してください。調べる商品を1つずつ入れた、3つの短い文字列の JSON 配列だけで答えてください。\" },' '];' '// 記録済みサンプル。どのモデルも答えないときだけ使います。' 'const sample = JSON.stringify([\"おにぎり\", \"お茶\", \"キウイ\"]);' > plan1.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
計画するエージェントを書く(2)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function step(text) {' ' const key = Object.keys(PRICES).find(function (k) { return text.indexOf(k) >= 0; });' ' if (key === undefined) return { ok: false, note: \"合う道具がありません: \" + text };' ' return { ok: true, note: key + \" は \" + PRICES[key] + \" 円\" };' '}' >> plan1.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
計画するエージェントを書く(3)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' const reply = await ask(messages, sample, 100);' ' let plan = null;' ' try { plan = JSON.parse(reply.slice(reply.indexOf(\"[\"), reply.lastIndexOf(\"]\") + 1)); } catch (error) { }' ' if (Array.isArray(plan) === false) { console.log(\"リストではないので、固定の計画を使います。\"); plan = [\"おにぎり\", \"お茶\"]; }' ' const budget = 3, maxFails = 2;' ' let used = 0, fails = 0, outcome = \"完了\";' ' for (const text of plan) {' ' if (used === budget) { outcome = \"予算切れ\"; break; }' ' used += 1;' ' const r = step(String(text));' ' fails = r.ok ? 0 : fails + 1;' ' console.log(\"ステップ \" + used + \": \" + r.note);' ' if (fails === maxFails) { outcome = \"行き詰まり\"; break; }' ' }' ' console.log(\"結果: \" + outcome + \" (\" + used + \" ステップ)\");' '}' 'main();' >> plan1.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
実行して結果を読む
docker exec -w /home/node/project agent node plan1.jsここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
出力の一例
| 行 | 表示されるかもしれないもの |
|---|---|
| ステップ 1 と 2 | おにぎりとお茶の値段 |
| ステップ 3 | 合う道具がありません: キウイ |
| 結果 | 3ステップで完了。失敗は1回で、2回続いていないため |
学生が入力するセルは、このプレビューでは空白です。
実行の終わり方は3つ
実行は、仕事が完了した、エージェントが行き詰まった、予算を使い切った、のどれかで終わります。結果ごとに、利用者へのメッセージも、記録の行も違います。
この順に調べます。許された最後のステップで終わった実行は、予算超過ではなく完了です。行き詰まりは、進まないまま失敗が続くことです。
よくある間違い
注意
「予算だけで停止ルールになる」と考える人が多くいます。予算は費用の上限にすぎず、完了と行き詰まりを区別できません。予算は最後の手段にして、完了と行き詰まりのルールを足します。