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

無料レッスン

幻覚率を測る

このレッスンのあとで: 答えが原文にないことを言う頻度を、測れる。

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

答えは、どれくらい事実を作るか

幻覚とは、答えの中の主張で、原文が裏づけていないもののことです。図書館の案内ボットが、9時開館なのに 8 時と言えば、幻覚です。

これを管理するには、率として測り、その率がどれくらい確かかを言います。

このレッスンのゴール

メモ

答えが原文にないことを言う頻度を、測れる。

キーワード

ことばいみ
主張答えの中で述べられた一つの事実
原文答えが頼るべき文章
裏づけなし原文が支えていない主張
率全部の主張に対する、裏づけなしの主張の割合
区間本当の率が入っているかもしれない幅

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

主張を一つずつ原文と照らす

答えを、事実一つずつの主張に分けます。主張ごとに、原文がそう言っているかを調べます。

最初の一通りは、キーワードで行います。日本語には言葉の間の空白がないので、キーワードが原文の中にそのまま入っているかを見ます。一つでも入っていなければ、裏づけなしです。

例: 一つの原文と四つの主張

主張キーワード原文に入っているか判定
9 時に開く9時、開き両方入っている裏づけあり
パソコンは 20 台パソコン、20台20台がない裏づけなし
遅れると 1 日 20 円20円、1日両方入っている裏づけあり
日曜日も開く日曜ない裏づけなし

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

この規則の限界を知る

キーワードの規則は、ごく単純です。原文に 12 台とあれば、2 台というキーワードも、文字の並びとして入っています。言葉は合っていても、意味は違うのです。

正しい言葉を並べた間違いも見逃します。だから、最初の一通りとして使い、疑わしいものは人が読みます。

率は、数を数で割ったもの

裏づけなしの主張を数え、全部の主張で割り、パーセントで書きます。8 件のうち 3 件なら、37.5 パーセントです。

数えるのは答えでなく、主張です。主張が五つあって一つが嘘の答えは、五つのうち悪いものが一つです。

再抽出で、率のあらさを見る

40 件の主張を、裏づけありは 0、裏づけなしは 1 として並べます。その列から 40 回、引いたものを元に戻しながら引き、1 を数えます。

これを 200 回くり返し、数を小さい順に並べます。6 番目と 195 番目が、幅の両端です。種を決めておくと、引き方は毎回同じです。

例: 40 件のうち 6 件が裏づけなし

手順結果
主張の数と、裏づけなしの数40 件と 6 件
率15 パーセント
幅の低い端の数2、つまり 5 パーセント
幅の高い端の数10、つまり 25 パーセント
報告すること15 パーセント、幅は 5 から 25

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

よくある間違い

注意

40 件のうち 6 件が裏づけなしなら、本当の率はちょうど 15 パーセントだと考える人が多いです。それは、この標本が示す値にすぎません。別の 40 件なら、10 にも 20 にもなります。率は区間と一緒に報告しましょう。

助っ人 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 source = \"みなと図書館は、平日の9時に開き、17時に閉まります。パソコンは12台あります。会員は6冊を3週間まで借りられます。遅れた本は、1日20円かかります。\";' 'const claims = [' '  [\"9時\", \"開き\"], [\"17時\", \"閉まり\"], [\"パソコン\", \"12台\"], [\"パソコン\", \"20台\"],' '  [\"6冊\", \"借り\"], [\"4週間\"], [\"20円\", \"1日\"], [\"日曜\"],' '];' > rate.js"

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

率と区間を書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function supported(needs) {' '  return needs.every(function (w) { return source.indexOf(w) >= 0; });' '}' 'const bad = claims.filter(function (c) { return supported(c) === false; });' 'const flags = \"0001000001000001000000100000100000010000\".split(\"\").map(Number);' >> rate.js"

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

率と区間を書く(3)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function interval(list, seed) {' '  const n = list.length;' '  const counts = [];' '  let s = seed;' '  for (let r = 0; r < 200; r++) {' '    let total = 0;' '    for (let k = 0; k < n; k++) { s = (s * 16807) % 2147483647; total += list[s % n]; }' '    counts.push(total);' '  }' '  counts.sort(function (a, b) { return a - b; });' '  return [counts[5] * 100 / n, counts[194] * 100 / n];' '}' >> rate.js"

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

率と区間を書く(4)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  console.log(\"裏づけなし: \" + claims.length + \" 件中 \" + bad.length + \" 件 (\" + (bad.length * 100 / claims.length) + \" パーセント)\");' '  const ones = flags.filter(function (f) { return f === 1; }).length;' '  const span = interval(flags, 12345);' '  console.log(\"大きなテスト: \" + flags.length + \" 件中 \" + ones + \" 件 = \" + (ones * 100 / flags.length) + \" パーセント\");' '  console.log(\"区間: \" + span[0] + \" から \" + span[1] + \" パーセント\");' '  const q = \"原文には、図書館は9時に開く、とあります。次の主張は原文で裏づけられますか。「8時に開く」。短く一文で答えてください。\";' '  const sample = \"いいえ、原文は9時に開くと書いているので、その主張は裏づけられません。\";' '  const reply = await ask([{ role: \"user\", content: q }], sample, 80);' '  console.log(\"モデル: \" + reply.text);' '}' 'main();' >> rate.js"

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

率と区間を動かす

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

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

Run の出力

行意味
裏づけなし: 8 件中 3 件 (37.5 パーセント)8 件の主張へのキーワード確認
大きなテスト: 40 件中 6 件 = 15 パーセント記録した 40 件の主張
区間: 5 から 25 パーセント再抽出で出した幅
モデル: ...ラボからの本物の確認一つ。答えがなければ記録済みサンプル

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

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

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