RAG 专项评测
RAG(Retrieval-Augmented Generation,检索增强生成)是一种将外部知识检索与大模型生成相结合的架构模式。它的核心思路是:大模型回答用户问题之前,先从知识库中检索出相关的文档片段,把这些片段作为上下文塞进 Prompt,再让大模型基于这些上下文来生成答案。📖 一句话理解 RAGRAG = 先查资料,再回答问题。它让大模型从"凭记忆回答"变成"查完资料再回答"。RAG
RAG 专项评测
检索增强生成的评测方法论 · 从认知到实操的五层递进
RAG(Retrieval-Augmented Generation)是目前企业落地大模型最主流的方式。本篇从"什么是 RAG"讲起,依次进入评测指标体系、分层测试方法论、工具实操,最后以企业级案例收尾。建议按顺序读完,遇到代码块建议上手跑一遍。
第1章:什么是 RAG
1.1 RAG 的定义与核心价值
RAG(Retrieval-Augmented Generation,检索增强生成)是一种将外部知识检索与大模型生成相结合的架构模式。它的核心思路是:大模型回答用户问题之前,先从知识库中检索出相关的文档片段,把这些片段作为上下文塞进 Prompt,再让大模型基于这些上下文来生成答案。
📖 一句话理解 RAG
RAG = 先查资料,再回答问题。它让大模型从"凭记忆回答"变成"查完资料再回答"。
RAG 解决的核心问题:
-
知识时效性:大模型训练数据有截止日期,无法获取最新信息。RAG 通过实时检索知识库弥补这一缺陷。
-
领域专业性:通用大模型对企业内部业务规则、产品文档、SOP 流程一无所知。RAG 将企业私有知识注入回答过程。
-
幻觉控制:让大模型"有据可依"地回答,而非凭空编造,从根本上降低幻觉率。
-
可溯源性:回答可以标注引用来源,用户可以核实原文,增强可信度。
1.2 RAG 在企业大模型应用中的普及程度
根据行业调研,目前超过 80% 的企业大模型应用都采用了 RAG 架构。典型场景包括:
| 应用场景 | 知识库类型 | 用户群体 | 典型规模 |
|---|---|---|---|
| 内部知识问答 | 公司制度、HR 政策、IT 手册 | 全体员工 | 数百~数千篇文档 |
| 客服智能助手 | 产品手册、FAQ、案例库 | 客服坐席 / 终端用户 | 数千~数万条 |
| 法律/合规咨询 | 法规条文、判例库、合同模板 | 法务/合规人员 | 数万~数十万条 |
| 研发文档助手 | API 文档、设计文档、代码注释 | 开发团队 | 持续增长 |
| 医疗知识库 | 诊疗指南、药品说明书、病例 | 医护人员 | 高度专业化 |
1.3 为什么 RAG 需要专项评测
很多团队测试 RAG 应用时,只看"回答对不对"。这种做法有一个致命问题:你不知道错在哪里。
不能只测"回答对不对"的原因
RAG 的回答质量取决于一条长长的链路:文档切分 → 向量化 → 检索 → 重排序 → Prompt 拼接 → 大模型生成。任何一个环节出问题都会导致最终回答错误。如果只看最终结果,你根本无法定位问题出在哪个环节。
💡 实例演示
同一个错误回答,可能有完全不同的根因:
现象 可能的根因 修复方向 回答错误 检索到了错误的文档 优化 Embedding 或检索策略 回答错误 检索正确但大模型没有使用 优化 Prompt 模板或模型选择 回答错误 文档切分把关键信息拆断了 优化分块策略 回答“不知道” 知识库里有但没检索到 检查 Embedding 质量和召回策略 回答“不知道” 知识库里确实没有 补充知识库 所以 RAG 评测必须分层进行,逐环节定位问题。
第2章:RAG 全链路架构
2.1 完整 RAG Pipeline
下面是一个典型的 RAG 系统完整链路。每个环节都可能出问题,每个环节都需要独立评测。
👤 用户提问 → Query 预处理 → Embedding 向量化 → 向量数据库检索 → (Rerank 重排序 → Prompt 拼接 → 大模型生成 → 后处理 → 返回用户)
2.2 每个环节可能出的问题
| 环节 | 常见问题 | 对最终回答的影响 |
|---|---|---|
| Query 预处理 | 改写过度/不足、意图误判、多轮上下文丢失 | 后续检索方向完全偏离 |
| Embedding 向量化 | 语义表达不准确、领域词汇覆盖不足 | 相关文档无法被召回 |
| 向量数据库检索 | 召回数量不足、噪声过多、Top-K 设置不当 | 关键信息缺失或被淹没 |
| Rerank 重排序 | 重排序模型性能差、把正确文档排到后面 | 关键片段被截断 |
| Prompt 拼接 | 上下文过长被截断、格式混乱、指令不清 | 大模型无法正确理解和利用上下文 |
| 大模型生成 | 忽略上下文自行编造、过度摘要丢失细节 | 幻觉、信息丢失 |
| 后处理 | 引用标注错误、格式丢失(表格/列表) | 用户无法溯源或格式不可读 |
2.3 RAG 测试为什么必须分层
分层测试的核心逻辑
如果只做端到端测试(问一个问题 → 看回答对不对),你面临的是一个“黑盒中的黑盒”。当回答错误时,你无法区分是检索问题、排序问题、Prompt 问题还是生成问题。分层测试的目的是:让每一层的输入和输出都可以独立验证。
-
端到端测试(黑盒):只看最终回答是否正确。优点:贴近用户体验。缺点:无法定位问题环节,调优成本高。
-
分层测试(灰盒):逐层验证:检索是否召回正确文档 → 重排序是否优先正确文档 → 生成是否基于上下文。优点:精准定位,高效调优。缺点:需要记录中间数据。
第3章:RAG 评测指标体系
3.1 核心指标详解
RAG 评测有一套被学界和工业界广泛认可的指标体系。以下是每个核心指标的详细解释:
| 指标 | 英文名 | 测量什么 | 直觉解释 | 取值范围 |
|---|---|---|---|---|
| 忠实度 | Faithfulness | 生成的回答是否基于检索到的上下文,而非自行编造 | 回答里的每一句话,是否都能在上下文中找到依据? | 0~1,越高越好 |
| 答案相关性 | Answer Relevancy | 生成的回答是否回答了用户的问题 | 用户问的是 A,你回答的内容和 A 有多相关? | 0~1,越高越好 |
| 上下文精准度 | Context Precision | 检索到的文档片段中,有多少是真正有用的 | 检索出来 5 段内容,其中有 3 段和问题有关,精准度 = 3/5 | 0~1,越高越好 |
| 上下文召回率 | Context Recall | 回答所需的信息是否都被检索到了 | 标准答案包含 4 个关键点,检索出来的上下文覆盖了几个? | 0~1,越高越好 |
| 答案正确性 | Answer Correctness | 生成的回答与标准答案的匹配度 | 综合语义相似度和事实要素覆盖度来衡量 | 0~1,越高越好 |
指标之间的关系
Faithfulness 高但 Answer Relevancy 低 = 回答忠实于上下文,但答非所问。
Answer Relevancy 高但 Faithfulness 低 = 回答看起来相关,但内容是编造的。
Context Recall 低 = 不管模型多好,巧妇难为无米之炊,关键信息根本没被检索到。
3.2 RAG Triad(RAG 三角)
RAG 评测指标可以组织成一个“三角”结构,分别覆盖检索质量、生成质量和端到端质量三个维度:
-
端到端质量:Answer Correctness, Answer Relevancy
-
检索质量:Context Precision, Context Recall
-
生成质量:Faithfulness, Answer Semantic Similarity
3.3 指标组合诊断表
当你拿到一组指标数值时,怎么快速判断系统哪里出了问题?
| Context Recall | Context Precision | Faithfulness | Answer Relevancy | 诊断结论 | 优化方向 |
|---|---|---|---|---|---|
| 低 | 任意 | 任意 | 低 | 检索层瓶颈:关键信息没有被召回 | 改进 Embedding、扩大检索范围、优化分块 |
| 高 | 低 | 任意 | 任意 | 检索噪声过多:信息被淹没 | 加 Rerank、缩小 Top-K、过滤低分结果 |
| 高 | 高 | 低 | 任意 | 模型幻觉:检索到了但没用 | 优化 Prompt 指令、换更强的模型、降温度 |
| 高 | 高 | 高 | 低 | 答非所问:忠实但不相关 | Query 改写、意图分类、Prompt 优化 |
| 高 | 高 | 高 | 高 | 系统健康 | 持续监控,关注边缘 case |
第4章:检索层评估方法
4.1 核心检索指标
| 指标 | 全称 | 含义 | 适用场景 |
|---|---|---|---|
| 召回率 | Recall@K | 前 K 个结果中包含了多少相关文档 | 关注“别漏掉” |
| 精准率 | Precision@K | 前 K 个结果中有多少是相关的 | 关注“别搞错” |
| MRR | Mean Reciprocal Rank | 第一个正确结果排在第几位 | 关注排序质量 |
| NDCG | Normalized DCG | 考虑排序位置的综合质量分 | 关注整体排序合理性 |
4.2 计算公式与直观解释
Recall@K(召回率)
公式:Recall@K = 前K个结果中的相关文档数 / 所有相关文档总数
举例:知识库中有 3 篇和用户问题相关的文档。检索返回 Top-5,其中包含 2 篇相关文档。
Recall@5 = 2 / 3 = 0.667
含义:有 1 篇该检索到的文档漏掉了。
Precision@K(精准率)
公式:Precision@K = 前K个结果中的相关文档数 / K
举例:检索返回 Top-5,其中有 2 篇相关、3 篇不相关。
Precision@5 = 2 / 5 = 0.4
含义:60% 的检索结果是噪声。
MRR(平均倒数排名)
公式:MRR = (1/N) × Σ (1 / rank_i),其中 rank_i 是第 i 个查询的第一个正确结果的排名
举例:3 个查询中,第一个正确结果分别排在第 1、3、2 位。
MRR = (1/3) × (1/1 + 1/3 + 1/2) = 0.611
含义:平均来看,正确结果大约在第 1.6 位才出现。
NDCG@K(归一化折损累计增益)
公式:DCG@K = Σ (rel_i / log₂(i+1)),NDCG@K = DCG@K / IDCG@K
NDCG 同时考虑了结果的相关性和排序位置。排在前面的相关文档权重更高。IDCG 是理想排序下的 DCG,用于归一化。
4.3 检索方式对比测试
| 检索方式 | 原理 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|---|
| 向量检索 | 将文本编码为向量,通过余弦相似度匹配 | 语义理解能力强,能匹配“同义表达” | 对精确术语、编号、日期不敏感 | 自然语言问答、模糊搜索 |
| 关键词检索 | BM25 等基于词频的匹配 | 精确匹配能力强,对术语和编号敏感 | 无法理解语义,同义词无法匹配 | 精确查找、法规条文检索 |
| 混合检索 | 向量 + 关键词结果融合(RRF 等) | 兼顾语义和精确匹配 | 融合权重需要调优 | 企业级 RAG,兼顾多种查询类型 |
测试建议
构建评测数据集时,刻意设计三类查询:纯语义查询(如“员工请假怎么办”)、精确查询(如“条款 3.2.1 的内容是什么”)、混合查询(如“2024年修订的数据安全管理办法第5条”)。然后分别测试三种检索方式的 Recall@K,找到最优策略。
第5章:生成层评估方法
5.1 基于知识库的幻觉检测
与通用大模型的幻觉检测不同,RAG 场景下的幻觉有一个明确的判断标准:回答是否忠实于检索到的上下文。如果回答中出现了上下文中没有的信息,就可以判定为幻觉。
幻觉检测方法
| 方法 | 原理 | 优缺点 |
|---|---|---|
| NLI(自然语言推理) | 把回答拆成独立声明(claims),逐条判断每个声明是否能被上下文“蕴含” | 颗粒度细,但依赖 NLI 模型质量 |
| LLM-as-Judge | 用另一个大模型判断回答与上下文的一致性 | 灵活度高,但成本较大且存在评判偏差 |
| 关键词交叉验证 | 提取回答中的实体和数值,检查是否出现在上下文中 | 简单高效,但只能检测表面层次的幻觉 |
💡 实例演示:幻觉检测示例
上下文:“公司年假制度规定:入职满一年可享受5天带薪年假,满五年增至10天。”
模型回答:“入职满一年可享受5天年假,满三年增至8天,满五年增至15天。”
检测结果:
✅ “入职满一年可享受5天年假” — 上下文支持
❌ “满三年增至8天” — 上下文无此信息,幻觉
❌ “满五年增至15天” — 上下文说10天,事实错误,幻觉
5.2 引用溯源准确率
很多 RAG 应用会在回答中标注引用来源(如 [文档1] [文档2])。引用溯源准确率衡量的是:标注的引用是否真的支撑了对应的内容。
公式:引用准确率 = 正确引用数 / 总引用标注数
常见问题:
-
虚假引用:标注了来源,但该来源中并不包含对应内容
-
张冠李戴:内容来自文档 A,却引用了文档 B
-
引用缺失:有关键声明但没有标注引用来源
5.3 多文档融合质量评估
当回答需要综合多个文档片段时,模型需要正确地理解和融合不同来源的信息。评测要点:
| 评测维度 | 关注点 | 检测方法 |
|---|---|---|
| 信息完整性 | 各文档中的关键信息是否都被覆盖 | 对照关键要素清单逐一核对 |
| 一致性处理 | 不同文档中的冲突信息如何处理 | 构造含矛盾信息的上下文测试 |
| 逻辑连贯性 | 多来源信息的组织是否有逻辑 | 人工或 LLM 评判连贯度 |
| 去重能力 | 重复信息是否被合理归并 | 提供包含重叠内容的上下文测试 |
5.4 拒答策略测试
一个好的 RAG 系统不仅要答对,还要会说“不知道”。当知识库中没有相关信息时,系统应该明确拒绝回答,而不是编造一个看起来合理的答案。
拒答测试设计方法
构造一批知识库中不存在的问题(如竞品的产品信息、未来的政策)
构造跨领域问题(如向技术知识库提问财务问题)
构造部分相关的问题(关键信息缺失,仅有部分上下文)
验证系统是否明确声明“当前知识库暂无相关信息”
| 测试类型 | 输入 | 期望行为 | 最差行为 |
|---|---|---|---|
| 完全无关问题 | “今天天气怎么样” | 明确拒答 | 编造天气信息 |
| 知识库无覆盖 | “竞品 X 的定价策略” | 明确拒答 | 用本公司信息冒充回答 |
| 部分覆盖 | “员工年假有多少天?加班费怎么算?” | 回答已知部分,声明未知部分 | 用已知信息推测未知信息 |
第6章:RAG 测试策略
6.1 分层测试矩阵
RAG 测试应覆盖检索层、理解层和生成层三个维度,每个维度有不同的测试关注点:
| 测试维度 ↓ / 层级 → | 检索层 | 理解层(Prompt/Rerank) | 生成层 |
|---|---|---|---|
| 功能正确性 | 相关文档被召回 | 重排序后排名合理 | 回答内容正确 |
| 噪声鲁棒性 | 不相关文档不干扰 | 干扰文档被过滤 | 不被噪声上下文误导 |
| 边界处理 | 空结果、超长文档 | 上下文截断策略 | 拒答、不确定性表达 |
| 一致性 | 同语义不同表达的召回一致性 | 上下文窗口一致性 | 多次生成结果稳定性 |
| 性能 | 检索延迟 (P50/P99) | Rerank 延迟 | 首 token 延迟、总生成时间 |
| 安全性 | 权限隔离检索 | 防 Prompt 注入 | 敏感信息过滤 |
6.2 数据集构建方法
一个好的 RAG 评测数据集是整个评测的基础。以下是从知识库中系统化构建评测数据集的方法:
选取知识库文档 → 人工/LLM 生成问题 → 标注标准答案 → 标注对应文档片段 → 分类与分级
| 构建步骤 | 具体操作 | 注意事项 |
|---|---|---|
| 文档选取 | 从知识库中按类别均匀抽取文档 | 覆盖不同主题、长度、格式(文本/表格/列表) |
| 问题生成 | 基于文档内容生成自然语言问题 | 包含简单事实型、推理型、多文档综合型、否定型 |
| 答案标注 | 人工撰写标准答案(ground truth) | 答案必须完全基于对应文档,不能引入外部知识 |
| 片段标注 | 标记支撑答案的具体文档片段 | 用于评估 Context Recall 和 Precision |
| 难度分级 | 标注问题难度(简单/中等/困难) | 简单 = 单段落答案,困难 = 跨文档推理 |
6.3 Golden Set 设计
Golden Set 是一组精心标注的“黄金”测试集,包含已知的正确答案和对应的文档片段。它是 RAG 评测的基准参照。
Golden Set 结构
每条测试数据包含四个字段:
question:用户问题
ground_truth:标准答案
contexts:支撑答案的文档片段列表
metadata:问题类型、难度等级、涉及文档 ID
json
{
"question": "新员工入职第一年有多少天年假?",
"ground_truth": "根据公司《员工手册》第4.2条规定,新员工入职满一年后可享受5天带薪年假。",
"contexts": [
"4.2 年假制度:员工自入职之日起满一年,可享受5天带薪年假。满五年者,年假增至10天。满十年者,年假增至15天。"
],
"metadata": {
"type": "factual",
"difficulty": "easy",
"source_doc": "员工手册_v3.2.pdf",
"tags": ["HR", "年假"]
}
}
第7章:RAG 常见缺陷模式
7.1 缺陷分类总览
以下是 RAG 系统中最常见的 18 种缺陷模式,按所属环节分类:
| # | 缺陷名称 | 所属环节 | 触发条件 | 检测方法 |
|---|---|---|---|---|
| 1 | 检索未命中 | 检索层 | Embedding 不佳或 Top-K 过小 | 对比 ground_truth contexts 和实际召回 |
| 2 | 检索噪声过多 | 检索层 | 语义模糊的查询 | 计算 Precision@K,人工审查 Top-K 相关性 |
| 3 | 切分导致信息断裂 | 索引层 | Chunk 边界恰好在关键信息中间 | 检查跨 Chunk 的信息完整性 |
| 4 | 跨文档冲突 | 知识库 | 不同版本的文档包含矛盾信息 | 构造含矛盾的测试用例,验证模型取舍策略 |
| 5 | 引用标注错误 | 后处理 | 引用映射逻辑有 bug | 逐条验证引用标注与原文的对应关系 |
| 6 | 超出知识库编造 | 生成层 | 上下文不足但模型没有拒答 | Faithfulness 检测 + 拒答测试 |
| 7 | 格式丢失 | 索引/生成层 | 原文是表格或列表,切分后格式破坏 | 用包含表格/列表的文档做测试 |
| 8 | 时效性问题 | 知识库 | 知识库未及时更新 | 用涉及时间的问题测试,验证是否返回最新版本 |
| 9 | 多轮上下文丢失 | Query 预处理 | 多轮对话中前文引用未传递 | 构造需要指代消解的多轮对话 |
| 10 | Query 改写过度 | Query 预处理 | 改写器把用户意图改变了 | 对比原始 Query 和改写后 Query 的语义 |
| 11 | Rerank 排序异常 | Rerank 层 | Rerank 模型把正确文档排到后面 | 对比 Rerank 前后的排序结果 |
| 12 | 上下文截断 | Prompt 拼接 | 上下文超过模型窗口被截断 | 用长上下文测试,验证关键信息是否被保留 |
| 13 | 过度摘要 | 生成层 | 模型将详细信息压缩为笼统描述 | 验证数值、日期、条件等关键细节是否保留 |
| 14 | 权限穿透 | 检索层 | 用户查到了无权限的文档 | 用不同角色账号测试同一问题 |
| 15 | 语言混淆 | Embedding/生成 | 中英文或多语言文档混合 | 用中文问题检索英文文档,验证跨语言能力 |
| 16 | 数值/日期幻觉 | 生成层 | 数字和日期最容易被模型“微调” | 提取回答中的数值与上下文严格比对 |
| 17 | 否定语义翻转 | 生成层 | 上下文说“不允许”,回答变成“允许” | 构造含否定信息的测试用例 |
| 18 | 拒答过度 | 生成层 | 知识库有信息但模型仍拒绝回答 | 用明确有答案的问题测试拒答率 |
缺陷优先级建议
在企业场景中,优先关注的缺陷:#6(编造)> #1(未命中)> #14(权限穿透)> #4(跨文档冲突)> #16(数值幻觉)。这些缺陷的业务影响最大,而且用户往往无法自行发现。
第8章:RAGAS 工具实操
8.1 RAGAS 介绍
RAGAS(Retrieval Augmented Generation Assessment)是目前 GitHub 上最高星的开源 RAG 评测框架。它提供了一套标准化的指标和评估流程,能够自动化地评估 RAG 系统的各个维度。
RAGAS 核心特点
基于 LLM 的自动评估,无需人工打分
支持 Faithfulness、Answer Relevancy、Context Precision、Context Recall 等核心指标
与 LangChain、LlamaIndex 等框架无缝集成
支持自定义评估指标
8.2 安装与基础配置
bash
pip install ragas datasets
如果需要使用 OpenAI 作为评估模型:
bash
pip install openai export OPENAI_API_KEY="sk-your-key-here"
8.3 完整代码示例
第一步:准备评测数据集
python
from datasets import Dataset
questions = [
"新员工入职第一年有多少天年假?",
"公司的加班审批流程是什么?",
"试用期员工可以请年假吗?",
"年假可以跨年使用吗?",
"员工离职时未休年假如何处理?"
]
ground_truths = [
["入职满一年后可享受5天带薪年假。"],
["加班需提前一天由直属主管在OA系统中审批,紧急加班可事后24小时内补审批。"],
["试用期员工不享受年假,转正后从转正日开始计算年假资格。"],
["年假原则上不跨年使用,特殊情况经部门总监审批后可延至次年3月31日前使用。"],
["离职时未休年假按日薪标准折算补偿,计算公式为:月薪÷21.75×未休天数。"]
]
# 这些是 RAG 系统实际检索返回的上下文
contexts = [
["4.2 年假制度:员工自入职之日起满一年,可享受5天带薪年假。满五年者增至10天。"],
["5.1 加班管理:所有加班需提前一天由直属主管在OA系统中提交审批。如遇紧急情况,可在加班后24小时内补充审批流程。"],
["4.1 试用期管理:试用期一般为3个月,试用期内不享受年假和带薪病假。",
"4.2 年假制度:员工自入职之日起满一年,可享受5天带薪年假。"],
["4.2.3 年假跨年规定:年假原则上应在当年12月31日前休完,不可跨年累积。",
"如有特殊原因,经部门总监书面审批后,最迟可延至次年3月31日前使用完毕。"],
["6.3 离职结算:员工离职时,人力资源部应在最后工作日前完成以下结算...",
"未休年假按照以下公式折算补偿:月薪÷21.75×未休天数。"]
]
# RAG 系统实际生成的回答
answers = [
"根据公司规定,新员工入职满一年后可以享受5天带薪年假。",
"加班需要提前一天由直属主管在OA系统中审批。紧急情况下可以在加班后24小时内补审批。",
"试用期员工不能请年假。根据公司制度,试用期内不享受年假,需要转正后从转正日起计算年假资格。",
"年假原则上不能跨年使用,但经部门总监书面审批后可以延至次年3月31日前使用。",
"离职时未休年假会按日薪标准折算补偿,计算公式为月薪除以21.75再乘以未休天数。"
]
eval_dataset = Dataset.from_dict({
"question": questions,
"answer": answers,
"contexts": contexts,
"ground_truth": [gt[0] for gt in ground_truths]
})
第二步:配置评估指标并运行
python
from ragas import evaluate
from ragas.metrics import (
faithfulness,
answer_relevancy,
context_precision,
context_recall,
answer_correctness
)
result = evaluate(
eval_dataset,
metrics=[
faithfulness,
answer_relevancy,
context_precision,
context_recall,
answer_correctness
]
)
print(result)
第三步:解读结果
python
# 输出示例:
# {
# 'faithfulness': 0.9500,
# 'answer_relevancy': 0.9200,
# 'context_precision': 0.8800,
# 'context_recall': 0.9000,
# 'answer_correctness': 0.8700
# }
# 转为 DataFrame 查看每条的详细结果
df = result.to_pandas()
print(df[['question', 'faithfulness', 'context_recall', 'answer_correctness']])
# 找出表现最差的问题
worst = df.sort_values('answer_correctness').head(3)
print("表现最差的 3 个问题:")
print(worst[['question', 'faithfulness', 'context_recall', 'answer_correctness']])
结果解读指南
faithfulness = 0.95:95% 的回答内容有上下文支撑,仅 5% 存在潜在幻觉
context_recall = 0.90:90% 的必要信息被成功检索到,有 10% 的信息缺失
context_precision = 0.88:检索结果中 88% 是有用的,12% 是噪声如果某个指标突然下降,顺着本章第3节的“诊断表”去定位问题
第9章:自定义 RAG 评测脚本
9.1 分段计时:定位性能瓶颈
RAG 链路的每个环节都有耗时,找到性能瓶颈需要分段计时。
python
import time
import json
from openai import OpenAI
client = OpenAI()
def rag_pipeline_with_timing(query: str, knowledge_base, embed_model, reranker=None):
"""RAG 全链路带分段计时"""
timings = {}
# 1. Embedding 耗时
t0 = time.perf_counter()
query_vector = embed_model.encode(query)
timings["embedding_ms"] = round((time.perf_counter() - t0) * 1000, 2)
# 2. 检索耗时
t0 = time.perf_counter()
raw_results = knowledge_base.search(query_vector, top_k=20)
timings["retrieval_ms"] = round((time.perf_counter() - t0) * 1000, 2)
# 3. Rerank 耗时
if reranker:
t0 = time.perf_counter()
reranked = reranker.rerank(query, raw_results, top_k=5)
timings["rerank_ms"] = round((time.perf_counter() - t0) * 1000, 2)
else:
reranked = raw_results[:5]
timings["rerank_ms"] = 0
# 4. 大模型生成耗时
contexts = "\n---\n".join([r["text"] for r in reranked])
prompt = f"基于以下上下文回答用户问题。如果上下文中没有相关信息,请明确说明。\n\n上下文:\n{contexts}\n\n问题:{query}"
t0 = time.perf_counter()
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}],
temperature=0.1
)
timings["generation_ms"] = round((time.perf_counter() - t0) * 1000, 2)
timings["total_ms"] = round(sum(timings.values()), 2)
return {
"answer": response.choices[0].message.content,
"contexts": [r["text"] for r in reranked],
"timings": timings
}
# 输出示例:
# {
# "timings": {
# "embedding_ms": 12.35,
# "retrieval_ms": 45.67,
# "rerank_ms": 128.90,
# "generation_ms": 2340.12,
# "total_ms": 2527.04
# }
# }
9.2 检索质量自动验证
python
def evaluate_retrieval_quality(test_cases: list) -> dict:
"""
test_cases 格式:
[{"query": "...", "expected_doc_ids": ["doc1", "doc2"], "retrieved_doc_ids": ["doc2", "doc3", "doc4"]}]
"""
total_recall, total_precision, total_mrr = 0, 0, 0
for case in test_cases:
expected = set(case["expected_doc_ids"])
retrieved = case["retrieved_doc_ids"]
retrieved_set = set(retrieved)
hits = expected & retrieved_set
recall = len(hits) / len(expected) if expected else 0
precision = len(hits) / len(retrieved) if retrieved else 0
rr = 0
for i, doc_id in enumerate(retrieved):
if doc_id in expected:
rr = 1 / (i + 1)
break
total_recall += recall
total_precision += precision
total_mrr += rr
n = len(test_cases)
return {
"avg_recall": round(total_recall / n, 4),
"avg_precision": round(total_precision / n, 4),
"mrr": round(total_mrr / n, 4),
"total_cases": n
}
9.3 LLM-as-Judge 评估回答质量
python
def llm_judge_answer(question: str, context: str, answer: str, ground_truth: str) -> dict:
"""用 LLM 从三个维度评判回答质量"""
judge_prompt = f"""你是一个严格的RAG系统评审员。请根据以下信息评估回答质量。
【用户问题】
{question}
【检索到的上下文】
{context}
【系统回答】
{answer}
【标准答案】
{ground_truth}
请从以下三个维度打分(1-5分),并给出简短理由:
1. 忠实度:回答是否完全基于上下文,没有编造信息
2. 完整性:回答是否覆盖了问题所需的全部关键信息
3. 准确性:回答与标准答案的事实一致程度
请以 JSON 格式输出:
{{"faithfulness": {{"score": X, "reason": "..."}}, "completeness": {{"score": X, "reason": "..."}}, "accuracy": {{"score": X, "reason": "..."}}}}"""
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": judge_prompt}],
temperature=0,
response_format={"type": "json_object"}
)
return json.loads(response.choices[0].message.content)
# 用法示例
result = llm_judge_answer(
question="新员工年假几天?",
context="4.2 年假制度:员工自入职之日起满一年,可享受5天带薪年假。",
answer="新员工入职满一年后可享受5天带薪年假。",
ground_truth="入职满一年后可享受5天带薪年假。"
)
# 输出: {"faithfulness": {"score": 5, "reason": "完全基于上下文"}, ...}
第10章:TruLens 实操
10.1 TruLens 介绍
TruLens 是由 Truera 公司开源的 LLM 应用评测和追踪框架。它的核心理念是 RAG Triad——用三个维度来衡量 RAG 系统的质量。
TruLens 核心能力:
-
自动化的 RAG Triad 评测
-
可视化仪表盘(Leaderboard)
-
应用调用的完整追踪记录
-
与 LangChain / LlamaIndex 集成
RAG Triad 三维度:
-
Context Relevance:检索到的上下文与问题的相关性
-
Groundedness:回答是否基于上下文(≈ Faithfulness)
-
Answer Relevance:回答与问题的相关性
10.2 安装与配置
bash
pip install trulens trulens-providers-openai
10.3 RAG Triad 评测配置
python
from trulens.core import TruSession, Feedback, Select
from trulens.providers.openai import OpenAI as TruOpenAI
# 初始化
session = TruSession()
provider = TruOpenAI(model_engine="gpt-4o")
# 定义 RAG Triad 三个反馈函数
f_context_relevance = (
Feedback(provider.context_relevance_with_cot_reasons, name="Context Relevance")
.on_input()
.on(Select.RecordCalls.retrieve.rets[:])
.aggregate(lambda x: sum(x) / len(x) if x else 0)
)
f_groundedness = (
Feedback(provider.groundedness_measure_with_cot_reasons, name="Groundedness")
.on(Select.RecordCalls.retrieve.rets[:].collect())
.on_output()
)
f_answer_relevance = (
Feedback(provider.relevance_with_cot_reasons, name="Answer Relevance")
.on_input()
.on_output()
)
10.4 包装 RAG 应用并追踪
python
from trulens.apps.custom import TruCustomApp, instrument
class RAGApp:
@instrument
def retrieve(self, query: str) -> list:
"""检索环节 — TruLens 会自动追踪这个方法"""
# 你的检索逻辑
results = vector_db.search(query, top_k=5)
return [r["text"] for r in results]
@instrument
def generate(self, query: str, contexts: list) -> str:
"""生成环节"""
context_str = "\n".join(contexts)
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": f"上下文:{context_str}\n问题:{query}"}]
)
return response.choices[0].message.content
@instrument
def query(self, question: str) -> str:
"""完整 RAG 调用"""
contexts = self.retrieve(question)
return self.generate(question, contexts)
rag_app = RAGApp()
# 用 TruLens 包装
tru_app = TruCustomApp(
rag_app,
app_name="企业知识库问答",
app_version="v1.0",
feedbacks=[f_context_relevance, f_groundedness, f_answer_relevance]
)
# 运行评测
test_questions = [
"新员工年假有多少天?",
"加班审批流程是什么?",
"出差报销标准是多少?"
]
with tru_app as recorder:
for q in test_questions:
rag_app.query(q)
10.5 启动仪表盘查看结果
python
from trulens.dashboard import run_dashboard run_dashboard(session) # 打开 http://localhost:8501 查看可视化仪表盘 # 仪表盘包含: # - 应用排行榜(Leaderboard) # - 每条调用的详细追踪记录 # - RAG Triad 三个维度的得分分布 # - 低分记录的自动高亮
TruLens 仪表盘的核心价值
对比不同版本(v1.0 vs v2.0)的 RAG 系统表现
快速定位低分问题,查看具体哪个环节出了问题
追踪每次调用的完整链路(检索 → 上下文 → 生成)
支持持续集成——每次发布后自动运行评测集
第11章:案例 — 企业知识库问答系统评测
11.1 场景描述
评测对象
某中型互联网公司的内部知识库问答系统(HR 制度、IT 运维、财务报销),使用 LlamaIndex + Milvus + GPT-4o 搭建。知识库规模约 1200 篇文档,涵盖公司制度手册、技术文档、FAQ 等。
11.2 评测数据集(15条示例)
| # | 问题 | 类型 | 难度 | 标准答案(摘要) |
|---|---|---|---|---|
| 1 | 新员工入职第一年有几天年假? | 事实型 | 简单 | 满一年后5天 |
| 2 | 加班审批流程是怎样的? | 流程型 | 简单 | OA 提前一天申请,主管审批 |
| 3 | 年假可以跨年使用吗? | 条件型 | 中等 | 原则不可,特批可延至次年3月底 |
| 4 | 出差报销的住宿标准是多少? | 事实型 | 简单 | 一线城市500/天,二线350/天 |
| 5 | 如何申请 VPN 账号? | 操作型 | 简单 | 在 IT 工单系统提交申请 |
| 6 | 试用期被辞退有没有补偿? | 法规型 | 中等 | 无经济补偿,但需提前3天通知 |
| 7 | 公司支持远程办公吗?需要什么条件? | 多条件 | 中等 | 支持,需主管审批+VPN+周报 |
| 8 | 2024年修订的数据安全管理办法第5条说了什么? | 精确引用 | 困难 | 第5条内容全文 |
| 9 | 产假和陪产假分别是多少天? | 多点事实 | 中等 | 产假158天,陪产假15天 |
| 10 | 研发部门和市场部门的加班审批流程有什么区别? | 对比型 | 困难 | 研发需CTO审批,市场需CMO审批 |
| 11 | 公司有没有宠物托管的福利? | 拒答测试 | 简单 | 知识库无此信息,应拒答 |
| 12 | 竞品A的薪酬体系是怎样的? | 拒答测试 | 简单 | 应明确拒答 |
| 13 | 同时满足哪些条件可以申请居家办公? | 条件汇总 | 困难 | 需汇总3个文档的条件 |
| 14 | 上个季度公司营收是多少? | 时效性 | 中等 | 应说明信息可能不是最新或拒答 |
| 15 | 员工手册里关于“迟到”的规定(原文有表格) | 格式保持 | 困难 | 应保持表格格式输出 |
11.3 分层评测结果
| 评测维度 | 指标 | 得分 | 判定 | 备注 |
|---|---|---|---|---|
| 检索层 | Context Recall | 0.82 | 待改进 | #8 精确引用型和 #13 跨文档型未召回 |
| 检索层 | Context Precision | 0.75 | 待改进 | 平均每个问题有 25% 的噪声上下文 |
| 生成层 | Faithfulness | 0.91 | 良好 | #9 存在数值幻觉(158→180天) |
| 生成层 | Answer Relevancy | 0.88 | 良好 | #10 对比型问题回答偏离 |
| 端到端 | Answer Correctness | 0.79 | 待改进 | 被检索层拖累 |
| 端到端 | 拒答准确率 | 0.50 | 差 | #11 编造了宠物托管福利 |
11.4 问题定位与优化建议
| 问题 | 根因 | 优化方案 | 优先级 |
|---|---|---|---|
| 精确引用型检索失败 | Embedding 对“第X条”等结构化引用表达不敏感 | 引入混合检索(BM25 + 向量),给精确查询走关键词通道 | P0 |
| 拒答率低,会编造信息 | Prompt 中缺少“无信息时拒答”的强制指令 | 在系统 Prompt 中增加拒答规则,添加“仅基于以下上下文”的约束 | P0 |
| 跨文档综合检索不足 | 单次检索 Top-5 无法覆盖分散在多个文档中的信息 | 增大 Top-K 到 10,加 Rerank 筛选;或使用子问题拆分策略 | P1 |
| 数值幻觉 | 模型对数值信息的复现不够精确 | 在 Prompt 中添加“数值务必与原文保持一致”的指令,降低 temperature | P1 |
| 检索噪声过多 | 缺少 Rerank 环节 | 引入 Rerank 模型(如 bge-reranker-v2),过滤低相关性片段 | P2 |
优化后的预期效果
根据经验,实施 P0 级优化(混合检索 + 拒答策略)后,Context Recall 通常可提升至 0.90+,拒答准确率可提升至 0.85+。配合 Rerank 的加入,Context Precision 通常可达 0.85+。
第12章:练习
🎯 练习1:构建 RAG 评测数据集
选择你所在团队的一个 RAG 应用(或使用公开的知识库问答系统),完成以下任务:
从知识库中选取 10 篇有代表性的文档
基于这些文档,构建 20 条测试数据(覆盖事实型、流程型、对比型、拒答型)
为每条数据标注 question、ground_truth、contexts
使用 RAGAS 运行评估,记录五项核心指标
找出得分最低的 3 条数据,分析根因并提出优化建议
🎯 练习2:分层诊断一个 RAG 缺陷
假设你的 RAG 系统出现以下现象:
用户问:“公司差旅报销的住宿标准是多少?”
系统回答:“一线城市住宿标准为每天800元,二线城市为500元。”
标准答案:“一线城市500元/天,二线城市350元/天。”
请完成以下分析:
这是检索层问题还是生成层问题?列出你的判断依据。
设计 3 个实验来验证你的假设(例如:检查检索到的上下文是否正确)。
根据实验结果,给出具体的修复方案。
🎯 练习3:编写自动化 RAG 回归测试
编写一个 Python 脚本,实现以下功能:
从 JSON 文件加载 Golden Set(至少 10 条)
逐条调用 RAG 系统 API,获取回答和检索到的上下文
计算 Recall@5 和 Precision@5
用 LLM-as-Judge 打分 Faithfulness(1-5分)
生成评测报告,包含:整体通过率、各指标均值、最差 case 列表
当任一指标低于阈值时,脚本返回非零退出码(用于 CI/CD 集成)
补充参考答案要点
-
练习1构建数据集时,必须同时标注问题、标准答案、支撑文档片段和问题类型,否则后续无法做分层评测。
-
练习2分层诊断时,要先区分是没召回、召回错、拼接错,还是生成阶段乱说,不能把所有问题都归成“幻觉”。
-
练习3自动化回归时,至少要输出检索指标、答案指标和拒答指标,并保留 case 级结果用于 diff 分析。
更多推荐


所有评论(0)