ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

RAG落地实战:纯向量检索为何不如混合检索与重排?

RAG落地实战:纯向量检索为何不如混合检索与重排?

做 RAG 项目有些年头了,前前后后落地过几个知识库问答、客服辅助、私有数据检索的系统。最早我也迷信过纯向量检索,觉得自己用某某 embedding 模型把用户 query 和文档都转成向量,然后往向量数据库里一丢,近似最近邻搜索一把梭,效果应该就很好了。结果真上了业务,发现根本不是那么回事。后来陆陆续续研究过一些大厂公开分享的 RAG 架构,也翻了不少开源框架的源码,才慢慢理解:大厂 RAG 里,纯向量检索从来不是默认选项,甚至不是主流选项。这背后的原因,不光是"效果不好"四个字能概括的,它牵扯到召回逻辑、排序策略、工程成本、甚至线上延迟分配。这篇文章我就把这些年的踩坑和观察掰开揉碎讲一讲。

1. 纯向量检索的纸面优势,到了 RAG 场景就漏气

先别急着否定向量检索。单纯从技术演进的角度看,把文本映射到高维语义空间,再用距离度量相似度,这个思路本身没毛病,而且在一对一的"找相似"任务上表现确实亮眼。比如以图搜图、相似推荐、去重聚类,纯向量方案都很能打。它的核心优势非常直观:能抓到语义层面的相近,而不是字面上的重复。用户说"我想退掉这笔订单",embedding 之后能跟"申请退款"这种文档匹配上,这在关键词时代是不敢想的。

但 RAG 和这些场景有个本质区别:RAG 的最终目的不是"找相似",而是"找有用"。它要给大模型喂上下文,让模型基于检索到的内容回答问题。这里就出现了一个被很多人忽略的鸿沟——语义相似不等于信息相关,信息相关不等于生成有用。我在项目里做过一个很典型的测试:知识库里有一篇文档标题是《苹果的生长习性与病虫害防治》,内容全是种植技术;另一篇是《苹果 2024 年新款手机发布信息汇总》。用户 query 是"苹果最近发布了什么新品"。纯向量检索跑出来的 top 结果,排在第一的居然是那篇种植技术的文章,因为"苹果"这个词的语义向量权重被农业语境拉偏了。你说它"语义相似"吗?在 embedding 空间里可能真的很接近,但对回答用户问题一点帮助都没有。

这还不是最致命的。RAG 对召回的敏感度极高,这是它和传统搜索最大的不同。传统搜索里,用户看到搜索结果列表,自己会判断点哪个;RAG 链路里,大模型对喂进去的上下文几乎是"照单全收"的,检索召回了垃圾内容,模型就会一本正经地基于垃圾内容编答案。召回这一层出错,后面生成环节再强也救不回来。而且你还没法指望大模型"慧眼识珠"自动忽略无关片段,因为指令遵循能力强的模型恰恰会努力把上下文内容组织进答案里。所以 RAG 系统对召回精度的要求,不是一个 soft requirement,而是直接影响系统能不能上线使用的硬指标。

我后来复盘过为什么明明知道纯向量有这些问题,当初还是踩坑了。很大程度是因为 demo 阶段太有迷惑性。你拿几个精心挑选的 query 去测,比如"什么是 RAG""怎么处理长文本",向量检索效果确实惊艳,语义理解能力强,答案贴得很准。等到了真实业务,query 的长尾分布、文档的长度差异、术语的多样性全暴露出来,纯向量的短板就被放大了。所以我才想说,别被基础 demo 骗了,RAG 线上和 demo 是两种物种。

2. 三个最典型的翻车现场:意思对了,要素没了,答案也歪了

纯向量检索在 RAG 场景里的问题,不是偶发的,而是有规律可循的。我总结了三个反复出现的类型,几乎每次纯向量方案效果崩坏,都逃不出这三类。

第一个类型叫"意思对了,要素没了"。embedding 模型擅长捕捉"话题"层面的相似,但对"实体"和"数值"这类精确信息非常迟钝。举个例子,你问"帮我查一下 A 产品线的季度毛利率",文档库里恰好有一篇《B 产品线季度毛利率分析》,还有一篇《A 产品线营收结构拆解》。从语义向量看,前一篇跟 query 的相似度可能更高,因为"产品线""季度""毛利率"这些关键词在向量空间里强相关。但它回答不了你的问题——你要的是 A 产品线,它给你 B 产品线的数据。这类问题在真实业务里占比极高,财务数据、产品型号、合同编号、错误码、库存 SKU,全是硬匹配需求。embedding 对这类信息的表达能力天然不足,不是调参就能解决的。

