Ragasを用いたRAGシステムの評価:FaithfulnessとContext Relevanceの自動測定ガイド

AI tutorial - IT technology blog
AI tutorial - IT technology blog

Retrieval-Augmented Generation(RAG)システムを本番環境にデプロイすることは、始まりに過ぎません。本当の頭痛の種は1週間後に現れます。ユーザーからわずかなハルシネーション(幻覚)が報告され始めたり、生成された回答が運用手順書(Runbook)と密かに矛盾していることにエンジニアが気づいたりするのです。1日5,000件のクエリを処理する規模になると、こうしたリグレッション(品質低下)を手動で検知することは不可能です。

そこで必要となるのが定量的なガードレールです。Ragas(Retrieval Augmented Generation Assessment)は、「LLM-as-a-judge(評価者としてのLLM)」フレームワークを採用することでこの課題を解決します。検索の品質と生成の精度を自動的に採点し、ログ出力を手動で何十時間もレビューする負担からチームを解放します。

クイックスタート(5分)

わずか5分足らずでベースラインのベンチマークを取得できます。必要なのはPython 3.10以降、OpenAI APIキー(またはOpenAI互換のエンドポイント)、そして質問、検索されたコンテキストのパッセージ、生成された回答からなる少数のインタラクションサンプルだけです。

まず、コアとなる依存関係をインストールします:

pip install ragas langchain-openai datasets

次に、最小限の評価スクリプトを作成します。Ragasは、クエリ、検索されたドキュメントのパッセージ、生成された回答、およびグラウンドトゥルース(正解データ)のリファレンスを含むデータセットを想定しています:

import os
from datasets import Dataset
from ragas import evaluate
from ragas.metrics import faithfulness, context_precision

os.environ["OPENAI_API_KEY"] = "your-openai-api-key"

# RAGサービスから取得したサンプルログ
eval_data = {
    "question": [
        "クラスタのバックアップ設定はどこに保存されていますか?",
        "内部サービスメッシュ呼び出しのタイムアウト閾値はいくつですか?"
    ],
    "contexts": [
        ["すべてのバックアップスケジュールとストレージターゲットは /etc/backup/cluster-spec.yaml で設定されています。"],
        ["Envoyサイドカーを経由するHTTPリクエストは、デフォルトの接続タイムアウトとして5秒を使用します。"]
    ],
    "answer": [
        "クラスタのバックアップ設定は /etc/backup/cluster-spec.yaml にあります。",
        "タイムアウト閾値はすべてのメッシュサイドカーで15秒です。"
    ],
    "ground_truth": [
        "/etc/backup/cluster-spec.yaml",
        "5秒"
    ]
}

dataset = Dataset.from_dict(eval_data)

# FaithfulnessとContext Precisionの評価を実行
results = evaluate(
    dataset=dataset,
    metrics=[faithfulness, context_precision]
)

print(results.to_pandas()[["question", "faithfulness", "context_precision"]])

このスクリプトを実行すると、Ragasは各回答を取得されたコンテキストと照合して解析し、0.0から1.0までのスコアを返します。出力の2行目に注目してください。コンテキストには明確に5秒と記載されているにもかかわらず、モデルが15秒とハルシネーションを起こしたため、faithfulnessスコアは0.0に急落しています。

ディープダイブ:FaithfulnessとContext Precisionの理解

すべてのRAGパイプラインは、リトリーバー(検索器)とジェネレーター(生成器)という2つのコンポーネントに処理を分割しています。不適切な回答が生じた場合、そのどちらにも原因がある可能性があります。これらを個別に切り分けて評価することで、的外れな調査に時間を浪費するのを防ぐことができます。

1. Faithfulness(ジェネレーターの品質)

Faithfulness(忠実性)は事実への適合度を測定します。すなわち、LLMが提供されたドキュメントを忠実に遵守しているか、それとも事前学習時の記憶から架空の事実を引き出していないかを検証します。Faithfulnessの低下は、ハルシネーションの発生を直接示しています。

Ragasは、洗練された2段階のプロセスでこれをスコアリングします:

  • クレーム抽出(Claim Extraction):評価用LLMが、生成された回答を独立した検証可能なアサーション(主張)に分割します。
  • 論理的帰結の検証(Entailment Verification):評価用LLMは、各主張が取得したパッセージのテキストによって直接裏付けられているかどうかをチェックします。

計算方法は非常にシンプルです:

Faithfulness = (裏付けられたクレーム数) / (生成されたクレームの総数)

たとえば、アシスタントが3つの技術的主張を出力したとします。パッセージによってそのうち2つが確認され、3つ目が根拠のないものであった場合、faithfulnessスコアは正確に0.67となります。

2. Context PrecisionとRelevance(リトリーバーの品質)

Context Precision(コンテキスト適合率)はSN比(シグナルとノイズの比率)を測定します。リトリーバーが関連性の高いスニペットを上位に抽出できているか、それとも不要なノイズの中に埋もれさせてしまっているかを評価します。

