混合检索:BM25 + 向量 + RRF

T2-5模块 2 · RAG 工程化面试权重 更新于 2026-08
前置T2-3T2-4
关联题目Q2-09Q2-10Q2-15

这篇学完你能回答什么

  • 「为什么纯向量检索会漏掉型号、编号、人名这类查询?」
  • 「BM25 的分数和向量相似度为什么不能直接加权相加?主流的融合方案怎么选?」
  • 「RRF 里那个 k=60 是干嘛的?RRF 有什么缺点?」——这是面试官最爱的第三层追问。

从一个真实故障讲起

假设你给一家设备厂商做手册问答系统,上线一周收到 badcase:用户问「SK-3200 报 E05 错误怎么处理」,系统返回的却是《常见故障处理总览》,正确的那页《SK-3200 错误码对照表》根本没被召回。

排查后发现问题出在检索层:你用的是纯向量检索。Embedding 模型(向量模型)擅长理解「意思」,但 "SK-3200"、"E05" 这类低频符号在它眼里几乎没有独立语义——被压缩进向量后和别的型号长得差不多。向量检索天生擅长「意思相近」,不擅长「一字不差」。

于是你想:那换关键词检索?马上出现反向 badcase——用户问「机器出毛病了保修吗」,文档里写的是「设备异常」「质保条款」,关键词一个都对不上,照样搜不到。

两种检索各有盲区,谁也替代不了谁。这就是混合检索(Hybrid Retrieval / Hybrid Search)存在的理由。

两次 badcase,暴露的是同一件事
设备手册问答上线一周:先是型号搜不到,换个方案又是口语问法搜不到

  1. 用户提问

    「SK-3200 报 E05 错误怎么处理」

  2. 纯向量检索

    把问题压成 embedding,按语义距离找最近邻

  3. SK-3200 / E05 被压平断点

    低频符号在向量里几乎没有独立语义,和别的型号长得差不多

  4. 返回《常见故障处理总览》

    正确的《SK-3200 错误码对照表》根本没被召回

向量检索的强项「意思相近」不擅长「一字不差」
换成关键词检索型号能搜到了「机器出毛病了保修吗」又搜不到
文档里的实际写法「机器出毛病」「设备异常」「质保条款」
两种检索各有盲区,谁也替代不了谁 —— 这就是混合检索(Hybrid Retrieval)存在的全部理由。注意故障不是「模型不够好」,是检索方式和查询类型不匹配

核心概念:先打比方,再给定义

想象图书馆里有两位管理员:

  • 老王只认字面。你报书名、书号、作者名,他秒找,从不出错;但你说「想看讲人性挣扎的小说」,他一脸茫然。——这是 BM25(Best Matching 25),一种基于词频统计的关键词检索算法,TF-IDF 的工业级改良版,也叫稀疏检索(Sparse Retrieval)
  • 小李懂意思。模糊的需求他能听懂,还会举一反三;但你报一个精确书号,他可能凭印象拿错版本。——这是向量检索(Dense Retrieval,稠密检索):把文本变成 embedding 向量,按语义距离找最近邻。

混合检索就是:同一个问题让两人各找一摞书,然后把两摞合并成一份最终榜单。难点全在「怎么合并」——这正是面试的追问重点。

图书馆里的两位管理员
先记住比喻,再记术语 —— 两路检索的强项与盲区,是所有融合方案的前提

老王 · 只认字面

报书名、书号、作者名 —— 秒找,从不出错

「想看讲人性挣扎的小说」—— 一脸茫然

对应
BM25 · 稀疏检索

Sparse Retrieval

基于词频统计的关键词检索,TF-IDF 的工业级改良版

词频饱和 k1IDF 稀有词长文惩罚 b
小李 · 懂意思

模糊需求能听懂,还会举一反三

报一个精确书号 —— 可能凭印象拿错版本

对应
向量检索 · 稠密检索

Dense Retrieval

文本转 embedding 向量,按语义距离找最近邻

同义改写口语化跨语言
混合检索 = 同一个问题让两人各找一摞书,再把两摞合并成一份最终榜单。难点全在「怎么合并」 —— 这正是面试的追问重点。

