← RAG 检索增强

RAG 为什么要做混合检索?BM25、向量检索和 RRF 如何配合?

高频 中等 混合检索与 RRF 融合 · 第 1 / 2 问 更新于 2026/09/29
RAG混合检索BM25RRF
本题落地项目AI Agentic RAG高级企业知识库平台

简化版

BM25 擅长精确关键词、编号、专有名词(字面匹配),向量检索擅长语义相近但字面不同的表达(同义改写),两者短板互补。混合检索并行召回两路结果再融合。RRF(Reciprocal Rank Fusion) 按文档在各结果列表中的名次累加倒数分数,不依赖两套原始分数在同一尺度——这是它比「直接加分」稳健的关键。

详细版

  • BM25:基于词频、逆文档频率、长度归一化,适合产品型号、错误码、人名等精确匹配;
  • Dense Retrieval:用 Embedding 比语义,适合同义改写、自然语言意图、跨字面匹配。

混合检索并行取两路 Top-n,再用加权分数或 RRF 融合。RRF 的典型形式:

score(d) = Σ_i  1 / (k + rank_i(d))

rank_i 是文档在第 i 个列表的名次,k 是平滑常数。文档在多路都靠前,融合分更高。融合后的候选还可交给 Cross-Encoder 重排。

完整版教学

一、纯向量检索为什么不够

向量模型压缩语义,但对罕见编号、版本号、精确短语、拼写细节可能不敏感:

查询"错误码 E1047":
  向量检索可能召回 E1052、E1039(语义都是"错误码",但用户要的是字面完全命中的 E1047)
  → 语义相近的其他错误码反而是噪声

向量还可能把「如何开启功能」和「如何关闭功能」判得很近(主题相同、动作相反)。关键词和结构化过滤能补这些细粒度差异。

二、BM25 为什么仍然重要

BM25 不是简单数关键词次数,它有三个机制:逆文档频率(IDF)提高稀有词权重、饱和函数限制重复词收益、按文档长度归一化。它可解释、成熟、无需训练,在专有词密集场景经常非常强。

但 BM25 不理解同义词——「退款步骤」和「如何把钱退回来」若无共同词就可能匹配不到,所以需要向量召回补充。二者是天生互补关系。

三、为什么不能直接相加原始分数

这是 RRF 存在的理由,也是高频考点:

BM25 分数范围可能是 0~30,余弦相似度是 0~1
甚至同一算法在不同查询上尺度也变
→ 直接相加:BM25 的 25 分会碾压向量的 0.9,某一路"无意中支配"结果

可以先归一化再加权,但归一化对异常值敏感。RRF 只看排名、不依赖分数尺度,工程上稳健又好实现。

四、RRF 的计算与权衡(带数字)

看一个例子(取 k=60):

文档 D 在 BM25 列表排第 1,在向量列表排第 3:
  score(D) = 1/(60+1) + 1/(60+3) = 0.0164 + 0.0159 = 0.0323
文档 E 只在向量列表排第 1,BM25 未召回:
  score(E) = 1/(60+1) = 0.0164
→ 两路都靠前的 D 胜出,但只在一路靠前的 E 也被保留

平滑常数 k 越大,不同名次的分差越小。RRF 不学习业务相关性——有充足标注数据时可训练 Learning-to-Rank 融合更多特征。要点:融合前各路要召回比最终 Top-k 更多的候选(否则融合空间太小),去重用稳定的文档/chunk ID。

五、典型生产链路

1. 查询规范化 + 提取权限/时间等过滤条件
2. BM25 与向量索引【并行】召回各自 Top-n
3. RRF 或校准后的加权分数融合
4. 去重、按元数据过滤
5. Cross-Encoder Reranker 精排
6. 选满足 token 预算且有多样性的上下文

混合检索的价值来自互补召回,不来自“两个分数相加”;融合前必须先明确排名口径、候选去重和验证集查询分布。

六、常见误区与追问

  • 误区:有了向量检索就不需要 BM25。 向量对编号/版本号/精确短语不敏感,BM25 在专有词场景常更强,二者互补。
  • 误区:两路分数直接相加就行。 BM25 和余弦尺度/分布不同,直接加会让一路支配结果,要用 RRF 或校准加权。
  • 误区:混合检索就是把两路 Top-k 都塞进 prompt。 还要融合、去重、重排、上下文去重,不是简单拼接。
  • 误区:RRF 会学业务相关性。 它只按名次投票、不学习,要更强融合得上 Learning-to-Rank。
  • 追问:BM25 的三个核心机制? IDF 提稀有词权重、饱和函数限重复词收益、长度归一化。
  • 追问:RRF 为什么比加分稳健? 只看排名不依赖分数尺度,避免某一路因尺度大而支配。
  • 追问:融合前各路要召回多少? 比最终 Top-k 更多的候选,否则融合空间太小。
  • 追问:混合检索一定更好吗? 不一定每类查询都更好,可按查询类型(编号/实体/自然语言/多跳)分桶评估甚至做查询路由。

