RAG 系统效果评估完整指南
RAG(Retrieval-Augmented Generation)系统由 检索(Retrieval) + 生成(Generation) 两个核心模块组成,评估需分层进行,不能只看最终答案。
***用户问题 → [检索器] → 相关文档 → [生成器] → 最终答案
↓ ↓
检索质量评估 生成质量评估
↘ ↙
端到端效果评估***
一、评估维度与核心指标
🔍 1. 检索侧评估(Retrieval Metrics)
| 指标 | 含义 | 公式/说明 | 适用场景 |
|---|---|---|---|
| Hit Rate@K | 前 K 个结果中是否包含至少一个相关文档 | #queries with hit / total queries |
快速判断检索是否"碰对" |
| Recall@K | 相关文档中被检索到的比例 | #retrieved relevant / total relevant |
评估查全率,对知识完整性敏感的场景 |
| Precision@K | 检索结果中相关文档的比例 | #retrieved relevant / K |
评估查准率,减少噪声干扰 |
| MRR (Mean Reciprocal Rank) | 第一个相关文档的排名倒数均值 | 1/rank_first_relevant |
关注"最快命中",如客服场景 |
| NDCG@K | 考虑相关性等级的排序质量 | 折扣累积增益归一化 | 文档有相关性打分(0/1/2/3)时 |
| Context Precision | 相关文档在检索结果中的排序质量 | RAGAS 专用指标 | 评估生成器能否"看到"关键信息 |
✍️ 2. 生成侧评估(Generation Metrics)
| 指标 | 含义 | 评估方式 | 关键问题 |
|---|---|---|---|
| Faithfulness(忠实度) | 答案是否完全基于检索上下文,无幻觉 | LLM-as-a-judge / NLI 模型 | "答案中的每个事实都能在文档中找到依据吗?" |
| Answer Relevance(答案相关性) | 答案是否直接回应了用户问题 | 嵌入相似度 / LLM 打分 | "答案是否跑题?" |
| Context Relevance(上下文相关性) | 检索的文档是否对回答问题有帮助 | LLM 提取关键句 + 计算比例 | "文档里有多少内容是真正有用的?" |
| Answer Correctness(答案正确性) | 答案与标准答案的语义一致性 | 嵌入相似度 + 事实比对 | "答案对吗?"(需 gold answer) |
🎯 3. 端到端评估(End-to-End Metrics)
| 指标 | 说明 | 获取方式 |
|---|---|---|
| Task Success Rate | 用户任务是否成功完成(如:找到正确配置项) | 人工标注 / 规则判断 |
| User Satisfaction (CSAT) | 用户主观满意度(1-5 分) | 用户反馈 / A/B 测试 |
| Latency | 端到端响应时间(检索 + 生成) | 系统埋点监控 |
| Cost per Query | 单次查询的 Token/计算成本 | 资源监控 |
| Fallback Rate | 触发"我不知道"/转人工的比例 | 日志统计 |
二、评估方法与数据准备
方法 1:基于标准测试集(Gold Standard)
# 评估数据集示例(JSONL)
{
"question": "如何重置 MiniAgent 的会话记忆?",
"answer": "调用 agent.reset() 方法,或发送 /reset 命令。",
"contexts": [
"def reset(self): self.session['history'] = []...",
"HELP_DETAILS 包含 /reset 命令说明"
],
"metadata": {"source": "docs", "difficulty": "easy"}
}
✅ 优点:结果可复现、便于迭代对比
❌ 缺点:构建成本高、覆盖有限
方法 2:LLM-as-a-Judge(大模型当裁判)
python
# 用 LLM 评估 Faithfulness 的 prompt 示例
faithfulness_prompt = """
判断答案是否完全基于给定上下文,无外部知识幻觉。
上下文:
{context}
问题: {question}
答案: {answer}
请输出 JSON:
{{
"statements": ["答案中的事实1", "事实2", ...],
"verdicts": [1 if 事实可在上下文找到 else 0, ...],
"faithfulness_score": 0.0-1.0
}}
"""
✅ 优点:无需人工标注、可扩展
❌ 缺点:裁判模型偏差、成本高、需设计鲁棒 prompt
方法 3:对抗测试 / 压力测试
python
# 构造挑战性问题测试系统鲁棒性
adversarial_questions = [
"请编造一个不存在的 API 参数", # 测试幻觉抑制
"用英文回答但文档全是中文", # 测试跨语言检索
"问一个 2025 年才发生的事", # 测试时间敏感性
"故意拼错关键词:recieve file", # 测试检索容错
]
方法 4:线上真实用户反馈
python
# 埋点收集用户行为信号
user_signals = {
"thumbs_up/down": bool, # 显式反馈
"copy_answer": bool, # 答案被复制 → 可能有用
"follow_up_question": str, # 追问 → 可能未解决
"session_length": int, # 会话轮数 → 任务复杂度
"escalate_to_human": bool, # 转人工 → 系统失败
}
三、主流评估工具对比
| 工具 | 核心能力 | 优点 | 局限 | 适用场景 |
|---|---|---|---|---|
| RAGAS | Faithfulness, Answer Relevance, Context Precision 等 7+ 指标 | 开箱即用、支持 LLM/NLI 多种裁判、可视化报告 | 依赖 OpenAI/本地大模型、中文支持需调优 | 快速建立评估基线 |
| TruLens | 自定义评估链、反馈函数、实验追踪 | 灵活定制、集成 LangChain/LlamaIndex、Dashboard | 学习曲线稍陡 | 中大型项目持续评估 |
| DeepEval | 语义相似度、毒性检测、自定义 metric | 单元测试风格、支持 CI/CD 集成 | 社区相对小 | 工程化团队、自动化测试 |
| ARES | 合成评估数据 + 自动标注 | 减少人工标注成本 | 配置复杂 | 冷启动/数据稀缺场景 |
| BEIR | 18+ 公开检索基准数据集 | 学术对比、检索器专项评估 | 不包含生成评估 | 检索模块专项优化 |
🔧 RAGAS 快速上手示例
python
from ragas import evaluate
from ragas.metrics import (
faithfulness,
answer_relevancy,
context_precision,
context_recall
)
from datasets import Dataset
# 准备评估数据(至少需要 question, answer, contexts 三列)
eval_data = {
"question": ["如何重置会话?", "write_file 工具怎么用?"],
"answer": ["调用 agent.reset()", "使用 <tool name='write_file'>..."],
"contexts": [
["def reset(self): ...", "HELP_DETAILS 包含 /reset"],
["build_tools 中定义了 write_file", "示例: <tool name=\"write_file\"..."]
],
"ground_truth": ["agent.reset() 或 /reset 命令", "参考 tool_write_file 实现"] # 可选
}
dataset = Dataset.from_dict(eval_data)
# 执行评估
result = evaluate(
dataset,
metrics=[faithfulness, answer_relevancy, context_precision, context_recall],
llm="qwen3.5:4b", # 支持 Ollama/本地模型
embeddings="local:BAAI/bge-m3" # 本地嵌入模型
)
print(result)
# 输出: {'faithfulness': 0.92, 'answer_relevancy': 0.88, ...}
四、分层评估策略(推荐实践)
*🔹 Level 1:单元测试(开发阶段)
├─ 检索器:用 BEIR 或小规模标注集测 Recall@10
├─ 生成器:用固定 context + question 测 Faithfulness
└─ 工具调用:用 FakeModelClient 测参数解析准确率
🔹 Level 2:集成测试(迭代阶段)
├─ 构建 50-200 条黄金问答对(覆盖高频/边界/对抗场景)
├─ 用 RAGAS/TruLens 自动化跑分 + 生成报告
└─ 设置指标阈值(如 Faithfulness < 0.8 阻断发布)
🔹 Level 3:线上监控(生产阶段)
├─ 埋点收集用户反馈 + 行为信号
├─ 定期抽样人工复核(如每周 50 条)
├─ A/B 测试新检索策略/生成 prompt
└─ 设置告警:Fallback Rate > 15% 或 Latency P95 > 5s*
五、针对你之前代码的 RAG 评估建议
你之前分析的 Mini-Coding-Agent 本质是一个 Code-RAG 系统,评估需特别关注:
✅ 代码场景特有指标
| 指标 | 说明 | 实现思路 |
|---|---|---|
| Code Correctness | 生成的代码能否通过语法/单元测试 | ast.parse() + 运行 pytest |
| Patch Precision | patch_file 的 old_text 是否精确匹配 |
检查 text.count(old_text) == 1 |
| Path Safety | 文件操作是否越权 | 单元测试 path_is_within_root() |
| Tool Call Accuracy | 模型是否正确选择工具+参数 | 用 FakeModelClient + 规则校验 |
🔍 评估数据集构建建议
python
# code_rag_eval_samples.jsonl
[
{
"question": "如何添加一个新工具 list_dirs?",
"answer": "在 build_tools 中添加字典项,实现 tool_list_dirs 方法...",
"contexts": ["build_tools 函数源码", "tool_list_files 实现参考"],
"expected_tool_calls": [
{"name": "read_file", "args": {"path": "mini_agent.py"}},
{"name": "write_file", "args": {"path": "mini_agent.py", "content": "..."}}
],
"code_diff_expected": "+ def tool_list_dirs...", # 用于比对生成代码
"difficulty": "medium"
},
...
]
🧪 自动化测试示例
python
def test_tool_call_parsing():
"""测试模型输出能否被正确解析为工具调用"""
from mini_agent import MiniAgent
# 模拟模型输出
raw_output = '<tool>{"name":"read_file","args":{"path":"README.md"}}</tool>'
kind, payload = MiniAgent.parse(raw_output)
assert kind == "tool"
assert payload["name"] == "read_file"
assert payload["args"]["path"] == "README.md"
def test_path_traversal_blocked():
"""测试路径穿越攻击被拦截"""
agent = create_test_agent(read_only=False)
with pytest.raises(ValueError, match="path escapes workspace"):
agent.path("../../etc/passwd")
🚀 六、持续优化闭环
1️⃣ 收集 bad cases
├─ 用户反馈 "答案不对"
├─ 监控指标异常(Faithfulness↓)
└─ 人工复核抽样
2️⃣ 根因分析(分层定位)
├─ 检索失败?→ 查 Recall@K / 关键词匹配
├─ 生成失败?→ 查 Faithfulness / prompt 设计
├─ 工具调用失败?→ 查 parse 准确率 / 参数校验
3️⃣ 针对性优化
├─ 检索:query 重写 / 混合检索(关键词+向量)/ rerank
├─ 生成:prompt 优化 / 增加 few-shot / 约束解码
├─ 工具:增强 schema 描述 / 加验证逻辑 / 改进错误提示
4️⃣ A/B 验证 + 回归测试
└─ 确保优化不破坏已有能力
🔑 一句话总结
评估 RAG = 检索质量 × 生成质量 × 系统鲁棒性
用 分层指标 + 自动化工具 + 真实反馈 构建评估闭环,避免"只看最终答案"的片面优化。