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

無料レッスン

AI エージェントの計画と停止

このレッスンのあとで: エージェントにステップを計画させ、ルールで止められる。

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

終わらなかったエージェント

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つ

実行は、仕事が完了した、エージェントが行き詰まった、予算を使い切った、のどれかで終わります。結果ごとに、利用者へのメッセージも、記録の行も違います。

この順に調べます。許された最後のステップで終わった実行は、予算超過ではなく完了です。行き詰まりは、進まないまま失敗が続くことです。

よくある間違い

注意

「予算だけで停止ルールになる」と考える人が多くいます。予算は費用の上限にすぎず、完了と行き詰まりを区別できません。予算は最後の手段にして、完了と行き詰まりのルールを足します。

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

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