RAG 检索不准?BM25 + 向量混合检索、RRF 融合与 Reranker 重排序实战

RAG 检索不准?BM25 + 向量混合检索、RRF 融合与 Reranker 重排序实战

RAG 检索不准往往不是模型不够大

知识库明明有答案,向量库也返回了“差不多”的段落,模型却仍然答非所问。真正的问题通常不是生成,而是正确文档没有进入候选集,或进入后没有排进最终上下文。

**本文结论:**用 BM25 保住错误码、型号与专有名词,用 Dense 检索理解同义表达;两路结果用 RRF 融合,再用 Cross-Encoder 精排。调参先保召回,再谈延迟。

01 先把“检索不准”拆开

错误答案至少有四种来源:召回阶段漏掉正确文档;融合阶段把它压出窗口;精排阶段没进 Top N;正确片段已进入上下文,却被截断、重复或冲突内容淹没。

因此不要一看到答案错就换 Embedding。先保存每个阶段的文档 ID、名次、过滤原因和耗时,确认故障发生在哪一层。

图 1|第一阶段扩大候选,第二阶段精细排序。原创教学图(Image2 生成)。

关键原则:第一阶段漏掉的文档,后面的 Reranker 再强也找不回来。

02 为什么向量检索还需要 BM25

向量检索擅长同义表达。例如“网页连接被重置怎么办”可以匹配“TCP 连接被对端中断的排查方法”。但向量是有损压缩,未必稳定保留错误码、显卡型号、补丁编号、API 字段和内部项目名。

BM25 不理解深层语义,却善于精确锚定稀有词。真实查询往往同时包含自然语言和不能改写的实体,所以二者不是竞争关系。

图 2|BM25 抓精确词,Dense 抓换一种说法,Hybrid 负责不漏。原创教学图(Image2 生成)。

中文系统还要检查分词。下划线、连字符、点号和英文大小写一旦被预处理破坏,错误码和型号就无法精确匹配。建议保留 keyword 字段,并对领域专名配置 analyzer。

03 两个分数为什么不能直接相加

BM25 分数与余弦相似度没有共同量纲。简单写成0.5 × BM25 + 0.5 × cosine,看似公平,实际可能被某一路支配。没有成熟评测集时,按名次融合更稳。

图 3|Qdrant 提供 Dense 与 Sparse 融合以及 RRF。来源:Qdrant Documentation,原始页面。

RRF 的常见形式是Σ 1 / (k + rank):文档在某一路越靠前,贡献越高;多路都靠前,贡献会叠加。它只依赖名次,不要求先校准两套原始分数。

图 4|RRF 用排名融合不同检索器。原创教学图(Image2 生成);同分文档由稳定排序或业务规则打破。

from collections import defaultdictdef rrf(rankings, k=60): scores = defaultdict(float) for ranking in rankings: for rank, doc_id in enumerate(ranking, 1): scores[doc_id] += 1 / (k + rank) return sorted(scores.items(), key=lambda x: (-x[1], x[0]))

04 Reranker 是“最后一公里”

Bi-Encoder 分别编码查询和文档,适合从大语料快速召回。Cross-Encoder 把查询与候选文档一起输入,能更细致地判断否定、条件、版本和实体关系,但每个候选都要重新推理,成本更高。

因此正确用法是:先召回几十个候选,再精排;不是让 Cross-Encoder 扫描整个知识库。

图 5|官方两阶段流程:Retriever 召回,Cross-Encoder 重排。来源:Sentence Transformers Documentation,原始页面。

Reranker 输入最好包含“文档标题 + 章节路径 + chunk”。同时检查最大输入长度,避免证据在尾部被截断。

05 Top K 怎么调,不靠拍脑袋

图 6|候选太少会漏,太多会增加成本与噪声。原创教学图(Image2 生成)。

正确顺序是:

  1. 固定一批真实查询与相关文档标注;
  2. 先提高 BM25、Dense 和融合后的 Recall@K;
  3. 再调整 Reranker 候选数,观察 MRR 与 nDCG;
  4. 控制最终上下文数量、去重和 token 预算;
  5. 最后用并行召回、批量精排、缓存和小模型优化 P95 延迟。

BM25 Top 50 + Dense Top 50、合并后精排 50、最终保留 5–10 个片段,可以作为实验起点,但不是万能答案。FAQ、代码库、规章与商品库的最佳窗口完全不同。

06 一棵实用排错树

图 7|同一 Mermaid 教学图已渲染为静态 HTTPS 图片,适用于公众号编辑器。

若正确文档没进候选集,检查分词、字段、向量模型、切块、过滤器和候选窗口;若进入候选却没进 Top N,检查 RRF 与 Reranker;若已进入上下文,检查重复块、父子块扩展、token 截断、提示词和引用约束。

07 用一个真实问题走一遍

假设用户问:“Windows 11 更新后 Docker 报 WSL version too old 怎么办?”

规范化阶段保留原问题,同时抽取Windows 11DockerWSLversion too old。BM25 会命中包含精确实体和错误短语的文档;Dense 会补充“升级 WSL 内核”“Docker Desktop 无法启动”等同义表达。

两路候选用统一文档 ID 去重。RRF 把两边都靠前的文档提升,不比较两套原始分数。Cross-Encoder 再区分“安装 Docker”“启用 WSL”“更新 WSL 版本”这三类看似相关、解决步骤却不同的内容。

最终上下文不能简单取前五个 chunk。如果五个都来自同一篇文章的相邻段落,应按 parent_id 去重,保留“版本检查、升级命令、重启验证”等互补证据。

