混合检索和向量检索 BM25 有什么区别

接入与开发

给 RAG 工程师讲清 BM25 与向量检索在召回上的差异、各自失效的场景,以及混合检索怎么融、怎么调权重。

做 RAG 的人多半踩过这个坑:关键词明明在文档里,向量检索就是不召回;反过来换个说法问,BM25 一个都命中不了。这篇不堆公式,只讲两条召回路线各自擅长什么、什么时候会失手,以及混合检索的融合、权重和验证该怎么做。

做 RAG 的人多半踩过这个坑:关键词明明写在文档里,向量检索就是不召回;反过来换个说法提问,BM25 一条都命中不了。这两个现象不是模型坏,是两条召回路线在本质上比的东西不一样。这篇不堆公式,只讲 BM25 和向量检索各自擅长什么、什么时候会失手,以及混合检索的融合、权重和验证该怎么做。

先给一个判断标准:如果你的查询里大量出现型号、错误码、字段名、人名这类低频词,先别急着上向量;如果你的知识库同一件事有好几种说法、用户提问又很口语,先别只靠 BM25。真正要做的不是二选一,而是把两路的失效场景摊开,再决定怎么融、怎么调。判断依据和各家模型的实际表现,可以到 /models 核对当时的数字。

两条召回路线到底在比什么

BM25 比的是词面。它靠倒排索引做精确匹配,一个词在不在文档里、出现几次、这个词在整个语料里稀不稀,三个因素一算就是一个分数。它完全不理解同义词,也不知道「退钱」和「退款」是一回事,但它对稀有词的区分度极高。向量检索比的是语义,把查询和文档各压成一个向量,比方向接近程度,换个说法、跨语言、同义改写都能命中,代价是它记不住没见过的专有名词和编号。

匹配单位
BM25 匹配词,向量匹配整段语义方向
同义词
BM25 学不会,向量天然能覆盖
稀有专有名词
BM25 强项,向量常压不出区分度
可解释性
BM25 能拆到具体词,向量只能给出相似度

所以不是谁更先进的问题,是两种失手方式不一样。你需要先判断自己这批查询偏哪一类,再去选召回路线。如果两类的量都不小,那就进入混合检索的范畴,而不是纠结选哪个。

什么时候 BM25 反而更准

查询里带型号、错误码、订单号、人名、API 字段名这类低频词时,词面匹配几乎没有误召回。用户输入本身就是文档里的原话时,向量化反而会把这点精度抹掉,因为语义模型会把相近但不同的编号压到很近的位置。还有一类场景是必须能解释「为什么召回这条」,BM25 的打分能拆到词,业务方问起来你答得上。

  • 查询含编号、错误码、字段名等低频标识符
  • 用户输入就是文档原话或接近原话
  • 需要把召回理由讲给业务方听的合规或审计场景
  • 术语表、配置项、接口文档这类高度结构化的库

判断动作很具体:把你最近的查询日志捞出来,看有多少比例包含数字、英文缩写或长串标识符。这个比例超过一定程度,BM25 就该保留在链路里,别被「向量更先进」的说法带偏。

什么时候向量检索更稳

用户问的是意思而不是原词时,向量检索更稳。比如把「怎么退钱」映射到「退款流程」这类段落,词面一个都不重叠,但语义很近。跨语言、跨表述的知识库也是向量占优,一份资料有多种说法时召回复用率高。长文档按语义切块后,块内主题集中,向量能把相关块一起捞出来。

场景特征优先倾向原因
口语化问句、同义改写多向量词面不重叠但语义近
跨语言知识库向量语义空间可对齐
编号、编码、专有名词密集BM25词面精确匹配无歧义
用户输入即文档原话BM25向量化会抹掉精度

不适用的地方也要说清:专有名词、缩写、数字编码密集的库,向量模型没见过这些词就压不出区分度,两段不同编号的文本向量可能几乎一样。这类库如果只走向量,召回质量会明显打折。

混合检索的几种融合做法

混合检索不是简单把两路结果拼在一起,融合方式选错等于白做。最常见的三类做法各有适用面,工程上要从省事和可控两个角度权衡。

  1. 并列召回再用 RRF 合并两路各取一批候选,用倒数排名融合按名次合并。它只看名次不看原始分数,所以不依赖两路分数可比,工程上最省事,适合作为第一版基线。
  2. 加权分数融合把两路分数归一化后按权重相加。灵活,但要处理量纲不一致的问题,归一化方式一改结果就变,调参要格外小心。建议固定一种归一化方式并记录在案。
  3. 一路粗召回再补一路常见是向量先召回,再用 BM25 只对关键词做二次筛选。适合查询里关键词信号很强的场景,但对纯语义查询帮助有限。
  4. 顺序上先融合再 Rerank把融合后的候选交给 Rerank 精排。别指望 Rerank 去救一路完全没召回的答案,Rerank 只能重排已经进候选池的内容。

如果你还在评估不同检索方案的实际效果差异,可以先到 /tools/speed-test 跑一轮对比,把两路和混合的召回情况放在一起看,而不是凭感觉判断哪种更好。

