检索效果评估与 Bad Case 分析
RAG 效果好不好,不能凭感觉。怎么衡量检索质量?召回率怎么算?Bad Case 怎么分类分析?这篇讲检索评估的指标体系、测试集构建、Bad Case 分析方法论,以及迭代优化的流程。
大家好,我是黒漂技术佬。
很多人做 RAG,优化全靠感觉------「我觉得好像准了一点」「这个问题好像答对了」。这样迭代效率很低,而且不知道到底变好还是变差了。
做工程要有量化指标,检索效果也要数据说话。
这篇讲怎么评估检索效果、指标怎么选、Bad Case 怎么分析、怎么迭代优化。
一、为什么要做检索评估?
1. 量化效果
不用「感觉差不多」,用数字说话:Recall@5 是 85% 还是 92%,一目了然。
2. 优化有方向
知道哪里差,才能针对性优化:
- 召回率低 → 优化检索策略
- 排序差 → 加重排序
- 某类问题总错 → 针对性补数据
3. 版本对比
每次优化后跑一遍测试集,知道是变好还是变差了,不会越优化越烂。
4. 上线有标准
达到什么指标可以上线?有个明确的标准,不是拍脑袋。
二、检索评估指标
1. Recall@K(召回率)
Top K 个检索结果里,包含正确答案的比例。
Recall@5 = 检索前5条包含正确文档的查询数 / 总查询数
RAG 里最重要的指标。因为检索到了,大模型才可能答对;检索不到,大模型再强也没用。
K 一般取 3、5、10。RAG 常用 Recall@5。
2. Precision@K(精确率)
Top K 个结果里,有多少是相关的。
Precision@5 = 前5条中相关的数量 / 5
精确率低说明噪声多,会浪费大模型上下文,还可能干扰答案。
3. MRR(平均倒数排名)
正确答案排在第几位。排第一得分 1,排第二得分 1/2,排第十得分 1/10。
MRR = 所有查询的 (1/排名) 的平均值
看重排序质量的时候用。RAG 里正确答案排第一和排第五,大模型效果可能不一样。
4. NDCG@K
考虑相关度等级的排序指标,比 MRR 更精细。一般检索系统用得多,RAG 场景 MRR 就够了。
5. 命中率
有没有检索到(不管排第几),和 Recall 类似。
RAG 场景下的优先级
Recall@K > MRR > Precision@K
- 首先要保证能检索到(Recall 高)
- 其次尽量排前面(MRR 高)
- 最后才是结果尽量都相关(Precision)
因为大模型有一定的抗噪声能力,混进去一两条不相关的影响不大,但漏了正确的就完了。
三、测试集怎么构建?
评估的前提是有一个好的测试集。
测试集构成
每条数据包含:
- query:用户问题
- positive_doc_ids:相关的文档 ID 列表(可以多个)
json
[
{
"query": "怎么申请退货?",
"positive_docs": ["doc_001", "doc_023"]
},
{
"query": "保修期是多久?",
"positive_docs": ["doc_045"]
}
]
测试集哪里来?
方法 1:人工标注
从真实用户问题里抽样,人工标注相关文档。
- 优点:质量高,贴近真实场景
- 缺点:费人力
方法 2:自动生成
从每个文档里生成问题:
- 拿一段文档内容,让大模型生成几个用户可能问的问题
- 文档本身作为正确答案
- 优点:快,量大
- 缺点:问题分布可能和真实用户不一样
方法 3:混合
- 核心场景人工标注
- 长尾场景自动生成补充
测试集多大?
- 50-100 条:大概看看效果,不够精确
- 200-500 条:比较靠谱的评估
- 1000+ 条:统计显著,细分分析有意义
建议至少 200 条起步,覆盖主要场景。
测试集的多样性
要覆盖:
- 不同类别(产品、售后、技术、财务等)
- 不同问法(口语化、正式、简略、详细)
- 不同难度(简单直接的、需要推理的、模糊的)
- 常见问题和长尾问题
全是简单问题的测试集,分数虚高,上线就崩。
四、Bad Case 分析流程
第一步:跑测试集,收集所有失败案例
把测试集全跑一遍,找出:
- 完全没检索到的(Recall 漏掉的)
- 检索到了但排太靠后的
- 检索结果不相关的
第二步:按错误类型分类
类型 1:完全漏检(Top K 里没有)
原因:检索策略本身召回不够
类型 2:排得靠后(有,但在 5 名开外)
原因:排序质量差,需要重排序
类型 3:关键词匹配不上
原因:纯向量检索的短板,需要加 BM25
类型 4:表述差异大
原因:用户说法和文档里的不一样,需要查询改写
类型 5:答案跨多个块
原因:分块问题,一块装不下完整答案
类型 6:文档里确实没有
原因:知识库缺内容,不是检索的锅
统计每种类型的占比,找到主要矛盾。
第三步:按场景/类别分析
再按业务维度分:
- 哪个类别召回率最低?
- 哪种问题最难?
- 是不是某类文档分块有问题?
第四步:根因分析
每个主要错误类型,深挖原因:
例:技术类问题召回率低
- 可能原因 1:技术术语多,Embedding 没学好
- 可能原因 2:代码和命令行匹配不上
- 可能原因 3:技术文档分块太大,噪声多
验证方法:挑几个典型 case,看检索结果,分析为什么没命中。
五、常见 Bad Case 与优化方法
Case 1:专业术语/型号搜不到
现象:用户搜具体型号、错误码、API 名称,向量检索匹配不到。
原因:Embedding 对精确关键词不敏感。
优化:
- 加 BM25 混合检索,关键词精确匹配
- 元数据里提取关键词,加权匹配
- 领域微调 Embedding 模型
Case 2:口语化问题匹配差
现象:用户说「东西坏了找谁」,文档里写「售后服务联系方式」,匹配不上。
原因:表述差异大,语义距离远。
优化:
- 查询改写,把口语化问题转成正式表述
- 补充 FAQ 数据,覆盖各种问法
- 更好的 Embedding 模型
Case 3:短问题效果差
现象:用户只打几个字「退货」「保修」,检索结果散。
原因:信息太少,语义不明确。
优化:
- 查询扩展,补充相关词
- 多查询生成,从不同角度检索
- 热门问题直接匹配 FAQ
Case 4:答案跨多个分块
现象:答案需要好几段拼起来,检索只拿到一段,信息不全。
原因:分块太小,或者内容被切断了。
优化:
- 加大分块大小
- 增加重叠
- 父子分块(检索小块,返回大块)
- 相邻块扩展,命中了把前后几块也带上
Case 5:热门问题排不准
现象:常见问题检索结果里有正确答案,但排不在第一。
原因:排序精度不够。
优化:
- 加重排序(Rerank)
- 热门问题人工置顶
- 查询词权重调整
Case 6:知识库没有相关内容
现象:用户问的问题,文档里确实没有。
原因:知识库不全,不是检索的问题。
优化:
- 补充文档内容
- RAG 系统里加「不知道」的判断,别瞎答
- 收集这类问题,定期补充知识库
六、迭代优化流程
检索优化是个循环,不是一锤子买卖。
第一轮:基线
- 基础版检索(纯向量)
- 跑测试集,记录 baseline 指标
- Bad Case 分析,找出 Top3 问题
第二轮:针对性优化
- 针对主要问题改(比如加混合检索)
- 再跑测试集,看提升多少
- 分析剩下的 bad case
第三轮:继续优化
- 加下一个优化手段(比如 Rerank)
- 评估效果
- 循环直到达到目标
第四轮:上线后持续优化
- 收集真实用户查询
- 定期抽样标注,加入测试集
- 监控线上效果
- 持续迭代
优化优先级建议
- 分块优化:基础中的基础,先做好
- Embedding 模型选型:选个好的基线模型
- 混合检索:提升明显,实现简单,性价比最高
- 重排序:排序精度大幅提升,推荐做
- 查询改写:锦上添花,成本高一些
- Embedding 微调:终极手段,成本最高,最后考虑
七、自动化评估工具
评估脚本
写个脚本一键跑评估:
python
def evaluate(retriever, test_set, k=5):
recall = 0
mrr = 0
for item in test_set:
query = item["query"]
positives = set(item["positive_docs"])
# 检索
results = retriever.search(query, top_k=k)
doc_ids = [r["id"] for r in results]
# Recall
hits = set(doc_ids) & positives
if hits:
recall += 1
# MRR
for i, doc_id in enumerate(doc_ids):
if doc_id in positives:
mrr += 1 / (i + 1)
break
recall /= len(test_set)
mrr /= len(test_set)
return {"recall@5": recall, "mrr": mrr}
每次优化跑一遍,对比指标。
Bad Case 导出
把失败案例导出来,方便人工分析:
query: xxx
正确文档: doc_001
检索结果:
1. doc_123 (score: 0.89)
2. doc_456 (score: 0.85)
...
错误类型: 漏检 / 排序靠后
八、实际案例
企业知识库检索优化记录
基线:纯向量检索,bge-base
- Recall@5:78%
- MRR:0.62
第一轮优化:分块优化
- 从固定 500 字改成递归字符分块,保留语义边界
- 重叠加到 15%
- Recall@5:78% → 81%(+3%)
第二轮优化:混合检索
- 加 BM25,RRF 融合
- Recall@5:81% → 87%(+6%)
- 提升最大的一步
第三轮优化:Rerank
- 召回 30 条 → bge-reranker-base 重排 → Top 5
- Recall@5:87% → 92%(+5%)
- MRR:0.71 → 0.85(排序提升明显)
第四轮优化:查询扩展
- 高频问题预生成扩展关键词
- Recall@5:92% → 93%(+1%)
- 边际收益递减
最终:Recall@5 从 78% 提到 93%,MRR 从 0.62 提到 0.86。
九、常见误区
误区 1:只看一个指标
Recall 很高但都排最后,大模型也用不上。MRR 也要看。
误区 2:测试集和训练集混了
测试问题就是从文档里抄的,当然检索准。要模拟真实用户的问法。
误区 3:测试集太小
50 条测试集,波动很大,这次 80% 下次 85%,说明不了问题。至少 200 条起步。
误区 4:只优化检索不看最终答案
检索准了不代表答得对,还要结合大模型的效果一起看。但检索是基础,先把检索做好。
误区 5:Bad Case 不分类
只知道召回率低,不知道为什么低。分类分析才能针对性优化。
十、本篇小结
- 检索评估要量化,不能凭感觉
- 核心指标:Recall@K(最重要)、MRR(排序质量)、Precision
- 测试集要覆盖多样场景,人工标注质量最高
- Bad Case 分析:分类统计 → 找主要问题 → 根因分析 → 针对性优化
- 常见问题:术语搜不到、口语化匹配差、短问题、跨块答案
- 迭代流程:基线 → 针对性优化 → 评估 → 再优化,循环提升
- 优化优先级:分块 → 选模型 → 混合检索 → Rerank → 查询改写 → 微调
下一篇讲Prompt 工程与答案生成优化:检索到了内容,怎么让大模型回答得又准又不胡说八道。
我是黒漂技术佬。