答えは、どれくらい事実を作るか
幻覚とは、答えの中の主張で、原文が裏づけていないもののことです。図書館の案内ボットが、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 パーセント | 再抽出で出した幅 |
| モデル: ... | ラボからの本物の確認一つ。答えがなければ記録済みサンプル |
学生が入力するセルは、このプレビューでは空白です。