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

背景

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

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

課題: セルフレビューでは指示の欠陥に気付けない

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

手法の全体像

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

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

シナリオとチェックリストは、修正の前に固定する

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

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

自己申告と機械採点は、どちらか一方では足りない

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

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

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

収束は「連続2回クリア + hold-out」で判定する

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

さらに、収束候補になった時点で、それまで一度も使っていない未知のシナリオ(hold-out)を1本追加して評価する。ここで精度が大きく落ちるなら、それまでの修正は「用意したシナリオだけに効く」過学習だったことになる。この場合は個別のパッチを重ねず、シナリオ設計自体を見直す。

具体例で見る

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

ベースラインのプロンプト(v1)

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

シナリオ

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

要件チェックリスト

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

Iteration 1(ベースライン)

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

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

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

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

Iteration 2・3(新しい白紙の実行者で2回連続実行)

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

hold-outでの検証

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

これは過学習である。個別のシナリオを付け足すのではなく、要件チェックリストとプロンプトの両方を「空文字、または前後の空白を除いて空になる場合は追加しない」という一段抽象度の高い条件に書き直し、イテレーションをもう一度回す。

hold-outを用意していなければ、この抜けはリリース後にはじめて見つかっていた。未知のシナリオで測るステップは、修正がシナリオの丸暗記になっていないかを検出するために存在する。

まとめ

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

参考

注釈

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