第二个类型叫"语言风格的距离偏见"。embedding 模型在训练时学到的不只是语义,还有语言的风格和领域特征。这会导致一个很诡异的現象:用户用大白话提问,比如"我们这月的销售额咋这么低",纯向量检索可能更倾向于召回同样口语化风格的文档,而漏掉用正规书面语撰写的运营分析报告。反过来,如果用户是商务出身,问得文绉绉的,召回结果可能又偏向正式文档。明明语义指向的是同一份数据报告,就因为语言风格不同,向量距离被拉远了。这在多品类混合的知识库里尤其明显,我在一个同时包含技术文档、销售话术、客服记录的库上做过实验,纯向量检索的 top 结果经常被"话术类"文档霸占,因为话术本来就口语化,跟用户 query 的语言风格更接近。

第三个类型叫"长尾 query 直接撤回垃圾"。热门问题、高频表述,向量检索往往表现还行,因为模型训练语料里这类文本多。但真实用户提问是高度长尾的:缩写、中英混排、错别字、口语省略、"那个啥""就是这个""类似这种"…… 一旦 query 本身带噪声,embedding 模型会把噪声也编码进向量里,导致检索结果被噪声牵引,本来还能匹配上的关键词反而被稀释了。我见过一个真实案例,用户问"mac 上跑 windows 虚拟机用哪个软件好",embedding 模型把"mac"和"windows"两个强实体向量化得很接近,结果召回了大量"Mac 和 Windows 系统的区别"这类科普文章,真正讲虚拟机方案的文档反而沉底了。后来我才意识到,这种场景恰恰是经典的关键词检索反而更稳——"虚拟机"这个关键词一匹配,答案就出来了。

这三个翻车现场不是独立出现的,在实际系统里往往是叠加暴击。纯向量检索在单一路由上同时承担语义理解和精确匹配两个职责,它两样都做得不够彻底。这也是后来所有大厂 RAG 架构都不约而同走向"多路召回 + 重排"这一范式的最根本原因。

3. 从纯向量到三段式:大厂 RAG 检索链路到底长什么样

如果只是讨论"向量检索效果不好",那方案也简单,换个召回模型就完事了。但真正深入研究过大厂公开分享的 RAG 落地经验之后,你会发现他们的检索链路根本不是"换个召回方式"那么简单,而是一整套召回层 → 粗排层 → 精排层的分阶段漏斗。这个结构和传统搜索系统惊人地相似,只是每一层的技术选型换上了语义时代的工具。

先看召回层。大厂实践中几乎不会只跑一路召回,常见配置是"BM25 关键词召回 + 向量召回 + 混合改写召回"三路并行,有些业务还会加一路基于规则的召回(比如正则匹配产品型号)。每路召回都会拉回一批候选,比如每路取 top 100,三路合并去重后还剩 200 条左右。这一步的核心目的是保召回率,宁可多拉一些不那么相关的,也不能漏掉真正有用的。为什么不敢只靠向量?因为上面三个翻车现场已经证明,向量召回在精确匹配和长尾 query 上会漏;而 BM25 在语义泛化上会漏。一路召回再强,总有它看不见的角落,多路并行才能把漏斗的第一层开口撑大。

然后是粗排层,这一层容易被默认省略,但大厂架构里很常见。粗排的目的是把几百条候选快速压到几十条,避免重排模型在大集合上消耗太多计算资源。粗排通常用轻量级的双塔模型,或者直接用向量相似度 + 文本特征(如 BM25 得分、文档热度、时效性权重)做加权打分。它不需要特别精准,只要能把明显不相关的切掉就行。我在实际项目里粗排常用一个数学公式来做加权融合,比如final_score = 0.4 * vector_sim + 0.3 * bm25_score + 0.2 * freshness_score + 0.1 * doc_quality_score,权重靠线上实验调优。虽然简陋,但已经从单点相似度迈向了多信号融合。

