報告は主張の一覧
ワーカーの報告は主張の集まりで、各主張は出典から来たと言っています。答えが見つからないワーカーは、それらしい答えを書いてしまうことがよくあります。
オーケストレーターは、読んだだけでは違いが分かりません。各主張を、挙げられた出典と照らして確かめる必要があります。
このレッスンのゴール
メモ
ワーカーの報告が出典で裏づけられていないときを見分け、通らない主張に印を付けられる。
キーワード
| ことば | いみ |
|---|---|
| 主張 | 報告の中の、正しいか間違いかが言える1つの文 |
| 出典 | 主張がそこから来たと言っている文 |
| 裏づけられた | 出典が、主張の言うとおりのことを本当に言っている |
| レビュアー | 主張とその出典を読む、2つ目のエージェント |
| 抜き取り確認 | 決まった規則で選んだ少数の主張を、手で読むこと |
| 作り話 | ワーカーが空白を埋めるために作った主張 |
学生が入力するセルは、このプレビューでは空白です。
3つの確認、安いものから高いものへ
いちばん安いのはプログラムです。挙げられた出典はあるか、主張の数字はそこにあるか。作られた出典と、間違った数字を捕まえます。
次はレビュアーで、主張と出典を読むモデルです。いちばん高いのは人で、決まった規則で選んだ少数の主張を読みます。
例: 各確認が捕まえるもの
| 確認 | 捕まえるもの | 見逃すもの |
|---|---|---|
| プログラム: 出典と数字 | 作られた出典、間違った数字 | 意味を逆にした主張 |
| レビュアーのモデル | 逆の意味の多く | 自分の間違いと、同意しがちな癖 |
| 人による抜き取り | 他の2つが見逃したもの | 選ばれなかったもの全部 |
学生が入力するセルは、このプレビューでは空白です。
ワーカーが作り話をする理由
ワーカーは答えを出すことでほめられるので、手ぶらは失敗に見えます。答えなしも許す、と伝えておきます。材料に書かれていないときは「見つからない」と答える、と依頼に書くのです。
そして「見つからない」の数を数えます。1回もそう答えないワーカーは、作り話をしている可能性が高いです。
よくある間違い
注意
出典の記載を、証拠だと読む人が多くいます。出典を挙げた主張でも、その出典について間違っていることがあります。確かめるのは、出典がそう言っているかどうかです。出典を挙げているかではありません。
モデル用の補助を書く(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人が来館しました。\",' '};' 'const CLAIMS = [' ' { text: \"400人のうち212人が日曜開館を希望しました。\", source: \"s1\", terms: [\"日曜\", \"開館\", \"希望\"] },' ' { text: \"日曜の人件費は10800円です。\", source: \"s2\", terms: [\"日曜\", \"人件費\"] },' ' { text: \"先月の土曜の来館は410人でした。\", source: \"s3\", terms: [\"先月\", \"土曜\", \"来館\"] },' ' { text: \"多くの利用者が貸出期間の延長を望んでいます。\", source: \"s1\", terms: [\"貸出\", \"延長\", \"期間\"] },' ' { text: \"職員は日曜開館を公平だと考えています。\", source: \"s7\", terms: [\"職員\", \"日曜\", \"公平\"] },' ' { text: \"平日の来館のほうが土曜より多いです。\", source: \"s3\", terms: [\"平日\", \"来館\", \"土曜\", \"多い\"] },' '];' > check.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
主張の確認を書く(2)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function numbers(t) { return t.match(/[0-9]+/g) || []; }' 'function found(terms, text) {' ' return terms.filter(function (w) { return text.includes(w); }).length;' '}' >> check.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
主張の確認を書く(3)
docker exec -w /home/node/project agent sh -c "printf '%s\n' '// 安い確認: 出典があり、数字が合い、言葉の半分以上が出典にある。' 'function why(c) {' ' const text = SOURCES[c.source];' ' if (text === undefined) return \"出典がありません\";' ' const have = numbers(text);' ' if (numbers(c.text).some(function (n) { return have.includes(n) === false; })) return \"数字が出典にありません\";' ' return 2 * found(c.terms, text) >= c.terms.length ? \"\" : \"言葉が出典にありません\";' '}' >> check.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
主張の確認を書く(4)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' CLAIMS.forEach(function (c, i) {' ' console.log((i + 1) + \" \" + (why(c) === \"\" ? \"確認を通過\" : \"要注意: \" + why(c)));' ' });' ' console.log(\"抜き取り確認、3件に1件: \" + [1, 4].join(\"、\"));' ' const c = CLAIMS[5];' ' const q = [{ role: \"user\", content: \"出典: \" + SOURCES.s3 + \" 主張: \" + c.text + \" 出典は主張を裏づけていますか。はいかいいえで答えてください。\" }];' ' const r = await ask(q, \"いいえ\", 10);' ' console.log(\"主張6についてのレビュアー: \" + r.text.trim());' '}' 'main();' >> check.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
主張の確認を実行する
docker exec -w /home/node/project agent node check.jsここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
プログラムに見えないもの
主張6は、平日の来館のほうが土曜より多いと言っています。出典は逆のことを言っています。言葉が合っているので、プログラムは通してしまいます。意味を読めるのは、レビュアーか人だけです。
ライブ呼び出しは、この主張についてレビュアーに尋ねます。答えは実行のたびに変わりえますし、間違うこともあります。
出力の一例
| 行 | 何を示すか |
|---|---|
| 1 確認を通過、2 確認を通過 | 数字も言葉も合っている |
| 3 要注意: 数字が出典にありません | 主張は410、出典は310 |
| 4 要注意: 言葉が出典にありません | 出典には貸出の話がない |
| 5 要注意: 出典がありません | 存在しない s7 を挙げている |
| 6 確認を通過 | 意味が逆なのに通った |
| 抜き取り確認、3件に1件: 1、4 | 3件に1件を手で読む。1番目と4番目の主張 |
| 主張6についてのレビュアー: … | 2つ目の意見であり、証拠ではない |
学生が入力するセルは、このプレビューでは空白です。