RAG評価基盤の作り方:精度・再現率・運用コストを同時に最適化する実践手順

RAG(Retrieval Augmented Generation)は導入が進んでいますが、運用で最も難しいのは「改善したつもり」が頻発する点です。embedding モデルを変えた、chunk サイズを変えた、reranker を追加した。どれも良さそうに見えるのに、ユーザー満足は上がらない。このギャップを埋めるのが評価基盤です。

本記事では、RAG を継続改善するための評価パイプラインを、データセット設計から CI 統合まで具体的に解説します。

RAG評価で見るべき3層

RAG の品質は 1 指標では測れません。最低でも次の3層を分けて評価します。

  1. Retrieval層: 正しい文書を取れているか
  2. Generation層: 回答が正確で有用か
  3. System層: レイテンシ・コスト・安定性

この分離がないと、生成品質低下の原因が retrieval なのか prompt なのか判別できません。

ステップ1:評価データセットを設計する

1-1. 問い合わせカテゴリを分割

例として次の5カテゴリに分けます。

  • 定義確認(用語説明)
  • 手順質問(How-to)
  • 例外対応(エラー解決)
  • 比較検討(A vs B)
  • 根拠提示(出典必須)

カテゴリごとに難易度と重要度を持たせ、偏りを防ぎます。

1-2. 正解の持ち方

正解は「理想回答1つ」では不十分です。RAGでは表現揺れが自然なので、次を保存します。

  • 期待要素(必須ポイント)
  • 禁止要素(誤情報、過剰断定)
  • 参照すべき文書ID

この形式にすると、自動評価と人手レビューを両立できます。

ステップ2:Retrieval評価を自動化

代表指標:

  • Recall@k
  • MRR
  • nDCG

例えば、正解文書IDを持つ場合は次のように計算します。

1
2
3
def recall_at_k(retrieved_ids, gold_ids, k=5):
    topk = set(retrieved_ids[:k])
    return 1.0 if len(topk.intersection(gold_ids)) > 0 else 0.0

運用では平均値だけでなく、カテゴリ別分布を見ることが重要です。手順質問だけ recall が低い場合、chunk 戦略や見出し抽出に問題がある可能性が高いです。

ステップ3:Generation評価の設計

自動評価では次を推奨します。

  • Faithfulness(出典との整合)
  • Answer Relevance(質問への適合)
  • Completeness(必要要素網羅)
  • Safety(禁止事項違反)

LLM-as-a-judge を使う場合、判定プロンプトを固定し、temperature=0 で再現性を確保します。さらに、週次で人手サンプル監査を入れて判定ドリフトを検出します。

ステップ4:System評価(遅延・コスト)

品質改善がコスト爆増を招くと継続できません。次を同時に計測します。

  • P50/P95 latency
  • 平均 input/output token
  • 1回答あたり推定コスト
  • timeout率、fallback率

この4指標を CI レポートに含めると、精度改善の副作用を早期に発見できます。

ステップ5:CIへの組み込み

PR ごとに評価ジョブを実行し、閾値を満たさない変更をブロックします。

判定例:

  • Recall@5: 0.82 以上
  • Faithfulness: 0.90 以上
  • P95 latency: 2500ms 以下
  • Cost/answer: $0.005 以下

疑似フロー:

  1. 変更ブランチでインデックス再構築
  2. 評価データセット100件で推論
  3. 指標を計算して前回基準と比較
  4. 差分レポートをPRコメントに投稿

これで「なんとなく改善」を排除できます。

ステップ6:オンライン評価との接続

オフライン評価だけでは実利用の多様性を拾えません。オンライン指標を接続します。

  • ユーザー評価(👍/👎)
  • 再質問率(同一セッションで再問い合わせ)
  • 人間オペレータ転送率

重要なのは trace_id でオフライン指標と紐づけることです。これにより「オフラインは良いのに本番満足が低い」差分を原因追跡できます。

改善ループの実例

ある社内ヘルプデスクRAGでの改善例:

  • 問題: 手順質問で誤回答が多い
  • 原因: chunk が短すぎ、手順文脈が分断
  • 対策: section-aware chunking + reranker導入

結果:

  • Recall@5: 0.74 → 0.88
  • Faithfulness: 0.81 → 0.93
  • P95 latency: +180ms(許容内)

このように、どの変更がどの指標に効いたかを記録すると、次回改善の再現性が高まります。

よくある失敗

  1. 評価データが少なすぎる
    • 20件程度では統計的に不安定。最低100件、理想300件。
  2. 単一スコアで判定する
    • 精度だけでコストを見ないと運用破綻。
  3. 判定プロンプトを頻繁に変える
    • 指標比較の連続性が失われる。
  4. 失敗事例をデータセットへ反映しない
    • 同じ不具合を繰り返す。

90日ロードマップ

  • 0-30日: 評価データセット整備、retrieval指標導入
  • 31-60日: generation指標 + CIゲート導入
  • 61-90日: オンライン評価統合、週次改善会の定着

この順序なら、運用負荷を抑えつつ確実に品質を上げられます。

まとめ

RAG の実力は、モデル選定より評価基盤で決まります。retrieval、generation、system の3層を分離し、CI に組み込むことで、改善の再現性が生まれます。

まずは小さく始めて、失敗ケースを評価データセットに反映し続けてください。評価が回り始めると、RAG は「当たるかどうかの賭け」から「制御可能なプロダクト」へ変わります。

実装例:評価結果をPRコメントに自動投稿する

運用で効くのは、評価結果を開発者が日常的に見る導線を作ることです。GitHub Actions で評価スクリプトを実行し、結果を PR コメントへ投稿します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
name: rag-eval
on: [pull_request]
jobs:
  evaluate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: uv sync
      - run: uv run python scripts/run_rag_eval.py --dataset evalset_v3.json --out report.json
      - run: uv run python scripts/post_pr_comment.py report.json

この仕組みがあると、レビュー段階で「この変更は Faithfulness を 0.04 落とすが latency は改善」という会話ができ、意思決定が定量化されます。

評価データセットの更新運用

評価セットを固定しすぎると、現実の問い合わせ変化に追従できません。次のルールを推奨します。

  • 月1回、実ユーザー失敗ケースを20件追加
  • 四半期ごとに古いケースを棚卸し
  • 重要カテゴリ比率を維持(例: 手順質問30%以上)

この更新を怠ると、指標が良くても体感品質が落ちる「評価腐敗」が起きます。

A/Bテストとの接続

大きな変更(embedding刷新、reranker導入)は、オフライン評価だけでなくオンライン A/B を併用します。

  • A群: 現行パイプライン
  • B群: 新パイプライン
  • 比較指標: 👍率、再質問率、回答時間、コスト

2週間程度の観測で統計差が出るケースが多く、主観ベースの議論を減らせます。

まとめ(定着のポイント)

RAG 改善を継続する鍵は、評価を「一回の検証」ではなく「開発フローの標準」にすることです。CI コメント、データセット更新、A/B テストを回すことで、品質向上が偶然ではなく再現可能な活動になります。

補足

評価結果は経営指標とも接続できます。問い合わせ解決率やサポート工数削減と紐づけることで、RAG 改善が事業価値にどう効いたかまで説明可能になります。