RAG 效果差先别调 Prompt:检索评测方法论 + 94 条实测

一、RAG 上线后效果差,先查哪一环?

RAG 系统是个流水线:切分 → 索引 → 检索 → 重排 → 生成。当用户说"回答得不对"时,最要命的场景是------你根本不知道问题出在哪一环

可能是检索没召回对文档,也可能是文档召回了但 LLM 没用好。如果两手一摊去调 Prompt,大概率是瞎忙:把生成端调得再好,检索给的是错的,答案还是错的。

所以工程上的第一原则是:

先量化检索,再谈优化生成。

本文是我在两个 RAG 项目(HeritageMind 非遗知识问答、LexRAG 法律条文问答)里做检索评测的完整方法:评测集怎么构造、怎么自动验证、比什么指标、怎么解读结果。全文数据和脚本均可复现。


二、第一步:构造评测集(Query 集)

评测集是地基。地基层次不够,后面所有数字都是自我安慰。

2.1 两条设计原则

原则 1:按难度分型,不要混在一起

只报一个"总体准确率"等于没报------它掩盖了系统在哪种问题上强、哪种问题上弱。我们把 query 分成两类:

类型 定义 例子
简单题 直问,问题里包含技艺名 "景泰蓝的制作工艺是怎样的?"
难题 间接提问,问题里不含技艺名 "掐丝珐琅的另一个名称是什么?"

为什么难题重要?因为真实用户的提问往往是难题------他们不知道"那个东西"叫什么,只能用特征描述。只测简单题,测的是"玩具场景"。

原则 2:query 必须覆盖全量语料主题

每个知识域至少 3~5 条 query,确保评测不是"只测了系统擅长的几篇文档"。

2.2 锚词自动验证:防住"无效 query"

这是我认为最值得讲的一个工程细节。

手工写评测集有个隐蔽的坑:你以为 query 的答案在文档里,实际上可能不在------或者答案在,但你记错了关键词。这种"无效 query"混进评测集,会把分数拉低,而你还以为是系统的问题。

解法:给每条 query 配一个锚词(anchor) ,写个脚本自动验证"锚词是否真的出现在期望文档里":

python 复制代码
# (query, 期望文档, 锚词, 难度类型)
Q = [
    ("东阳木雕有哪些主要雕刻技法?", "东阳木雕", "镂空雕", "simple"),
    ("哪种木雕以平面浮雕见长?", "东阳木雕", "平面浮雕", "hard"),
    # ... 100 条
]
​
valid, invalid = [], []
for q, exp, anchor, typ in Q:
    with open(f"data/crafts/{exp}.txt", encoding="utf-8") as f:
        txt = f.read()
    if anchor in txt:
        valid.append((q, exp, anchor, typ))   # 锚词在文档里 → query 有效
    else:
        invalid.append((q, exp, anchor, typ)) # 锚词不在 → query 无效,剔除
​
print(f"有效 query: {len(valid)} / {len(Q)}")

实测效果 :我们写了 100 条 query(40 简单 + 60 难题),自动验证后剔除了 6 条无效 query(锚词不在期望文档里),最终评测集 94 条。

如果不做这一步,这 6 条无效 query 会稳定地"失败",把真实 Hit@5 从 100% 拉低到 94%------你会误判系统有问题,然后开始一轮毫无意义的调参。


三、第二步:选指标,为什么是 Hit@5?

检索评测的常见指标:Hit@K、MRR、NDCG。我们选 Hit@5 作为主指标,理由很工程:

  1. 贴近实际用法:我们的 RAG 管线检索 Top-5 送入重排/生成,所以"正确答案是否出现在 Top-5"就是系统能不能工作的直接判据
  2. 判定简单、可自动:Hit@K 只要判断"期望文档是否在返回列表里",不需要人工打分,评测可以全自动跑
  3. 生成端的前置条件:如果 Top-5 里连正确答案都没有,后面重排和生成做得再好也白搭

判定规则:返回的 chunk 属于期望文档 即算命中。因为我们的语料按文档分文件、chunk 带 craft_id 元数据,判定是精确的、可复现的。


四、第三步:三路检索对比实验

评测的价值在对比。只测一路检索,你不知道自己的方案在同行里算什么水平;三路对比,你能看清每路检索的优缺点。

我们比了三路:

路线 原理 特点
BM25 词频 + 逆文档频率(稀疏检索) 快、可解释、依赖关键词重合
向量检索 BGE-M3 编码后余弦相似度(稠密检索) 语义理解强、需要 embedding 模型
RRF 融合 对前两路排名做倒数排名融合 取长补短,工业界标配

RRF 融合的核心代码很简洁:

python 复制代码
def reciprocal_rank_fusion(ranked_lists, k=60):
    """RRF: 每个文档在各路结果中的排名取倒数,求和排序"""
    scores = {}
    for lst in ranked_lists:
        for rank, doc_id in enumerate(lst):
            scores[doc_id] = scores.get(doc_id, 0) + 1.0 / (k + rank + 1)
    return sorted(scores.items(), key=lambda x: x[1], reverse=True)

评测脚本结构(伪码):