原理拆解

两路分数没法比,那就只比名次
RRF(d) = Σ 1 / (k + rank_d),k 通常取 60 —— 手算一遍就懂了

query
两路并行召回
BM25 · 关键词命中 SK-3200E05 这类字面符号
向量 · 语义命中「机器出毛病」这类口语改写
各出一份榜单
分数无上界rank 1..N
余弦有界 0~1rank 1..N
只看名次,不看分
RRF 融合Σ 1/(k + rank)k = 60
最终 Top-K
手算一遍(k = 60)
文档BM25 名次向量名次RRF 分读法
A131/61 + 1/63 ≈ 0.0323两路都靠前,稳赢
B2没进榜1/62 ≈ 0.0161单路第二
C没进榜11/61 ≈ 0.0164单路第一,略胜 B

k=60 是个缓冲值。没有 k 时 1/1 是 1/2 的两倍,第 1 名对第 2 名形成碾压;加了 60 之后 1/61 和 1/62 几乎持平。k 越小越「精英主义」,越大越「平均主义」。60 来自原论文(Cormack et al., 2009),没有评测集之前不要乱动

新手最常见的错:0.5×BM25分 + 0.5×余弦相似度。余弦有界 0~1,BM25 无上界且随语料漂移 —— 直接相加等于拿身高加体重。这是面试第一层追问的埋伏点。

RRF 不是免费午餐:只看名次 = 丢掉分数强度。BM25 第 1 名比第 2 名高 10 倍置信,和只高 0.1 分,在 RRF 眼里一模一样 —— 后果是单路超强信号被稀释,型号类查询是典型受害者。所以它是最好的起点,不一定是终点。

BM25 那一路:三个直觉就够了

面试不需要背 BM25 公式,但要能讲出它比「数词频」聪明在哪的三个设计:

  1. 词频饱和:一个词出现 3 次比 1 次重要,但出现 100 次不会比 10 次重要多少——得分随词频增长但会「饱和」(由参数 k1 控制,常用 1.2~2.0)。
  2. 稀有词更值钱(IDF):全库都有的「设备」「系统」不提供信息量;只在几篇文档出现的「E05」权重极高。这正是 BM25 抓型号、编号的底气。
  3. 长文档惩罚:长文档天然含更多词,不惩罚就永远排前面(由参数 b 控制,常用 0.75)。

一个中文特有的前置条件:BM25 依赖分词。「混合检索效果差」经常不是算法的锅,而是分词器把「SK-3200」切碎了——jieba/IK 加自定义词典往往比调任何参数都见效。

向量那一路

query 和文档各自过 embedding 模型,算余弦相似度,用 HNSW 之类的索引做近似最近邻(原理见 T2-3T2-4,此处不重复)。它的强项是同义改写、口语化表达、跨语言;弱项就是开头故障里那种「一字不差」需求。

真正的难题:两路分数没法直接比

新手最常见的做法是 最终分 = 0.5 × BM25分 + 0.5 × 余弦相似度——这是错的,也是面试第一层追问的埋伏点

因为两者根本不在一个量纲上:余弦相似度有界(通常 0~1),BM25 分数无上界,8.7 和 23.5 都可能出现,且分布随语料、query 长度漂移。直接相加约等于「拿身高加体重排名」。由此分出两条技术路线:

路线一:归一化后加权(Weighted / Convex Combination)

先把两路分数各自归一化(min-max 或 z-score)拉到同一量纲,再 α × 向量分 + (1-α) × BM25分。优点是可精调、保留分数强度信息;缺点是 α 依赖评测集才能调,而且分数分布一漂移(换 embedding 模型、语料增长),辛苦调好的 α 就失效了。min-max 本身还怕离群值——一个异常高分会把其他分数全压扁。

路线二:RRF(Reciprocal Rank Fusion,倒数排名融合)

思路很妙:分数不可比,那就不看分数,只看名次。每路检索给出排名,文档的融合分 =

RRF(d) = Σ 每一路 1 / (k + rank_d)     其中 k 通常取 60

手算一遍就懂了(k=60):

