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

無料レッスン

オーケストレーターとワーカー

このレッスンのあとで: 仕事を、それだけで通じる依頼に分け、結合する前に各結果を確かめられる。

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

ワーカーは依頼しか知らない

オーケストレーターとワーカーの型は、1つのエージェントが仕事を依頼に分け、ワーカーに渡し、結果をまとめるプログラムです。ワーカーは、依頼に書かれたこと以外を何も知りません。

あいまいな依頼からは、間違った質問への自信たっぷりの答えが返ります。それだけで通じる依頼からは、確かめられる答えが返ります。

このレッスンのゴール

メモ

仕事を、それだけで通じる依頼に分け、結合する前に各結果を確かめられる。

キーワード

ことばいみ
依頼ワーカーが受け取るすべて。質問、材料、答えの形
結果の形ワーカーが返さなければならない項目
材料ワーカーが答えに使ってよい文
検証結果を使う前に確かめること
結合受理した結果をまとめること
知らない出典ワーカーが挙げたが、渡されていない出典

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

依頼に入れるもの

ワーカーには、仕事全体も、他の依頼も、会話も見えません。依頼にないものは、存在しないのと同じです。

ですから依頼には、質問、使ってよい材料、答えの形、大きさの上限を入れます。材料は文そのものです。ワーカーが探しに行ってくれる、という約束ではありません。

例: 1つの依頼

項目例入れる理由
question日曜1日の人件費はいくらですか。仕事全体ではなく1つの質問
material人件費の表を、文としてワーカーはそれ以外を使えない
sourcess2答えが出どころを言えるように
replyanswer と sources を持つオブジェクトオーケストレーターが確かめられるように

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

結合する前に結果を検証する

結果は、あなたが制御できない部分から来たデータです。まず形を確かめます。答えはあるか、出典のリストはあるか。次に、各出典が依頼で渡したものかを確かめます。

通ったものだけを結合します。エージェントを作るモジュールでは、エージェント間でメッセージを渡しました。ここでは、戻ってきたものを信じてよいかを決めます。

よくある間違い

注意

全部の結果を結合してから、あとで直す人が多くいます。すると悪い結果が、最終的な答えの中で良い結果と同じ重さを持ちます。入り口で却下して、理由を残してください。

モデル用の補助を書く(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\");' 'const SOURCES = {' '  s1: \"アンケート: 400人のうち212人が日曜開館を希望しました。\",' '  s2: \"人件費: 時給1800円で6時間働くと、日曜1日で10800円かかります。\",' '  s3: \"来館数: 先月、土曜は310人、平日は120人が来館しました。\",' '};' '// 依頼には、ワーカーが使えるものがすべて入っています。質問と、文です。' 'function brief(id, question, ids) {' '  const material = ids.map(function (i) { return SOURCES[i]; });' '  return { id: id, question: question, sources: ids, material: material, reply: \"answer と sources を持つオブジェクト\" };' '}' > team.js"

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

オーケストレーターを書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' '// 台本どおりのワーカー。各自、自分の依頼だけを見ます。' 'const WORKERS = {' '  b1: function (b) { return { answer: \"400人中212人が希望しています\", sources: [\"s1\"] }; },' '  b2: function (b) { return { answer: \"日曜1日で10800円です\", sources: [\"s2\"] }; },' '  b3: function (b) { return { answer: \"週末は混みます\", sources: [\"s9\"] }; },' '};' 'function problems(b, r) {' '  const out = [];' '  const full = typeof r.answer === \"string\" && r.answer.trim().length > 0;' '  if (full === false) out.push(\"答えがありません\");' '  if (Array.isArray(r.sources) === false || r.sources.length === 0) out.push(\"出典がありません\");' '  else r.sources.forEach(function (s) { if (b.sources.includes(s) === false) out.push(\"知らない出典 \" + s); });' '  return out;' '}' >> team.js"

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

オーケストレーターを書く(3)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  const own = \"週末の1日に、図書館はどれくらい混みますか。\";' '  const q = [{ role: \"user\", content: \"週末の図書館の混み具合について、短い調査の質問を1つ書いてください。\" }];' '  const text = (await ask(q, own, 30)).text.trim();' '  const briefs = [' '    brief(\"b1\", \"日曜開館を希望する来館者は何人ですか。\", [\"s1\"]),' '    brief(\"b2\", \"日曜1日の人件費はいくらですか。\", [\"s2\"]),' '    brief(\"b3\", text.length >= 5 && text.length <= 60 ? text : own, [\"s3\"]),' '  ];' '  for (const b of briefs) {' '    const r = WORKERS[b.id](b);' '    const p = problems(b, r);' '    console.log(b.id + \" [出典\" + b.material.length + \"件] \" + b.question);' '    console.log(\"   \" + (p.length ? \"却下: \" + p.join(\"、\") : \"受理: \" + r.answer));' '  }' '}' 'main();' >> team.js"

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

オーケストレーターを実行する

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

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

ワーカーは台本どおり

ラボにあるモデルは1つだけです。本物のチームは、1つのモデルが全部の役を演じることになります。ここの3人のワーカーは、記録済みの答えを返す普通の関数です。ライブ呼び出しは、調査の質問文を作らせるだけです。

本物のシステムは、各依頼をモデルに送ります。確かめる部分は同じです。

出力の一例

行何を示すか
b1 [出典1件] 日曜開館を希望する来館者は何人ですか。材料つきの依頼
受理: 400人中212人が希望しています形も出典も通った
b2 [出典1件] 日曜1日の人件費はいくらですか。2つ目の依頼
受理: 日曜1日で10800円です2人目のワーカーも通った
b3 [出典1件] 週末の1日に、図書館はどれくらい混みますか。3つ目の質問文はモデルが作るので、実行のたびに変わる
却下: 知らない出典 s93人目は、渡されていない出典を挙げた

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

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

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