检索效果评估与 Bad Case 分析

检索效果评估与 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)
  • 评估效果
  • 循环直到达到目标

第四轮:上线后持续优化

  • 收集真实用户查询
  • 定期抽样标注,加入测试集
  • 监控线上效果
  • 持续迭代

优化优先级建议

  1. 分块优化:基础中的基础,先做好
  2. Embedding 模型选型:选个好的基线模型
  3. 混合检索:提升明显,实现简单,性价比最高
  4. 重排序:排序精度大幅提升,推荐做
  5. 查询改写:锦上添花,成本高一些
  6. 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 工程与答案生成优化:检索到了内容,怎么让大模型回答得又准又不胡说八道。

我是黒漂技术佬。

相关推荐
神奇的代码在哪里1 小时前
AI编程时代,PPT已成为过去,单个HTML文件创造无限可能
javascript·html·powerpoint·ai编程·ppt
海兰2 小时前
【AI编程思考:第八篇】从演示到生产:AI工程部署实战指南
大数据·人工智能·ai编程
Goodbye2 小时前
从零开始构建AI Agent —— 基于LangChain的智能体开发实践
agent
前端双越老师2 小时前
我多年积累的 100+ 简历优化经验,整理成了 Skill
面试·agent
先吃饱再说2 小时前
LangChain 到底帮你干了什么活?——Agent 开发框架完全解读
langchain·llm·agent
用户2930750976692 小时前
拆解 AI Agent:用 LangChain 构建你的第一个智能工具
agent
卡卡罗特AI2 小时前
卡兹克大佬网站被攻击?新手Vibe Coding上线安全指南!保姆级教程
ai编程·vibecoding
Darling噜啦啦2 小时前
从零手写 AI Agent:LLM + Tool + LangChain,打造能干活的大模型
langchain·llm·agent
名不经传的养虾人2 小时前
从0到1:企业级AI项目迭代日记 Vol.61|记忆不是越多越好,装一道门比装满更重要
数据库·人工智能·ai编程·ai工作流·企业ai
_冷眸_2 小时前
用 OpenAI SDK 统一调用 Claude、Gemini、DeepSeek:聊聊 AI API 聚合网关的实践
人工智能·ai·llm·agent