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

無料レッスン

合成した評価データを作る

このレッスンのあとで: 種から新しい事例を作り、それが写しでないと言える。

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

ずるをせずに、事例を作る

合成した評価データとは、プログラムが作った事例のことです。千件の事例を手で書くのは大変なので、型から作るチームが多くいます。

作った事例は、重なったり、自分の答えを漏らしたりします。このレッスンでは、種から事例を作り、悪いものを取り除きます。

このレッスンのゴール

メモ

種から新しい事例を作り、それが写しでないと言える。

キーワード

ことばいみれい
型空所を埋めて使う文{item}を取り替えたいです
種生成を毎回同じにする、始めの数
近い重複ほかの事例とほとんど同じ事例
漏れ自分の答えや、学習用の文章を漏らす事例
似ている度合い二つの文が共通して持つ文字の組の割合

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

型と種が、事例を作る

型とは、空所のある文です。たとえば「{item}を取り替えたいです」です。空所は、品物の一覧から埋めます。型ごとに、良い機能が出すべき答え、ラベルを付けておきます。

種とは、数え役を動かし始める数です。同じ種からは、いつも同じ型と品物が選ばれるので、事例は繰り返せます。

例: 種のある生成

手順何が起こるか
始める種が最初の数になる
引く16807 を掛け、2147483647 で割った余りを取る
選ぶその数を一覧の大きさで割った余りで選ぶ
埋める選んだ品物を空所に入れる
くり返す同じ種なら、毎回同じ事例ができる

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

近い重複は、集まりを大きく見せる

一語しか違わない二つの事例からは、新しいことを学べません。日本語は 2 文字ずつの組にして、共通する組を数えます。それを、二つの文の組を合わせた種類の数で割ります。重なった組は一度だけ数えます。

80 パーセント以上なら、近い重複とします。最初の事例を残し、あとの事例をはねます。

よくある間違い

注意

作った事例が多ければ、いつも良いテストになると考える人が多いです。多くが写しなら、集まりは見た目より小さいのです。近い重複でない事例だけを数えましょう。

二つの漏れが、テストをだめにする

答えの漏れとは、事例が自分のラベルを含むことです。ラベルが返金の事例に「返金してください」と書くと、機能は、その言葉を見つけるだけで通れます。

学習用の文章の漏れとは、機能がすでに見た文章と事例が合うことです。それで点数が高くても、力ではなく、記憶を示すだけです。

助っ人 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 templates = [' '  [\"{item}が{fault}届きました。お金を返してほしいです\", \"返金\"],' '  [\"{item}を返金してください。{fault}届きました\", \"返金\"],' '  [\"{item}はどこにありますか。まだ届いていません\", \"配送\"],' '  [\"{item}を色違いのものと取り替えたいです\", \"交換\"],' '  [\"{item}が{fault}しまい、代金を戻してほしいです\", \"返金\"],' '  [\"{item}の注文の状況を教えてください\", \"配送\"],' '];' 'const items = [\"やかん\", \"ランプ\", \"マフラー\", \"マグカップ\"];' 'const faults = [\"壊れて\", \"傷ついて\", \"割れて\"];' 'const train = [\"やかんはどこにありますか。まだ届いていません\", \"ランプを色違いのものと取り替えたいです\"];' > synth.js"

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

生成のプログラムを書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'let s = 23;' 'function next(size) { s = (s * 16807) % 2147483647; return s % size; }' 'function generate(n) {' '  const out = [];' '  for (let i = 1; i <= n; i++) {' '    const t = templates[next(templates.length)];' '    let text = t[0];' '    if (text.indexOf(\"{item}\") >= 0) text = text.replace(\"{item}\", items[next(items.length)]);' '    if (text.indexOf(\"{fault}\") >= 0) text = text.replace(\"{fault}\", faults[next(faults.length)]);' '    out.push({ id: i, text: text, label: t[1] });' '  }' '  return out;' '}' >> synth.js"

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

生成のプログラムを書く(3)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function pairs(text) {' '  const t = text.toLowerCase().replace(/[、。?! ,.?]/g, \"\");' '  const out = [];' '  for (let i = 0; i + 1 < t.length; i++) {' '    const p = t.slice(i, i + 2);' '    if (out.indexOf(p) < 0) out.push(p);' '  }' '  return out;' '}' 'function similarity(a, b) {' '  const wa = pairs(a);' '  const wb = pairs(b);' '  const shared = wa.filter(function (w) { return wb.indexOf(w) >= 0; }).length;' '  return Math.floor(shared * 100 / (wa.length + wb.length - shared));' '}' 'function near(text, list) {' '  return list.some(function (t) { return similarity(text, t) >= 80; });' '}' >> synth.js"

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

生成のプログラムを書く(4)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  const kept = [];' '  const reasons = {};' '  generate(12).forEach(function (c) {' '    let why = \"\";' '    if (c.text.indexOf(c.label) >= 0) why = \"答えが漏れている\";' '    else if (near(c.text, train)) why = \"学習用の文章が漏れている\";' '    else if (near(c.text, kept.map(function (k) { return k.text; }))) why = \"重複\";' '    if (why === \"\") kept.push(c);' '    else reasons[why] = (reasons[why] || 0) + 1;' '  });' >> synth.js"

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

生成のプログラムを書く(5)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' '  console.log(\"採用 \" + kept.length + \" 件 / 12 件\");' '  console.log(\"却下: \" + JSON.stringify(reasons));' '  console.log(\"最初に採用: \" + kept[0].text + \" -> \" + kept[0].label);' '  const sample = \"ラベルの言葉が、文章の中に入らないように、型を直します。\";' '  const q = \"一文で短く答えてください。作った事例が、自分の答えを漏らさないようにするには、どうしますか。\";' '  const reply = await ask([{ role: \"user\", content: q }], sample, 80);' '  console.log(\"モデル: \" + reply.text);' '}' 'main();' >> synth.js"

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

生成を動かす

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

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

Run の出力

行意味
採用 8 件 / 12 件確認のあとに残った事例
却下: {...}何件はねられ、理由は何か
最初に採用: ... -> ...きれいな事例一つと、そのラベル
モデル: ...ラボからの一文。答えがなければ記録済みサンプル

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

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

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