メインコンテンツへスキップ
友田 陽大
本番LLMアプリ実装(信頼できるAI)
生成AI
LLM
評価
テスト
LLM-as-judge
RAG
CI/CD
AI駆動開発
品質保証
アーキテクチャ設計

LLMアプリの評価・テスト実践ガイド 2026|LLM-as-judge・回帰テスト・CIゲート

生成AI/LLMアプリを本番で壊さないための評価・テスト実践ガイド。非決定的な出力をどう測るか、評価データセット(ゴールデンセット)の作り方、決定的採点とLLM-as-judgeの使い分け、RAGの評価指標(RAGAS)、そして回帰をCIでゲートする方法まで、一次情報準拠のTypeScript実コードで解説します。

公開日
読了時間
10分
著者
友田 陽大
シェア

「デモは完璧に動いたのに、本番でユーザーの入力に晒したら壊れた」——LLMアプリで最も多い失敗です。原因は明快で、LLMの品質は“目視”では守れないからです。プロンプトを1行変えただけで、直したはずのケースが直り、直っていたケースが壊れる。決定論的なコードなら単体テストが守ってくれる領域を、LLMでは評価(Evaluation)という別の工学で守る必要があります。

結論から言えば、本番のLLMアプリの品質は次の3本柱に集約されます。

  1. 評価データセット(ゴールデンセット) — 代表例・エッジケース・敵対的入力を集めた“試験問題”。
  2. 自動採点 — 決定的チェック+LLM-as-judgeで、出力をスコア化する。
  3. CIゲート — デプロイを評価スコアで止める。回帰を人間の目ではなくパイプラインで検知する。

この記事は、生成AIパイプラインを本番運用してきた立場から、一次情報(OpenAI / Anthropic のeval公式ガイド、LLM-as-judgeの原典論文、RAGAS)に準拠して、TypeScriptの実コードで“本番で回る評価”を設計します。これは、LLMアプリのセキュリティMCP本番サーバーと並ぶ、「信頼できる本番AI」の第3の柱です。

なぜLLMアプリのテストは“従来と違う”のか

従来の単体テストは assert(f(x) === expected) です。入力に対して唯一の正解があり、一致するかを二値で判定します。LLMではこれが3点崩れます。

  • 非決定的 — 同じ入力で出力が揺れる。1回のパスは“たまたま”かもしれない。
  • 出力が自由文 — 「正解」が一意でない。言い回しは違っても意味が正しいことがある。
  • 品質が連続量 — 合否ではなく「どれくらい良いか」。だから**アサーションではなく評価(スコアリング)**が要る。

そこで発想を変えます。合否の1/0ではなく、データセット全体の“合格率とスコア分布”で品質を見る。 個々のテストが赤/緑ではなく、「90%のケースで基準を満たすか」をゲートにするのです。

評価データセット(ゴールデンセット)の作り方

すべての評価は“試験問題”から始まります。ここで手を抜くと、以降の採点がいくら精緻でも意味を持ちません。

  • 代表例・エッジケース・敵対的入力を混ぜる。 OpenAIもテストデータに「典型的なケース、エッジケース、敵対的なケース」を含めるべきとしています。無関係な入力、極端に長い入力、有害な入力、本質的に曖昧な入力——これらを意図的に入れます。
  • 少数から始め、反復的に育てる。 権威ある一次情報は「最低◯件」といった特定の件数を定めていません。手元の代表例から始め、本番で見つけた失敗を1件ずつ足していくのが実務です。OpenAIは評価データを「時間とともに広げていく動的な空間」と表現します。
  • 量を優先する。 Anthropicは明快で、「質より量」——少数の高品質な人手採点より、多少ノイズがあっても自動採点できる多数の設問の方が良い、としています。理由は次章に直結します。

採点の3方式を使い分ける

出力をどう採点するか。3つの方式があり、**「決定的に測れるものは決定的に測る」**が鉄則です(安く・速く・再現可能)。

