次のレッスンからは、頼み方を工夫する技法に入っていきます。その前に、このレッスンだけ技法を扱いません。技法より先に、もっと地味で、もっと効く仕組みの話をします。評価です。
なぜ、技法より先に評価なのか
プロンプトを書いたあと、多くの人がたどる道は3つあります。そのまま放置する。なんとなく気になって勘で直す。そして、もっとも少ない道が、仕組みを作って確かめる、です。
2番目の「勘で直す」道でよく起きるのが、テストの罠です。手元で2つ3つの例を試し、答えが良さそうに見えたので、そのまま本番に出す。ところが本番では、手元で試した例とは少し違う入力が次々に来ます。想定していなかった書き方の質問、極端に短い入力、逆に長すぎる入力。手元の数例では見えていなかった崩れ方が、量をこなすうちに表面化します。
この罠が厄介なのは、「良くなった気がする」という感覚そのものが、あてにならないところです。プロンプトを直したあと、直した本人は「前より良くなった」と感じやすくなります。自分が意図して直した変更なので、その意図どおりに動いた例だけが目に入りやすいからです。一方で、直したことで新しく崩れた入力のパターンには、意図的に探しにいかない限り気づけません。
つまり、主観だけでは「良くなったか、悪くなったか」を判定できないというのが、評価を先に置く理由の核心です。技法(見本を渡す、XMLタグで構造化する、段階を踏ませる、など)はどれも効果があるとされていますが、「効果があるとされている」という一般論と、「自分のこの道具で、この入力に対して効果があった」という個別の事実は別物です。後者を確かめる手段を先に持っていないと、技法を1つ足すたびに、それが本当に効いたのか、たまたま今回の数例に合っただけなのかを見分けられません。
視点
順序が逆だと何が起きるか
評価の仕組みがないまま技法を重ねていくと、変更のたびに「良くなったはず」という感覚だけが積み重なります。半年後、プロンプトは長く複雑になっているのに、最初の頃より本当に良くなっているのかを誰も答えられない、という状態に陥りやすくなります。先に物差しを持っていれば、その都度スコアで確かめられます。
評価ループの5ステップ
評価は、一度作って終わりの装置ではなく、プロンプトを直すたびに回し続けるループです。
プロンプトを書く
最初の案。完璧である必要はない
評価データセットを作る
実際に来そうな入力を、幅を持たせて集める
Claudeに通す
データセットの全件を、今のプロンプトで実行する
採点する
1件ごとに、基準を満たしたかを判定する
直して繰り返す
採点結果を見て、狙いを絞って直す。02〜05を再び回す
評価データセットは、最初から完璧である必要はありません。まずは10〜20件ほど、実際の利用場面で来そうな入力を並べるところから始めます。典型的な入力だけでなく、短すぎる入力、情報が欠けた入力、意地悪な言い回しの入力も混ぜておくと、後になって気づく崩れ方を先に見つけられます。
採点の2つのやり方
「基準を満たしたか」の判定には、大きく2つの方法があります。
決定論的なコードで判定する。JSONとして正しくパースできるか、必須の項目が揃っているか、文字数の上限を超えていないか、といった機械的に確認できる基準に向く
評価基準を渡し、別のClaude呼び出しに「この答えは基準を満たしているか」を判定させる。トーンが適切か、必要な論点を網羅しているか、といった機械では測りにくい基準に向く
コード採点は速く、安く、同じ入力なら毎回同じ結果を返します。ただし、内容の質そのものは測れません。モデル採点は内容の質まで踏み込めますが、判定役のClaude自身にもぶれが生じます。実務では、形式面はコード採点、内容面はモデル採点、というように両方を組み合わせて使う場面が多くなります。
コード採点の最小例です。
def score_has_required_fields(answer_text):
required = ["会社名", "要件", "期限"]
return all(field in answer_text for field in required)
def run_eval(prompt_fn, test_cases):
results = []
for case in test_cases:
answer = prompt_fn(case["input"])
passed = score_has_required_fields(answer)
results.append({"input": case["input"], "passed": passed})
return results
モデル採点は、評価基準(ルーブリック)を文章にして、別のClaude呼び出しに渡す形になります。
def score_with_model(answer_text, rubric):
judge = client.messages.create(
model="claude-sonnet-5",
max_tokens=200,
messages=[{
"role": "user",
"content": f"次の基準に沿っているか、YESかNOだけで答えてください。\n\n基準: {rubric}\n\n答え: {answer_text}",
}],
)
text = next(b.text for b in judge.content if b.type == "text")
return text.strip().upper().startswith("YES")
やってみよう
演習1: 意地悪な入力を3つ考える
自分が作ろうとしている道具に対して、評価データセットに入れておくべき「意地悪な入力」を3つ考えてください。情報が欠けている、極端に短い、想定外の言い回し、といった崩れ方のもとになる入力です。
演習2: 採点方法を割り当てる
その道具が満たすべき基準を3つ挙げ、それぞれコード採点とモデル採点のどちらで測るべきかを考えてください。形式的に確認できる基準か、内容の質を見る基準かで分かれます。
今日のまとめ
3行で振り返ります。
- 手元の数例だけで「良さそう」と判断すると、本番で初めて崩れ方に気づく。この主観の頼りなさが評価を先に置く理由
- 評価ループはプロンプト作成→データセット作成→実行→採点→改善の繰り返し
- コード採点は形式面、モデル採点は内容面に向く。実務ではしばしば両方を組み合わせる
次のレッスンからは、このループの上で技法を試していきます。アプリに組み込む頼み方の作法を扱います。
セルフチェック
1. 「テストの罠」の説明として正しいものはどれですか。
2. 評価を技法より先に置く理由として、本文が挙げているものはどれですか。
3. コード採点とモデル採点の使い分けとして適切な説明はどれですか。