答案仍然错误时,沿决策树找到标准文档消失的位置:从未进入候选,查索引和分词;进入 RRF 却没进 Top N,查 Reranker 输入与截断;已经送入 LLM,才查提示词与冲突上下文。

08 指标如何对应故障

Recall@K回答“正确文档进候选了吗”;MRR回答“第一个正确结果离榜首多远”;nDCG@K观察多级相关性的整体排序;答案正确性和引用忠实度则检查生成阶段。

从线上抽取约 200 条代表性查询就能建立第一版评测集。覆盖错误码、同义改写、多条件、跨文档、代码和无答案问题。保存每一路完整排名,而不只保存最终 Top 5。

如果 Recall@50 下降,优先检查召回、过滤和索引;Recall 不变但 MRR 下降,检查融合与精排;检索指标不变但答案变差,才检查上下文和生成。平均值提升还不够,必须观察各查询类型是否有人明显退化。

09 查询改写与过滤的边界

查询改写必须保留原句和精确标识符。让模型自由扩写许多版本,可能引入用户没说过的产品或条件。改写只能作为新增通道,并限制数量;有没有收益用评测决定。

租户和权限过滤属于安全边界,失败时默认拒绝。语言、时间和产品版本属于相关性过滤,字段缺失或候选过少时可受控降级。日志要记录过滤表达式以及过滤前后数量,否则“没有召回”和“召回后被删掉”看起来完全一样。

一份文档往往同时存在于原始库、BM25 和向量索引。更新时要携带document_versionchunk_versionindexed_atembedding_version,合并时剔除旧版本。升级 Embedding 建议构建新索引、验证后切别名,避免半数文档使用新模型、半数仍是旧向量。

10 上线前的工程清单

  • BM25 与 Dense 并行执行,分别设置超时和降级;
  • 所有索引使用统一稳定的文档 ID;
  • 日志保存各路排名、过滤数量、模型版本与阶段耗时;
  • 权限过滤必须在生成前执行;
  • 相邻 chunk 去重,限制同一父文档霸榜;
  • Reranker 分数不要未经校准就当作概率;
  • 评测按错误码、同义改写、多条件、无答案等类型切片;
  • 同时看 Recall@K、MRR、nDCG、答案忠实度和 P95 延迟。

图 8|从双路召回到上下文构造的完整静态流程。对应 Mermaid 源码保存在code/hybrid-retrieval-flow.mmd

上线最好分三步:先离线重放同一语料快照;再用影子流量计算新排名但不影响用户;最后才小比例 A/B。除了答案正确率,还看 P95 延迟、空候选率、降级率、追问率和负反馈。

BM25 与 Dense 可并行执行并分别超时。某一路失败时可以降级,但必须记录degraded=true。Reranker 采用批量推理和长度分桶;缓存键包含租户、过滤条件、索引版本和模型版本,避免新文档上线后仍返回旧结果。

11 无答案问题,宁可拒答也不要硬编

混合检索提高的是召回上限,不代表每个查询都有答案。最高精排结果也可能只是“最不差”,并不足以支持结论。系统需要在领域验证集上校准拒答条件:最高相关性是否达标、多个来源是否冲突、文档版本是否过期、引用片段是否真的包含回答依据。

Reranker 的原始输出通常不是概率,不能把score > 0.8机械解释成“80% 可信”。阈值要结合人工标注和不同查询类型分别验证。证据不足时,清楚说明缺少什么,并给出最接近的来源或建议用户补充条件,比生成一个流畅但错误的答案更有价值。

12 一次发布应留下可复现记录

每次实验至少保存:代码提交、语料快照、BM25 analyzer、Embedding 与 Reranker 版本、RRF 参数、候选窗口、过滤规则、评测集版本和结果报告。只有这样,线上退化才能回放,模型升级才能判断收益来自算法还是语料变化。

对核心查询建立回归门禁:相关文档不能跌出指定 K;权限查询不得出现越权候选;无答案查询误答率不得上升;P95 延迟与单次费用不得超过预算。效果、安全、延迟和成本四项同时通过,再扩大流量。

写在最后

RAG 的检索质量不是一个相似度阈值能解决的问题。BM25 与 Dense 负责“尽量别漏”,RRF 负责“稳定合并”,Cross-Encoder 负责“把真正相关的候选推到前面”,上下文构造器负责“把少而准、权限正确的证据交给模型”。

遇到错误答案,先问两句:**正确文档有没有进入候选集?进入后为什么没出现在最终上下文?**只要这两层可观测,RAG 就不再是玄学调参,而是可回归、可比较、可持续优化的检索工程。

把“模型答错”拆成可观测的召回、融合、精排与上下文问题。

学AI大模型的正确顺序,千万不要搞错了

🤔2026年AI风口已来!各行各业的AI渗透肉眼可见,超多公司要么转型做AI相关产品,要么高薪挖AI技术人才,机遇直接摆在眼前!

有往AI方向发展,或者本身有后端编程基础的朋友,直接冲AI大模型应用开发转岗超合适!

就算暂时不打算转岗,了解大模型、RAG、Prompt、Agent这些热门概念,能上手做简单项目,也绝对是求职加分王🔋

📝给大家整理了超全最新的AI大模型应用开发学习清单和资料,手把手帮你快速入门!👇👇

学习路线:

✅大模型基础认知—大模型核心原理、发展历程、主流模型(GPT、文心一言等)特点解析
✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑
✅开发基础能力—Python进阶、API接口调用、大模型开发框架(LangChain等)实操
✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用
✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代
✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经

以上6大模块,看似清晰好上手,实则每个部分都有扎实的核心内容需要吃透!

我把大模型的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费