RAG評価がなぜ難しいのか

RAGシステムの評価は、従来の分類や回帰モデルの評価よりもはるかに困難です。理由は3つあります。まず、RAGの効果は2つのコンポーネントの連携に依存します。つまり、リトリーバーが見つけたドキュメントが関連性があるか(検索品質)、そしてジェネレーターがこれらのドキュメントに基づいて生成した回答が正確か(生成品質)です。どちらかの部分に問題があれば、最終的な効果は損なわれます。次に、評価基準は主観性が強いです。「良い回答」とは何か?ユーザーやシナリオによって基準はまったく異なる可能性があります。第三に、標準化されたテストセットが不足しています。各RAGアプリケーションのナレッジベースは異なるため、一般的な評価データセットでは実際の効果を反映するのは困難です。

しかし、測定がなければ改善はありません。RAGシステムがどの側面で優れているか、どの側面を最適化する必要があるかを知ることで、的を絞った改善が可能になります。本記事では、3層のRAG評価フレームワークを構築し、「感覚的に良い」から「データで証明された良い」へとアップグレードするのに役立てます。

第1層:検索品質評価

検索品質評価は、「リトリーバーが正しいドキュメントを見つけたかどうか」に焦点を当てます。主要な指標は次のとおりです。Recall@k(上位k件の結果に含まれる関連ドキュメントの割合)は、最も重要な検索指標です。見つけられなければ、後の生成がいかに優れていても無意味です。MRR(Mean Reciprocal Rank)(最初の関連ドキュメントのランクの逆数の平均)は、最も関連性の高いドキュメントを上位にランク付けする能力を測定します。NDCG@k(Normalized Discounted Cumulative Gain)(ランク位置の重みを考慮した正規化累積利得)は、関連性だけでなく、関連性の程度(部分的に関連 vs 完全に関連)とランク位置も考慮します。

これらの指標を計算するには、ラベル付きテストセットが必要です。各クエリに対して、どのドキュメントが関連するかをラベル付けします。これは、人手によるアノテーション(高品質だがコストが高い)またはLLMによる自動アノテーション(低コストだがバイアスの可能性)で実現できます。

import numpy as np
from openai import OpenAI

client = OpenAI(api_key="your-deepseek-api-key", base_url="https://api.deepseek.com")

class RetrievalEvaluator:
    def __init__(self):
        self.metrics = {}

    def recall_at_k(self, retrieved_ids, relevant_ids, k):
        """Recall@k:上位k件の結果で関連ドキュメントをどれだけカバーしたか"""
        top_k = set(retrieved_ids[:k])
        relevant = set(relevant_ids)
        if not relevant:
            return 0.0
        return len(top_k & relevant) / len(relevant)

    def mrr(self, retrieved_ids, relevant_ids):
        """MRR:最初の関連ドキュメントのランクの逆数"""
        relevant = set(relevant_ids)
        for i, doc_id in enumerate(retrieved_ids):
            if doc_id in relevant:
                return 1.0 / (i + 1)
        return 0.0

    def evaluate_all(self, test_queries):
        """一括評価"""
        recalls = {1:[], 3:[], 5:[], 10:[]}
        mrrs = []
        for q in test_queries:
            retrieved = q["retrieved_ids"]
            relevant = q["relevant_ids"]
            for k in recalls:
                recalls[k].append(self.recall_at_k(retrieved, relevant, k))
            mrrs.append(self.mrr(retrieved, relevant))
        result = {
            f"Recall@{k}": np.mean(v) for k, v in recalls.items()
        }
        result["MRR"] = np.mean(mrrs)
        return result

evaluator = RetrievalEvaluator()
test_data = [
    {"retrieved_ids":[1,3,5,7,9], "relevant_ids":[3,7]},
    {"retrieved_ids":[2,4,6,8,10], "relevant_ids":[4,6,10]},
]
results = evaluator.evaluate_all(test_data)
for metric, value in results.items():
    print(f"{metric}: {value:.3f}")

第2層:生成品質評価

生成品質評価は、「検索されたドキュメントに基づいて、モデルが生成した回答の品質」に焦点を当てます。主要な指標は次のとおりです。Faithfulness(忠実度):生成された回答が検索されたドキュメントに忠実であり、存在しない情報(幻覚)を作り出していないか。これはRAGシステムで最も重要な生成品質指標です。Answer Relevance(回答関連性):生成された回答がユーザーの質問に直接関連しており、脱線していないか。Context Relevance(コンテキスト関連性):検索されたドキュメントがユーザーの質問に関連しているか(関連のないドキュメントばかり検索された場合、後の生成は失敗する運命にあります)。

これらの指標を評価する最も実用的な方法は、LLM-as-a-Judgeを使用することです。つまり、より強力なLLM(DeepSeekなど)を使用して別のLLMの出力を評価します。これにより評価バイアスが生じる可能性がありますが、人手によるアノテーションがない場合、これが最も実行可能なソリューションです。RAGASフレームワークは、このアプローチを体系化する最良のツールです。