ini 复制代码
for query in eval_set:
    bm25_top5    = bm25.retrieve(query)              # 稀疏路
    vec_top5     = vector_retrieve(query)            # 稠密路(BGE-M3, 1024维)
    rrf_top5     = rrf_fuse(bm25_top5, vec_top5)     # 融合路
    # 分别判断期望文档是否在 Top-5,按 simple/hard 分型统计

五、实测结果与解读

5.1 HeritageMind(非遗知识问答,94 条有效 query)

检索路线 简单题 (40) 难题 (54) 总体
BM25 100% 100% 100%
向量检索(BGE-M3) 100% 100% 100%
RRF 融合 100% 100% 100%

三路全部 100%,是不是显得很假?恰恰相反,这个 100% 是可以被解释的,解释比数字本身更重要

  1. 语料小:非遗知识库 6 类技艺、几十个文档、500 字窗口切分后只有几百个 chunk------检索空间小,命中概率天然高
  2. 主题分离:每类技艺一个文档,文档间几乎没有语义重叠。问"景泰蓝"的 query 和"剪纸"文档的相似度极低,向量检索天然不会串
  3. 判定宽松:Hit@5 判定"在 Top-5 内即可",不需要第一名------正确文档只要进前五就算过

给面试官讲这套数字时,一定要主动说出这三个原因。 100% 不是"我强",而是"我的评测场景简单";主动解释反而显得你有方法论、不吹牛。

5.2 LexRAG(法律条文问答,15 条咨询 query)

换到法律场景,数字立刻出现分化:

检索路线 准确率
BM25 87%
向量检索(BGE-M3) 100%
RRF 融合 100%

BM25 掉到 87%,这是一个非常有价值的失败案例。原因也清晰:法律咨询里用户问题常常和法条原文用词不一致------用户问"合同签了但对方反悔怎么办",法条里写的是"当事人一方不履行合同义务",关键词零重合,BM25 的稀疏匹配就抓瞎了;而向量检索能理解语义等价。

这组对比直接证明了"为什么 RAG 必须上向量检索/混合检索" ------单靠 BM25 的关键词匹配,在语义鸿沟大的领域(法律、医疗)撑不住。


六、评测的边界:检索 100% 不等于问答 100%

必须诚实地说清楚评测的边界。Hit@5=100% 只证明了一件事:检索能把对的文档捞上来。它不证明:

  1. 生成端用得好不好:文档对了,LLM 可能还是答错/答不全------这是另一层评测(答案正确性、引用准确性)
  2. 覆盖面够不够:检索只能回答"知识库里有的问题"。知识库没有的内容,检索做得再好也是"优雅地失败"

针对第 2 点,我们做了补充验证------覆盖缺口 query:6 条特意问"知识库里没有的内容"的 query(如某非遗技艺知识库里没收录的细节)。结果符合预期:检索找不到对应文档。

这 6 条 query 没有白测,它们直接支撑了一个产品特性:gap_detector(知识缺口检测) ------当检索分数普遍偏低时,系统不硬答,而是诚实告知"这个问题超出了我的知识范围"。用评测数据反推产品设计,这是评测的最高价值。


七、方法学总结(可直接迁移)

把这套方法抽象成四个步骤,任何 RAG 项目都能用:

css 复制代码
① 构造评测集:按难度分型 + 全主题覆盖
② 锚词自动验证:剔除无效 query(防自欺欺人)
③ 三路对比:BM25 vs 向量 vs RRF,分型统计 Hit@5
④ 结果解读:先解释"为什么是这个数字",再决定调什么

几个关键认知:

  • 先量化检索,再优化生成:检索不达标,调 Prompt 是浪费生命
  • 评测集要自动验证:手写 query 无效率可能高达 6%,不验证就是在跟幻觉数据搏斗
  • 100% 也要能解释:语料小、主题分离、判定宽松------数字背后的原因才是面试和复盘的重点
  • 失败案例比满分更有价值:BM25 在法律场景的 87%,是"必须上向量检索"的最强论据
  • 评测要能反推产品:覆盖缺口 query 直接催生了 gap_detector 功能
相关推荐
dong_junshuai35 分钟前
每天一个开源项目#99 OpenResearch:2.2K星的本地研究Agent工作台
开源·github·agent
花椒技术44 分钟前
把 AI 视频接进直播:提前生成、按次生成、持续生成怎么选?
agent·音视频开发
用户8082598666871 小时前
用 LangGraph 重写自己手写的 Agent:框架替你解决了什么,什么它不管
agent
能不能静下心来看1 小时前
从 RAG 到 Agent:跑通两个 Demo 后,我终于分清了这两个词
agent
ZGi.ai1 小时前
知识库权限变了,怎样避免答错?
agent·权限管理·知识库·工作流·zgi·客服运营
大模型真好玩1 小时前
DeepSeek Harness 入门很简单(四)——DeepSeek Harness接入插件
人工智能·agent·deepseek
掰头战士2 小时前
MCP、Skill、Plugin,都是给agent拓展能力,到底有何区别?
typescript·llm·agent
嘟嘟嘟95273 小时前
AI Agent 的边缘困境
人工智能·架构·agent
HYDtomako3 小时前
Agent checkpoint设计
ai·agent·checkpoint·claude code
梦在远山后3 小时前
从需求到架构:我的企业研发 Agent 整体设计
langchain·agent