最核心的是精排层。这里大厂基本统一用的是cross-encoder(交叉编码器),就是那种把 query 和候选文档拼接在一起,过一遍完整的 Transformer 编码器,输出相关性分数 0 到 1 的模型。这一步的代价很高,因为每对 query-doc 都要过一次完整模型推理,所以只对粗排留下的 top 50 条做。但换来的是极度精准的相关性判断——交叉注意力机制让 query 里的每个 token 都能和文档里的每个 token 细粒度交互,模型能捕捉到"文档里提到的到底是 A 产品线还是 B 产品线"这种细节,这是双塔向量模型做不到的。精排输出的 top 5 结果,才会真正拼装进 prompt 喂给大模型。

这套三段式结构,本质上回答了一个问题:为什么不用统一的一个模型把所有事干完?答案很简单,效率和质量在单模型上不可兼得。双塔编码器的优势是快,embedding 可以预计算、离线存库,线上只需要编码 query 一次,但缺点是 query 和 doc 没有交互,信息被压缩进了固定维度向量里。交叉编码器质量高,却没法预计算文档向量,每一对都要实时推理,成本高一个量级。大厂的做法是让两者各司其职:向量负责从几十万文档里快速捞出可能相关的一百条,交叉编码器负责在这一百条里精确挑出最好的五条。快和准,两头我都要,用分层结构换取两头兼顾。

4. 关键词检索没死,BM25 至今还是召回层的一路主力

很多做 RAG 的人容易犯一个认知错误,觉得有了语义向量,传统的词汇匹配就该被扫进历史垃圾堆。但你去拆大厂或开源框架的实际实现,会发现BM25 不但没被淘汰,还稳稳占据着召回层的一路席位,有时候权重比向量还高。这不是保守,是纯粹基于效果的实用主义。

为什么 BM25 不可替代?核心在于它给系统提供的是一种向量检索完全不具备的能力:精确的术语与实体匹配。前面提到的产品型号、合同编号、错误码、人名、地名、SKU、日期数值,这些信息本质上不是"语义"问题,而是"字面"问题。A 型号就是 A 型号,它跟 B 型号在语义上再接近,也不该混为一谈。BM25 对这类信息的匹配是硬性的、无歧义的:query 里的关键词出现在文档里了,就得高分;没出现,就没分。这在向量检索里经常翻车,但在 BM25 这里是确定性行为。

另一个容易忽略的点是:BM25 对长文档更友好,更"稳"。embedding 模型在把整段文档压成单个向量时,信息被平均了。一篇 5000 字的技术文档里包含十个知识点,向量化之后这十个点揉成了一个混合向量,一个问"压缩空气干燥器怎么保养"的 query,和这个文档向量的距离,可能还不如跟一篇 200 字的同主题短文的距离近。而 BM25 是基于词频统计的,5000 字文档里只要频繁出现"干燥器""保养""滤芯"这些词,它就会被准确命中。这个特性使 BM25 在混有长短文档的知识库中经常表现出人意料地好。

当然,BM25 也不是没有短板。它的硬伤是词表覆盖问题:同一件事,文档里叫"退款",用户问的是"退钱",BM25 匹配不上。同义词、上下位词、语序颠倒、口语化表述,它统统不擅长。而这恰好是向量检索的主场。所以你会发现,BM25 和向量检索的优缺点几乎是完美互补的——一个擅长精确匹配、对长文本稳,一个擅长语义泛化、理解口语。这也就是为什么工业界最终选择了把它们混合使用,而不是二选一。

混合检索的融合策略也值得展开说。常见做法有三种:

  • 得分归一化后加权求和:把 BM25 得分和向量余弦相似度各自做 min-max 或 z-score 归一化,然后线性加权。简单直接,但问题在于两个分数分布形态差异大,权重很难调到普适,容易在不同 query 上忽高忽低。
  • 级联式:先跑 BM25,如果结果置信度足够(比如得分超过阈值),就直接用;否则再补一路向量检索兜底。这种方案能省算力,但需要设置合理的置信度阈值,实操时调参成本也不低。
  • RRF(Reciprocal Rank Fusion):不直接看分数,只看排名,score = Σ(1 / (k + rank_i)),k 通常取 60。把 BM25 结果排名和向量结果排名按这个公式合并,有效规避了不同计分体系不可比的问题,对异常值和分数分布鲁棒性很好。我在多数项目里默认推荐 RRF,不是因为它最优,而是因为它最省心,不容易翻车。

