Gemini を本番で使っていると、応答が「だいたい正しい」状態には比較的早く到達します。ただしその先、「時々だけ微妙に間違う」という状態は、気合だけでは消せません。私は自分で運用しているサービスで、この「時々だけの間違い」を検知するために、本番環境で静かに回る自動評価ループを作って運用しています。
ここではその設計と実装、そして運用して見えてきた落とし穴を、具体的なプロンプトとともに共有します。Gemini に限らず、LLM をプロダクションで使う人に参考になる内容です。
私自身、個人開発でいくつかのアプリを運用しており、その問い合わせ応答や説明文の生成に Gemini を組み込んでいます。評価ループを回し始めたのは、ある機能をリリースした翌週に AdMob の収益が説明もつかないまま数%下がったときでした。原因を辿るうちに行き着いたのは、サーバー側のエラーでもクラッシュでもなく、応答そのものが静かに劣化していたという事実です。ユーザーは黙ってアプリを閉じるだけで、こちらには何も届きません。あのときの、地面が少しだけ傾いていたような感覚が、この仕組みを作る出発点になりました。
なぜ自動評価が必要なのか
テストデータセットでの事前評価は、もちろん重要です。ただ、本番環境では以下のような事象が起きます。
- ユーザーが想定外の入力をする
- プロダクトの UI が変わってプロンプトも少しずつ変わる
- Gemini のモデルが内部的にアップデートされる
- ドキュメントや FAQ の更新でコンテキストが変わる
どれも、事前テストの範囲を超えて品質に影響します。事前テストだけで本番品質を担保しようとすると、テストは肥大化し、実態と乖離していきます。本番の実トラフィックに対する評価を、軽くても継続的に回すほうが現実的 です。
私がこの仕組みを作ってよかったと一番強く感じたのは、モデルの静かな挙動変化に気づけるようになったときです。ある機能の精度がじわじわ下がっていて、ユーザーからのクレームもなかったのですが、評価ループのダッシュボードには明確にトレンドが出ていました。
本番評価で見るべき4つの観点
私が本番応答に対して自動で評価しているのは、以下の4つです。
- 事実の正確性(Factuality): 応答内の事実主張が、与えられたコンテキストと矛盾しないか
- 指示追従(Instruction following): システムプロンプトの要件(フォーマット、長さ、禁止事項)を守っているか
- ユーザー入力への関連性(Relevance): ユーザーの質問に対して、実際に答えになっているか
- 安全性(Safety): 機微情報の開示、攻撃的な内容、偏見などを含んでいないか
これら全てを常に評価するのは、コスト的に現実的ではありません。私は、リクエストの種類とリスクによって、何を評価するかを振り分けています。
たとえば FAQ ボットの応答なら 1・3 を重点、生成系の応答なら 2・4 を重点、という具合です。全部を測ろうとすると、評価コストが本体処理コストを上回ることもあります。
LLM-as-a-Judge の具体的なプロンプト
各観点の評価は、別モデル(私は Haiku クラスの安いモデル、または Gemini のより小さいモデル)を Judge として動かしています。以下は「事実の正確性」を判定するプロンプトの例です。
あなたは LLM の応答を評価する審査員です。以下の情報が与えられます。
[コンテキスト]
{source_document}
[ユーザーの質問]
{user_query}
[評価対象の応答]
{model_answer}
次の手順で評価してください:
1. 応答の中で事実を主張している文を全て抜き出す
2. 各事実主張について、コンテキストと矛盾しないか判定
3. 全体の判定: "consistent" / "partially_inconsistent" / "inconsistent"
根拠をできるだけコンテキストから引用してください。
推測での判定はせず、コンテキストに情報がない場合は "insufficient_context" としてください。
JSON で返してください:
{
"overall": "...",
"claims": [
{"text": "...", "verdict": "...", "evidence": "..."}
]
}
ポイントは「推測での判定はせず、コンテキストに情報がなければ insufficient_context と返す」という指示です。この一文がないと、Judge 側までハルシネーションを起こします。 評価者が推測で「正しい」「間違っている」を言い始めると、評価全体が崩壊します。
自己評価バイアスを回避する仕組み
同じ Gemini モデルで生成し、同じ Gemini で評価すると、モデル自身が無意識に自分の応答を好意的に判定するバイアスが出ます。これは論文でも指摘されている現象で、私の観測でも明らかに出ます。
私がとっている対策は以下です。
- 評価には別ファミリーのモデルを使う: 生成が Gemini なら、評価は Claude Haiku や GPT の小型モデル
- 2つの Judge で多数決を取る: 判定が割れた応答だけを人間レビューのキューに回す
- 週次で Judge 自身の品質も検証する: 既知の正解データセットで Judge を回して、精度低下を検知
2つ目が特に効きます。常に全件を多重評価するとコストが2倍になりますが、判定が割れた応答だけ に絞れば、実用的なコストで異常検知の精度が大きく上がります。
コストを現実的な範囲に収めるサンプリング戦略
全トラフィックを評価するのは、コスト的に現実的ではありません。私は以下の階層でサンプリングしています。
- 常時評価: 応答長が異常に長い/短い、特定のキーワードを含む、ユーザーがネガティブフィードバックを送った応答は全て評価
- ランダムサンプル: 全応答の 1〜5% をランダムに評価(日次レポート用)
- 深掘り評価: Judge が
inconsistent と判定した応答は、別のより大きいモデルで再評価
1つ目の「常時評価対象」の条件は、実は最も重要です。異常値は既に何かが起きているシグナルなので、サンプリングではなく全件追うべきです。
この階層的サンプリングで、評価コストは本体処理コストの 15% 程度に収まっています。これなら運用できます。
本番評価で見つかる典型的な失敗パターン
実際にこの仕組みを半年運用して見えてきた、Gemini 応答の典型的な失敗パターンを共有します。
- 指示追従の緩慢な劣化: プロンプトが少しずつ肥大化していくと、初期の指示が無視されるようになります。新しい指示ほど優先されがち
- コンテキスト肥大化時の事実誤認: コンテキストが長くなるほど、モデルは前半の情報を混同しやすくなる
- 出力フォーマットの微妙な逸脱: JSON で返すべき場面で、先頭に説明文が付いてくる(パースが壊れる)
- エッジケースでの安全フィルタ暴発: 医療や法律の話題で、正当な情報提供まで safety filter で止まる
4つ目は特に発見が難しい失敗です。ユーザーからは「応答が返ってこない」としか見えず、通常のエラー監視では検知できません。safety filter のブロック理由とブロック率を、評価ループとは別にメトリクス化しておくのが有効です。
しきい値の決め方 — 過去ログでキャリブレーションする
多数決で「人手レビューに回す/回さない」を分ける境界は、感覚で決めると必ずズレます。私は運用を始めて2週間ほど経ったところで、過去ログを使った一度きりのキャリブレーションを挟みました。
手順はそれほど大げさではありません。直近の本番応答から約300件を抜き出し、そのうち120件を自分の手で「これは間違い/問題なし」とラベル付けします。退屈な作業ですが、ここを省くとしきい値が宙に浮きます。残りはラベルなしのまま、コスト感を測るためのサンプルにします。
手ラベルした120件に対して、判定の境界を3通り変えて当てたのが次の結果です。見逃し率は「本当は間違いなのに通してしまった割合」、誤検知率は「問題ないのに人手キューへ送ってしまった割合」です。
| 人手キューへ回す条件 | キューに回る割合 | 見逃し率(実測) | 誤検知率(実測) |
| 2つの Judge が両方 inconsistent | 約3% | 22% | 4% |
| どちらか一方が inconsistent | 約11% | 6% | 19% |
| 5段階スコアの差が2以上 | 約7% | 9% | 8% |
数字を並べてみると、どれが正解という話ではないことがよく分かります。「両方 inconsistent」は人手の負担こそ軽いものの、見逃しが2割を超えていて、品質を守る目的には心もとない。「どちらか一方」は見逃しを6%まで下げますが、誤検知が2割近くまで膨らみ、人手レビューの中身が玉石混交になります。
私が落ち着いたのは、3つ目の「スコア差が2以上」でした。見逃しと誤検知のどちらも一桁台に収まり、キューに回る量も一日の手作業で捌ける範囲に収まります。ここで大事なのは、自分が一日に何件まで人手で見られるかという制約から逆算すること です。理想的な精度ではなく、続けられる精度を選ぶほうが、結局は長く回ります。
このキャリブレーションは一度やって終わりではありません。プロダクトの要件や扱う話題が変わると、同じしきい値でも見逃し率は動きます。私は四半期に一度、同じ手順で50件ほど引き直して、テーブルがどれくらいズレたかを確認するようにしています。
ダッシュボード化と運用
評価結果は、以下のようなメトリクスにまとめてダッシュボードに出しています。
- 日次の
inconsistent 比率(観点別)
- トップ3の「最も問題の多いプロンプトパターン」
- Judge 間の一致率(ここが下がると、Judge 側の品質劣化を疑う)
- 安全フィルタのブロック率推移
アラートは、inconsistent 比率が過去7日平均の 1.5 倍を超えたら Slack に通知するよう設定しています。急な劣化の早期発見に役立ちます。
この仕組みで失ったもの
得られるものだけ書くのはフェアではないので、失ったものも正直に書きます。
一番大きいのは、応答を一発ですぐ信用できなくなった ことです。どれだけ精度が高くても、「これは評価ループでどう判定されるだろう」という視点で応答を見るようになります。ある意味これは健全な懐疑心ですが、仕事のスピード感は少し落ちました。
もう一つは、評価プロンプト自体のメンテナンスコストです。プロダクトの要件が変わると、評価基準も変えないといけません。評価基準が現実からズレると、評価ループ自体が嘘をつくようになります。
自動評価ループを育てる価値
それでも、この仕組みを作って運用してよかったと私は思っています。何が起きているかを知っている状態 は、サービス運用者としての精神衛生に大きく効きます。
Gemini を本番で使っているなら、まずは最小限のサンプリング評価から始めてみてください。完璧な評価基準を最初から作ろうとせず、「inconsistent かどうか」だけを判定する簡易版でも、驚くほど多くの発見があります。それが、次の改善サイクルの起点になります。