原文示意
文档    BM25名次   向量名次    RRF 分
  A        1         3       1/61 + 1/63 ≈ 0.0323   ← 两路都靠前,稳赢
  B        2        没进榜     1/62        ≈ 0.0161
  C       没进榜      1        1/61        ≈ 0.0164   ← 单路第一略胜单路第二

k=60 是干嘛的? 它是个「缓冲值」,防止第 1 名对第 2 名形成碾压(没有 k 时 1/1 是 1/2 的两倍;加了 60 之后 1/61 和 1/62 几乎持平)。k 越小越「精英主义」(头部名次权重大),k 越大越「平均主义」。60 来自原始论文(Cormack et al., 2009)的经验值,各引擎默认都用它——没有评测集之前不要乱动

RRF 的杀手锏是免调参 + 免疫量纲问题,对分数分布不做任何假设。这就是「为什么很多团队直接用 RRF」的标准答案。

整条链路长这样:

原文示意
             ┌── BM25(关键词) ──► 排名列表 A ──┐
  query ─────┤                                 ├──► RRF / 加权融合 ──► Top-K ──► Rerank(T2-6) ──► LLM
             └── 向量(语义)   ──► 排名列表 B ──┘

RRF 不是免费午餐(第三层追问在这)

只看名次,意味着丢掉了分数强度信息:BM25 第 1 名比第 2 名高 10 倍置信度,和只高 0.1 分,在 RRF 眼里一模一样。后果是「单路超强信号被稀释」——型号类查询 BM25 一击命中,却被向量路的噪声结果拖后。

所以工程上的成熟答案是分层的:RRF 做默认起点(零成本解决 80% 问题)→ 有了评测集和稳定分数分布后,可回到加权融合精调 → 更进一步做 query 分类路由(识别出「型号/编号类」query 直接加重 BM25 权重甚至单走 BM25)。能把这条演进路线讲出来,面试就从「背概念」升级成「有工程判断」。

工程实践(截至 2026-08)

引擎怎么选:

引擎 混合方式 一句话点评
Milvus 2.5+ 内置 BM25 全文检索(稀疏向量)+ hybrid search,提供 RRFRanker / WeightedRanker 一个库搞定两路,当前新项目的主流选择
Elasticsearch / OpenSearch 老牌 BM25 + kNN 向量;ES 支持 RRF(注意版本与许可),OpenSearch 走 hybrid query + 归一化 pipeline 团队已有 ES 时的顺路方案
Weaviate hybrid 查询自带 α 参数(0 纯 BM25,1 纯向量) 加权式,默认偏向向量侧,需实测调
Qdrant 稀疏向量 + Query API 服务端融合(含 RRF) 轻量好用
pgvector + PG 全文检索 应用层自己融合 起步省事,量大再迁

经验值与常见坑:

  • RRF 的 k=60、两路各取 top 20~100 再融合,是无评测集时的安全默认。
  • 加权融合前必须归一化;分数分布会随语料漂移,α 要定期用评测集回归。
  • 中文效果一半取决于分词,专有名词务必进自定义词典。
  • 新趋势:**learned sparse(学习型稀疏向量,如 BGE-M3、SPLADE)**可替代传统 BM25,兼顾字面与轻量语义扩展。但注意边界:全是内部代号、型号的语料(模型没见过这些词),传统 BM25 反而更稳。
  • 混合负责「召得全」,后面通常还要接 Rerank 负责「排得准」(见 T2-6)。
  • 评估别只看总平均:按 query 类型分桶建评测集(型号类 / 口语类 / 长问题),看 recall@k、MRR——混合之后某一桶变差是常见现象,总平均会把它藏起来。
引擎怎么选,参数怎么定
没有评测集之前,先用安全默认值跑起来;有了评测集再谈精调