更进阶的做法是让模型学习融合权重,比如用一个 LR 模型基于 query 特征(长度、是否含数字、词频统计)预测各路召回的权重系数。搞过搜索系统的人应该很熟悉这套路,本质上就是把搜索排序里的"特征工程"思路搬进了 RAG。这套方案在 query 分布极度不均衡的业务里效果尤好,能把"靠人工挑权重"变成"让模型自己学",但要积累足够的线上日志才能训,前期还是以 RRF 起步比较稳。

5. 精度之外的隐形账:向量检索的工程成本,比你想的贵得多

聊完了效果,再聊一个经常被纯向量爱好者忽略的维度:成本。很多人在技术选型时只盯着效果指标看,等到系统真正做大了,才发现向量检索带来的工程代价远超预期,这才是一部分大厂不敢把全部身家押在纯向量上的现实原因。

第一笔账是存储和内存。拿 OpenAI 的 text-embedding-3-large 来说,输出维度 3072,就算用相对较小的 1536 维模型,单条文档的向量如果存 float32,算下来是 1536×4 字节 = 6144 字节 ≈ 6KB。1000 万条文档就是 60GB,这还只是原始向量,没算索引开销。要知道 HNSW 这类图索引为了保持搜索速度,实际内存占用通常是原始数据的 1.2 到 1.5 倍。对比之下,BM25 的倒排索引在同量级文档上可能只需要几 GB。为了省内存,工业界被迫引入各种量化手段:把 float32 降到 int8(4 倍压缩),或者用 PQ 乘积量化,但代价是检索精度继续下降——精度下降又进一步加剧了召回层的短板。这个循环下去,纯向量方案在成本上越来越不划算。

第二笔账是索引更新。传统搜索里,新文档进来,直接更新倒排索引就行,分钟级甚至秒级可见。向量索引则麻烦得多,embedding 先要算出来,再插入 HNSW 图里;批量插入会导致图结构劣化,需要定期重建段或者做合并,这个过程重则让查询延迟飙升。如果业务是知识库每天更新数万条内容,纯向量方案的索引运维复杂度远高于关键词方案。我做过一个每天凌晨全量更新数据的系统,用向量索引时,重建任务要跑一个多小时,期间线上检索只能读旧索引,数据新鲜度硬生生被拖垮一天。

第三笔账是过滤条件与多维约束。真实业务里,检索很少是全局搜索:要按租户隔离、按时间范围过滤、按文档类型筛选、按权限范围切断。在 BM25 倒排索引上做这些过滤非常自然,遍历结果集时顺手判断布尔条件就行;但在向量 HNSW 图上做过滤就麻烦了,你只能在图上先跑出 top K 个邻居,再过滤掉不合条件的——万一 top K 里不合条件的结果占比很高,比如某个租户的文档只占全库 1%,那真正满足条件的结果可能一条都没被捞出来,召回率直接崩。为了解决这个问题,工业界的笨办法是多建几套索引,比如按租户分片、按类型分列,或者用"先过滤再检索"的强制条件,实现起来复杂不说,索引数量翻倍,存储成本也翻倍。

还有一笔容易被忽视的账是embedding 计算本身的延迟和 QPS。在线推理时,纯向量检索多了一道编码用户 query 的环节,如果 embedding 服务跟不上高并发,整个 RAG 接口的延迟就会被拖上去。这也是为什么有些系统会把 embedding 模型蒸馏成很小的版本,或者直接离线把常见 query 的向量缓存起来。层层的性能优化,掩盖的其实是"纯向量方案在工程上是笨重的"这一事实。不是说这些成本不可承受,而是当别的路召回效果一样好、成本只有零头时,理性的架构师自然会做选择。

6. 不只靠"效果感觉",用数据说明纯向量哪里输了

说了一堆定性的分析,最后落点还是要用数据说话。我在一个模拟项目上做过一组 A/B 对比实验,数据基准是某企业内部的客服知识库,共约 20 万篇文档(包含 FAQ、操作手册、故障排查、产品公告等混合类型),测试 query 有 500 条,包含高频问题、长尾口语问题、专用术语问题三类。基线方案是纯向量检索(双塔模型 + HNSW),对照组是"BM25 + 向量双路召回 + 交叉编码器重排",两组都取 top 5 喂给同一个大模型生成答案,由人工标注答案正确率。

结果很有代表性:纯向量方案整体答案正确率只有 61%,而混合检索加重排的方案做到了 82%,提升了整整 21 个百分点。这 21 个点的差距最集中地体现在两类 query 上:一类是包含具体产品型号和数值的,另一类是口语化长句。前者纯向量经常漏掉关键信息,后者纯向量容易被风格干扰。更值得注意的是,纯向量方案里还有 5% 的案例出现了"上下文完全跑偏但模型一本正经回答"的情况——检索到的内容跟问题毫无关系,但模型硬是靠通用知识把问题答完了,表面看起来像回事,实际引用的信息根本不是知识库里的。这种问题在 QA 场景里危害极大,因为答案看起来有出处,实际上出处是错的。

这个实验也帮我想明白了一件事:评估 RAG 不能只看"检索到的内容像不像",要看"最终生成的答案对不对"。纯向量方案在检索阶段的相似度指标(Recall@5)可能也不算太差,比如 Recall@5 在 74% 左右,但答案正确率掉到 61%,中间 13 个百分点的流失,正是因为召回的候选"看着相关、用起来不相关",让重排和生成环节没法纠偏。所以判断一个检索方案好不好,必须把评估指标定义在 RAG 的最终输出上,而不是检索中间结果上。这也是很多团队做了很久纯向量优化却收效甚微的原因——优化目标本身选错了。

7. 哪些场景下用纯向量真的没问题?我给的务实清单

说了这么多纯向量的问题,也要说句公道话:纯向量检索不是一无是处,有些场景下它确实够用,不需要上全套三段式。我根据自己的项目经验,给一个务实的判断清单,帮你决定该不该上混合方案。

如果你的业务满足下面这些条件,纯向量方案可以先用着,不用急着加复杂度:

  • 知识库体量小(比如 1 万条以内),且内容经过人工整理,质量高、冗余少。
  • 文档以短文为主,每条 100-500 字,不存在长文档多知识点揉杂的问题。
  • Query 高度重复,高频问题覆盖了绝大部分流量,长尾占比低。
  • 业务场景是"知识科普"或"泛领域问答",对精确实体、数值、时效性要求不高。
  • 打工人手有限,没有专职算法工程师去维护重排模型,也没有标注数据训练交叉编码器。

反过来,只要你的业务触及下面任何一条,我建议尽早把混合检索纳入架构设计:

  • 文档里有产品型号、订单号、合同编号、错误码、财务指标这类硬信息。
  • 文档长度差异大,从几十字的公告到上万字的操作手册并存。
  • 用户提问高度口语化,或者中英混排、有大量缩写噪声。
  • 知识库更新频繁,每天有大量新文档上线,需要精确到小时的新鲜度。
  • 系统要对答案准确率背责任,不能接受"看起来相关但信息错了"的生成结果。

这个清单不是我拍脑袋写的,每个条件背后都对应着踩过的坑。尤其是第一条和第二条,几乎是我看到的所有纯向量方案翻车的重灾区。只要踩中,就不要再犹豫,直接跳到混合检索架构。

对了,如果你决定上混合检索,有一个务实的启动顺序可以参考:先只加一路 BM25,用 RRF 做融合,这一步改动量最小,收益往往已经很明显;然后攒数据,慢慢迭代出一个交叉编码器做精排;等线上日志充足了,再考虑用模型学习各路召回权重。不要一上来就追求大而全的三层架构,先把 BM25 补上,效果往往就能天翻地覆。

最后再分享一个我个人的体会:技术选型这件事上,的的确确存在"技术时髦度"和"工程实用性"的冲突。向量检索这个概念好听、好讲、好演示,但它只是整个 RAG 检索链路里的一块拼图。真正决定系统能否落地的,是能不能形成一个"召回不漏、排序精准、成本可控"的完整闭环。纯向量在这三点上单独作战都不够硬,把它放回正确的链路位置,让它和 BM25、交叉编码器各司其职,整个系统的可靠程度才会真正上一个台阶。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进