肥大化したベクトル検索の結果は、運用上よくある2つの問題を引き起こします:

  1. トークンコストの急増:プロンプトごとに無関係な8,000トークンを詰め込むと、予算はすぐに底をつきます。
  2. LLMの集中力低下:関連する詳細情報が長大で無関係な段落の間に挟まれると、モデルは重要な事実を見落としがちになります。

Ragasは、各パッセージ内の文が質問に直接寄与しているかどうかを検証することでチャンクを評価します。リトリーバーがネットワークドキュメントから1,200語を取得したものの、目的のCIDRブロックが含まれているのがわずか2行だけだった場合、Context Precisionは低下します。チャンクサイズの調整、ハイブリッド検索の重み付けのチューニング、クロスエンコーダーによるリランカーの追加を行うことで、このスコアを即座に改善できます。

高度な活用法:カスタムジャッジとCI/CD統合

迅速なローカル検証にはデフォルトのクラウドエンドポイントで十分です。しかし、企業のコンプライアンス要件や10,000クエリを超える評価バッチでは、通常社内モデルが求められます。標準のLangChainクライアントラッパーを使用すれば、評価タスクをプライベートインフラにルーティングできます。

セルフホストのジャッジモデルへの切り替え

Llama 3.1 70BなどのオープンウェイトモデルをホストするローカルのvLLMまたはLiteLLMゲートウェイを設定する方法は次のとおりです:

from langchain_openai import ChatOpenAI
from ragas.llms import LangchainLLMWrapper
from ragas.metrics import Faithfulness, ContextPrecision
from ragas import evaluate

# 社内のvLLMまたはLiteLLMインスタンスに接続
custom_llm = ChatOpenAI(
    model="meta-llama/Meta-Llama-3.1-70B-Instruct",
    base_url="http://internal-vllm.infra.local:8000/v1",
    api_key="dummy-token"
)

judge_llm = LangchainLLMWrapper(custom_llm)

# カスタムジャッジを各メトリクスに直接バインド
faithfulness_metric = Faithfulness(llm=judge_llm)
precision_metric = ContextPrecision(llm=judge_llm)

results = evaluate(
    dataset=dataset,
    metrics=[faithfulness_metric, precision_metric]
)

CIパイプラインにおけるスコアゲートの自動化

検索コードをリファクタリングする際、厳密なメトリクスは非常に価値を発揮します。データ取り込みサービスを画一的な500トークンチャンクからセマンティックチャンキングに移行した際、自動テストスイートによってContext Precisionが即座に18%低下したことが検知されました。これにより、ステージング環境へのデプロイ前にリグレッションを特定して修正することができました。

この評価スクリプトをGitHub Actionsワークフロー内で実行すれば、品質低下を自動的にブロックできます:

# eval_gate.py
import sys
from datasets import load_from_disk
from ragas import evaluate
from ragas.metrics import faithfulness, context_precision

test_dataset = load_from_disk("./tests/fixtures/rag_golden_dataset")
results = evaluate(test_dataset, metrics=[faithfulness, context_precision])

avg_faithfulness = results["faithfulness"]
avg_precision = results["context_precision"]

print(f"Faithfulness: {avg_faithfulness:.2f} | Context Precision: {avg_precision:.2f}")

# デプロイの品質閾値を強制
if avg_faithfulness < 0.85 or avg_precision < 0.75:
    print("品質チェックに失敗しました:スコアが本番環境の閾値を下回りました。")
    sys.exit(1)

print("品質チェックに合格しました。デプロイを続行します。")
sys.exit(0)

Ragasを大規模運用するための実践ノウハウ

大規模なテストセット全体でRAGベンチマークを自動化するには、実務上の落とし穴が伴います。以下の運用プラクティスを念頭に置いてください:

  • 50〜100問のゴールデンセットを厳選する:単純なハッピーパス(正常系)の合成データは避けましょう。マルチホップクエリ、口語表現、そしてモデルが回答を拒否すべき範囲外(out-of-scope)のプロンプトを含めます。
  • 生成されたモデルの応答をキャッシュする:Ragasは行ごとに複数の評価呼び出しを実行します。リトリーバーの変更のみをベンチマークする場合は、キャッシュされたジェネレーターの応答を読み込むことで、不要なAPI課金を回避できます。
  • 小規模なジャッジモデルを避ける:13Bパラメータ未満のモデルは、論理的帰結(含意)タスクで一貫して苦戦します。スコアの再現性を維持するためには、最低でも70Bパラメータのモデル、または実績のある8x7B MoEアーキテクチャを採用してください。
  • プロンプトを微調整する前に根本原因を特定する:Context Precisionが高くFaithfulnessが低い場合は、システムプロンプトに問題があることを示唆しています。Context Precisionが低い場合は、プロンプトの書き直しをやめ、代わりにチャンキング戦略、上位k件(top-k)の検索深度、または埋め込みインデックスを調整してください。
Share: