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

無料レッスン

模擬ユーザーでチャットボットを試験する

このレッスンのあとで: 台本どおりのユーザーで対話を試験し、会話を採点できる。

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

気持ちが変わるお客様

模擬ユーザーとは、アシスタントとの会話でお客様を演じるスクリプトです。必要な理由は、対話には唯一の正解がなく、試験用のチャットを手で打つ方法は、数が増えると続かないからです。

ミナさんは返金を頼み、注文を1つ挙げ、そのあと気持ちを変えます。アシスタントは付いていけるでしょうか。

このレッスンのゴール

メモ

台本どおりのユーザーで対話を試験し、会話を採点できる。

キーワード

ことばいみ
模擬ユーザーお客様を演じるスクリプト
人物像ユーザーが誰で、どう書くか
目的ユーザーが最後に望むこと
終了条件対話を止めるルール
記録会話全体を、1行ずつ並べたもの

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

ユーザーをスクリプトとして書く

ユーザーに人物像、目的、発言の一覧を与えます。さらに終了条件を加えます。さようならの一言や、ターン数の上限などで、対話が必ず止まるようにするためです。

スクリプトなら、実行のたびに同じユーザーになります。モデルがユーザーを演じると、毎回変わり、1行ごとにクレジットを使い、失敗を再現しにくくなります。まずスクリプトから始めます。

例: ミナさんの4行

行ミナさんの発言試すこと
1こんにちは、返金をお願いしますどの注文かを尋ねるか
2注文A17です返金を開始するか
3やっぱり注文B02にしてください気持ちの変化に対応するか
4ありがとう、さようなら対話を終えるか

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

返事ごとではなく、記録を採点する

記録全体で、3つを確かめます。目的は達成されたか。ターン数は上限以内か。動作は正しい回数だったか。

最後の確認が、目立たない欠点を見つけます。A17 の返金を開始し、さらに B02 の返金も開始するアシスタントは、目的を達成しながら、2回返金したことになります。

モデル用の補助を書く(1)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '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 || 200 }),' '      signal: AbortSignal.timeout(30000),' '    });' '    if (res.ok === false) throw new Error(\"status \" + res.status);' '    return (await res.json()).choices[0].message.content;' > model.js"

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

モデル用の補助を書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' '  } catch (error) {' '    console.log(\"記録済みサンプル: モデルが答えませんでした (\" + error.message + \")。\");' '    const list = [].concat(sample);' '    const turn = messages.filter(function (m) { return m.role === \"assistant\"; }).length;' '    return list[Math.min(turn, list.length - 1)];' '  }' '}' 'module.exports = { ask };' >> model.js"

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

対話の進行役を書く(1)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' '// 台本どおりのユーザー: 人物像、目的、発言、そして3行目での気持ちの変化です。' 'const user = {' '  persona: \"ミナ。急いでいて、短いメッセージを書く\",' '  goal: \"注文B02の返金\",' '  lines: [\"こんにちは、返金をお願いします\", \"注文A17です\", \"やっぱり注文B02にしてください\", \"ありがとう、さようなら\"],' '};' '// 規則でできた代役のアシスタント。本物は、試験する対象のエージェントです。' 'function assistant(text) {' '  const order = text.match(/[AB][0-9][0-9]/);' '  if (order) return order[0] + \" の返金を開始しました。\";' '  if (text.includes(\"さようなら\")) return \"さようなら。\";' '  return \"注文番号を教えてください。\";' '}' > sim.js"

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

対話の進行役を書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function drive(maxTurns) {' '  const transcript = [];' '  for (let i = 0; i < user.lines.length && i < maxTurns; i = i + 1) {' '    transcript.push(\"ユーザー: \" + user.lines[i]);' '    const reply = assistant(user.lines[i]);' '    transcript.push(\"アシスタント: \" + reply);' '    if (reply.includes(\"さようなら\")) break;' '  }' '  return transcript;' '}' 'const transcript = drive(6);' 'transcript.forEach(function (line) { console.log(line); });' 'const refunds = transcript.filter(function (line) { return line.includes(\"返金を開始しました\"); });' >> sim.js"

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

対話の進行役を書く(3)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'console.log(\"目的の達成: \" + transcript.join(\" \").includes(\"B02 の返金を開始しました\"));' 'console.log(\"使ったターン: \" + transcript.filter(function (line) { return line.startsWith(\"ユーザー\"); }).length);' 'console.log(\"開始された返金: \" + refunds.length + \" (ユーザーが望んだのは1件)\");' 'async function main() {' '  const system = \"あなたは店のサポートアシスタントです。返金の前に、必ず注文番号を尋ねてください。短く答えてください。\";' '  const sample = \"かしこまりました。注文番号を教えてください。\";' '  const text = await ask([{ role: \"system\", content: system }, { role: \"user\", content: user.lines[0] }], sample, 60);' '  console.log(\"ライブの返事: \" + text.trim());' '  console.log(\"注文について尋ねている: \" + text.includes(\"注文\"));' '}' 'main();' >> sim.js"

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

ミナさんでアシスタントを動かす

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

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

進行役が表示するもの

行示すこと
記録ユーザーの4行とアシスタントの4行
目的の達成true
使ったターン4
開始された返金2件。ユーザーが望んだのは1件
ライブの返事出力例: 注文についての質問

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

試してみましょう

ヒント

sim.js で3行目の「やっぱり注文B02にしてください」を取り除いて、もう一度実行します。開始された返金は1件になりますが、目的は達成されません。その理由を説明します。

よくある間違い

注意

最後の返事がもっともらしければ、対話は合格だと考える人がいます。2回の返金のあとに、丁寧なさようならが来ることもあります。アシスタントが記録全体で何をしたかを採点します。目的、動作、ターン数です。

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

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