例を見せると意図が伝わる
数個の例をプロンプトに入れる方法を、フューショットといいます。モデルは見たパターンをまねるので、例がラベルの付け方と書き方を教えます。
例は誤解も生みます。「良い」が四つ、「悪い」が一つのプロンプトは、感想の大半が良いと教えてしまいます。
このレッスンのゴール
メモ
モデルに意図が伝わる例を選べます。
キーワード
| ことば | いみ |
|---|---|
| 例 | 入力と、望む答えの組 |
| ラベル | 例に付ける答え |
| クラス | モデルが選べるラベルの一つ |
| バランス | 各クラスが同じ程度に出ること |
| フューショット | 数個の例を入れたプロンプト |
| ゼロショット | 例を入れないプロンプト |
学生が入力するセルは、このプレビューでは空白です。
例はいくつ要るか
例がなければ、モデルは仕事の一般的な感覚で答えます。例が一つあれば、形が決まります。二、三個あれば、幅が見えます。五、六個を超えると、増やしてもトークンが増えるだけです。
互いにちがう例を選んでください。そっくりな三つの例は、一つと同じことしか教えません。
同じラベルで、偏りの有無
| 例の組 | 良い | 悪い | モデルが学ぶこと |
|---|---|---|---|
| 偏りあり | 4 | 1 | 大半が良いので、良いと答える |
| バランスよし | 2 | 2 | 両方のラベルがよくある |
| クラスが欠ける | 3 | 0 | 悪い感想は存在しない |
学生が入力するセルは、このプレビューでは空白です。
モデル用の補助を書く(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 examples = [' ' { text: \"温かくておいしい\", label: \"良い\" },' ' { text: \"ご飯が冷めていた\", label: \"悪い\" },' ' { text: \"量が多くて満足\", label: \"良い\" },' ' { text: \"店員さんが親切\", label: \"良い\" },' ' { text: \"待たずに出てきた\", label: \"良い\" },' '];' > ex2.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
例の集計を書く(2)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function counts(list) {' ' const out = {};' ' for (const e of list) out[e.label] = (out[e.label] || 0) + 1;' ' return out;' '}' 'function buildPrompt(list, text) {' ' const blocks = list.map(function (e) { return \"文: \" + e.text + \"\nラベル: \" + e.label; });' ' blocks.push(\"文: \" + text + \"\nラベル:\");' ' return \"学食の感想に「良い」か「悪い」を付けてください。\n\n\" + blocks.join(\"\n\n\");' '}' >> ex2.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
例の集計を書く(3)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' const c = counts(examples);' ' console.log(\"数: 良い \" + c[\"良い\"] + \"、悪い \" + c[\"悪い\"]);' ' for (const name of Object.keys(c)) {' ' if (c[name] * 2 > examples.length) console.log(\"警告: 「\" + name + \"」が例の半分を超えています\");' ' }' ' const prompt = buildPrompt(examples, \"味が薄くて残念\");' ' const reply = await ask([{ role: \"user\", content: prompt }], \"悪い\", 10);' ' console.log(\"モデル: \" + reply.text);' '}' 'main();' >> ex2.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
ラベルを数えて実行する
docker exec -w /home/node/project agent node ex2.jsここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
Run が表示するもの
最初の行はラベルの数で、良い 4、悪い 1 です。次の行は、「良い」が例の半分を超えているという警告です。こうした組がモデルに届く前に、この検査が見つけます。
最後の行は、短い答えです。モデルがなければ、先に「記録済みサンプル」と出ます。
よくある間違い
注意
「例の順番は関係ない」と考えがちです。モデルは最後の例に引かれることが多く、それが悪い例なら、新しい入力も悪いと言われやすくなります。最後がいつも同じクラスにならないよう、混ぜてください。