RAG 召回率低怎么办?我把 chunk 从 512 改成 384+64,top_k 调成 20 后,NLP 问答准确率从 61% 到 79%

🔑 关键词:RAG,召回率,文本分块,BM25,Embedding

📖 摘要:一篇从真实调试出发的 NLP 实战文:对比 BM25、Embedding、RAG 和微调,给出 chunk、overlap、top_k、rerank、维度、评估集的具体参数和步骤,并给出一个不太讨喜的观点:大多数 NLP 项目先别急着换大模型,先修检索和标注。

上周三晚上 10 点,我还在客户现场改一个客服问答机器人。 工单库 3000 条,用的是 text-embedding-3-small,1536 维,模型是 GPT-4o。 老板说答案不准,想换 claude 或者 qwen-max。 我先跑了一遍评估:top-20 召回 73%,top-5 召回只有 48%,答案准确率 61%。 问题根本不在生成,在检索。换模型?换完还是 61%。

图片

先给结论,可能不太好听: 大多数 NLP 项目,80% 的收益来自数据切分、召回和评估集,不是模型参数量。 大模型是通用近似,检索是精确记忆。top-20 里没有答案,GPT-4o 也只能编。 下面这张表是我们从 BM25 到 RAG 再到微调,踩过一遍后的对比。

图片

方案 适合什么 关键参数 我踩过的坑
BM25 关键词、型号、订单号 k1=1.2, b=0.75 同义词不行,用户说“充电慢”匹配不到“充电速度”
Embedding 检索 语义相似、FAQ BGE-M3 1024 维,max 8192;text-embedding-3-small 1536 维 长文本截断,512 以上语义漂移
RAG 私有知识、频繁更新 chunk 256-512,overlap 64-96,top_k 20 只做向量,不做 rerank,top-5 拉胯
微调 风格、格式、分类 LoRA r=8/16, alpha=32, lr=2e-4, epochs 3 500 条以下别碰,容易背答案

图片

我们的修复步骤很土,但有效。 第一步,先别动模型。我拉了 200 条评估集,每条标问题、标准答案、相关文档 ID。 第二步,把 512 tokens 一刀切改成 384+64。中文 FAQ 用 256-384,合同类用 768+96。 第三步,混合检索:BM25 取 top 50,向量取 top 50,用 RRF 融合,k=60。 第四步,上 bge-reranker-v2-m3,top 20 进,top 5 出,batch size 16。 第五步,生成 prompt 只允许引用,temperature=0.1,max_tokens=512。

图片

改完第一版,召回@5 从 48% 到 82%,答案准确率 61% 到 79%。 我们没换 GPT-4o,也没加什么黑科技。 中间有个小插曲:一个实习生把“相关”标成“直接回答算 1 分,部分回答算 0.5”,另一个标成二分类。 结果评估集自己打架,nDCG@10 从 0.71 掉到 0.52。 后来统一标注协议,才稳定到 0.78。

图片

说个可能得罪人的观点:NLP 不是 NLP,是信息检索加标注工程。 很多人一上来就研究 attention、MoE、上下文长度,却不肯花 2 小时写 50 条标注规则。 我见过一个团队花 3 周微调 7B 模型,最后不如把 top_k 从 5 调到 20,再加个 rerank。 中文分词这事也别太魔怔。BM25 用 jieba 的搜索模式就够,向量模型对分词不敏感,但对 chunk 边界极其敏感。 BGE-M3 标称 8192 tokens,我实测超过 512 后,句向量相似度排序会乱,尤其是多主题文档。

图片

如果你现在正遇到 RAG 召回率低,按这个清单排:

  1. 查全半角、大小写、空格、换行,工单号“A-1024”和“a1024”可能是两个东西。
  2. 查 chunk 是不是切断了一句完整的话。
  3. 查 embedding 模型对不对口,中文别用只训英文的 MiniLM。
  4. 查 top_k,5 太小,20 起步。
  5. 查有没有 rerank,没有就先加。
  6. 查 metadata 过滤,部门、时间、权限筛完再排。
  7. 查评估集,如果两个人都标不一致,先别怪模型。 最后一句,不是金句,是我上周五在便利店啃饭团时想通的:模型是租来的,数据和评估才是你买的房。
🏷️ 标签: