RAG优化的多路召回-混合检索
总结:
混合检索 = 关键词 + 语义向量检索
建两套索引,一个关键词 (稀疏检索,BM25),一个向量(稠密检索)
多路召回怎么融合,最简单的就是排名求和(倒数排序融合),计算两种索引召回准确率的排名,然后把段落排名求和取排名最前的,文本片段。
---------详细介绍--------------------------------------
先搞清:RAG 的检索召回层在干嘛?
把 RAG 想象成一个开卷考试的学霸:
用户问一个问题(考题)
他先去翻一堆参考书(检索召回),找到最相关的几段话
然后把这些段落抄下来,结合自己的理解,拼成最终答案(生成)
你问的“检索召回层”,就是那个翻书找段落的环节。它不用生成任何新内容,只管“找到可能用得上的资料”。
为什么需要“混合检索”?单一检索不够吗?
早期翻书只有一种方法:看关键词。比如你搜“苹果手机”,它就去找所有包含“苹果手机”这四个字的页面。这叫关键词检索(像图书馆的卡片索引,学名稀疏检索,BM25 是代表作)。
但问题来了——用户问“水果里那种红红的、脆甜的果子”,它一个字都没提“苹果”,关键词检索就会傻眼,什么都找不到。
后来有了大模型,能把句子变成一串数字(向量),意思相近的句子,数字也挨得近。于是可以按语义找,你说“红红的脆甜果子”,它能找到“苹果”的段落。这叫语义检索(也叫稠密检索)。
但语义检索也不是万能:
它可能把“苹果手机”和“苹果水果”搞混(模糊性)
对一些特别精确、专有的名词(比如产品型号 XJ-882),反而容易漏掉,不如直接搜字符串来得准。
所以,混合检索 = 关键词检索 + 语义检索。两者互补,一个抓精确匹配,一个抓意思相近,召回的段落更全更准。
实际工程中,到底是怎么做的?
这就好比你要同时查两种目录:一个是传统的书末“关键词索引”,一个是新潮的“概念地图”。在工程上,你需要搭建两个不同的“索引库”,然后把两个结果巧妙地揉在一起。
第一步:建好两个“库”
你得预先把所有参考书(你的文档库)处理成两种形态:
关键词索引库(给 BM25 用)
把每段文本拆词,建立“倒排索引”:哪个词出现在了哪几个段落里。
常用工具:Elasticsearch(最常用)、OpenSearch、Lucene。它们自带强悍的 BM25 算法。
你只需要把文本丢进去,它内部就建好了。
语义向量库(给向量检索用)
用一个大模型(比如 text-embedding-ada-002 或开源的 BGE)把每个段落都算成一个向量(比如 1024 维的一串小数)。
把这些向量存进一个专门的向量数据库。
常用工具:Milvus、Pinecone、Weaviate、Qdrant、FAISS(Facebook 的库,常被集成)。
所以,你的一份文档,会变成两份副本,存在两个不同的库里。这叫双索引架构。
第二步:接到问题,同时发问
当用户问题来了,你也得准备两路:
关键词查询:直接把问题文本丢给 Elasticsearch,让它用 BM25 去找。Elasticsearch 会返回最匹配的 N 个段落,并给每个段落打个相关性分数(比如 score=5.2)。
语义查询:用同一个 embedding 模型把用户问题也转成向量,然后去向量数据库里搜最相似的 M 个段落。向量库也会返回每个段落一个相似度分数(比如 0.89)。
这两路查询完全独立,可以同时进行,不会相互等待。这是工程上能快的关键。
第三步:把两个结果“揉”在一起(这才是难点)
现在你手上有两份结果列表,可能长这样:
关键词结果(BM25): [(段落A, 5.2), (段落B, 4.1), (段落D, 3.8) ...]
语义结果(向量): [(段落C, 0.91), (段落A, 0.88), (段落B, 0.75) ...]
你想把它们合成一个最终列表,给大模型去读。怎么合?直接用分数相加吗?绝对不行!因为分数的尺度不一样:BM25 的分数可能是 1 到几十,向量相似度是 0 到 1。直接加,谁大谁说了算,完全乱套。
工程师们主要有两种成熟招数:
招数一:排名融合(RRF,倒数排序融合)——最流行、最省事
完全不看具体分数,只看排名。
段落A:在关键词路排第1,在语义路排第2。
段落C:在语义路排第1,在关键词路压根没进前10(排第20)。
RRF 会给每个排名位置一个固定的分:第1名得
1/(60+1),第2名得1/(60+2)...(60是个魔术常数)。然后把同一段落在不同路上的分加起来,按总分重新排。这样,两边都靠前的段落会排在前面,只在一边露头的也能有个说得过去的分数。
招数二:分数校准后加权求和——需要调参
用一些数学方法(比如把分数都映射到差不多的范围,或用统计分布)把两路分数变得可比,然后按权重相加:最终分 = a * BM25分 + b * 向量分。这要求你调权重a和b,比较吃经验,换一批文档可能又要重调。
实际工程中,RRF 因为零参数、效果好,被大量使用。
一个典型的实际架构图(手绘版)
text
用户问题 | +-------------------+ | | [关键词查询] [语义向量化] | | Elasticsearch 向量数据库 (BM25检索) (ANN近似检索) | | 结果集1 (带BM25分) 结果集2 (带相似度分) | | +----> 结果融合器 <---+ (例如RRF算法) | 最终 Top-K 段落 | 发给大模型生成
有没有更省事的一站式方案?
有的。现在很多新式数据库看到了这个需求,直接在一个系统里同时维护关键词索引和向量索引,你只需要一次查询,它内部就帮你把混合检索做了。比如:
Elasticsearch 8.x+:自带了向量字段,一条查询可以同时写 BM25 条件和 kNN 向量搜索,内部用线性加权或 RRF 融合。
Weaviate、Pinecone等现代向量数据库:大多都增加了 BM25 或混合搜索的支持。
但即使如此,理解上述分离的原理也至关重要,因为调优时你还是得知道里面发生了什么。
总结:实际工程的三个核心
双索引:同时维护一个倒排索引和一个向量索引。
多路并发:查询时间时并行发出,汇合结果。
排名融合:用类似 RRF 这样不看绝对分数的技巧,公平地合并两个排名。
这就是现在绝大多数 RAG 系统在做“混合检索”时的落地方式。它不神秘,就是把两种找资料的方法结合起来,用“排名”而不是“分数”来达成共识。希望这样讲,你能抓住它的工程内核。如果还有想深挖的点,随时聊
