RAG评估指标
RAG 系统的评估是确保系统质量的关键环节。需要从检索质量和生成质量两个维度进行系统化评估。
本篇为评估「概览」:检索层指标(Recall/Precision/MRR/NDCG)与生成层指标(Faithfulness/Answer Relevance)的逐项定义、公式、达标标准与诊断矩阵详见下文。
RAG 评估的核心问题
| 问题 | 对应指标 |
|---|---|
| 检索到的文档相关吗? | Context Precision / Context Recall |
| 模型回答忠于检索到的内容吗? | Faithfulness |
| 模型回答切题吗? | Answer Relevance |
| 系统面对噪声是否鲁棒? | Noise Robustness |
RAGAS 评估框架
RAGAS(Retrieval Augmented Generation Assessment)是目前最流行的 RAG 评估框架。
核心指标
| 指标 | 公式/说明 | 评估目标 |
|---|---|---|
| Context Precision | 相关文档在 Top-K 中的排名是否靠前 | 检索精度 |
| Context Recall | 参考答案所需的信息是否被检索到 | 检索召回 |
| Faithfulness | 生成内容是否可以从上下文中推导出来 | 忠实度 |
| Answer Relevance | 生成的回答是否与问题相关 | 回答相关性 |
Context Precision 检索精度
含义: 在检索到的 Top-K 文档中,有多少是真正相关的?相关文档的排名是否靠前?
检索到 5 个文档:[相关, 无关, 相关, 无关, 相关]
Precision@5 = 3/5 = 0.6
但如果相关文档排名靠前:
[相关, 相关, 相关, 无关, 无关]
Precision@5 = 3/5 = 0.6(但质量更好)
所以实际计算会考虑排名:
Weighted Score = Σ(precision@k × rel_k) / total_relevant
优化方向:
-
提高 Embedding 模型质量
-
使用 Re-ranker 重排序
-
优化分块策略
Context Recall 检索召回
含义: 参考答案所需的信息是否都被检索到了?
标准答案需要 3 条信息:A, B, C
检索到的文档覆盖了 A 和 B,遗漏了 C
Recall = 2/3 = 0.67
优化方向:
-
增加 Top-K 数量
-
使用混合检索(BM25 + 向量)
-
查询扩展(HyDE、多查询)
-
优化文档覆盖度
Faithfulness 忠实度
含义: 模型的回答是否基于检索到的上下文,而非”编造”的内容?
上下文:"北京是中国首都,人口约2185万"
生成回答:"北京是中国首都,人口约2185万,面积约16410平方公里"
面积信息不在上下文中 → Faithfulness 降低
计算方式:
-
将回答拆分为多个独立声明(claims)
-
对每个声明检查是否可以从上下文中推导出来
-
Faithfulness = 可推导的声明数 / 总声明数
优化方向:
-
Prompt 中强调”只基于提供的上下文回答”
-
使用更强的 LLM
-
降低 temperature
-
添加”我不知道”的兜底策略
Answer Relevance 回答相关性
含义: 模型的回答是否真正回答了用户的问题?
问题:"什么是机器学习?"
回答:"深度学习是机器学习的一个子领域..."
→ 部分相关,但没有直接定义机器学习
计算方式:
-
根据生成的回答反向生成多个可能的问题
-
计算生成的问题与原始问题的相似度
-
相似度越高,回答越相关
完整评估指标体系
检索层指标
| 指标 | 说明 | 优化方向 |
|---|---|---|
| Hit Rate | Top-K 中是否包含至少一个相关文档 | 增大 K、混合检索 |
| MRR (Mean Reciprocal Rank) | 第一个相关文档的排名倒数 | Re-ranker、优化排序 |
| NDCG | 考虑排名位置的评估 | 排序模型优化 |
| MAP | 所有相关文档的平均精度 | 综合优化 |
生成层指标
| 指标 | 说明 | 计算方式 |
|---|---|---|
| Faithfulness | 忠实度 | LLM-as-Judge |
| Answer Relevance | 回答相关性 | 逆向问题生成 + 相似度 |
| Correctness | 正确性 | 与参考答案对比 |
| Completeness | 完整性 | 是否覆盖了所有要点 |
端到端指标
| 指标 | 说明 |
|---|---|
| 任务完成率 | 最终是否成功完成用户任务 |
| 用户满意度 | 人工评估或用户反馈 |
| 响应时间 | 从提问到回答的总延迟 |
| 成本效率 | 每次查询的平均成本 |
评估方法
1. LLM-as-Judge
使用强 LLM(如 GPT-4)作为评估器:
judge_prompt = """
评估以下回答的质量。
问题:{question}
上下文:{context}
回答:{answer}
请从以下维度评分(1-5分):
1. 忠实度:回答是否基于上下文
2. 相关性:回答是否切题
3. 完整性:回答是否全面
"""
优点: 灵活、可扩展、能评估主观质量
缺点: 成本高、可能有偏差
2. 基准测试
使用标准数据集进行客观评估:
| 数据集 | 评估内容 |
|---|---|
| MS MARCO | 段落检索、问答 |
| Natural Questions | 真实问题检索 |
| HotpotQA | 多跳推理 |
| TriviaQA | 事实性问答 |
3. A/B 测试
graph LR TRAFFIC[用户流量] -->|50%| VA[RAG 版本 A] TRAFFIC -->|50%| VB[RAG 版本 B] VA --> COMP[比较:用户满意度、点击率、任务完成率] VB --> COMP
4. 人工评估
| 维度 | 评分标准 |
|---|---|
| 准确性 | 信息是否正确 |
| 相关性 | 是否回答了问题 |
| 完整性 | 是否遗漏关键信息 |
| 可读性 | 回答是否清晰易懂 |
| 引用质量 | 引用是否准确、充分 |
评估流水线
graph TD S1[Step 1: 构建评估数据集] --> S1a[收集真实用户问题] S1 --> S1b[标注标准答案] S1 --> S1c[标注相关文档] S1 --> S2[Step 2: 运行 RAG 系统] S2 --> S2a[检索文档] S2 --> S2b[生成回答] S2 --> S2c[记录完整链路] S2 --> S3[Step 3: 自动化评估] S3 --> S3a[检索指标计算] S3 --> S3b[生成指标计算 RAGAS] S3 --> S3c[端到端指标] S3 --> S4[Step 4: 分析与优化] S4 --> S4a[识别薄弱环节] S4 --> S4b[A/B 测试优化方案] S4 --> S4c[持续迭代] S4c -.->|回到| S1
一、为什么 RAG 需要参数调优?
1.1 RAG 有多少参数可调?
一个典型的 RAG 系统涉及三类可调参数三类可调参数,组合起来搜索空间爆炸:
| 参数类别 | 具体参数 | 典型取值范围 |
|---|---|---|
| 分块参数 | chunk_size | 128 / 256 / 512 / 1024 / 2048 |
| chunk_overlap | 0 / 64 / 128 / 256 | |
| 分块策略 | 递归切分 / 语义分块 / 结构化 | |
| 检索参数 | top_k | 1 / 2 / 3 / 5 / 8 / 10 |
| 检索类型 | 纯向量 / 纯BM25 / 混合检索 | |
| rerank | 无 / bge-reranker / cohere | |
| similarity_threshold | 0.5 / 0.6 / 0.7 / 0.8 | |
| 生成参数 | temperature | 0 / 0.3 / 0.7 |
| LLM 模型 | GPT-4o / Claude / 开源模型 |
1.2 调优的核心原则
调优顺序必须遵循:
二、分块参数调优
2.1 chunk_size 的黄金区间
chunk_size 是 RAG 调优中影响最大的单一参数影响最大的单一参数,没有之一。
| chunk_size | 优势 | 劣势 | 适用场景 |
|---|---|---|---|
| 128~256 | 检索精度极高,噪声少 | 上下文碎片化,语义不完整 | 精确问答、FAQ、事实检索 |
| 256~512 | 精度与上下文的最佳平衡点 | — | 大多数 RAG 场景的首选 |
| 512~1024 | 上下文完整,适合长答案 | 可能引入噪声,检索精度下降 | 报告生成、综合分析 |
| 1024~2048 | 信息覆盖最全 | 噪声严重,LLM 注意力分散 | 探索性搜索、知识浏览 |
2.2 chunk_overlap 的选择
| overlap | 效果 | 建议场景 |
|---|---|---|
| 0 | 无重叠,无冗余 | chunk_size 小 + 文档结构清晰 |
| 10%~20% | 最佳平衡点 | 大多数场景的默认选择 |
| >30% | 冗余严重,检索结果高度重复 | 仅当 chunk_size 极大时考虑 |
经验公式经验公式:overlap ≈ chunk_size × 0.15 ~ 0.2overlap ≈ chunk_size × 0.15 ~ 0.2
例如 chunk_size=512 → overlap=64~128
2.3 分块策略对比
| 策略 | 原理 | 优势 | 劣势 | 推荐场景 |
|---|---|---|---|---|
| 递归切分 | 按分隔符层级递归切分 | 简单高效,保留语义边界 | 不考虑语义连贯性 | 默认首选 |
| 语义分块 | 基于句子 embedding 相似度断点 | 语义完整性最强 | 计算成本高 | 高精度问答 |
| 结构化分块 | 按文档标题/章节结构切分 | 保留文档层次结构 | 依赖文档格式清晰 | 技术文档/法律文本 |
| 句子窗口 | 单句建索引,命中后扩窗 | 检索精度 + 丰富上下文 | 实现复杂 | 长文档问答 |
三、检索参数调优
3.1 top_k 的选择逻辑
top_k 控制传给 LLM 的上下文数量,直接影响召回率 vs. 噪声召回率 vs. 噪声的平衡。
| top_k | 召回率 | 噪声量 | Token 消耗 | 适用场景 |
|---|---|---|---|---|
| 1~2 | 低 | 极低 | 少 | 简单事实性问答 |
| 3~5 | 中高 | 可控 | 适中 | 大多数场景的最佳区间 |
| 5~8 | 高 | 较高 | 多 | 复杂分析、多方面问题 |
| 8~10 | 很高 | 高 | 很多 | 探索性搜索、研究调研 |
3.2 检索类型选择
| 检索类型 | 原理 | 擅长 | 不擅长 |
|---|---|---|---|
| 纯向量检索 | embedding 余弦相似度 | 语义相近的查询 | 精确专有名词、编号 |
| 纯 BM25 | 关键词词频匹配 | 精确术语、编号、代码 | 语义相近但表述不同 |
| 混合检索 + RRF | 向量 + BM25 + 倒数排名融合 | 兼顾语义和精确匹配 | — |
3.3 Rerank 的价值
| 配置 | Precision@5 | Faithfulness | 说明 |
|---|---|---|---|
| 无 Rerank | 0.55 | 0.72 | 基线 |
| 加 Rerank | 0.78 | 0.91 | Precision 提升 42%,幻觉率大幅下降 |
Rerank 的本质Rerank 的本质:检索是”粗筛”(从万级文档中选百级),Rerank 是”精排”(从百级中选十级给 LLM)。跳过 Rerank = 把噪声直接喂给 LLM。
四、多阶段网格搜索实验框架
4.1 什么是网格搜索?
网格搜索(Grid Search)的核心思想:穷举所有参数组合穷举所有参数组合,每种组合跑一遍评估,选出最优。
4.2 为什么要分阶段?
**全部参数一起网格搜索 = 组合爆炸。**全部参数一起网格搜索 = 组合爆炸。
例子:5 个 chunk_size × 4 个 top_k × 3 种检索 × 2 种 rerank × 3 种 embedding = 360 种组合360 种组合。每种跑 50 条测试用例 = 18000 次 LLM 调用。
分阶段调优分阶段调优 = 每阶段只调 1~2 个参数,大幅缩减搜索空间:
| 阶段 | 调优参数 | 固定参数 | 组合数 |
|---|---|---|---|
| 第一阶段 | chunk_size × overlap | top_k=5, 向量检索, 无 Rerank | 5×3 = 15 |
| 第二阶段 | top_k × 检索类型 | 最优分块, 无 Rerank | 4×3 = 12 |
| 第三阶段 | rerank × threshold | 最优分块 + 检索 | 3×4 = 12 |
| 第四阶段 | temperature | 全部最优 | 3×1 = 3 |
| 总计 | — | — | 42 |
从 360 缩减到 42,效率提升 8.5 倍8.5 倍。
4.3 完整实验代码框架
import itertools
import numpy as np
from dataclasses import dataclass
from typing import List, Dict, Any
@dataclass
class ExperimentConfig:
"""一组参数配置"""
chunk_size: int
chunk_overlap: int
top_k: int
retrieval_type: str # "vector", "bm25", "hybrid"
use_rerank: bool
rerank_model: str = ""
similarity_threshold: float = 0.5
@dataclass
class ExperimentResult:
"""一组实验结果"""
config: ExperimentConfig
hit_rate: float
precision: float
recall: float
faithfulness: float
answer_relevance: float
latency_ms: float
class RAGGridSearch:
def __init__(self, documents, test_suite, embed_model, llm):
self.documents = documents
self.test_suite = test_suite
self.embed_model = embed_model
self.llm = llm
self.results: List[ExperimentResult] = []
def build_index(self, config: ExperimentConfig):
"""根据配置构建索引"""
# 1. 分块
splitter = RecursiveCharacterTextSplitter(
chunk_size=config.chunk_size,
chunk_overlap=config.chunk_overlap
)
chunks = splitter.split_documents(self.documents)
# 2. 建索引
if config.retrieval_type == "vector":
index = VectorStore.from_documents(chunks, self.embed_model)
elif config.retrieval_type == "bm25":
index = BM25Index.from_documents(chunks)
else: # hybrid
index = HybridSearchIndex.from_documents(chunks, self.embed_model)
return index
def run_single_experiment(self, config: ExperimentConfig) -> ExperimentResult:
"""跑单组实验"""
# 1. 建索引
index = self.build_index(config)
# 2. 逐条测试
hits, precisions, recalls = [], [], []
faith_scores, rel_scores, latencies = [], [], []
for case in self.test_suite:
import time
t0 = time.time()
# 检索
retrieved = index.retrieve(case["question"], top_k=config.top_k)
# 可选 Rerank
if config.use_rerank:
retrieved = rerank(retrieved, case["question"], model=config.rerank_model)
# 过滤低分
retrieved = [r for r in retrieved if r.score >= config.similarity_threshold]
latency = (time.time() - t0) * 1000
# 检索指标
retrieved_ids = {r.id for r in retrieved}
relevant_ids = set(case["relevant_chunk_ids"])
tp = len(retrieved_ids & relevant_ids)
hits.append(1 if tp > 0 else 0)
precisions.append(tp / max(len(retrieved_ids), 1))
recalls.append(tp / max(len(relevant_ids), 1))
# 生成 + 生成指标
answer = self.llm.generate(case["question"], [r.text for r in retrieved])
faith = evaluate_faithfulness(case["question"], [r.text for r in retrieved], answer)
rel = evaluate_relevance(case["question"], answer)
faith_scores.append(faith)
rel_scores.append(rel)
latencies.append(latency)
return ExperimentResult(
config=config,
hit_rate=np.mean(hits),
precision=np.mean(precisions),
recall=np.mean(recalls),
faithfulness=np.mean(faith_scores),
answer_relevance=np.mean(rel_scores),
latency_ms=np.mean(latencies)
)
def run_grid_search(self, param_grid: Dict[str, List]) -> List[ExperimentResult]:
"""网格搜索"""
# 生成所有组合
keys = list(param_grid.keys())
values = list(param_grid.values())
combinations = list(itertools.product(*values))
print(f"共 {len(combinations)} 种组合待测试")
for i, combo in enumerate(combinations):
config = ExperimentConfig(**dict(zip(keys, combo)))
print(f"\n[{i+1}/{len(combinations)}] chunk={config.chunk_size}, "
f"overlap={config.chunk_overlap}, top_k={config.top_k}, "
f"retrieval={config.retrieval_type},
rerank={config.use_rerank}")
result = self.run_single_experiment(config)
self.results.append(result)
print(f" → Hit={result.hit_rate:.2f}, P={result.precision:.2f}, "
f"R={result.recall:.2f}, Faith={result.faithfulness:.2f}")
return self.results
def find_best(self, metric: str = "faithfulness") -> ExperimentResult:
"""找最优配置"""
return max(self.results, key=lambda r: getattr(r, metric))
# ========== 使用示例 ==========
if __name__ == "__main__":
# 第一阶段:只调分块参数
grid_phase1 = {
"chunk_size": [256, 512, 1024],
"chunk_overlap": [0, 64, 128],
"top_k": [5],
"retrieval_type": ["vector"],
"use_rerank": [False],
"similarity_threshold": [0.5],
}
searcher = RAGGridSearch(documents, test_suite, embed_model, llm)
results = searcher.run_grid_search(grid_phase1)
best = searcher.find_best("recall")
print(f"\n最优配置: chunk_size={best.config.chunk_size}, "
f"overlap={best.config.chunk_overlap}")
print(f"Recall={best.recall:.2f}, Precision={best.precision:.2f}")
五、LlamaIndex ParamTuner 实战
LlamaIndex 提供了内置的 ParamTunerParamTuner,可以直接用于 RAG 参数网格搜索。
5.1 基本用法
from llama_index.experimental.param_tuner import ParamTuner
# 定义参数网格
param_dict = {
"chunk_size": [256, 512, 1024],
"top_k": [1, 2, 5],
}
# 固定参数
fixed_param_dict = {
"docs": docs,
"eval_qs": eval_qs[:10],
"ref_response_strs": ref_response_strs[:10],
}
# 创建调优器
param_tuner = ParamTuner(
param_fn=objective_function, # 评估函数
param_dict=param_dict,
fixed_param_dict=fixed_param_dict,
show_progress=True,
)
# 运行网格搜索
results = param_tuner.tune()
# 输出最优结果
best = results.best_run_result
print(f"最优 Score: {best.score}")
print(f"最优 chunk_size: {best.params['chunk_size']}")
print(f"最优 top_k: {best.params['top_k']}")
5.2 Ray Tune 分布式调优
当参数组合特别多时,可以用 Ray Tune 做分布式并行搜索:
from llama_index.experimental.param_tuner import RayTuneParamTuner
param_tuner = RayTuneParamTuner(
param_fn=objective_function,
param_dict=param_dict,
fixed_param_dict=fixed_param_dict,
)
results = param_tuner.tune()
六、调优结果分析
6.1 结果可视化表格
假设我们完成了第一阶段(分块参数)的网格搜索:
| chunk_size | overlap | Hit@5 | Precision@5 | Recall@5 | F1 |
|---|---|---|---|---|---|
| 256 | 0 | 0.72 | 0.68 | 0.58 | 0.63 |
| 256 | 64 | 0.78 | 0.72 | 0.65 | 0.68 |
| 512 | 128 | 0.88 | 0.80 | 0.82 | 0.81 |
| 512 | 256 | 0.86 | 0.74 | 0.84 | 0.79 |
| 1024 | 128 | 0.82 | 0.60 | 0.88 | 0.71 |
| 1024 | 256 | 0.84 | 0.55 | 0.90 | 0.68 |
分析分析:
-
chunk_size=256 时 Recall 明显不足(信息碎片化)
-
chunk_size=1024 时 Precision 低(噪声太多)
-
chunk_size=512 + overlap=128 是最优平衡点chunk_size=512 + overlap=128 是最优平衡点,F1 最高
6.2 多阶段调优结果汇总
七、生产环境调优 Checklist
7.1 调优前必做
-
准备标准化测试集标准化测试集(至少 50 条,覆盖正常/边缘/恶意 query)
-
确定评估指标优先级(Recall 优先还是 Precision 优先?)
-
建立基线配置(Baseline)
-
确定参数搜索空间(不要盲目扩大)
7.2 调优中注意
-
每阶段只调 1~2 个参数只调 1~2 个参数,控制变量
-
每组实验至少跑 3 次取均值3 次取均值(LLM 输出有随机性)
-
记录每次实验的完整配置和指标完整配置和指标(用 DataFrame 或 CSV)
-
注意 Token 成本Token 成本(评估 100 组 × 50 条 = 大量 API 调用)
7.3 调优后验证
-
最优配置在测试集之外测试集之外的数据上也验证通过
-
关注延迟指标延迟指标(调优后的配置不能太慢)
-
纳入 CI/CD 回归测试CI/CD 回归测试(防止后续改动劣化)
-
灰度上线,收集线上真实反馈线上真实反馈
八、常见问题速答
Q1:RAG 系统有哪些关键参数需要调优?
Q2:chunk_size 怎么选?
Q3:top_k 越大越好吗?
Q4:什么是多阶段网格搜索?为什么不直接全部参数一起搜?
Q5:如何判断调优是否有效?
九、核心金句
-
“RAG 调优不是炼丹,是科学实验。先定义评估基准线,再用网格搜索自动化遍历参数组合,用数据驱动选最优配置。""RAG 调优不是炼丹,是科学实验。先定义评估基准线,再用网格搜索自动化遍历参数组合,用数据驱动选最优配置。”
-
“chunk_size 是 RAG 中影响最大的单一参数。黄金区间 256~512 tokens,配合 10%~20% 的 overlap。""chunk_size 是 RAG 中影响最大的单一参数。黄金区间 256~512 tokens,配合 10%~20% 的 overlap。”
-
“多阶段网格搜索的核心思想:每阶段只调 1~2 个参数,控制变量。从 120 种组合缩减到 36 种,效率提升 3 倍。""多阶段网格搜索的核心思想:每阶段只调 1~2 个参数,控制变量。从 120 种组合缩减到 36 种,效率提升 3 倍。”
-
“混合检索是生产环境标配。纯向量检索在精确匹配场景下效果差,加 BM25 后 Hit@3 通常提升 15%~25%。""混合检索是生产环境标配。纯向量检索在精确匹配场景下效果差,加 BM25 后 Hit@3 通常提升 15%~25%。”
-
“Rerank 是检索精排的关键步骤。跳过 Rerank 等于把噪声直接喂给 LLM,Precision 提升 40%+,幻觉率大幅下降。""Rerank 是检索精排的关键步骤。跳过 Rerank 等于把噪声直接喂给 LLM,Precision 提升 40%+,幻觉率大幅下降。“
十、参考资料
| 来源 | 链接 | 内容 |
|---|---|---|
| CSDN - RAGs性能调优实战 | https://blog.csdn.net/gitblog_00658/article/details/151743762 | Chunk Size 与 Top-K 调优策略 |
| CSDN - ParamTuner 超参数优化 | https://blog.csdn.net/ppoojjj/article/details/140310019 | LlamaIndex ParamTuner 网格搜索 |
| CSDN - RAG评估与优化指南 | https://blog.csdn.net/zhangzhentiyes/article/details/148527841 | RAGAS/ARES 评估框架实战 |
| CSDN - RAG 文本切分方法 | https://juejin.cn/post/7545087762838126630 | 分块策略全面对比 |
| LlamaIndex 官方文档 | https://docs.llamaindex.io/ | ParamTuner / RayTuneParamTuner |
| RAGAS 官方文档 | https://docs.ragas.io/ | RAG 评估指标与框架 |
一、为什么 RAG 评估必须分两层?
1.1 混在一起测 = 盲人摸象
RAG 系统 = **检索器(Retriever)**检索器(Retriever) + **生成器(Generator)**生成器(Generator)。一条 Fail 的用例,可能是:
-
检索没召回对内容(检索层问题)
-
LLM 没用好召回的片段(生成层问题)
-
两者都有问题
混在一起只能得到模糊结论混在一起只能得到模糊结论,无法指导优化方向。
1.2 分层评估的诊断价值
| 症状 | 检索层指标 | 生成层指标 | 问题定位 |
|---|---|---|---|
| 回答完全错误 | Recall 低 | Faithfulness 低 | 检索没召回 |
| 回答部分正确但有幻觉 | Recall 高 | Faithfulness 低 | LLM 编造 |
| 回答正确但不完整 | Recall 中 | Faithfulness 高 | TopK 太小 |
| 回答跑题 | Recall 高 | Relevance 低 | Prompt 问题 |
二、检索层指标详解
检索层的核心问题:**给定 query,系统能否从文档库中召回最相关的片段?**给定 query,系统能否从文档库中召回最相关的片段?
2.1 混淆矩阵基础
在信息检索中,我们把结果分为四类:
| 实际相关 | 实际不相关 | |
|---|---|---|
| 被系统检索 | TP(真正例) | FP(假正例) |
| 未被检索 | FN(假负例) | TN(真负例) |
2.2 核心检索指标
定义定义:检索到的文档中,有多大比例是真正相关的?
公式公式:Precision = TP / (TP + FP)
通俗理解通俗理解:你抓回来 10 条结果,有几条是真的有用的?
RAG 场景意义RAG 场景意义:Precision 低 = 大量无关片段被召回,干扰大模型,易产生幻觉。必须加 Rerank 过滤。
理想标准理想标准:≥ 70%
定义定义:所有相关文档中,成功检索到了多大比例?
公式公式:Recall = TP / (TP + FN)
通俗理解通俗理解:库里有 20 条相关内容,你找回来几条?
RAG 场景意义RAG 场景意义:Recall 低 = chunk 切割不合理、Embedding 能力弱、缺少关键词检索。
理想标准理想标准:≥ 90%
定义定义:只看 Top-K 结果中的 Precision 和 Recall。
RAG 场景意义RAG 场景意义:K 通常取 3 或 5(因为 LLM 上下文有限)。Recall@K 是 RAG 检索评估的核心指标Recall@K 是 RAG 检索评估的核心指标。
定义定义:Precision 和 Recall 的调和平均数。
公式公式:F1 = 2 × (Precision × Recall) / (Precision + Recall)
适用场景适用场景:需要平衡精确率和召回率时。单一指标看 F1,避免”偏科”。
理想标准理想标准:≥ 0.8
定义定义:有多大比例的查询,在前 K 个结果中至少检索到了一个相关文档?
公式公式:Hit@K = 至少有一个相关文档出现在 TopK 的查询数 / 查询总数
通俗理解通俗理解:用户提问后,前 K 条结果里有没有”正确答案”?
适用场景适用场景:快速验证检索器是否有基本召回能力。
定义定义:第一个相关文档的排名的倒数,取平均值。
公式公式:MRR = (1/|Q|) × Σ(1/rank_i)
其中 rank_i 是第 i 个查询的第一个相关文档的排名。
通俗理解通俗理解:第一个正确答案平均排在第几位?排第 1 得 1 分,排第 2 得 0.5 分,排第 3 得 0.33 分…
RAG 场景意义RAG 场景意义:问答场景中,通常第一个片段命中最重要。MRR 越高,说明正确答案越靠前。
| rank | 得分 |
|---|---|
| 1 | 1.0 |
| 2 | 0.5 |
| 3 | 0.33 |
| 4 | 0.25 |
| 5 | 0.2 |
定义定义:综合衡量排序质量,考虑相关性的”分级”(不是简单的是/否)。
计算步骤计算步骤:
-
CG@KCG@K(Cumulative Gain):前 K 个结果的相关性得分累加
-
DCG@KDCG@K(Discounted CG):排名越靠后,权重越低(折损)
- 公式:DCG@K = Σ((2^rel_i - 1) / log2(i + 1))
-
IDCG@KIDCG@K(Ideal DCG):最优排序下的 DCG
-
NDCG@KNDCG@K = DCG@K / IDCG@K
适用场景适用场景:搜索结果需要分级相关性(如:不相关=0,部分相关=1,完全相关=2)。
2.3 检索指标对比速查表
| 指标 | 关注重点 | 适用场景 | 公式复杂度 | 是否需要分级标注 |
|---|---|---|---|---|
| Precision | 结果纯度 | 控制噪声传入 LLM | 简单 | 否 |
| Recall | 结果覆盖 | 确保不遗漏关键信息 | 简单 | 否 |
| F1 | 平衡性 | 综合评估检索能力 | 简单 | 否 |
| Hit@K | 是否有正确答案 | 快速验证召回能力 | 简单 | 否 |
| MRR | 正确答案位置 | 问答场景 | 简单 | 否 |
| NDCG | 排序质量 | 搜索结果排序 | 复杂 | 是 |
2.4 检索常见问题诊断
| 指标异常 | 可能原因 | 优化方向 |
|---|---|---|
| Recall 低 | chunk 过大/过小、Embedding 弱、无关键词检索 | 调 chunk_size、换 Embedding 模型、加 BM25 混合检索 |
| Precision 低 | 大量无关片段召回 | 加 Rerank、调相似度阈值、优化 query 改写 |
| MRR 低 | 正确答案排名靠后 | 换更强的 Rerank 模型、调向量检索参数 |
| Hit@3 < 0.8 | 检索器基础能力不够 | 重新选型检索方案 |
三、生成层指标详解
生成层的核心问题:**基于召回的上下文,LLM 生成的回答是否忠实、相关、有用?**基于召回的上下文,LLM 生成的回答是否忠实、相关、有用?
3.1 生成评估的难点
-
没有参考答案没有参考答案:同一问题可以有多种正确回答
-
语义理解语义理解:文字相似不代表语义正确
-
幻觉检测幻觉检测:LLM 可能编造不存在的信息
解决方案解决方案:LLM-as-Judge(用大模型当裁判打分)
3.2 核心生成指标
定义定义:回答中的每个陈述,是否都能被检索到的文档支持?
通俗理解通俗理解:LLM 有没有”胡说八道”?
评估方式评估方式:
-
声明提取声明提取:把回答拆成一个个事实声明
-
证据匹配证据匹配:逐个检查声明是否能在 context 中找到支持
-
打分打分:支持的声明数 / 总声明数
RAG 场景意义RAG 场景意义:最核心的生成指标最核心的生成指标。回答可以不完整,但不能编造。
理想标准理想标准:≥ 0.9(生产环境要求幻觉率 ≤ 5%)
定义定义:回答是否贴合用户的问题?有没有答非所问?
评估方式评估方式:
-
把回答反向生成问题(Reverse Query Generation)
-
比较生成的问题和原始问题的语义相似度
-
或者用 LLM 直接判断”这个回答是否解决了用户的问题”
RAG 场景意义RAG 场景意义:检测”跑题”现象——虽然用了正确的文档,但回答方向偏了。
定义定义:回答与参考答案(Ground Truth)的一致性。
评估方式评估方式:
-
语义相似度语义相似度:用 Embedding 计算回答与参考答案的相似度
-
LLM 判断LLM 判断:让 LLM 对比回答和参考答案,给出 0~1 的分数
适用场景适用场景:有参考答案的测试集(如考试题、FAQ)。
定义定义:检索到的上下文中,相关片段的比例。反映检索结果的整体相关性密度。
RAGAS 版本RAGAS 版本:用 LLM 判断每个片段是否与 query 相关,计算比例。
定义定义:参考答案所需的参考信息,有多少被检索到了?
评估方式评估方式:
-
把参考答案拆成关键事实点
-
逐个检查这些事实点是否能在检索到的 context 中找到
-
计算比例
3.3 生成指标对比速查表
| 指标 | 评估对象 | 是否有参考 | 核心用途 | 评估方式 |
|---|---|---|---|---|
| Faithfulness | 回答 vs Context | 无参考 | 防幻觉 | LLM-as-Judge |
| Answer Relevance | 回答 vs Query | 无参考 | 防跑题 | LLM-as-Judge |
| Answer Correctness | 回答 vs Ground Truth | 有参考 | 测准确性 | Embedding/LLM |
| Context Precision | Context vs Query | 无参考 | 测检索纯度 | LLM-as-Judge |
| Context Recall | Context vs Ground Truth | 有参考 | 测检索覆盖 | LLM-as-Judge |
3.4 幻觉检测专项
幻觉类型幻觉类型:
| 类型 | 定义 | 示例 |
|---|---|---|
| 事实性幻觉 | 编造不存在的事实 | ”公司成立于2010年”(实际是2015年) |
| 逻辑性幻觉 | 推理过程错误 | ”A>B, B>C, 所以 C>A” |
| 引用性幻觉 | 声称引用文档但文档无此内容 | ”根据第3条…”(实际没有) |
幻觉率计算幻觉率计算:幻觉率 = 含幻觉的样本数 / 总测试样本数 × 100%
生产要求生产要求:幻觉率 ≤ 5%
四、RAGAS 框架实战
4.1 RAGAS 简介
RAGAS(Retrieval-Augmented Generation Assessment)是 RAG 评估的行业标准框架,提供无参考评估无参考评估能力。
核心指标核心指标:
| 指标 | 类别 | 说明 |
|---|---|---|
| context_precision | 检索 | 上下文精确度 |
| context_recall | 检索 | 上下文召回率 |
| faithfulness | 生成 | 忠实度 |
| answer_relevancy | 生成 | 答案相关性 |
| answer_correctness | 生成 | 答案正确性(需参考) |
4.2 安装与基础使用
from ragas import evaluate
from ragas.metrics import (
context_precision,
context_recall,
faithfulness,
answer_relevancy,
answer_correctness
)
from datasets import Dataset
# 构造测试数据
data = {
"question": ["公司年假最多可以休几天?", "如何申请报销?"],
"answer": ["正式员工每年最多休10天年假", "需要填写报销单并提交发票"],
"contexts": [
["员工手册规定正式员工年假上限10天"],
["报销流程:填写报销单 → 提交发票 → 部门审批 → 财务打款"]
],
"ground_truth": ["正式员工年假每年最多10天", "填写报销单并提交发票即可申请报销"]
}
ds = Dataset.from_dict(data)
# 执行评估
result = evaluate(
ds,
metrics=[
context_precision,
context_recall,
faithfulness,
answer_relevancy,
]
)
print(result)
# 'faithfulness': 0.88, 'answer_relevancy': 0.85}
五、完整评估 Pipeline
Pipeline 架构
六、评估指标达标标准
行业参考标准
| 指标 | 合格线 | 优秀线 | 说明 |
|---|---|---|---|
| Recall@K | ≥ 80% | ≥ 90% | 关键信息不能漏 |
| Precision@K | ≥ 60% | ≥ 75% | 噪声控制 |
| F1-Score | ≥ 0.7 | ≥ 0.85 | 综合平衡 |
| Hit@3 | ≥ 0.7 | ≥ 0.85 | 基础召回能力 |
| MRR | ≥ 0.6 | ≥ 0.8 | 正确答案位置 |
| Faithfulness | ≥ 0.85 | ≥ 0.95 | 防幻觉核心 |
| Answer Relevance | ≥ 0.8 | ≥ 0.9 | 贴合问题 |
| Hallucination Rate | ≤ 10% | ≤ 5% | 越低越好 |
诊断矩阵
| 象限 | Recall | Faithfulness | 问题定位 | 优化优先级 |
|---|---|---|---|---|
| 第一象限 | 高 | 低 | LLM 没用好文档 / Prompt 问题 | 调 Prompt、加约束 |
| 第二象限 | 高 | 高 | 理想状态 | 保持监控 |
| 第三象限 | 低 | 低 | 检索器根本不行 | 换检索方案 |
| 第四象限 | 低 | 高 | 检索召回不够 | 调 chunk、加混合检索 |
七、常见问题速答
Q1:如何评估一个 RAG 系统的效果?
Q2:Faithfulness 和 Answer Relevance 的区别?
Q3:RAGAS 的 Context Precision 和 Context Recall 与传统 IR 指标的区别?
Q4:没有参考答案怎么评估 RAG?
Q5:hallucination 怎么量化?
Q6:Hit@K 和 Recall@K 的区别?
八、核心金句
-
“RAG 评估必须先分层:检索层和生成层是两回事,混在一起测只能得到模糊结论。""RAG 评估必须先分层:检索层和生成层是两回事,混在一起测只能得到模糊结论。”
-
“90% 的 RAG 问题出在检索环节。Hit@3 < 0.8 时,先修检索再调生成。""90% 的 RAG 问题出在检索环节。Hit@3 < 0.8 时,先修检索再调生成。”
-
“Faithfulness 是第一生成指标。回答可以不完整,但不能胡说。""Faithfulness 是第一生成指标。回答可以不完整,但不能胡说。”
-
“LLM-as-Judge 不是圣杯。开源 Judge 模型在中文场景下表现参差不齐,建议至少做 20% 人工抽检校准。""LLM-as-Judge 不是圣杯。开源 Judge 模型在中文场景下表现参差不齐,建议至少做 20% 人工抽检校准。”
-
“标准 IR 指标和 RAGAS 高阶指标是两套体系,前者衡量检索器本身,后者用 LLM 打分做整体评估,混在一起会得出矛盾结论。""标准 IR 指标和 RAGAS 高阶指标是两套体系,前者衡量检索器本身,后者用 LLM 打分做整体评估,混在一起会得出矛盾结论。“
九、参考资料
| 来源 | 链接 | 内容 |
|---|---|---|
| CSDN - RAG测评系统全链路搭建指南 | https://blog.csdn.net/m0_58868237/article/details/162827441 | 检索+生成指标详解与代码实现 |
| CSDN - RAG评估指标理论篇 | https://blog.csdn.net/ngadminq/article/details/147857146 | 指标公式与定义 |
| CSDN - RAG项目完整效果评估体系 | https://blog.csdn.net/2501_92990656/article/details/162809923 | 三层评估体系与 RAGAS 实战 |
| CSDN - RAGAS 框架详解 | https://blog.csdn.net/u013538542/article/details/158312178 | RAGAS 指标原理与使用 |
| 51CTO - LLM-as-Judge 实现 | https://www.51cto.com/article/816568.html | LLM 评估系统实践 |
| RAGAS 官方文档 | https://docs.ragas.io/ | 官方指标定义与 API |
▶ 对应实操:22-MCP Client:自定义客户端 + JSON-RPC over HTTP + 连接池 + 幂等重连
▶ 对应实操:10-RAG 评估:检索指标 + 生成指标
速记卡(面试闪卡)
Q1:一句话讲清「RAG评估指标」到底是什么?
A:RAG 评估分两层:检索层看找得准不准(Recall/NDCG),生成层看答得好不好(Faithfulness),拆开测才定位根因。
Q2:为什么必须分两层 —— 怎么理解?
A:RAG = 检索器 + 生成器,一条 Fail 可能是检索没召回、LLM 没用好片段、或两者都有;混测只能盲人摸象。分层诊断矩阵按 Recall×Faithfulness 四象限定位:如 Recall 高但 Faithfulness 低就该调 Prompt。
Q3:检索层指标详解 —— 怎么理解?
A:Precision 看结果纯度(≥70%)、Recall 看覆盖(≥90%)、Hit@K 看前 K 有无答案、MRR 看首条排名、NDCG 看分级排序质量——Recall@K 是 RAG 检索核心指标,K 通常取 3 或 5。
Q4:生成层指标与幻觉检测 —— 怎么理解?
A:Faithfulness(声明能否被 context 支持)是第一生成指标(≥0.9);Answer Relevance 防跑题;Correctness 需参考答案。幻觉率=含幻觉样本/总数,生产要求 ≤5%——回答可不完整但不能编。
Q5:RAGAS 框架与评估方法 —— 怎么理解?
A:RAGAS 是行业标准、用 LLM-as-Judge 做无参考评估(context_precision/recall、faithfulness、answer_relevancy);另有基准测试(MS MARCO 等)、A/B 测试、人工评估——LLM-as-Judge 不是圣杯,需 20% 人工校准。
Q6:核心速记主线有哪些?
-
两层拆分:检索层(找得准)+ 生成层(答得好)
-
检索指标:Precision/Recall/Hit@K/MRR/NDCG
-
生成指标:Faithfulness(第一)/Answer Relevance/Correctness
-
诊断矩阵:Recall×Faithfulness 四象限定位根因
-
RAGAS + LLM-as-Judge 无参考评估,仍需人工校准
口诀
A:RAG 评估分两层,检索生成各管账;
Recall Precision 看准全,MRR 排名不迷向;
Faithfulness 防幻觉,答非所问 relevance 挡;
RAGAS 用 Judge 评,分层定位问题藏。
相关链接
快速问答
| 问题 | 参考答案 |
|---|---|
| RAG 评估的核心指标有哪些? | Context Precision(检索精度)、Context Recall(检索召回)、Faithfulness(忠实度)、Answer Relevance(回答相关性) |
| Faithfulness 和 Answer Relevance 的区别? | Faithfulness 评估回答是否基于检索到的上下文(不编造);Answer Relevance 评估回答是否切题(回答了问题) |
| RAGAS 框架是什么? | 开源的 RAG 评估框架,使用 LLM-as-Judge 方法,自动计算 Context Precision/Recall、Faithfulness、Answer Relevance |
| 如何评估检索质量? | Hit Rate、MRR、NDCG、MAP 等信息检索指标。需要标注相关文档作为 ground truth |
| 什么是 LLM-as-Judge? | 用强 LLM(如 GPT-4)作为评估器,根据定义的评分标准对 RAG 输出进行打分。灵活但成本高 |
| 如何构建 RAG 评估数据集? | 收集真实用户问题 → 标注参考答案 → 标注相关文档。建议至少 100-200 条,覆盖多种问题类型 |
| Faithfulness 低怎么办? | ① Prompt 强调只基于上下文 ② 降低 temperature ③ 增加上下文相关性 ④ 使用 Re-ranker ⑤ 添加兜底策略 |
| 除了 RAGAS 还有哪些评估工具? | DeepEval(开源)、LangSmith(LangChain 平台)、Phoenix(Arize AI)、TruLens(开源) |