方式何を測るかコスト使いどころ
決定的(コードベース)完全一致・JSON schema適合・正規表現・数値の許容誤差・キーワード包含極小形式・構造・事実の一部。最優先
LLM-as-judge自由文の意味的品質(忠実性・関連性・トーン)決定的に測れない“良さ”
人間最終的な妥当性・微妙な判断少数の重要ケース・judgeの較正

決定的採点はコードで書けます。Zodスキーマで出力の構造を、単純なチェックで内容を測ります。

import { z } from "zod";

type Case = { input: string; expected?: string; mustInclude?: string[] };
type Score = { name: string; pass: boolean; value: number };

// 完全一致(期待値がある設問だけ判定)
const exactMatch = (out: string, c: Case): Score => {
  const pass = c.expected === undefined || out.trim() === c.expected.trim();
  return { name: "exact_match", pass, value: pass ? 1 : 0 };
};

// 必須キーワードの包含(事実の欠落を安く検知)
const containsAll = (out: string, c: Case): Score => {
  const missing = (c.mustInclude ?? []).filter((k) => !out.includes(k));
  return { name: "contains_all", pass: missing.length === 0, value: missing.length ? 0 : 1 };
};

// 出力が期待するJSON構造かをスキーマで判定(形式崩れを回帰として捕まえる)
const matchesSchema = <T>(out: string, schema: z.ZodType<T>): Score => {
  const parsed = schema.safeParse(safeJson(out));
  return { name: "schema", pass: parsed.success, value: parsed.success ? 1 : 0 };
};

LLM-as-judge を“正しく”使う

自由文の品質は、強いLLMに採点させる LLM-as-judge が現実解です。原典論文(Zheng et al., 2023)は、GPT-4級のjudgeが人間同士の一致度と同等(80%超)でヒトの選好を近似できると示しました。スケーラブルで説明可能——ただし同じ論文が明確なバイアスも報告しています。

  • 位置バイアス — 先に提示された回答を有利に採点しがち。
  • 冗長性バイアス — 長い回答を過大評価しがち。
  • 自己優遇バイアス — 自分(同系統モデル)の出力を好みがち。
  • 推論の弱さ — 数学・論理の採点は苦手。

対策は設計で効かせます。(1) rubric(採点基準)を先に固定し曖昧さを消す、(2) ペア比較では順序を入れ替えて両方向で採点し位置バイアスを相殺、(3) 判定は必ずスキーマで構造化する、(4) まず強モデルで始め、人間の評価と一致することを確認してから軽量モデルへスケール(OpenAIの公式推奨)。

import { generateObject } from "ai";
import { z } from "zod";

// judge の出力は必ず構造化する(自由文で"良い"と言わせない)
const Judgment = z.object({
  faithful: z.boolean(), // 与えた文脈に忠実か(ハルシネーションなし)
  relevant: z.boolean(), // 質問に答えているか
  score: z.number().int().min(1).max(5), // rubric に基づく5段階
  reason: z.string().max(300),
});

async function judge(input: string, output: string, context: string) {
  const { object } = await generateObject({
    // 判定は強モデルで開始。人間と一致したら軽量モデルへ置換してコストを下げる。
    model: "anthropic/claude-opus-4-8",
    schema: Judgment,
    prompt:
      "次の回答を rubric で採点。基準: (1)文脈に忠実か (2)質問に関連するか。\n" +
      `# 質問\n${input}\n# 文脈\n${context}\n# 回答\n${output}`,
  });
  return object; // 検証済みの構造化スコア
}

RAG特有の評価:検索と生成を分けて測る

RAG(検索拡張生成)は、検索の失敗生成の失敗が混ざります。切り分けて測らないと、どこを直すべきか分かりません。RAG評価の定番 RAGAS の指標(公式定義):

  • Faithfulness(忠実性) — 回答が検索された文脈に対してどれだけ事実整合的か(ハルシネーション検知)。
  • Answer / Response Relevancy — 回答がユーザーの質問にどれだけ関連するか。
  • Context Precision — 取得した文脈のうち、関連チャンクを上位に並べられたか(検索の適合率)。
  • Context Recall — 必要な関連文書をどれだけ取りこぼさず取得できたか(検索の再現率)。

