TestingEvaluationLLM APICI/CDProduction Engineering

LLM APIのテストと評価:CI/CDパイプラインの構築(2026)

約1分

3.2%という数字が最初に監査レポートに現れます——100,000回のAPI呼び出しあたり3,200個の壊れたJSONペイロード。それぞれが静かなビジネスロジック障害です。

原因は1つのモデル文字列の変更でした。どのダッシュボードも検知しませんでした。HTTPは緑のまま、構造化出力は静かに劣化し、あなたは3スプリント前まで遡って残骸を追跡します。

CI統合されたevalは、プルリクエスト時点でセマンティックリグレッションを捕捉します——nullポインタをブロックするユニットテストと同じ力で。

このパイプラインは、決定論的チェックからLLM-as-Judgeによるスコアリングまでをカバーし、今日の失敗を明日のCIテストケースに変えるクローズドループを備えています。

「それっぽく見える」は約50レビューで限界になる——そして失敗する

「それっぽく見えるか?」はなぜスケールしないのか

LLMの出力をじっと見つめる人間のレビュアーは、具体的で測定可能な3つの点で信頼できません:

  1. 疲労。 約50回連続でレビューすると、精度は急激に低下します。51回目の判断は5回目よりも著しく悪い——しかもその低下にあなたは気づきません。
  2. 一貫性の欠如。 同じLLM出力セットに対する2人の人間のレビュアー間の評価者間信頼性は、通常0.6を下回ります——つまり2人の有資格者が「これは正しいか?」について40%の確率で意見が分かれるということです。
  3. コストとレイテンシ。 1,000出力 × レビュー1件90秒 = 人間の時間25時間。eval実行1回あたり$750-2,500——しかもスケジュール調整に数日かかります。

機械評価は一貫しており、即時的で、ほぼ無料です。しかし「機械評価」は1つのものではありません——テスト対象に応じて組み合わせる3つのプリミティブのスタックなのです。

3つの評価プリミティブ

レイヤー1:決定論的チェック。 マイクロ秒。APIコストゼロ。JSON Schemaバリデーション。完全一致文字列マッチ。ツール呼び出しの成功/失敗カウント。引用の存在検証。拒否(refusal)のregexマッチング。これらは実世界の失敗の約50%を捕捉します——そして予算を気にせずあらゆるリクエストで実行できる唯一のレイヤーです。ここから始めましょう。

レイヤー2:Embeddingベースのメトリクス。 ミリ秒。チェックあたり約$0.001。BERTScore。参照回答とのコサイン類似度。「gold」回答があり、言い換えに寛容な類似性判定が必要な場合に有用です。複数の正解が存在するオープンエンド生成には不向きです。

レイヤー3:LLM-as-Judge。 数百ミリ秒。チェックあたり$0.01-0.10。高性能なLLMがchain-of-thought推論を使ってルーブリックに照らして出力をスコアリングします。決定論的チェックが見逃すセマンティック失敗——不忠実な要約、役に立たない回答、不適切な拒否——を捕捉します。人間ラベルに対するキャリブレーションと、積極的なバイアス軽減(位置バイアス、冗長バイアス、自己増強バイアス)が必要です。

6層の本番評価スタック

Dataset —Metrics/Rubrics —Judge —CI Gate —Production Observation —Closed Loop

どのリンクも断たれると、評価は誰も読まないオフラインレポートになります。データセットは本番からサンプリングされ、失敗に重み付けされます。ルーブリックは「正しさ」を測定可能な条件で定義します。ジャッジは一貫して、かつ大規模にスコアリングします。CIゲートはマージ前にリグレッションをブロックします。本番観測はCIが見逃すものを捕捉します。クローズドループは、今日の本番障害を明日のCIテストケースに変えます。6つのレイヤー。1つのパイプライン。抜け穴なし。

体系的なテストがすべてを変える理由

リグレッションの隠れたコスト

