プロンプトの最初の版は下書きです。望むものに近いものが得られることは多く、近いと正しいのあいだの差は、反復改善によって埋まります。意図してプロンプトを変え、同じ入力でもう一度実行し、その変更が役立ったかを確かめるのです。いいかげんにやると、反復改善は、たまたま1つの出力が良く見えるまで手当たりしだいに言い換える作業になります。小さな実験としてやれば、試した1つの入力だけでなく、次の100個の入力でも機能するプロンプトが手に入ります。
方法は5つのステップです。良い答えを定義する、テスト入力を固定する、一度に1か所だけ変える、出力を比べる、やめどきを見極める。
良い答えとはどういうものかを定義する
何かを編集する前に、出力がしなければならないことを、はいかいいえで答えられるチェックとして書き出してください。「良いコミットメッセージ」は確認できませんが、次のものなら確認できます。
- 件名の行が50文字以内である。
- Conventional Commits 形式(
fix:、feat:など)に従っている。 - 本文が、差分を見ればわかることではなく、なぜ変更が必要だったかを述べている。
- issue があれば、その番号に触れている。
基準には2つの役割があります。1つは、プロンプトに何を足すべきかを教えてくれることです。基準の1つ1つが、足りない指示であることがよくあるからです。もう1つは、聞こえの良さで出力を判断するのを防ぐことです。それこそが、自信ありげで間違った答えを受け入れてしまう最も簡単な道です。
小さなテスト入力のセットを用意する
入力を3〜10個選び、作業中は固定しておきます。典型的なケース、扱いにくいケースを2つほど(空の欄、とても長い入力、プロンプトが想定していない言語)、そして以前に失敗したすべての入力を含めてください。1つの例に合わせて調整したプロンプトは、その例には合っても、次の例で失敗しがちです。
プロンプトは、入力の差し込み口を持つテンプレートとして書いてください。そうすれば、どの版もまったく同じ素材で実行できます。
一度に1か所だけ変える
役割、形式、例を一度に変えて出力が良くなっても、どの変更が効いたのかはわからず、役に立たない編集を2つ残しているかもしれません。1か所変えて、実行して、比べる。下のタブは1つのプロンプトの3つの版で、それぞれ前の版から1か所だけ変えています。
- if len(password) > 8:
+ if len(password) >= 8:
return Trueパスワードの長さの検証を更新
このコミットでは、比較演算子を > から >= に変更して、パスワードの検証ロジックを更新します。その結果、ちょうど8文字のパスワードも有効とみなされるようになります。この変更により検証の精度が上がり、アカウントを作成するユーザーの体験が向上します。
第1版は基準2と3を満たしていません。件名に type の接頭辞がなく、本文は差分を言葉を増やして言い直しているだけです。第2版は形式の要件を足し、基準1と2には合格しますが、本文はまだ差分を説明しています。次に思いつく編集は、さらに指示を足す(「理由を説明して」)ことですが、モデルは与えられていない理由を説明できません。第3版は代わりに足りないコンテキストを加え、本文と issue への言及は頼まなくてもついてきました。これが反復改善で最もよく得られる教訓です。指示を足しても出力が直らないとき、プロンプトにたいてい足りないのは強調ではなく情報です。
出力を並べて比べる
どの版もすべてのテスト入力で実行し、それぞれ複数回実行してください。チャットモデルは言葉をサンプリングするので、同じプロンプトでも2回の実行で結果が変わります。出力を並べ、前回の実行の記憶ではなく、基準に照らして確かめます。
正確な基準なら、モデルへのもう1回の呼び出しに一次採点をまかせられます。基準を明記した採点用のプロンプトに出力を貼り付けてください。
| 基準 | 出力 A | 出力 B |
|---|---|---|
| 1. 件名が50文字以内 | 合格:件名は24文字 | 合格:同じ件名で24文字 |
| 2. Conventional Commits | 合格:「fix:」で始まっている | 合格:「fix:」で始まっている |
| 3. 本文が理由を説明している | 不合格:「長さのチェックを > から >= に変更」は差分の言い直し | 合格:「案内どおりに入力したユーザーが登録できなかった」 |
| 4. issue に触れている | 不合格:issue 番号がない | 合格:「Fixes #412」 |
モデルによる採点役は、審判ではなく助手として扱ってください。Zheng らの2023年の論文「Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena」は、長い答えをひいきする、特定の位置の答えをひいきするといった、モデルの審査員の偏りを記録しています。基準は確認できるものにし、根拠となる引用を求め、2つを比べるときは A と B の順番を入れ替え、出力の一部は自分で読んでください。文字数のようなチェックは、モデルの判断よりコード1行のほうが確実です。
会話ではなく、プロンプトを直す
チャットでは、フォローアップで答えを直したくなります。「もっと短く」「違う、issue に触れて」「もう1つの形式で」。それで良い出力が1つ得られても、プロンプトは悪いままです。修正がうまくいったら、それをプロンプトに移し、プロンプトを新しく実行してください。次にその結果が必要になったとき、5回繰り返す代わりに、メッセージを1通貼り付けるだけで済みます。
古い版は、何を変えて何が直ったかを1行で書いたメモと一緒に残しておいてください。プレーンテキストのファイルで十分です。あとの編集で悪くなったとき、プロンプトが以前どう書かれていたかを思い出そうとする代わりに、元に戻せます。
コードで比較を実行する
プロンプトを API 経由で実行するようになれば、短いスクリプトで、すべての版とすべてのテスト入力を並べた一覧を作れます。これは OpenAI の Python SDK を使い、上から順に読める Markdown ファイルを書き出します。
from openai import OpenAI
client = OpenAI()
MODEL = "your-model-id" # e.g. from your provider's model list
# each prompt file contains {input} where the test diff goes
PROMPTS = {
"v2": open("prompts/commit_v2.txt").read(),
"v3": open("prompts/commit_v3.txt").read(),
}
TESTS = [open(f"tests/diff_{i}.txt").read() for i in range(1, 6)]
with open("results.md", "w") as out:
for i, test in enumerate(TESTS, 1):
out.write(f"## Test {i}\n\n")
for name, template in PROMPTS.items():
for run in (1, 2):
response = client.chat.completions.create(
model=MODEL,
messages=[{"role": "user", "content": template.replace("{input}", test)}],
)
out.write(f"### {name}, run {run}\n\n{response.choices[0].message.content}\n\n")
やめどき
何回か実行して、すべてのテスト入力ですべての基準に合格したらやめてください。それ以上足しても、たいてい長さが増えるだけで、指示を1つ足すごとに、ほかの指示と矛盾しうるものが1つ増えます。
変更が失敗を交換しはじめたときもやめどきです。ある編集がテスト2を直してテスト4を壊し、次の編集がそれを逆にする。このパターンは、1つの指示では固定できないことをプロンプトに求めているというサインです。よくある抜け道は、いくつかの例で形式を見せる(Few-shot プロンプティング)、プロンプトチェーンで仕事をステップに分ける、あるいは文字数を数えたり形式を確かめたりといった決定的な部分を、出力を確認するコードに移すことです。アイデアに行き詰まったら、メタプロンプトが役立ちます。モデルにプロンプト、入力、悪い出力を渡し、プロンプトのどの部分が原因である可能性が最も高いかを尋ねてください。
よくある質問
悪い答えを返すプロンプトはどう改善すればいいですか?
悪い答えを見て、何が悪いのかを言葉にします。形式が違う、事実が足りない、読み手が違う、長すぎる。次に、プロンプトが何を言っていればそれを防げたかを見つけ、その1つを足して、同じ入力で新しい版を実行します。悪い答えの原因は、言い回しよりも、コンテキストや形式の指示が足りないことのほうが多いのです。
プロンプトをテストするにはテスト入力がいくつ必要ですか?
繰り返し使うプロンプトなら、たいてい3〜10個で十分です。典型的なケースをいくつか、境界ケース(とても短い、とても長い、珍しい)を1〜2個、そして以前に失敗した入力を1つ。改善しているあいだはそれらを固定しておけば、出力の変化が入力の違いではなくプロンプトの変更から来ていると言えます。
同じプロンプトをもう一度実行すると違う答えが返るのはなぜですか?
チャットモデルは各単語を確率分布からサンプリングするので、実行ごとに出力が変わります。2つの版のプロンプトを比べるときは、同じ入力でそれぞれを複数回実行してください。どの実行でも現れる差はおそらく本物で、1回だけ現れる差は偶然かもしれません。API 経由なら、temperature を下げてばらつきを減らすこともできます。
プロンプトの出力の採点に AI を使えますか?
「本文に変更が必要だった理由が書かれている」や「issue 番号に触れている」のように、正確に述べられる基準なら使えます。採点役には基準をそのまま渡し、基準ごとに合格か不合格かを、根拠となる引用つきで答えさせてください。モデルによる採点には、長い答えをひいきする、2つのうち特定の位置のほうをひいきする、といった既知の偏りがあるので、出力の一部は自分で読み、2つを比べるときは順番を入れ替えてください。
プロンプトの改善はいつやめればいいですか?
何回か実行して、すべてのテスト入力ですべての基準に合格したらやめます。あるいは、新しい変更が1つのケースを直すたびに別のケースを壊すようになったらやめます。その時点で問題はたいていプロンプトではありません。タスクに例が必要か、ステップに分ける必要があるか、コードでのチェックが必要なのです。