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

無料レッスン

マルチエージェントの失敗の型

このレッスンのあとで: やり取りの中の失敗を見つけ、その種類を言える。

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

チームは1つのエージェントと違う壊れ方をする

マルチエージェントの失敗とは、エージェントのチームが、単独のエージェントなら起こさない形で道を外れることです。欠陥はエージェント同士の会話にあるので、1つずつ見ると、どれも正常に見えます。

見つけるには、やり取りの記録を読みます。送られたメッセージの一覧です。

このレッスンのゴール

メモ

やり取りの中の失敗を見つけ、その種類を言える。

キーワード

ことばいみ
やり取りの記録エージェントが送ったメッセージを、順に並べたもの
繰り返し同じメッセージが何度も送られること
にらみ合い2つのエージェントが、互いに相手を待つこと
暴走するコスト予算を超えて増え続けるトークンの使用
推測が事実に推測が、あとで事実として繰り返されること
防止策失敗を早く止める、コードの中の規則

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

チームが道を外れる4つの形

繰り返しは、同じメッセージをくり返します。にらみ合いは、2つのエージェントが、相手が先に動くのを待ちます。暴走するコストは、毎ラウンドがそれまでの全履歴を読むので増え続けます。

4つ目は、気づきにくい形です。ワーカーが推測し、次のエージェントが推測を繰り返し、3つ目では事実として書かれます。

例: 兆候と防止策

失敗記録に出る兆候防止策
繰り返し (loop)同じ送り手、受け手、文が3回3回目の繰り返しで止める
にらみ合い (deadlock)「待機中」で始まる2つのメッセージが逆向き時間の上限と、先に動く側の決め方
推測が事実に (passed-on)推測のあと、同じ文が事実として出る状態を主張と一緒に運ぶ
暴走 (runaway)ラウンドごとのトークンが増え続ける実行全体の予算

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

はっきりした兆候から調べる

実際のやり取りには、兆候が複数出ることがあります。順番を決めて、それを守ります。にらみ合いも繰り返しも仕事を止めるので、コストより先に名づけます。

エージェントを作るモジュールでは、繰り返しの防止策を扱いました。このレッスンは、4つとも見分けることが目的です。どの防止策を足すかを決めるためです。

よくある間違い

注意

チームが止まると、リトライを足す人が多くいます。リトライは繰り返しを長くしますが、にらみ合いは短くしません。先に失敗に名前を付け、それに合う防止策を選んでください。

モデル用の補助を書く(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\");' 'function m(from, to, text, tokens, status) {' '  return { from: from, to: to, text: text, tokens: tokens, status: status };' '}' 'const T = {};' 'T.loop = [m(\"書き手\", \"確認役\", \"下書きを確認して\", 300, \"none\"), m(\"確認役\", \"書き手\", \"出典を足して\", 200, \"none\"),' '  m(\"書き手\", \"確認役\", \"下書きを確認して\", 300, \"none\"), m(\"確認役\", \"書き手\", \"出典を足して\", 200, \"none\"),' '  m(\"書き手\", \"確認役\", \"下書きを確認して\", 300, \"none\")];' 'T.deadlock = [m(\"計画役\", \"査読役\", \"待機中 査読を待ってから計画します\", 150, \"none\"),' '  m(\"査読役\", \"計画役\", \"待機中 計画を待ってから査読します\", 150, \"none\")];' > fail.js"

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

失敗の検出を書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'T.passed = [m(\"読み手\", \"計画役\", \"土曜の来館が4割増えた\", 200, \"guess\"),' '  m(\"計画役\", \"書き手\", \"土曜の来館が4割増えた\", 200, \"fact\")];' 'T.grows = [m(\"a\", \"b\", \"第1ラウンド\", 1000, \"none\"), m(\"b\", \"a\", \"第2ラウンド\", 2000, \"none\"), m(\"a\", \"b\", \"第3ラウンド\", 4000, \"none\"),' '  m(\"b\", \"a\", \"第4ラウンド\", 8000, \"none\"), m(\"a\", \"b\", \"第5ラウンド\", 16000, \"none\")];' 'T.fine = [m(\"計画役\", \"読み手\", \"日曜の需要を調べて\", 200, \"none\"), m(\"読み手\", \"計画役\", \"400人中212人\", 150, \"fact\")];' >> fail.js"

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

失敗の検出を書く(3)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function some2(ms, test) {' '  return ms.some(function (x, i) { return ms.some(function (y, j) { return i < j && test(x, y); }); });' '}' 'function deadlock(ms) {' '  return some2(ms, function (x, y) {' '    return x.text.startsWith(\"待機中\") && y.text.startsWith(\"待機中\") && x.from === y.to && x.to === y.from;' '  });' '}' 'function loop(ms) {' '  return ms.some(function (x) {' '    return ms.filter(function (y) { return y.from === x.from && y.to === x.to && y.text === x.text; }).length >= 3;' '  });' '}' >> fail.js"

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

失敗の検出を書く(4)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function passedOn(ms) {' '  return some2(ms, function (x, y) { return x.status === \"guess\" && y.status === \"fact\" && x.text === y.text; });' '}' 'function total(ms) { return ms.reduce(function (a, x) { return a + x.tokens; }, 0); }' 'function find(ms, budget) {' '  if (deadlock(ms)) return \"deadlock\";' '  if (loop(ms)) return \"loop\";' '  if (passedOn(ms)) return \"passed-on\";' '  return total(ms) > budget ? \"runaway\" : \"none\";' '}' >> fail.js"

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

失敗の検出を書く(5)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  for (const name of Object.keys(T)) {' '    console.log(name + \": \" + T[name].length + \"件、\" + total(T[name]) + \"トークン、判定 \" + find(T[name], 20000));' '  }' '  const q = [{ role: \"user\", content: \"2つのエージェントが同じメッセージを永遠に送り合うのを防ぐ、簡単な規則を1文で答えてください。\" }];' '  const r = await ask(q, \"メッセージごとに数え、3回目の繰り返しで止めます。\", 40);' '  console.log(\"モデル: \" + r.text.trim());' '}' 'main();' >> fail.js"

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

失敗の検出を実行する

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

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

記録済みのやり取りです

本物の実行は、壊れたチーム1つでラボのクレジットを使い切ります。そのため5つのやり取りは、短く作った記録済みのデータです。検出関数は本物のコードです。

ライブ呼び出しは、規則を1つ頼むだけです。言葉は実行のたびに変わります。

出力の一例

行何を示すか
loop: 5件、1300トークン、判定 loop同じメッセージが3回
deadlock: 2件、300トークン、判定 deadlock互いに相手を待つ
passed: 2件、400トークン、判定 passed-on推測が事実になった
grows: 5件、31000トークン、判定 runaway予算20000を超えた
fine: 2件、350トークン、判定 none失敗の兆候なし

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

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

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