Faithfulnessが低ければ生成(プロンプト・モデル)を、Context Recallが低ければ検索(埋め込み・チャンク・認可フィルタ)を疑います。RAGの精度改善は RAGの本番アンチパターン、検索設計は pgvectorによる本番RAG を参照してください。

回帰テストをCIに組み込む

評価は、**CIに組み込んで初めて品質を“守る”**ものになります。手元で1回良くても意味がない。デプロイを評価スコアでゲートします。固定データセットに対する合格率が閾値を割ったら、ビルドを失敗させます。

// 集計とCIゲート:合格率が閾値未満なら exit 1 でデプロイを止める
type Grader = (out: string, c: Case) => Score;

async function runEval(
  cases: Case[],
  runApp: (input: string) => Promise<string>,
  graders: Grader[],
  threshold = 0.9,
): Promise<void> {
  let passed = 0;
  for (const c of cases) {
    const out = await runApp(c.input);
    // 決定的グレーダーは全通過を要求(ここに judge を足して重み付けもできる)
    const ok = graders.every((g) => g(out, c).pass);
    if (ok) passed++;
  }
  const rate = passed / cases.length;
  console.log(`pass rate: ${(rate * 100).toFixed(1)}% (${passed}/${cases.length})`);
  if (rate < threshold) {
    console.error(`❌ eval ${(rate * 100).toFixed(1)}% < 閾値 ${threshold * 100}% — デプロイを中止`);
    process.exit(1); // CI が赤 → マージ/デプロイされない
  }
}

ツールを使うなら promptfoo が実務的です。GitHub Actionが、PRでプロンプト変更の前後を評価して結果をPRに投稿します——コードレビューと同じ粒度で“品質のdiff”が見えるわけです。CIの土台は GitHub Actions の鍵レスCI/CD と同じ発想で組めます。

補足:これは AI駆動開発の品質ゲート(AIが“書いたコード”の品質を守る話)とは別レイヤーです。本記事は、AIアプリが“生成する出力”そのものの品質を守る話です。両方が揃って初めて本番品質になります。

オフライン評価とオンライン評価:両輪で回す

  • オフライン評価(事前) — 固定した評価データセットに対し、デプロイ前に品質・エッジケース・堅牢性を測る。CIゲートはここ。
  • オンライン評価(本番)本番トラフィックをサンプリングして継続的に評価し、ドリフト・品質劣化を検知する。ユーザーのフィードバック(👍/👎)や、judgeによる本番出力の抜き取り採点を組み合わせます。

オフラインは「壊れたものを出さない」、オンラインは「出した後の劣化に気づく」。片方では不十分です。オンライン評価はログ・トレースが土台になるので、OpenTelemetryによる本番可観測性と一体で設計します。LLM出力の実行時検証(構造化出力)は structured output の信頼性設計へ。

導入チェックリスト(本番投入前)

  • ゴールデンセット — 典型例・エッジケース・敵対的入力を含む評価データを用意し、失敗を足して育てているか。
  • 決定的採点を最優先 — 形式・構造・キーワード・数値は決定的グレーダーで測っているか(安く再現可能)。
  • LLM-as-judge — rubricを固定し、判定をスキーマで構造化し、順序入れ替えでバイアスを抑えているか。強モデルで開始したか。
  • RAGは分離評価 — faithfulness / relevancy / context precision・recall で検索と生成を切り分けているか。
  • CIゲート — 合格率が閾値未満ならデプロイを止めているか。PRで品質のdiffが見えるか。
  • オンライン評価 — 本番トラフィックをサンプリングして継続評価し、ドリフトを検知しているか。
  • 可観測性 — 入出力・スコア・レイテンシ・コストを記録し、劣化を追えるか。

まとめ

