[Claude Code] プロンプトの良し悪しは実測でしか分からない

背景

AIエージェント向けの指示書(skillやタスクプロンプト)を書いたあと、自分で読み返して「これなら伝わるはずだ」と判断してから使い始めていた。しかし実際にエージェントへ使わせると、自分では気付かなかった曖昧な箇所で判断がぶれる。

原因は単純で、書いた本人はプロンプトの外側にある文脈をすでに知っている。だから曖昧な一文があっても「自分は分かる」で無意識に補って読んでしまい、それが曖昧である事実そのものに気付けない。これはレビューの丁寧さの問題ではなく、書いた本人が読み手になれないという構造的な限界である。

毎回まっさらな読み手が必要な理由

この限界を避けるには、指示を「まだ何も知らない読み手」へ実際に読ませ、実際に動かしてもらうしかない。かつ、その読み手は毎回まっさらである必要がある。同じ読み手に2回目を頼むと、1回目のやりとりで学習した分だけ指示の欠陥を自分で補ってしまい、指示そのものの品質を測れなくなる。

手法の全体像

やることは次の6ステップである。

  1. 評価シナリオ(典型ケース1 + edgeケース1〜2)、収束判定用のhold-outシナリオ、成果物が満たすべき要件チェックリストを先に固定する
  2. 白紙の実行者(対象プロンプトについて一切の前提知識を持たない、新規のエージェント)にシナリオを実行させる
  3. 実行結果を、実行者自身の自己申告と、要件チェックリストに基づく機械採点の両面で記録する
  4. 見つかった曖昧点を、最小限の修正でプロンプトに反映する
  5. 新しい白紙の実行者で再評価する(同じ実行者は使い回さない)
  6. 「連続2回、新規の曖昧点がゼロ」かつ「未知のhold-out1シナリオでも精度が落ちない」ことを確認できたら収束とする

シナリオとチェックリストの事前固定

シナリオは「よくある使われ方」を1つ(典型)と、「境界に近い使われ方」を1〜2つ(edge)用意する。要件チェックリストは、成果物が満たすべき項目を3〜7個列挙し、そのうち最低1つには「これが崩れたら失敗」というマーク(以下、critical)を付ける(このマークを含む項目が1つでも未達なら、その実行は失敗として扱う)。

このチェックリストは、修正を始める前に固定し、収束判定の途中では変更しない。後から「この項目は厳しすぎた」と判断して緩めると、修正が効いたのか基準を緩めただけなのかが区別できなくなる。

自己申告と機械採点の突き合わせ

実行者が返すレポートには、次の2種類の情報を含める。

  • 機械採点は、チェックリストの各項目が○か×か、そこから出る精度(達成項目数/全項目数)、ツール呼び出し数、所要時間である
  • 自己申告は、どこで解釈に迷ったか、指示に書かれていない判断をどこで自分の裁量で埋めたか、同じ判断を何回やり直したかを実行者本人が申告する

機械採点だけを見ると、たまたま正解を引いただけの実行と、指示が明確だったから迷わず正解した実行を区別できない。自己申告だけを見ると、実行者が「特に迷いませんでした」と言っていても、成果物自体は要件を満たしていない、ということが起こる。両方を突き合わせてはじめて、指示のどこを直すべきかが見える。

収束の判定基準

1回のイテレーションで曖昧点がゼロになっても、それだけでは収束と判定しない。たまたまそのシナリオがうまくハマっただけの可能性があるためで、連続2回クリアしてはじめて収束候補とする。

さらに、収束候補になった時点で、未知のシナリオ(hold-out)を1本追加して評価する。ここで精度が大きく落ちるなら、それまでの修正は「用意したシナリオだけに効く」過学習だったことになる。この場合は個別のパッチを重ねず、要件チェックリストとプロンプトの条件そのものを見直し、新しいチェックリストで収束判定を最初からやり直す。

ToDoアプリのタスク追加機能を例にした流れ

ToDoアプリのタスク追加機能を例に、流れを追う(数値と実行結果は説明のために作った例であり、実測値ではない)。

ベースラインのプロンプト

Todoアプリにタスク追加機能を実装してください。
ユーザーがタスク名を入力して追加ボタンを押すと、
一覧に追加されるようにしてください。

シナリオ

  • シナリオA(典型)は、「牛乳を買う」のような通常のタスク名を入力して追加する
  • シナリオB(edge)は、タスク名を空文字のまま追加ボタンを押す

要件チェックリスト

  1. [critical]空文字のタスク名は一覧に追加されない
  2. 有効なタスク名は一覧に追加される
  3. 追加後に入力欄がクリアされる
  4. 追加されたタスクが一覧の末尾に表示される

イテレーション1(ベースライン)

シナリオ成功/失敗精度
A○100% (4/4)
B×75% (3/4)

シナリオBの実行者の自己申告:「空文字の扱いが指示に書かれていなかったため、追加してよいと判断した」。critical項目が未達のため、この実行は失敗として扱う。

プロンプトの修正

プロンプトに次の一文を足す。

タスク名が空文字の場合は追加せず、入力欄の内容を保持する。

イテレーション2と3(新しい白紙の実行者で2回連続実行)

どちらもシナリオAとBが○で、精度100%、新規の曖昧点はなかった。2回連続クリアで収束候補になる。

hold-outでの検証

ここで、最初から用意していたが一度も使っていなかったシナリオC(タスク名が空白だけ、例えば" ")を、ここではじめて使う。修正した条件は「空文字」の判定であり、trimしていない空白だけの文字列は空文字と一致しないため、実行者は「空文字ではない」と判断してそのまま追加してしまう。critical項目が未達になり、精度が落ちる。

これは過学習である。シナリオCを個別に付け足しても、次の未知の入力で同じ抜けが再発する。そこで、要件チェックリストとプロンプトの両方を「空文字、または前後の空白を除いて空になる場合は追加しない」という一段抽象度の高い条件に書き直し、新しいチェックリストで収束判定を最初からやり直す。

hold-outを用意していなければ、この抜けは評価をすり抜けていた。

注意点

この手法は、評価のたびに新しい実行者を起動する時間とコストがかかる。変更が小さく影響範囲の明らかな修正や、hold-outに回せる未知のシナリオを用意できない場合は、簡易的な自己レビューで代用してよい。一方で、本番投入する重要度の高いプロンプトほど、このコストを払う価値がある。

まとめ

  • プロンプトの品質は、書いた本人が読み返しても分からない。曖昧さは「自分は文脈を知っている」ことで見えなくなる
  • 白紙の実行者に実際に動かしてもらい、自己申告と機械採点の両面で評価する
  • 1回のクリアで満足せず、連続2回クリア、かつ未知のシナリオ(hold-out)でも精度が落ちないことまで確認する
  • hold-outは、修正が用意したシナリオだけに効く過学習になっていないかを検出するための工程である

参考

注釈

  1. hold-outシナリオとは、収束判定のために意図的に評価から除外しておいた未知のシナリオのこと。修正が特定のシナリオに過学習していないかを検出するために用いる。 ↩