3.2%の静かに破壊されたJSONレスポンスは、100,000回のAPI呼び出しあたり3,200個の壊れた出力を意味します。それらの出力が下流のアクションを駆動しているなら、あなたは3,200件のビジネスロジック障害を抱えている——そして財務の照合が一致しないまで、つまり数週間後まで、それに気づかないでしょう。

evalパイプラインは、モデル文字列の変更が本番に到達する前に、その3.2%をCIで捕捉します。パイプライン構築のコストは、1件のインシデントのコストより低いのです。

Promptドリフトの検知

マイナーなモデルバージョンの変更——gpt-5.5-2026-07-01からgpt-5.5-2026-07-15——には挙動変更のノートが付属しません。チェンジログには「指示従属性の改善」とだけ書かれています。あなたの構造化抽出の精度は4ポイント低下しました。すべてのモデルバージョンに対して同じevalスイートを実行していなければ、あなたはそれを知ることはありません。

マルチプロバイダー評価の問題

モデル間でルーティングしているなら——コストと信頼性のために、そうすべきです——ルーティングプール内のすべてのモデルについてeval結果が必要です。プライマリだけでなく。統合APIエンドポイントを使えば、1つのインテグレーションで全モデルに対して同じevalスイートを実行できます。同じリクエスト形式。同じテストケース。同じジャッジモデル。変わる唯一の変数はmodel: "..."だけです。

evalスイートを構築する前に、ルーティングプール内の各モデルのパフォーマンスとコスト特性を理解しましょう。当社のクロスプロバイダーベンチマーク比較は、テストの優先順位を決定づけるモデル別データを提供します。

評価パイプラインの構築方法

ステップ1:Evalデータセットを構築する

データセットは最も難しいステップであり、ほとんどのチームが最も投資不足に陥る部分です。悪いデータセットは、間違ったものに対して正確なスコアを与えます。良いデータセットは、本番からサンプリングされ、失敗に重み付けされ、毎週更新されます。

構築プロセス:

  1. 本番ログからリクエストを200〜500件ランダムにサンプリングします。テスト環境からではありません。実ユーザーは、テスト作成者が思いつかない質問をします。
  2. それぞれを手動で注釈付けします:正解は何か?レスポンスを間違ったものにする要素は何か?モデルが処理すべきエッジケースは何か?
  3. 難易度で層化します:簡単3分の1、普通3分の1、難しい3分の1。evalセットがすべて簡単なクエリだと、スコアは水増しされます。
  4. 毎週更新:本番ログの直近7日分から新しいデータをサンプリングします。evalセットの最古の20%を置き換えます。これにより、evalはユーザーが実際に尋ねていること——時間とともに変化するもの——と整合し続けます。

最も一般的なミスを防ぐルール: evalセットの少なくとも20%は、過去の失敗に由来しなければなりません。evalセットにハッピーパスのクエリしか含まれていないなら、あなたはモデルが理想的な条件下で機能するかをテストしているだけ——本番で実際に発生する条件下で優雅に失敗するかをテストしていないのです。

ステップ2:「良いかどうか」ではなくルーブリックを定義する

よくキャリブレーションされた4つのルーブリックは、ノイズの多い15個に勝ります。各ルーブリックには次が必要です:

  • 正確な定義:「faithfulness = レスポンス内のすべての事実的主張が、取得されたコンテキストによって裏付けられている」
  • スコアリング尺度:1〜5または0〜1
  • 合格しきい値:「faithfulness ≥ 0.85」
  • ジャッジモデル用のキャリブレーション参照として、スコア付きの例を2〜3件

ほとんどのLLM APIアプリケーションの中核的なルーブリックセット:faithfulness(事実は正しいか?)、answer relevance(レスポンスはクエリに対応しているか?)、context precision(取得されたチャンクは実際に関連しているか?)、task completion(モデルは求められたことを実行したか?)、refusal correctness(モデルは拒否すべきときに拒否し——拒否すべきでないときには拒否しなかったか?)。

ステップ3:ジャッジを選択し、キャリブレーションする

