出す前のチェックリスト
安全の見直しは、エージェントを使う前に、その設計をチェックリストに照らして確かめます。どの項目も「はい」か「いいえ」で答える問いなので、二人が見ても同じ結果になります。
このモジュールのレッスンは、すべてそろって初めて役に立ちます。フォルダはよくても、止める方法がない設計は、やはり安全ではありません。
このレッスンのゴール
メモ
エージェントの設計を、チェックリストに照らして見直すことができる。
キーワード
| ことば | いみ |
|---|---|
| チェックリスト | 「はい」か「いいえ」で答える問いの、決まった一覧 |
| 設計 | エージェントが持つツール、データ、上限 |
| 上限 | 手順や費用の、上の限り |
| 停止スイッチ | 人がエージェントを止める方法 |
| ログ | エージェントがしたことの記録 |
学生が入力するセルは、このプレビューでは空白です。
六つの分野、八つの問い
チェックリストは六つの分野にわたります。ツール、データ、フォルダ、上限、止める方法、そして記録です。どの分野にも、「はい」か「いいえ」の問いが一つ以上あります。
すべての問いに通って初めて、設計は合格です。失敗は分野と一緒に報告すると、直す場所が見つけやすくなります。
例: 三つの設計
| 設計 | 失敗 | どれか |
|---|---|---|
| helper | 0 | なし: 合格 |
| builder | 4 | shell がある、どこにでも書ける、手順の上限なし、ログなし |
| scout | 5 | 許可リストなし、プロンプトに秘密、上限なし、停止なし |
学生が入力するセルは、このプレビューでは空白です。
よくある間違い
注意
強い対策が一つあれば、設計は安全だ、と考える人が多いです。そうではありません。builder には許可リストと停止スイッチがありますが、どこにでも書けます。安全は層でできていて、足りない層のうち、一番弱いところから先に破られます。
数には境目が要る
上限は、境目があって初めて確認になります。ここでは、実行は多くて 20 手までです。20 の設計は合格で、21 の設計や、上限のない設計は失敗です。
境目がどこかを言い、両側で試し、値がないときは失敗として扱います。
助っ人 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 checks = [' ' [\"ツール: 許可リストがない\", function (d) { return d.allowlist === false; }],' ' [\"ツール: shell がある\", function (d) { return d.tools.indexOf(\"shell\") >= 0; }],' ' [\"フォルダ: 書き込みが閉じ込められていない\", function (d) { return d.canWrite && (d.root === \"\" || d.root === \"/\"); }],' ' [\"データ: プロンプトに秘密がある\", function (d) { return d.secrets; }],' ' [\"上限: 手順の上限がない\", function (d) { return d.maxSteps === null || d.maxSteps > 20; }],' ' [\"上限: 費用の上限がない\", function (d) { return d.maxCost === null; }],' ' [\"停止: 止める方法がない\", function (d) { return d.stop === false; }],' ' [\"記録: ログがない\", function (d) { return d.log === false; }],' '];' 'function failures(d) { return checks.filter(function (c) { return c[1](d); }).map(function (c) { return c[0]; }); }' > review.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
設計の確認を書く(2)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const designs = [' ' { name: \"helper\", tools: [\"read\", \"write\"], allowlist: true, canWrite: true, root: \"work/\", secrets: false, maxSteps: 10, maxCost: 5, stop: true, log: true },' ' { name: \"builder\", tools: [\"read\", \"write\", \"shell\"], allowlist: true, canWrite: true, root: \"/\", secrets: false, maxSteps: null, maxCost: 20, stop: true, log: false },' ' { name: \"scout\", tools: [\"search\"], allowlist: false, canWrite: false, root: \"\", secrets: true, maxSteps: 50, maxCost: null, stop: false, log: true },' '];' >> review.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
設計の確認を書く(3)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' designs.forEach(function (d) {' ' const f = failures(d);' ' console.log(d.name + \": 失敗 \" + f.length + \"件\" + (f.length > 0 ? \": \" + f.join(\"; \") : \"\"));' ' });' ' const q = \"短く一文で答えてください。エージェントに止める方法がなければいけないのは、なぜですか。\";' ' const sample = \"うまくいかなくなったとき、人がすぐに止めて、何をしたかを確かめられなければいけないからです。\";' ' const reply = await ask([{ role: \"user\", content: q }], sample, 80);' ' console.log(\"モデル: \" + reply.text);' '}' 'main();' >> review.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
設計の確認を動かす
docker exec -w /home/node/project agent node review.jsここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
Run の出力
| 行 | 意味 |
|---|---|
| helper: 失敗 0件 | すべての確認に通った |
| builder: 失敗 4件: ツール: shell がある; ... | 四つの分野で失敗する |
| scout: 失敗 5件: ツール: 許可リストがない; ... | 一番多く失敗する |
| モデル: ... | 一文。言葉は毎回変わる |
学生が入力するセルは、このプレビューでは空白です。