权重和参数怎么调才不白调

调权重是混合检索里最容易浪费时间的一步,因为很多人没有固定评测集就开始拧参数。没有评测集,你调出来的只是让这一批查询好看,下一批就崩。所以第一件事不是调权重,是先把评测集和调整顺序定下来。

调整顺序先动什么为什么
第一步召回条数召回不够后面全白搭
第二步融合方式RRF 还是加权,影响面最大
第三步两路权重在前两步稳定后再微调
第四步Rerank 参数只影响精排,不该救召回
  • 按查询类型分流:短查询、带编号的查询多给 BM25,长自然语言问句多给向量
  • 每次改动只动一个变量,记录参数和指标,否则两轮后说不清是哪个变量起作用
  • 召回条数先给足,宁可多召回交给 Rerank 收,也别在召回阶段就卡死
  • 权重不是一次调定的,语料和分块一变就要重跑

判断标准很直接:如果调完权重后,纯语义查询和纯关键词查询的表现一升一降,说明你在拆东墙补西墙,应该考虑按查询类型分流而不是强行统一权重。分流的具体阈值,可以结合 /guides 里的检索配置思路来定。

分块方式会直接改写两边的表现

分块是混合检索里被低估的变量。块太长,向量被稀释、BM25 命中的词被淹没在大量无关文本里;块太短,语义不完整,向量的优势发挥不出来。很多人调了半天权重,最后发现真正的问题是分块把关键信息切开了,而不是权重没配好。

  • 给块保留标题、章节路径这类前缀,对 BM25 是直接加分,对向量也提供上下文
  • 表格、代码、日志类内容单独定切块方式,按自然段切往往把关键信息切开
  • 同一份文档的切块长度尽量一致,避免长短块混排影响召回稳定性
  • 改完分块必须重跑评测,它是最容易让之前调好的权重失效的变量

一个可落地的排查顺序:先确认分块是否把答案完整包含在一个块里,再确认这个块有没有被任一路召回到,最后才看融合和权重。前两步没过,调权重没有意义。

怎么验证混合检索真的变好了

验证混合检索有没有变好,靠的是固定问题集加标注答案,而不是抽查几条感觉不错。问题集要覆盖三类查询:纯关键词型、纯语义型、两者都有的混合型。三类都要有,否则你测出来的提升可能只是偏向了某一类。

  1. 建评测集准备一批真实查询加标注答案,三类查询都覆盖到,数量和比例固定下来。
  2. 单变量迭代每次只动一个变量,看召回率与最终回答质量是否同向改善,避免只看单一指标。
  3. 挑召回了但没用的块这类情况往往说明 Rerank 或拼装环节有问题,不是召回的问题,别错怪召回。
  4. 记录反例哪些查询两路都失手,这类通常要靠改文档格式或补语料解决,不是调参能救的。

两路都失手的查询最值得看,因为它们暴露的是数据问题而不是参数问题。把这类查询单独归档,作为补语料和改文档格式的输入,比反复调权重有效得多。

混合检索的价值不在于把两路拼起来,而在于你能说清每一路在什么查询上失手。
下一步想动手对比不同检索方案和模型在你自己数据上的表现,可以先到站内工具页跑一轮,把两路和混合的召回情况摆在一起看,再决定权重怎么分。

常见问题

小项目有必要上混合检索吗?

看查询形态。如果用户提问基本是自然语言,且知识库不大,先做向量检索加 Rerank,跑通再补 BM25 成本更低。反过来,库里全是编号、型号、专有名词,一开始就该把 BM25 加上,不然召回率上不去,后面调什么都白费。

BM25 和向量检索的分数能直接相加吗?

不建议直接加。两者量纲完全不同,BM25 分数理论上没有上界,向量相似度通常在有限区间内,直接相加等于让其中一路主导。稳妥做法是先用 RRF 按名次融合,或者各自归一化后再加权,并且把归一化方式固定下来做对比测试。

混合检索一定比单路好吗?

不一定。两路都召不回的查询,混合也救不了;融合还可能把单路本来排第一的结果挤到后面。判断标准是对着评测集看,如果在你的查询分布上单路已经够稳,多一路带来的延迟和维护成本就不划算,尤其是对响应时间敏感的场景。

BM25 要不要中文分词?

要。中文没有天然空格,分词粒度直接决定召回。分太细会把词拆碎导致误召,分太粗又匹配不上。常见的稳妥做法是加一份领域词典,把产品名、术语、编号补进去,然后拿一批真实查询回归验证,别一次换分词器就上线。

换嵌入模型后混合检索结果波动大怎么办?

先只重跑向量那一路,确认是模型本身导致的召回变化,再动融合参数。同时固定住评测集和分块方式,这两项一变就分不清是谁的锅。如果波动集中在含编号、缩写的查询上,说明 BM25 那一路该给更高权重。

本文依据各平台公开文档与官方公告整理,只做中文归纳;具体做法、参数与限制以官方文档为准。