class GenerationEvaluator:
    def evaluate_faithfulness(self, answer, context):
        """回答がコンテキストに忠実かどうかを評価(幻覚があるかどうか)"""
        prompt = f"""以下の回答が提供されたコンテキストに忠実かどうかを評価してください。

コンテキスト:
{context}

回答:
{answer}

回答内の各ステートメントがコンテキストで裏付けられるかどうかを判断してください。
JSON形式で出力:
{{
  "score": 0から1のスコア,
  "hallucinations": ["作り話のステートメント1", "作り話のステートメント2"],
  "reasoning": "評価の理由"
}}"""
        response = client.chat.completions.create(
 model="deepseek-chat",
            messages=[{"role":"user","content":prompt}],
            temperature=0.1
        )
        return response.choices[0].message.content

    def evaluate_relevance(self, answer, question):
        """回答が質問に直接関連しているかを評価する"""
        prompt = f"""質問:{question}
回答:{answer}

回答が質問に直接対応しており、逸脱していないかを評価してください。
JSON: {{"score": 0-1, "reasoning":""}}"""
        response = client.chat.completions.create(
            model="deepseek-chat",
            messages=[{"role":"user","content":prompt}],
            temperature=0.1
        )
        return response.choices[0].message.content

eval_gen = GenerationEvaluator()
faithfulness = eval_gen.evaluate_faithfulness(
    "Pythonはインタープリタ型言語です。",
    "PythonはGuido van Rossumによって作成されたプログラミング言語で、複数のプログラミングパラダイムをサポートしています。"
)

第3層:エンドツーエンド評価

エンドツーエンド評価は、ユーザーの視点からRAGシステム全体のパフォーマンスを評価します。一般的な方法には、A/Bテスト(ユーザーをRAGシステムの異なるバージョンにランダムに割り当て、満足度やタスク完了率などの主要なビジネス指標を比較する)、人間による評価(評価者が統一基準に従って、正確性、完全性、流暢性、有用性の4つの側面でスコアリングする)、自動ベンチマークテスト(RGB、CRUD-RAGなどの公開RAG評価データセットを使用した標準化評価)があります。エンドツーエンド評価は究極の試金石です——検索や生成のスコアがどれだけ高くても、ユーザーが満足しなければ、システムは失敗です。

継続的評価体制の構築

RAG評価は一度きりの活動ではなく、継続的なプロセスであるべきです。3層の評価体制を構築することをお勧めします:リリース前はオフライン評価(ラベル付きデータセット+自動化指標)で基本品質を確保;リリース後はオンライン評価(ユーザーフィードバックの収集+サンプリングによる手動レビュー)で継続的に監視;定期的(毎週/毎月)に回帰評価を実施し、システムの劣化を防ぎます。評価結果をダッシュボードに可視化し、チームが各指標のトレンドを直感的に確認できるようにします。

RAGASフレームワークの実践

RAGAS(Retrieval Augmented Generation Assessment)は、現在最も人気のあるオープンソースのRAG評価フレームワークです。標準化された評価指標と自動評価プロセスを提供します。RAGASの核となる考え方は、各評価次元をLLMが判断できるサブ質問に分解し、DeepSeekなどのモデルに自動スコアリングさせることです。RAGASを使用した典型的なフロー:評価データ(質問、正解、取得されたコンテキスト、生成された回答を含む)を準備し、RAGASの評価関数を呼び出して、faithfulness、answer_relevancy、context_precision、context_recallなどの指標を取得します。LLM-as-Judgeは便利ですが、100%信頼できるわけではないことに注意が必要です。定期的に(例:毎月)評価サンプルの一部を抽出して手動で再確認し、自動スコアリングの正確性を校正することをお勧めします。オンライン評価と本番監視:オフライン評価はテストセットでのモデルのパフォーマンスを反映するだけで、実際のオンライン効果を完全に表すことはできません。本番環境では、オンライン評価指標を設定する必要があります——ユーザーのいいね率、低評価率、コピー率(ユーザーがAIの回答をコピーしたかどうか)、共有率、およびユーザーがフォローアップの質問を続けるかどうか(ユーザーが同様の質問を繰り返す場合、AIが最初にうまく回答できなかったことを示します)。これらの指標はオフライン指標ほど正確ではありませんが、ユーザーエクスペリエンスをリアルタイムで反映し、毎日の監視のノーススター指標として適しています。運用ダッシュボードには、オフライン評価トレンド(毎週更新)とオンライン指標トレンド(リアルタイム更新)の両方を表示し、両方を比較することで、RAGシステムの品質を総合的に把握することをお勧めします。

このスキルチェーンを自分で编排してみませんか?

スキルチェーンで開く →