引擎选型
引擎混合方式一句话点评
Milvus 2.5+推荐起点内置 BM25 全文检索(稀疏向量)+ hybrid search,提供 RRFRanker / WeightedRanker一个库搞定两路,当前新项目的主流选择
ES / OpenSearch老牌 BM25 + kNN;ES 支持 RRF(注意版本与许可),OpenSearch 走 hybrid query + 归一化 pipeline团队已有 ES 时的顺路方案
Weaviatehybrid 查询自带 α 参数(0 纯 BM25,1 纯向量)加权式,默认偏向量侧,需实测调
Qdrant稀疏向量 + Query API 服务端融合(含 RRF)轻量好用
pgvector + PG 全文应用层自己融合起步省事,量大再迁
经验值与避坑
安全默认
RRF k=60,两路各取 top 20~100 再融合 —— 无评测集时的稳妥起点
加权前提
必须先归一化;分数分布随语料漂移,α 要定期用评测集回归
中文命门
效果一半取决于分词,专有名词务必进自定义词典(型号被切碎是最常见的假故障)
新趋势
learned sparse(BGE-M3 / SPLADE)可替代 BM25;但语料全是内部代号时模型没见过这些词,传统 BM25 反而更稳
职责边界
混合负责召得全,Rerank 负责排得准(T2-6),别混为一谈
评估纪律
按 query 类型分桶(型号类 / 口语类 / 长问题)测 recall@k、MRR,别只看总平均 —— 它会把变差的那一桶藏起来

面试视角

同一道题,10 秒就能分辨的分水岭
追问路径:为什么要混合 → 分数怎么融合 → k 和缺点 → 参数怎么定 → 说一个 badcase

  1. 30 秒开场先讲两种检索的互补盲区
  2. 点出真难点融合的难点是量纲不可比
  3. 给路线与取舍两条路各自代价,说你选了什么、为什么
  4. 主动带出评测「我按 query 类型分桶测 recall@k」
只读过:这些回答会暴露你
  • 「把两个分数加权平均一下就行」—— 踩中量纲陷阱,直接暴露没实操
  • 背得出 RRF 公式,但答不出 k 的含义或任意一个缺点
  • 「混合检索肯定比单路好」—— 绝对化;真实情况是分桶看,某些桶会变差
  • 全程没出现任何评测指标或验证方法 —— 只有方案,没有闭环
  • 把 Rerank 和融合混为一谈 —— 分不清「多路合并」与「精排」两个阶段
真做过:这些细节骗不了人
  • 说得出「BM25 无上界」这个具体原因,而不是笼统说「不太好」
  • 能手算 1/61 + 1/63 的小例子,说清 k 大小的取向差别
  • 主动讲 RRF 的代价:单路强信号被稀释,并举出型号类查询这个受害者
  • 讲得出演进路线:RRF 起点 → 评测集就位后加权精调 → query 分类路由
  • 第一反应是先归因分桶,而不是「换个 embedding 模型」
最后一步是真正的分水岭:主动讲「我按 query 类型分桶测 recall@k」的候选人,和只会背 RRF 公式的候选人,面试官 10 秒就能分辨。配套题目:Q2-09Q2-10Q2-15

面试官的典型追问路径:为什么要混合(Q2-09)→ 分数怎么融合(Q2-10,本章配套样板题)→ RRF 的 k 和缺点 → 你的参数怎么定、怎么评估 → 说一个 badcase。层层都在验证你是「做过」还是「读过」。

答题结构建议:先讲两种检索的互补盲区(30 秒)→ 点出融合的真难点是量纲不可比 → 给两条路线和各自取舍、说你选了什么为什么 → 主动带出评测方法。最后一步是分水岭:主动讲「我按 query 类型分桶测 recall@k」的候选人,和只会背 RRF 公式的候选人,面试官 10 秒就能分辨。

配套题目:Q2-09Q2-10Q2-15

小结与延伸

一句话总结:混合检索是让「认字面的」和「懂意思的」组队干活;RRF 之所以流行,是因为它用「名次」这门通用语言绕开了两路分数不可比的死结——代价是丢掉分数强度,所以它是最好的起点,而不一定是终点。

延伸阅读:RRF 原始论文(Cormack, Clarke & Buettcher, 2009);Milvus / Elasticsearch 官方 hybrid search 文档;BGE-M3 模型报告(dense + sparse + multi-vector 三合一)。

继续深入

本篇归属第 2 章「RAG 工程化」,去做这一章的题