七、检索信号判断表

信号擅长容易漏掉
BM25精确词、编号、专名同义改写
向量检索语义近似、自然语言改写稀有精确词
RRF 融合合并不同排名尺度不直接利用原始分数
学习排序按业务训练融合需要可靠标注

八、加强记忆

混合检索记「字面准 + 语义近,互补短板」:BM25 擅精确关键词/编号/专有名词(可解释、免训练、IDF+饱和+长度归一化),向量擅同义改写/自然语言意图。融合用 RRF(Σ 1/(k+rank)),只看名次投票、不依赖分数尺度——因为 BM25 和余弦尺度不同,直接加分会让一路支配。核心链路:两路并行召回(比 Top-k 更多)→ RRF 融合 → 去重过滤 → Reranker 精排。混合不保证每类查询都更好,必要时按查询类型分桶评估或路由。

项目实战落地

项目里怎么做的

在《AI Agentic RAG高级企业知识库平台》里,两路召回和融合都由检索策略表 retrieval_strategy 控制:vector_enabled / vector_top_k 管向量路,bm25_enabled / bm25_top_k 管关键词路,rrf_k 是 RRF 的平滑常数,默认 60。管理员在页面上拨开关就能组合出不同策略,检索代码不用改。

  • 向量路:问题用 Embedding 模型编码后,去 PostgreSQL + PGVector 里取最近的若干条片段。
  • BM25 路:没有引入 Elasticsearch。检索时从 MySQL 的 knowledge_chunk 表读出候选片段(按知识库和文档先收窄,一次最多 5000 条),用 jieba 分词、去停用词后交给 rank_bm25 在内存里打分,分数不大于 0 的直接丢掉。分词和打分是纯 CPU 计算,放进线程执行,不阻塞 FastAPI 的事件循环。
  • 型号分词:文档里写 GTE-3000,jieba 切成 gte、-、3000;用户输入 GTE3000,jieba 切成一个词 gte3000,两边一个词都对不上。项目在分词时把字母数字连写的词额外拆一份(gte3000 → gte、3000),原词也保留,型号才能命中。
  • RRF 融合:每一路的结果各算一份榜单,融合后保留的条数取两路 top_k 中较大的那个。同一片段被两路同时召回时只保留一份内容,来源标成「BM25检索+向量检索」,页面上一眼能看出哪些结果是两路都认可的。

项目预置了三套策略用来对比:「基线-纯向量检索」(向量 top 5)、「进阶-混合检索」(两路各 8 条)和「完整-混合检索加重排加改写」。同一批评测用例上,基线的综合分是 0.7988,完整策略是 0.9616。

为什么这样取舍

  • BM25 放在内存里算,而不是上搜索引擎。 项目是本地运行的学习项目,单个知识库的片段量可控,少一个中间件,部署和排错都简单。代价是每次检索都要读候选、临时建索引,所以一定先按知识库和文档收窄范围,并设置候选上限。
  • 融合用 RRF,不做加权求和。 向量分是 0 到 1 的余弦相似度,BM25 分没有上界,同一个知识库里可能是 2.3,也可能是 47.8,两个不可比的数加权求和,权重怎么调都说不清道理。
  • rrf_k 做成可配置字段,默认用论文经验值 60,想对比「多路共识优先」和「单路头名优先」时直接在策略里改。

面试官还会追问

  • 开了多查询改写之后,一个问题会产生几份榜单一起做 RRF?其中某一份是空的,要不要占融合位置?
  • 知识库用了父子分块,BM25 应该对哪些片段建索引,父块要不要参与打分?
  • 你怎么证明加了 BM25 这一路真的有用,而不是凭感觉?

学完《AI Agentic RAG高级企业知识库平台》,上面这些追问你都会迎刃而解。

本题落地项目地狱锤炼AI Agentic RAG高级企业知识库平台基于企业知识库、PGVector 向量检索、Agentic RAG、FastAPI + LangGraph、Function Calling,实现向量 + BM25 混合检索与 RRF 融合、Rerank 重排、HyDE 与多查询改写、父子分块召回、LangGraph 状态图自适应检索、Agent 执行时间线和 LLM-as-judge 四指标评测,覆盖从基础 RAG 到高级 RAG 调优的完整闭环。FastAPILangChainLangGraphRAGPGVector源码+SQL喂饭学习教程配套面试文档环境安装文档项目运行文档 学习这个项目