GPT-4は最も広く使われているLLMジャッジです——人間の注釈者との一致率はMT-Benchで80%超、G-Evalで85%超。しかしキャリブレーションされていないジャッジは、精密に見えて体系的に間違っている数字を与えます。

キャリブレーションプロセス: 人間が注釈付けした50件の例を用意します。それらをジャッジモデルに通します。ジャッジスコアと人間スコアの相関を計算します。いずれかのルーブリックで相関が0.75を下回る場合、そのルーブリックのジャッジプロンプトに手を加える必要があります——または別のジャッジモデルが必要です。

軽減すべき3つのバイアス:

  • 位置バイアス。 ジャッジは最初に表示されるレスポンスを好みます。修正:評価ごとにレスポンス順序をランダム化します。
  • 冗長バイアス。 ジャッジは品質に関係なく長いレスポンスを高く評価します。修正:関連性と完全性を別々の次元としてスコアリングします。
  • 自己増強バイアス。 ジャッジは同じモデルファミリーが生成した出力のスコアを水増しします。修正:本番で使うモデルファミリーとは異なるモデルファミリーをジャッジに使います。本番がClaudeなら、GPT-4で判定します。または専用のジャッジモデルを使います。ジャッジと本番モデルを安全に分離するAPIキーの分離とアクセス制御については、セキュリティベストプラクティスガイドを参照してください。

最も見落とされがちなルール: ジャッジモデルのバージョンを固定してください。ジャッジをGPT-4からGPT-4oにアップグレードすると、過去のスコアはすべて比較不能になります。本番モデルが改善されたのか、ジャッジが厳しくなったのか、判別できません。ジャッジのバージョンを一定に保つか、ジャッジをアップグレードするたびに50件の人間注釈例で再キャリブレーションし、新旧ジャッジ間のスコアマッピングを確立してください。

ステップ4:CIゲートを設定する

2つのツール、2つの哲学:

  • Promptfoo。 オープンソース。Git統合。YAMLでの宣言的設定。evalをコードとして、プロンプトと同じリポジトリに共存させたいチームに最適です。
  • DeepEval。 Pythonネイティブ。30以上の組み込みメトリクス。デコレータベースのCI/CD統合。evalをPythonテストスイートに深く統合したいチームに最適です。

ツールに関係なく、CIゲートのロジックは次のとおり:

tests:
  - path: eval_dataset.jsonl
    asserts:
      - type: python
        value: |
          def check_regression(output, context):
              baseline = context['baseline_scores']
              current = compute_scores(output)
              for rubric, score in current.items():
                  if baseline[rubric] - score > 2:
                      return False, f"{rubric} dropped {baseline[rubric] - score:.1f} points"
              return True, "All rubrics within threshold"

ベースラインから2ポイント以上低下したルーブリックがあれば——CIが失敗——マージはブロックされます。これはオプションではありません。重要なルーブリックで品質を3ポイント下げるプロンプト変更は、本番に到達すべきではありません。ユニットテストはnullポインタ例外をブロックします。evalゲートは同じ力でセマンティックリグレッションをブロックすべきです。CIゲートに供給されるプロンプト最適化ワークフローは、当社のプロンプトエンジニアリング本番ガイドで解説しています。

ステップ5:本番観測+クローズドループ

CI評価はデプロイ前のリグレッションを捕捉します。しかし、分布シフト、敵対的入力、evalセットがカバーしないエッジケースは捕捉できません。それらには、本番トレースに対する継続的評価が必要です。

evalスコアをOTelスパンにアタッチします。ローリングウィンドウ内でいずれかのルーブリックが2〜5ポイント低下し続けると、アラートがトリガーされます。ジャッジのキャリブレーション手法と、CIゲートに供給されるプロンプト最適化ワークフローは、どちらもこのガイドの前半のステップで解説済みです。ここで参照したchain-of-thought評価手法はG-Eval論文(Liu et al., 2023)で確立されました。失敗したトレースは、エラータイプ、プロンプトバージョン、モデルごとに自動クラスタリングされます。代表的な失敗を含む命名された問題は、オフラインのevalデータセットに戻されます——今回は手動で注釈付けされ、具体的な失敗パターンが文書化されます。

このクローズドループこそが、時間とともに低下していくevalスコアと、改善を続けるevalスコアの違いです。それがなければ、evalセットは陳腐化し、モデルはドリフトし、CIゲートは本番品質が劣化する中で通過する形骸になります。

特定のAPIシナリオのテストパターン

構造化出力のテスト

JSON Schemaバリデーションだけでも構造化出力の失敗の約70%を捕捉します。残りの30%にはビジネスルールチェックを追加します:「priceに負の値は不可」「emailはregexに一致必須」「totalはsubtotalとtaxの合計と等しくなければならない」。フィールド間の整合性チェック:「payment_methodが’credit_card’なら、last_fourはnullであってはならない」。

プロバイダー固有の落とし穴:OpenAIはfunction.argumentsをJSON文字列として返します。Anthropicはtool_use.inputをJSONオブジェクトとして返します。あなたのパーサーは両方を処理しなければならず——evalスイートも両方をテストしなければなりません。CIで両方のレスポンス形式をモックしてください。

プロバイダー間の完全なリクエスト・レスポンス形式リファレンス——構造化出力、ツール呼び出し、ストリーミングを含む——は、chat completions APIドキュメントを参照してください。

ツール呼び出しのテスト

失敗頻度の高い順に4つのチェック:(1) ツール名がスキーマと一致する。(2) 必須引数が存在し、正しい型である。(3) 並列ツール呼び出しが互いに干渉しない。(4) ツールエラー後、モデルが修正された引数でリトライする——またはエスカレーションする——ループしない。

テストでハードなループ制限を設定します:同じツールが3回以上連続して呼ばれたら——テストは失敗。モデルはパターンを認識すべきであり、繰り返すべきではありません。

RAG品質のテスト

3つの次元:コンテキスト関連性(取得されたチャンクはユーザーが尋ねた内容に関係しているか?)、回答の忠実性(回答内のすべての主張が取得されたチャンクによって裏付けられているか?)、引用の正確性(各引用が、引用された情報を実際に含むチャンクを指しているか?)。最小しきい値:top-1引用精度——90%以上。それ以下になると、ユーザーは信頼を失います——すぐに。

ほとんどのLLM evalパイプラインが3か月以内に失敗する理由

ハッピーパスのみをテストする

あなたのevalセットには「返品ポリシーは?」「パスワードをリセットするには?」——きれいで、友好的で、整ったクエリがあります。本番には「i cant log in wtf???」や「URGENT: my refund still hasn’t processed and it’s been TWO WEEKS」——タイポ、怒り、コンテキスト欠落があります。evalセットに本番的なエッジケースを含めていなければ、95%のevalスコアは何の意味もありません。

修正: 本番ログからサンプリングします。evalセットの少なくとも20%が過去の失敗——以前に誤った回答、拒否、またはハルシネーションを生んだクエリ——に由来することを確保してください。

ジャッジモデルのバージョンを固定していない

ジャッジをGPT-4からGPT-4oにアップグレードしました。すべてのevalスコアが3ポイント上昇しました。チームは「品質改善」を祝いました。本番では何も変わっていません。ジャッジが甘くなっただけです。

修正: ジャッジモデルのバージョンを固定してください。アップグレードが必要なら、50件の人間注釈例で再キャリブレーションし、スコアマッピングを確立してください。それがない限り、evalスコアの履歴はノイズです。

evalセット上での最適化

evalセットに合わせてプロンプトをチューニングしました。95%の精度。出荷しました。本番精度:68%。evalセットにはあなたが最適化したパターンが含まれていました。本番にはそれ以外のすべてが含まれています。

