RAG实战:别用“感觉”测试,聊聊我的评估踩坑经历
我之前在做一个内部知识库时就栽过这个跟头。当时我为了提升效果,反复调整了四次System Prompt,还尝试把Temperature从0.7调低到0.1,结果发现回答质量毫无变化,甚至有些地方变差了。我当时死磕LLM的生成能力,结果排查了两天发现:根本不是模型的问题,而是检索端(Retrieval)根本没把正确的文档片段捞出来。
这就是RAG最阴险的地方——如果检索失败了,LLM要么一本正经地胡说八道,要么告诉你不知道。如果你不量化评估,你根本分不清到底是“模型在撒谎”还是“它根本没看到真相”。
为什么手动抽测是无效的?
手动测试有个致命缺陷:幸存者偏差。我们潜意识里会问那些我们知道答案、且预期系统能回答对的问题。当你看到答案稍微有点偏差时,很容易自我安慰“差不多就行”。
而且,RAG系统极其敏感。你只要改动一个参数,比如把Chunk Size从500调到800,或者更换了一个Embedding模型,可能会在某些边缘case上产生严重的回归(Regression)。如果没有量化指标,这种性能下降在三周后通过用户投诉才会暴露出来。
建立离线评估(Offline Evaluation)的逻辑
想要真正知道RAG是否生效,必须建立一套离线评估机制。简单来说,就是不能靠心情打分,得靠“标准答案”。
我现在的实操流程是构建一个 Golden Dataset(黄金数据集)。这个数据集不是随便凑的,必须包含:
- 具体问题
- 预期的正确文档片段(Ground Truth Chunk)
- 预期的标准答案
- 必须引用的来源出处
在评估时,我把测试分为两个维度,绝对不能混淆:
- 检索质量(Retrieval Quality): 检查正确文档是否在召回的Top-K结果中。如果正确片段没被检索到,后面的Rerank或LLM生成再强也没用。
- 生成质量(Generation Quality): 在检索正确的前提下,LLM是否准确提取了信息,有没有产生幻觉。
一个简单的评估数据集结构示例
为了避免混乱,我会用JSON格式维护我的测试集,这样方便用脚本跑批处理对比。
[
{
"id": "test_001",
"query": "公司关于远程办公的报销标准是什么?",
"expected_chunk": "员工远程办公产生的宽带费用每月报销上限为100元,需提供发票。",
"expected_answer": "远程办公的宽带费用每月最高报销100元,且需要提供发票。",
"source_doc": "admin_policy_2024.pdf"
},
{
"id": "test_002",
"query": "如何申请年度体检?",
"expected_chunk": "年度体检需在每年的10月前通过HR系统提交申请。",
"expected_answer": "请在每年10月之前通过HR系统提交体检申请。",
"source_doc": "hr_benefits_guide.pdf"
}
]避坑指南:数据集不能全是“正确题”
很多新手在做数据集时,只写系统能回答对的问题。其实,一个硬核的评估集必须包含以下四类问题,才能真正压力测试你的工作流:
1. 标准查询: 答案就在文档里,测试基础召回。
2. 复杂推理: 需要结合文档中两个不同段落的信息才能得出答案,测试上下文整合能力。
3. 无答案查询: 故意问文档里根本没提到的内容,测试模型是否会诚实地回答“我不知道”,而不是强行编造(幻觉测试)。
4. 干扰项查询: 问一个与正确答案极其相似但细节不同的问题,测试Rerank的精细度。
只有当你在调整参数后,能通过脚本跑一遍这个数据集,看到“准确率从 72% 提升到 85%”这样的数字时,你才能真正确定你的优化是有意义的,而不是在测试自己的乐观情绪。