LLMアプリの品質保証は、勘や目視ではなく工学です。「非決定的で自由文な出力を、データセットと自動採点でスコア化し、CIでゲートする」——この規律が、デモと本番を分けます。

  • 測れるものは決定的に測る。 残りを LLM-as-judge(rubric固定・バイアス対策・強モデル開始)で。
  • RAGは検索と生成を分けて測る。
  • 評価はCIに組み込んでこそ品質を守る。 オフライン(事前ゲート)とオンライン(本番監視)を両輪で。

セキュリティ・MCP・評価——この3つが揃って、生成AIは「速く作れて、安全で、壊れない」本番システムになります。作る速さと、守る堅さは、正しく設計すれば両立します。

よくある質問

LLMアプリのテストは普通の単体テストと何が違いますか?
出力が非決定的で自由文のため、『入力→期待値の完全一致』だけでは測れません。決定的なチェック(形式・キーワード・数値の許容誤差)と、意味的な品質の『評価(スコアリング)』を組み合わせます。合否の1/0ではなく、スコアの分布と合格率で見るのが要点です。
LLM-as-judge(LLMに採点させる)は信頼できますか?
条件付きで有効です。GPT-4級のモデルによる判定は、人間同士の一致度と同等(80%超)という研究結果があります(Zheng et al. 2023)。ただし位置バイアス・冗長性バイアス・自己優遇バイアスがあるため、採点基準(rubric)を明示し、比較時は順序を入れ替え、まず強いモデルで始めて人間の評価と一致することを確認してから軽量モデルへスケールします。
評価データセット(ゴールデンセット)は何件必要ですか?
権威ある一次情報は特定の件数を定めていません。手元にある代表的な例から始め、典型例・エッジケース・敵対的入力を含め、本番ログや失敗事例を足して反復的に育てるのが実務です。Anthropicは『質より量(自動採点できる多数の設問)』を推奨しています。
RAG(検索拡張生成)の評価はどう測りますか?
検索と生成を分けて測ります。RAGASのfaithfulness(回答が検索文脈に忠実か=ハルシネーション検知)、answer/response relevancy(質問への関連性)、context precision・context recall(検索の適合率・再現率)が定番の指標です。
評価をCIに組み込むには?
デプロイを評価スコアでゲートします。固定データセットに対する合格率が閾値を下回ればビルドを失敗させ、デプロイを止めます。promptfooのGitHub Actionは、PRでプロンプト変更の前後を評価して結果をPRに投稿できます。
オフライン評価とオンライン評価の違いは?
オフライン評価(事前)は、固定した評価データセットに対してデプロイ前に品質・エッジケース・堅牢性を測ります。オンライン評価(本番)は、本番トラフィックをサンプリングして継続的に評価し、ドリフトや品質劣化を検知します。両輪で回すのが本番運用です。

参考文献

友田

友田 陽大

経済産業大臣賞 受賞プロダクト開発者。TypeScript + Python + AWS で、SaaS・業界DX・実用レベルの生成AI(RAG)を、要件定義からインフラ・運用まで一人で完遂します。

この記事の実装を、案件として承ります

セキュリティエンジニアリングを、設計から実装・運用まで承ります

脅威モデリングによる設計レビュー、暗号・認証認可の正しい実装、ログ設計と検知(検知エンジニアリング)、インシデント対応の体制づくりまで。一人 × 生成AIで経済産業大臣賞のB2B SaaSや本番二重課金0件の決済基盤を作ってきた知見で、御社のプロダクトを“速く作り、かつ守れる”状態に伴走します。設計でしか守れない縦のリスクは監査としても承ります。

プロジェクト単位(請負)・技術顧問のどちらにも対応可能です。まずは30分の無料技術相談から。

最短ルート:カレンダーから直接予約

相談内容が固まっている方は、フォーム送信よりその場で日程を確定する方がスムーズです。下記から空き時間をお選びください。

  • 30分のオンライン無料相談
  • Google Meet / Zoom / Microsoft Teams
  • NDA 商談前締結可・無理な営業はいたしません
無料相談の空き枠を予約する

あわせて読みたい