修正: train/eval/test分割(70/15/15)。最適化はトレーニングセットを対象に行います。CIはevalセットに対して実行します。テストセットは保持されます——リリース前に1回だけ実行し、そこで報告されるスコアが、デプロイ前に得られる本番性能の最も近い見積もりです。

CIでevalゲートが通過したら、カナリアリリースやフォールバックチェーンなどのデプロイパターンが本番の分布シフトから保護します。ロールアウト戦略とモデルフェイルオーバー設定については、本番最適化ガイドを参照してください。

さらに読む。 テストスイートの構造化出力側を、当社のJSON modeと構造化出力の比較で拡充しましょう。これは、CIパイプラインが検証する必要があるプロバイダー固有の形式処理をカバーしています。プロンプト最適化の手法についてはステップ4を、ロールアウト戦略とモデルフェイルオーバー設定については上記の本番最適化ガイドを参照してください。

FAQ

最初に必要なテストケースは何件?

方向性のフィードバックを得るための最小は50件です——変更が物事を良くしたか悪くしたかを知るには十分ですが、CIゲートにはノイズが多すぎます。100〜500件あれば統計的有意性が得られます——1件のエッジケース失敗でスコアが数ポイント以上揺れることはありません。50件から始めましょう。本番ログから毎週20〜30件の新しいケースを追加します。プログラムによるLLMテストが初めてで、まずAPIの基礎を学びたいなら、当社のLLM API入門ガイドが、evalスイートを構築する前のリクエスト構造を解説しています。

LLM-as-Judgeと人間の評価——ギャップはどれほど?

GPT-4ジャッジは、事実確認と指示追従タスクで人間の注釈者と80%超の確率で一致します。ギャップが最も大きいのは主観的次元(創造性、文体品質)です。客観的次元——faithfulness、形式準拠、タスク完了——では、LLMジャッジは個々の人間の注釈者に匹敵するか、それを上回ります。疲労と一貫性の欠如を排除するからです。

本番で使うモデルと同じモデルをジャッジに使うべきですか?

いいえ。自己増強バイアスは実在し、測定可能です——モデルは同じモデルファミリーの出力のスコアを5〜10%水増しします。異なるモデルファミリーか、専用のジャッジモデルを使いましょう。本番スタックがClaudeなら、GPT-4で評価してください。

ストリーミングレスポンスをどう評価しますか?

個々のトークンではなく、完全に連結されたレスポンスを評価します。パフォーマンスアサーションを追加します:TTFT(最初のトークンまでの時間)が目標しきい値以下、トークン間レイテンシP95が予算以下。SSEイベントデータ内のエスケープされていない改行がパーサーを壊すようなストリーミング固有のバグは、専用の決定論的チェックが必要です。

3つのプロバイダーで3つのアダプターを書かずに同じevalスイートを実行するには?

同一のテストケースを1つのベースURLに送り、modelパラメータだけをgpt-5.5claude-sonnet-4-20250514gemini-3.1-proの間で切り替えます。1つのリクエスト形式。1つのevalパイプライン。変わる唯一の変数はどのモデルがプロンプトを処理するか——それはまさにevalスイートが測定するように設計されたものです。単一のベースURLを通した最初の統合evalリクエストには、クイックスタートガイドに従ってください。

LLM評価は完了するフェーズではありません。維持するインフラです。6層スタック——データセット、ルーブリック、ジャッジ、CIゲート、本番観測、クローズドループ——は、LLM搭載機能が良くなっているのか悪くなっているのかを知るための最小実行可能システムです。

50件のテストケースと決定論的チェックから始めましょう。今週中にCIで実行します。本番ログから毎週20件追加します。1か月後には、統計的に意味のあるevalセットと、ユーザーが気づく前にリグレッションを捕捉するCIゲートができています。

evalスイートは、テストするすべてのモデルに対してプロバイダー固有のアダプターを必要とするべきではありません。TokSpanでテストを開始——単一の統合ポイントを通じて、同じ50件のテストケースをGPT、Claude、Geminiに対して実行できます。