- 「精度の平均」では RAG の品質はわからない
- RAG 評価の四つの次元
- オフライン評価: Golden Dataset の構築と自動測定
- オンライン評価: プロダクション品質のモニタリング
- 回帰防止パイプライン: CI で品質ゲートをかける
- RAGAS フレームワークの活用
- 障害シナリオ別の対応
- 参考資料

「精度の平均」では RAG の品質はわからない
RAG チャットボットの評価で最もよくある誤りは、単一の指標(例:全体正答率 82%)だけを見て配備を決めてしまうことだ。この数字の裏には、次のようなリスクが隠れている。
- Retrieval の失敗が回答品質を決める: 正解を含む文書を検索できなければ、LLM がどれほど優秀でもハルシネーションを生成する。全体正答率 82% が retrieval recall 60% + LLM の補正で作られた数値である可能性がある。
- Grounding のない回答はハルシネーションである: LLM が検索された文書を無視して自前の知識で答えると、たとえ正しくても信頼できない。Grounding rate(回答が検索文書に根拠を持つ割合)を別途測定する必要がある。
- 安全性は精度とは別物である: 正確な回答であっても、PII を含んだりビジネス規定に違反したりすれば配備できない。
本記事では、RAG チャットボットの品質を Retrieval、Grounding、Answer、Safety という四つの独立した次元で測定し、オフラインベンチマークからオンラインモニタリングまでの評価パイプライン全体を設計する。
RAG 評価の四つの次元
| 次元 | 測定対象 | 主要指標 | 失敗時の症状 |
|---|---|---|---|
| Retrieval | 検索段階が関連文書を見つけたか | Recall@K, MRR, nDCG | 見当違いなトピックの回答 |
| Grounding | 回答が検索された文書に根拠を持つか | Faithfulness, Citation Precision | ハルシネーション、根拠なき主張 |
| Answer | 最終回答がユーザーの質問に合うか | Answer Relevance, Correctness | 質問と無関係な回答 |
| Safety | 回答が安全で規定を遵守しているか | Toxicity Rate, PII Leak Rate | 有害コンテンツ、個人情報漏洩 |
オフライン評価: Golden Dataset の構築と自動測定
Golden Dataset の構造
"""
RAG 評価用の Golden Dataset。
各テストケースは質問、正解、正解根拠となる文書、期待カテゴリを含む。
"""
from dataclasses import dataclass, field
from typing import List, Optional
@dataclass
class GoldenTestCase:
"""単一の評価ケース"""
question_id: str
question: str
expected_answer: str
relevant_doc_ids: List[str] # 正解を含む文書 ID のリスト
category: str # faq, policy, product, troubleshooting
difficulty: str # easy, medium, hard
expected_citations: List[str] # 回答で引用されるべき文書 ID
negative_assertions: List[str] = field(default_factory=list) # 回答に含まれてはいけない内容
# 評価セットの例
GOLDEN_DATASET = [
GoldenTestCase(
question_id="faq_001",
question="返金処理には何日かかりますか?",
expected_answer="返金はリクエスト日から営業日基準で 3-5 日以内に処理されます。",
relevant_doc_ids=["doc_refund_policy_v3", "doc_faq_payment"],
category="faq",
difficulty="easy",
expected_citations=["doc_refund_policy_v3"],
negative_assertions=["即時返金", "当日処理"],
),
GoldenTestCase(
question_id="policy_002",
question="海外配送時の関税は誰が負担しますか?",
expected_answer="海外配送時の関税および付加価値税は受取人の負担です。",
relevant_doc_ids=["doc_shipping_international", "doc_customs_guide"],
category="policy",
difficulty="medium",
expected_citations=["doc_shipping_international"],
negative_assertions=["関税免除", "送料無料"],
),
GoldenTestCase(
question_id="trouble_003",
question="アプリで決済エラー P4021 が発生します。どう解決しますか?",
expected_answer="P4021 エラーはカード会社の認証失敗により発生します。カード会社のアプリでオンライン決済を有効化してから再試行してください。",
relevant_doc_ids=["doc_error_codes", "doc_payment_troubleshoot"],
category="troubleshooting",
difficulty="hard",
expected_citations=["doc_error_codes"],
negative_assertions=["カスタマーセンターに問い合わせ", "不明なエラー"],
),
]
Retrieval 品質の測定
"""
検索段階の品質を測定するモジュール。
Recall@K、MRR(Mean Reciprocal Rank)、nDCG を計算する。
"""
from typing import List, Dict
import numpy as np
def recall_at_k(
retrieved_doc_ids: List[str],
relevant_doc_ids: List[str],
k: int = 5,
) -> float:
"""
上位 K 件の検索結果に関連文書が含まれる割合。
例: relevant_docs = ["A", "B"], retrieved = ["C", "A", "D", "B", "E"]
recall@5 = 2/2 = 1.0
"""
retrieved_set = set(retrieved_doc_ids[:k])
relevant_set = set(relevant_doc_ids)
if not relevant_set:
return 1.0 # 関連文書がなければ recall は無意味
return len(retrieved_set & relevant_set) / len(relevant_set)
def mean_reciprocal_rank(
retrieved_doc_ids: List[str],
relevant_doc_ids: List[str],
) -> float:
"""
最初の関連文書の逆数順位。
例: relevant = ["B"], retrieved = ["A", "B", "C"] -> MRR = 1/2 = 0.5
"""
relevant_set = set(relevant_doc_ids)
for i, doc_id in enumerate(retrieved_doc_ids):
if doc_id in relevant_set:
return 1.0 / (i + 1)
return 0.0
def evaluate_retrieval(
test_cases: List[dict],
retriever,
k_values: List[int] = [3, 5, 10],
) -> Dict[str, float]:
"""
テストセット全体に対して retrieval 品質を測定する。
"""
results = {f"recall@{k}": [] for k in k_values}
results["mrr"] = []
for case in test_cases:
retrieved = retriever.search(
query=case["question"],
top_k=max(k_values),
)
retrieved_ids = [doc.id for doc in retrieved]
for k in k_values:
r = recall_at_k(retrieved_ids, case["relevant_doc_ids"], k)
results[f"recall@{k}"].append(r)
mrr = mean_reciprocal_rank(retrieved_ids, case["relevant_doc_ids"])
results["mrr"].append(mrr)
return {
metric: round(float(np.mean(values)), 4)
for metric, values in results.items()
}
LLM-as-a-Judge: Grounding と Answer 品質の測定
LLM を判定者として用い、回答の faithfulness(検索文書に基づく忠実度)と relevance(質問との関連性)を測定する。
"""
LLM-as-a-Judge パターンで RAG 回答の Grounding と Relevance を評価する。
OpenAI GPT-4o または Claude 3.5 Sonnet を判定者として使う。
"""
from dataclasses import dataclass
from typing import List, Optional
import json
FAITHFULNESS_PROMPT = """あなたは RAG チャットボット回答の忠実度を評価する専門の判定者です。
与えられる情報:
- ユーザーの質問: {question}
- 検索された文書群: {retrieved_contexts}
- チャットボットの回答: {answer}
評価基準:
1. 回答のすべての主張(claim)が検索された文書に根拠を持つか?
2. 文書にない内容を追加したり作り上げたりしていないか?
3. 文書の内容を歪曲していないか?
必ず以下の JSON 形式で応答してください:
{{
"faithfulness_score": <0.0-1.0>,
"claims": [
{{
"claim": "<回答から抽出した主張>",
"supported": <true/false>,
"evidence": "<根拠となる文書内容または 'no evidence found'>"
}}
],
"unsupported_claims_count": <int>,
"hallucination_detected": <true/false>
}}"""
RELEVANCE_PROMPT = """あなたは RAG チャットボット回答の関連性を評価する専門の判定者です。
与えられる情報:
- ユーザーの質問: {question}
- チャットボットの回答: {answer}
評価基準:
1. 回答が質問に直接答えているか?
2. 不要な情報が過度に含まれていないか?
3. 中核的な情報が欠落していないか?
必ず以下の JSON 形式で応答してください:
{{
"relevance_score": <0.0-1.0>,
"addresses_question": <true/false>,
"missing_information": "<欠落している中核情報または 'none'>",
"unnecessary_information": "<不要な情報または 'none'>"
}}"""
@dataclass
class JudgmentResult:
question_id: str
faithfulness_score: float
relevance_score: float
hallucination_detected: bool
unsupported_claims: int
missing_info: str
raw_judgment: dict
async def evaluate_with_llm_judge(
question: str,
answer: str,
retrieved_contexts: List[str],
judge_client, # OpenAI または Anthropic のクライアント
question_id: str = "",
) -> JudgmentResult:
"""LLM 判定者で faithfulness と relevance を評価する。"""
# Faithfulness の評価
faith_prompt = FAITHFULNESS_PROMPT.format(
question=question,
retrieved_contexts="\n---\n".join(retrieved_contexts),
answer=answer,
)
faith_response = await judge_client.chat.completions.create(
model="gpt-4o-2024-11-20",
messages=[{"role": "user", "content": faith_prompt}],
response_format={"type": "json_object"},
temperature=0.0, # 判定の一貫性のため temperature 0
)
faith_result = json.loads(faith_response.choices[0].message.content)
# Relevance の評価
rel_prompt = RELEVANCE_PROMPT.format(question=question, answer=answer)
rel_response = await judge_client.chat.completions.create(
model="gpt-4o-2024-11-20",
messages=[{"role": "user", "content": rel_prompt}],
response_format={"type": "json_object"},
temperature=0.0,
)
rel_result = json.loads(rel_response.choices[0].message.content)
return JudgmentResult(
question_id=question_id,
faithfulness_score=faith_result.get("faithfulness_score", 0.0),
relevance_score=rel_result.get("relevance_score", 0.0),
hallucination_detected=faith_result.get("hallucination_detected", False),
unsupported_claims=faith_result.get("unsupported_claims_count", 0),
missing_info=rel_result.get("missing_information", "unknown"),
raw_judgment={"faithfulness": faith_result, "relevance": rel_result},
)
オンライン評価: プロダクション品質のモニタリング
オフライン評価を通過したモデルがプロダクションに配備された後も、実トラフィックに対する品質を継続的にモニタリングする必要がある。
リアルタイム品質指標の収集
"""
プロダクション RAG チャットボットのリアルタイム品質指標を収集するミドルウェア。
すべてのリクエスト-レスポンス対に対して軽量な品質シグナルを収集する。
"""
import time
import hashlib
from dataclasses import dataclass, field
from typing import List, Optional, Dict
from prometheus_client import Histogram, Counter, Gauge
# Prometheus メトリクスの定義
RESPONSE_LATENCY = Histogram(
"rag_response_latency_seconds",
"RAG 応答の総所要時間",
["pipeline_stage"], # retrieval, generation, total
buckets=[0.1, 0.25, 0.5, 1.0, 2.0, 5.0, 10.0],
)
RETRIEVAL_EMPTY = Counter(
"rag_retrieval_empty_total",
"検索結果が 0 件のリクエスト数",
)
CITATION_RATE = Gauge(
"rag_citation_rate",
"直近 100 件のうち引用を含む応答の割合",
)
THUMBS_DOWN = Counter(
"rag_thumbs_down_total",
"ユーザーの否定的フィードバック数",
["category"],
)
@dataclass
class QualitySignals:
"""1 件のリクエスト-レスポンスから収集する軽量な品質シグナル"""
request_id: str
retrieval_count: int # 検索された文書数
retrieval_latency_ms: float
top_similarity_score: float # 最上位検索結果の類似度スコア
generation_latency_ms: float
response_length_chars: int
has_citation: bool # 応答に出典の引用が含まれているか
language_detected: str # 応答の言語
contains_hedging: bool # 「おそらく」「〜かもしれません」のような不確実表現の有無
def collect_quality_signals(
request_id: str,
query: str,
retrieved_docs: list,
response: str,
retrieval_time: float,
generation_time: float,
) -> QualitySignals:
"""リクエスト-レスポンス対から品質シグナルを抽出する。"""
top_score = max((doc.score for doc in retrieved_docs), default=0.0)
has_citation = any(
marker in response
for marker in ["[出典:", "[参考:", "[文書", "出典:"]
)
hedging_phrases = ["おそらく", "〜かもしれません", "正確でない可能性", "確認が必要です"]
contains_hedging = any(phrase in response for phrase in hedging_phrases)
signals = QualitySignals(
request_id=request_id,
retrieval_count=len(retrieved_docs),
retrieval_latency_ms=retrieval_time * 1000,
top_similarity_score=top_score,
generation_latency_ms=generation_time * 1000,
response_length_chars=len(response),
has_citation=has_citation,
language_detected="ko" if any('\uac00' <= c <= '\ud7a3' for c in response) else "en",
contains_hedging=contains_hedging,
)
# Prometheus メトリクスの記録
RESPONSE_LATENCY.labels(pipeline_stage="retrieval").observe(retrieval_time)
RESPONSE_LATENCY.labels(pipeline_stage="generation").observe(generation_time)
RESPONSE_LATENCY.labels(pipeline_stage="total").observe(retrieval_time + generation_time)
if signals.retrieval_count == 0:
RETRIEVAL_EMPTY.inc()
return signals
品質アラート閾値の設定
# prometheus-rules.yaml
groups:
- name: rag_quality_alerts
interval: 30s
rules:
# 検索の空結果比率が 10% を超えたら警告
- alert: RAGRetrievalEmptyRateHigh
expr: |
rate(rag_retrieval_empty_total[10m]) /
rate(rag_response_latency_seconds_count{pipeline_stage="total"}[10m]) > 0.10
for: 5m
labels:
severity: warning
team: chatbot
annotations:
summary: 'RAG 検索の空結果比率が 10% を超えています'
description: |
現在の空結果比率: {{ $value | humanizePercentage }}
インデックスの状態、埋め込みモデル、クエリ前処理を確認してください。
# 引用を含む比率が 70% を下回ったら警告
- alert: RAGCitationRateLow
expr: rag_citation_rate < 0.70
for: 10m
labels:
severity: warning
team: chatbot
annotations:
summary: 'RAG の引用を含む比率が 70% を下回っています'
description: |
現在の引用比率: {{ $value | humanizePercentage }}
LLM プロンプトの引用指示または検索品質を確認してください。
# 応答遅延が急増したら警告
- alert: RAGResponseLatencyHigh
expr: |
histogram_quantile(0.95,
rate(rag_response_latency_seconds_bucket{pipeline_stage="total"}[5m])
) > 5.0
for: 3m
labels:
severity: critical
team: chatbot
annotations:
summary: 'RAG 応答の p95 遅延が 5 秒を超えています'
# ユーザーの否定的フィードバックの急増
- alert: RAGNegativeFeedbackSpike
expr: |
rate(rag_thumbs_down_total[30m]) > 2 * rate(rag_thumbs_down_total[24h] offset 1d)
for: 15m
labels:
severity: warning
team: chatbot
annotations:
summary: 'ユーザーの否定的フィードバックが前日比 2 倍以上に増加しました'
回帰防止パイプライン: CI で品質ゲートをかける
RAG パイプラインの構成要素(プロンプト、検索設定、LLM モデル)を変更するたびに、品質の回帰を自動的に検知しなければならない。
"""
RAG 品質の回帰テスト。
Golden dataset に対して 4 つの次元の品質を測定し、
以前のバージョンに対する回帰の有無を判定する。
"""
import json
import sys
from pathlib import Path
from typing import Dict
# 品質のベースライン (以前の配備バージョンの成績)
BASELINE_SCORES = {
"recall@5": 0.88,
"mrr": 0.75,
"faithfulness": 0.91,
"relevance": 0.87,
"safety_pass_rate": 1.00,
"citation_rate": 0.82,
}
# 許容可能な下落幅 (絶対値)
REGRESSION_TOLERANCE = {
"recall@5": 0.03, # 3% の下落まで許容
"mrr": 0.03,
"faithfulness": 0.02, # faithfulness は厳格に
"relevance": 0.03,
"safety_pass_rate": 0.0, # safety は回帰を許さない
"citation_rate": 0.05,
}
def check_regression(current_scores: Dict[str, float]) -> dict:
"""
現在のスコアをベースラインと比較し、回帰の有無を判定する。
Returns: {"passed": bool, "regressions": [...], "improvements": [...]}
"""
regressions = []
improvements = []
for metric, baseline in BASELINE_SCORES.items():
current = current_scores.get(metric, 0.0)
tolerance = REGRESSION_TOLERANCE.get(metric, 0.0)
delta = current - baseline
if delta < -tolerance:
regressions.append({
"metric": metric,
"baseline": baseline,
"current": current,
"delta": round(delta, 4),
"tolerance": tolerance,
})
elif delta > 0.01: # 1% 以上の改善
improvements.append({
"metric": metric,
"baseline": baseline,
"current": current,
"delta": round(delta, 4),
})
passed = len(regressions) == 0
return {
"passed": passed,
"regressions": regressions,
"improvements": improvements,
"summary": (
f"PASSED: {len(improvements)} improvements, 0 regressions"
if passed
else f"FAILED: {len(regressions)} regressions detected"
),
}
if __name__ == "__main__":
# CI で実行: python eval/regression_check.py results.json
results_path = sys.argv[1] if len(sys.argv) > 1 else "eval_results.json"
with open(results_path) as f:
current_scores = json.load(f)
result = check_regression(current_scores)
print(json.dumps(result, indent=2, ensure_ascii=False))
if not result["passed"]:
print("\n=== REGRESSION DETAILS ===")
for reg in result["regressions"]:
print(f" {reg['metric']}: {reg['baseline']:.4f} -> {reg['current']:.4f} "
f"(delta: {reg['delta']:.4f}, tolerance: {reg['tolerance']:.4f})")
sys.exit(1)
CI ワークフロー全体の構成
# .github/workflows/rag-eval.yml
name: RAG Quality Evaluation
on:
push:
paths:
- 'src/rag/**'
- 'prompts/**'
- 'config/retrieval/**'
pull_request:
paths:
- 'src/rag/**'
- 'prompts/**'
jobs:
offline-eval:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: pip install -r requirements-eval.txt
- name: Run retrieval evaluation
run: |
python eval/retrieval_eval.py \
--dataset eval/golden_dataset.json \
--k-values 3,5,10 \
--output eval_results_retrieval.json
- name: Run LLM judge evaluation
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
python eval/llm_judge_eval.py \
--dataset eval/golden_dataset.json \
--judge-model gpt-4o-2024-11-20 \
--output eval_results_judge.json
- name: Run safety evaluation
run: |
python eval/safety_eval.py \
--dataset eval/golden_dataset.json \
--output eval_results_safety.json
- name: Merge results and check regression
run: |
python eval/merge_results.py \
eval_results_retrieval.json \
eval_results_judge.json \
eval_results_safety.json \
--output eval_results.json
python eval/regression_check.py eval_results.json
- name: Upload evaluation report
uses: actions/upload-artifact@v4
if: always()
with:
name: eval-report
path: eval_results*.json
RAGAS フレームワークの活用
RAGAS(Retrieval Augmented Generation Assessment)は RAG 評価のためのオープンソースフレームワークだ。上で自前実装した指標を RAGAS で置き換えたり補完したりできる。
"""
RAGAS フレームワークを活用した RAG 評価の例。
pip install ragas==0.2.6
"""
from ragas import evaluate
from ragas.metrics import (
faithfulness,
answer_relevancy,
context_precision,
context_recall,
)
from datasets import Dataset
# 評価データの準備 (RAGAS 形式)
eval_data = {
"question": [
"返金処理には何日かかりますか?",
"海外配送時の関税は誰が負担しますか?",
],
"answer": [
"返金は営業日基準で 3-5 日以内に処理されます。",
"海外配送時の関税と付加価値税は受取人が負担します。",
],
"contexts": [
["返金リクエスト日から営業日基準で 3-5 日以内に返金が処理されます。週末および祝日は営業日に含まれません。"],
["海外配送時に発生する関税および付加価値税は受取人の負担です。関税額は輸入国の税率によって変わります。"],
],
"ground_truth": [
"返金はリクエスト日から営業日基準で 3-5 日以内に処理されます。",
"海外配送時の関税および付加価値税は受取人の負担です。",
],
}
dataset = Dataset.from_dict(eval_data)
# RAGAS 評価の実行
results = evaluate(
dataset=dataset,
metrics=[
faithfulness, # 回答がコンテキストに忠実か
answer_relevancy, # 回答が質問に関連しているか
context_precision, # 検索されたコンテキストが正確か
context_recall, # 関連コンテキストを漏れなく検索できたか
],
)
print(results)
# {'faithfulness': 0.95, 'answer_relevancy': 0.92,
# 'context_precision': 0.88, 'context_recall': 0.90}
障害シナリオ別の対応
シナリオ 1: Faithfulness スコアの急落
症状: オフライン評価で faithfulness が 0.91 から 0.72 に低下
ユーザーからの報告: 「根拠のない回答が増えた」
点検の順序:
1. LLM モデルのバージョン変更の有無を確認
-> gpt-4o-2024-08-06 から gpt-4o-2024-11-20 に更新されていた
2. システムプロンプトの grounding 指示を確認
-> モデル更新後にプロンプトのチューニングがされていない
解決:
1. システムプロンプトに「必ず検索された文書に基づいて回答してください。
文書にない内容は『該当する情報が見つかりません』と回答してください。」を追加して強化
2. モデル更新前に必ずオフライン評価を実施するルールを策定
3. モデル別のプロンプトバージョン管理 (model_version -> prompt_version のマッピングテーブル)
シナリオ 2: 検索の空結果率の急増
症状: rag_retrieval_empty_total カウンタが平常時比で 5 倍に増加
エラーログ: なし (検索自体は成功するが結果が 0 件)
原因: 埋め込みモデル更新後、新しいクエリ埋め込みと既存文書の埋め込みの
ベクトル空間がずれた (cosine similarity が全般的に低下)
解決:
1. 直ちに以前の埋め込みモデルへロールバック
2. 新しい埋め込みモデル適用時は全文書の再埋め込みが必須
3. 埋め込みモデル変更手順に「再インデックス完了の確認」ステップを追加
シナリオ 3: LLM-as-a-Judge の評価コスト急増
症状: 月間 LLM Judge コストが $3,000 から $12,000 に増加
原因: テストセットが 50 件から 500 件に増え、PR ごとに実行していた
解決:
1. Golden dataset を core(50 件) + extended(450 件) に分離
2. PR では core のみ実行し、main へのマージ時に extended を含める
3. LLM Judge のキャッシュ: 同一入力に対する判定結果を 30 日間キャッシュ
4. 低コストモデル(gpt-4o-mini)で一次フィルタリングし、失敗ケースのみ gpt-4o で再判定
クイズ
Q1. RAG 評価を Retrieval、Grounding、Answer、Safety の四次元に分ける理由は?
||各次元で発生する問題の原因と解決方法が異なるからである。Retrieval の失敗はインデックス/埋め込みの問題であり、Grounding の失敗は LLM プロンプトの問題である。これを統合指標で見ると原因分析ができなくなる。||
Q2. LLM-as-a-Judge で temperature を 0 に設定する理由は?
||判定の再現性(reproducibility)を高めるためである。temperature が高いと同じ入力に対して異なる判定結果が出ることがあり、CI テストの安定性が下がる。||
Q3. オンラインモニタリングで「検索の空結果率」を別指標として追跡する理由は?
||検索結果が 0 件だと LLM が自前の知識で回答し、ハルシネーションのリスクが急増するからである。この指標が上昇したら、インデックス品質、埋め込みモデル、クエリ前処理に問題があるという強いシグナルだ。||
Q4. Safety 指標の回帰許容範囲を 0% に設定する理由は?
||PII の漏洩や有害コンテンツの生成は、一件であっても法的リスクとブランド毀損を招きうるからである。精度は小幅な低下を許容できるが、安全性は絶対基準である。||
Q5. RAGAS の context_precision と context_recall の違いは?
||context_precision は「検索された文書のうち実際に関連がある割合」であり、context_recall は「関連文書のうち検索できた割合」である。Precision が低いと不要な情報がプロンプトを汚染し、recall が低いと回答に必要な情報が欠ける。||
Q6. 回帰防止パイプラインで絶対基準と相対基準の両方を使うべき理由は?
||絶対基準(例: faithfulness > 0.85)だけだと、既存の 0.95 から 0.86 へ急落しても通過してしまう。相対基準(以前との delta)だけだと、もともとスコアが低いサービスで問題になる。二つの基準を組み合わせてこそ品質を多角的に守れる。||
Q7. Golden dataset に negative_assertions を含める理由は?
||正しい回答に近いが誤っている内容(例: 「即時返金」)が含まれるのを検知するためである。正解との類似度だけでは、こうした微妙な誤りを捉えられない。||
参考資料
- RAGAS 公式ドキュメント - Metrics Reference
- DeepEval - LLM Evaluation Framework
- TruLens - Feedback Functions for LLM Apps
- Lewis et al., "Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks" (arXiv:2005.11401)
- Es et al., "RAGAS: Automated Evaluation of Retrieval Augmented Generation" (arXiv:2309.15217)
- OpenAI Evals Framework
- OWASP Top 10 for LLM Applications