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

無料レッスン

モデルの悪い答えを直す方法

このレッスンのあとで: 悪い答えを、エラーを知らせとして付け、数回だけ再試行できる。

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

何が悪かったかを伝える

修復ループとは、悪い答えのあとにもう一度聞き、違反を送り返して、モデルに直してもらうことです。問題を知っている2回目は、何も知らない再試行が失敗するところで、成功することがあるからです。

フォームの入力ツールに、スキーマが許さない言葉の返事が来ます。捨てれば、作業が無駄になります。違反をメッセージに入れてもう一度聞けば、たいてい救えます。

このレッスンのゴール

メモ

悪い答えを、エラーを知らせとして付け、数回だけ再試行できる。

キーワード

ことばいみ
修復ループ悪い答えのあとに、知らせを付けてもう一度聞くこと
知らせ新しいメッセージで送り返す、違反
再試行の上限許す、追加の回数の最大
代わりの値上限に達したときに使う、安全な値
メッセージのリスト呼び出しのたびに送る、会話
あきらめる止めて、代わりの値を使うこと

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

違反を送り返す

答えを直すには、それまでの会話をすべて付けて、もう一度聞きます。悪い答えを、アシスタントのメッセージとして足します。次に、違反を並べ、決まりを繰り返すユーザーのメッセージを足します。JSON だけで答える、という決まりです。

メッセージのリストは、毎回2つずつ増えます。モデルは、自分が何を言い、何が悪かったかを見ます。

例: 3回の挑戦

回返事見つけた違反次に送るもの
1たぶん、含まれます。JSON のオブジェクトではない違反と、JSON だけで答える決まり
2{"answer": "どちらとも言えない"}answer は はい か いいえ違反と、決まりをもう一度
3{"answer": "はい"}なし何も送らない。受け入れる

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

上限と、代わりの値

再試行には、そのたびに時間とクレジットがかかります。ですから再試行の上限を決めます。最初の1回と、あと2回までです。上限に達したらあきらめて、代わりの値を使います。

代わりの値は、「不明」のような安全な値か、人が見るエラーです。起きたことを記録しておくと、どのくらいの頻度か分かります。

モデル用の補助を書く(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 allowed = [\"はい\", \"いいえ\"];' 'const MAX_TRIES = 3; // 最初の1回と、あと2回まで' '' 'function pullJson(text) {' '  const start = text.indexOf(\"{\");' '  const end = text.lastIndexOf(\"}\");' '  if (start === -1 || end < start) return null;' '  try { return JSON.parse(text.slice(start, end + 1)); } catch (error) { return null; }' '}' > repair3.js"

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

修復ループを書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function problemsOf(text) {' '  const reply = pullJson(text);' '  if (reply === null) return [\"JSON のオブジェクトではない\"];' '  if (Object.prototype.hasOwnProperty.call(reply, \"answer\") === false) return [\"answer がない\"];' '  if (allowed.includes(reply.answer) === false) return [\"answer は はい か いいえ\"];' '  return [];' '}' >> repair3.js"

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

修復ループを書く(3)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function repairLoop(question, samples) {' '  const messages = [{ role: \"user\", content: question }];' '  for (let go = 1; go <= MAX_TRIES; go = go + 1) {' '    const reply = await ask(messages, samples, 60);' '    const found = problemsOf(reply);' '    console.log(go + \" 回目: \" + (found.length === 0 ? \"ok\" : found.join(\"、\")));' '    if (found.length === 0) return { ok: true, reply: pullJson(reply), tries: go };' '    messages.push({ role: \"assistant\", content: reply });' '    messages.push({ role: \"user\", content: \"次の問題を直し、JSON だけで答えてください。\" + found.join(\"、\") });' '  }' '  return { ok: false, reply: null, tries: MAX_TRIES };' '}' >> repair3.js"

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

修復ループを書く(4)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  const question = \"小麦粉にはグルテンが含まれますか。キー answer を持つ JSON オブジェクトだけで答えてください。answer の値は はい か いいえ です。\";' '  // 記録済みサンプル。モデルが答えないときだけ使う。悪い返事が2つ、そのあとに良い返事が1つ。' '  const samples = [\"たぶん、含まれます。\", JSON.stringify({ answer: \"どちらとも言えない\" }), JSON.stringify({ answer: \"はい\" })];' '  const result = await repairLoop(question, samples);' '  const fallback = { answer: \"不明\" };' '  console.log(\"使った回数:\", result.tries);' '  console.log(\"結果:\", JSON.stringify(result.ok ? { answer: result.reply.answer } : fallback));' '}' 'main();' >> repair3.js"

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

ループを実行する

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

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

出力の一例

行表示されるかもしれないもの
1 回目ok。モデルが最初から正しい JSON を返したとき
2 回目、3 回目1回目が失敗したときだけ。違反、または ok
記録済みサンプル: ...モデルが答えなかったときだけ、各回の前に1行ずつ出る
使った回数1から3までの数
結果返事、または代わりの値 {"answer":"不明"}

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

よくある間違い

注意

「うまくいくまで再試行すれば安全」と考える人が多くいます。モデルがいつまでも正しい形を出さなければ、上限のないループは終わらず、毎回、時間とクレジットがかかります。必ず上限を決め、代わりの値を先に決めてください。

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

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