大厂做RAG(检索增强生成)已经不是什么新鲜话题了,但真正进去做过的人会发现一个有意思的现象:生产环境里几乎见不到“纯向量检索”方案。哪怕外面各种技术博客把向量数据库吹得天花乱坠,到了工业级落地的时候,大家还是老老实实把 BM25 请回来,做成混合检索。这篇文章不聊概念,直接讲清楚三件事:纯向量检索到底哪里不行、大厂实际用什么架构替代它、以及你照着落地时需要避开哪些坑。如果你正在设计知识库问答系统、智能客服或者文档助手,这篇内容应该能帮你省下不少试错成本。
1. 纯向量检索在大厂行不通的三个本质原因
先纠正一个常见认知:纯向量检索不是“不好”,它是“不够”。在演示 Demo 里,向量检索的表现确实惊艳,语义相近的句子能召回,口语化的提问也能命中知识库里的标准表述。但一到生产环境,问题就一批接一批地冒出来。
1.1 术语与精确匹配能力严重不足
向量模型的本质是把文本映射到高维语义空间,相近语义的文本向量距离更近。这套机制对“语义相似”特别擅长,但对“精确匹配”极其糟糕。
打个比方:你问“iPhone 15 Pro 支持多少瓦快充”,知识库里写的是“iPhone 15 Pro 支持 27W 快充”,这在语义上是完全一致的,向量检索能轻松召回。但如果问的是“A2-2024-0712 号订单的物流状态”,其中“A2-2024-0712”是一个订单号,知识库原文就是这一串字符,你指望向量模型把它“语义理解”出来?基本不可能。embedding 模型会把“A2-2024-0712”当成一个整体语义单元,一旦用户输入时少写了一个短横线,或者把数字顺序稍微打乱,向量距离就会明显变大,召回质量直线下降。
这是工业级场景里最致命的问题。真实业务永远充斥着型号、合同号、工单编号、法条编号、SKU 编码这类精确值。对它们来说,字符级别的精确匹配才是刚需,语义匹配反而退居其次。BM25 恰恰在这方面有天然优势——它基于词频和逆文档频率做字面匹配,差一个字符都能通过词项匹配捞回来。
1.2 向量召回天然缺少“文本反哺”闭环
RAG 系统上线之后一定面临一个问题:怎么迭代效果?企业的知识库每天都在增长,新文档进来、旧文档下线,用户的提问方式也会随产品迭代而变化。这些变化必须快速反映到检索系统里。
BM25 这类稀疏检索有个极好的工程特性:每一项文档的索引可以独立更新,新增一篇文档只需要分词、统计词频、更新倒排索引。而且用户搜不到某些内容时,运营人员可以直接看索引里的关键词分布,判断是知识库缺少内容,还是关键词被埋得太深。
向量检索引擎则不一样。它的召回能力完全取决于 embedding 模型的语义理解水平。如果一款模型对新领域的术语理解不到位,你能做的只有等模型升级、或者找数据重新微调。索引里的向量一旦生成,语义层面就固化了,你能调的只是距离阈值和 TopK 参数。换句话说,文本层面出了问题,你无法用文本手段解决,必须回到模型层面。这种“不可解释、不可快速修补”的特性,在生产环境里是致命的。
1.3 分数体系不具备可解释性
线上系统一旦出问题,第一件事是定位原因。比如用户问了一个问题,系统没有召回正确答案,这时候你需要回答:是因为检索的分数阈值设太高了?还是文档本身跟问题语义太远?还是 rerank 阶段把正确答案压下去了?
用 BM25 做稀疏检索时,你还能拆开分数看看——某个查询词项在目标文档里出现了几次,逆文档频率是多少,哪个词贡献了主要得分。这套逻辑可以被逐项审计。向量检索的分数是模型计算出的余弦相似度或内积,它背后是高维空间的几何距离,你没法逐维度解释“这个分数为什么是 0.82 而不是 0.79”。大厂的知识库检索链路通常涉及多个业务方,跨团队协作时,一个无法解释的分数会给问题排查带来极大困难。
注意:这三个问题不是“优化一下就能解决”的,而是模型机制层面决定的。纯向量检索在开放域、语义泛化的场景能玩得转,但在企业知识库这种“高精确率要求、高频精确匹配、强审计需求”的场景里,必须用混合检索方案来兜底。
2. 大厂普遍采用的混合检索架构解构
大厂主流方案并不花哨,就是“BM25 稀疏检索 + 向量稠密检索”双路召回,再加一个融合排序层。上图(实际工作中这个架构会画满一张白板)看起来很朴素,但每个环节都有非常具体的设计原因。
2.1 混合检索不是简单拼模型
双路召回的核心原则是:让两种机制各管一摊。BM25 负责字面匹配、精确词项、稀有实体、编号类查询;向量检索负责语义泛化、同义改写、口语化表达、跨语言查询。两条路线的结果合并之后,再用融合算法统一排序。
但这里有一个细节经常被忽略:两条路的召回数量需要单独配置。BM25 通常召回 30-50 条,向量检索召回 50-100 条,融合之后再做精排。为什么向量检索要召回更多?因为语义检索的精度相对低,TopK 取少了容易漏掉正确答案,宁可多召回一些噪声,把精确筛选工作交给下游。BM25 本身的精度较高,召回数量可以小一些,降低后续排序阶段的压力。
两条路的结果集合并时还需要去重。同一篇文档可能同时被两条路召回,不能在最终列表里出现两次。更麻烦的是“近似重复”——比如同一份产品说明的中文版和英文版,字面完全不一样,但语义完全一致。这种文档在向量路上会同时排在前面,融合时如果不做去重,就会在最终结果里霸占两个坑位,挤压其他相关内容。
2.2 RRF 融合算法为什么被工业界选中
业界最常用的融合算法是 RRF(Reciprocal Rank Fusion,倒数排名融合)。原理极其简单:对每条候选文档,按照它在不同检索结果里的排名计算一个融合分。
假设某文档在 BM25 结果里排第 3,在向量检索结果里排第 6,RRF 分数就是 1/(60+3) + 1/(60+6),其中 60 是一个经验常量,用于平滑排名差异。最终分数由所有检索路线的排名共同决定,跟原始相关度分数无关。
为什么工业界如此青睐 RRF?因为它完全不关心两条路线的分数分布。BM25 的分数可以是从 0 到几十的浮点数,向量相似度是 0 到 1 的区间,很难直接加权相加——你没法解释“BM25 的 8.5 分相当于余弦相似度的多少”。RRF 把问题简化成“只看排名”,彻底绕开了跨模型分数可比性的难题。
使用 RRF 时要特别注意常量的选择。业界常用的 k 值在 60 左右,具体取值需要根据召回结果做实验。k 值越小,排名越靠前的文档优势越明显;k 值越大,排名差异的影响越小。如果你发现融合结果里排在第一位的内容总来自某一路检索,通常就是 k 值不合适。
2.3 业务约束与字段加权怎么叠加
双路召回+RRF 只是基础框架,大厂实际落地时还会叠加一层业务规则。知识库文档往往带有结构化字段——来源部门、文档类型、更新时间、作者、业务线。这些字段不是给模型看的,而是给业务规则用的。
常见的加权方式包括:
- 时效性加权:新闻资讯类知识库,两周内发布的内容在融合分上加权 0.2;法规类知识库反而要给旧版本加权
- 类型加权:常见问题(FAQ)文档和操作手册文档的权重不同,面向客服场景时 FAQ 优先
- 来源加权:来自官方渠道的文档,比用户社区自助整理的文档权重更高
这部分加权通常放在 RRF 融合之后再处理,用线性加权的方式乘到最终得分上。业务字段的加权逻辑必须做成可配置项,因为知识库的内容构成和业务需求每个月都可能变化。我见过做得比较成熟的团队,会把加权规则配成 JSON 下发到线上,运营同学自己就能调整,不用每次改代码发版本。
3. 从召回到精排:工业级 RAG 的完整漏斗设计
很多教程把 RAG 简化成“检索+生成”两步,实际企业落地时是一条完整的漏斗链路。每一个环节都在过滤信息,把候选集合从几万条逐步缩到最终送给大模型的寥寥几条。理解这条链路,比理解某个单一算法更重要。
3.1 召回层的准召平衡与 TopK 设定
召回层的任务不是“找到最正确的文档”,而是“把可能正确的文档尽量捞回来”。在这个阶段,宁可多捞一些不相关的,也不能让正确答案漏掉。因为漏掉就意味着后续所有环节都没有机会了。
下表是一个典型的召回层参数配置参考:
| 检索路线 | 召回数量 | 适用场景 | 备注 |
|---|---|---|---|
| BM25 稀疏检索 | 30-50 | 精确术语、订单号、法条编号、代码片段 | 可并行执行 |
| 向量稠密检索 | 50-100 | 口语化描述、语义改写、跨语言搜索 | 对模型效果敏感 |
| 混合检索融合 | 50-80 | 统一候选集合 | 需去重与业务加权 |
要注意,召回数量不是设得越大越好。召回量过大会把大量低质量内容送进精排阶段,增加延迟;召回量太小又会牺牲召回率。一个比较实用的调优策略是:先固定精排模型不变,把召回量从 20 调到 100 做几组对比实验,观察最终问答效果和 P95 延迟的平衡点。
3.2 精排层为什么必须用 Rerank 模型
召回层给精排层传入的候选文档通常有几十上百条,但大模型输入上下文窗口有限,而且塞入过多不相关内容会严重干扰生成质量。所以精排层的任务是把召回结果压缩到 3-5 条高质量文档。
精排阶段的核心工具是 Rerank 模型。这种模型跟 embedding 模型不一样,它会同时接收“查询语句”和“候选文档”作为输入,输出一个相关度分数。这本质上是一个交互式建模过程,能够捕捉 query 和文档之间更深层的匹配信号,效果普遍优于向量检索的双塔式表示。
实际工程中,Rerank 模型通常采用跨编码器架构,输入格式类似于[CLS] 查询语句 [SEP] 候选文档 [SEP]。推理时会根据候选文档数量进行 batch 处理。一次处理 50 条候选文档,延迟大概在 50-100 毫秒之间,属于可以接受的范围。如果候选量过大,可以先用规则或者轻量模型粗筛到 20 条以内,再送精排。
3.3 一个可参考的混合检索落地配置表
结合两三个实际项目的落地经验,我整理了一份基础的配置参考。它不适用所有场景,但作为起步配置足够稳定:
| 配置项 | 推荐值 | 说明 |
|---|---|---|
| 分块大小 | 500-800 tokens | 太小丢失上下文,太大稀释语义 |
| 分块重叠 | 100-150 tokens | 保留跨块语义衔接 |
| 向量召回 TopK | 80 | 保证召回率 |
| BM25 召回 TopK | 40 | 精确匹配一般不需要太多 |
| RRF 融合 k 值 | 60 | 初始推荐,需实验调优 |
| Rerank 候选量 | 20 | 精排输入规模 |
| 最终送入 LLM 文档数 | 3-5 | 控制上下文复杂度和延迟 |
这份配置是“起点”而非“终点”,每个数值都需要根据你实际的知识库规模和查询类型做调整。调参的先后顺序建议是:先定分块策略,再定召回量,最后定融合参数。很多团队一上来就猛调 RRF 系数,结果效果不好,改了半天才发现是分块粒度本身就有问题。
提示:知识库规模在 10 万篇以下时,混合检索的收益主要来自 BM25 对精确匹配的补充;知识库规模在 100 万篇以上时,向量检索的扩展性和召回率优势才会越来越明显。两套方案在不同规模下的贡献度是不一样的。
4. 实操工程细节与避坑经验
方案设计得再好,工程实现不到位仍然白搭。这一节分享几个高频踩坑点,每一条都是真金白银换来的经验。
4.1 Embedding 模型选型与分块策略
Embedding 模型的选择直接决定了向量检索的召回天花板。通用模型适合做验证,但不建议直接上生产。比较好的做法是拿你的领域语料做效果评测,用一批真实用户问题作为测试集,比较不同模型的 Recall@5 和 nDCG@10。评测不通过,说得再好也不要上。
领域模型的微调也值得考虑。某个开发者文档问答系统,最初用通用 embedding 模型,代码类问题的召回率不理想。后来用内部的代码文档片段和用户问题构造了一批三元组(query, 正例, 负例)做微调,召回率提升超过 20%。微调数据量不需要太大,几千到一两万条就够用,关键是负例要足够“难”才能逼模型学到更细的语义边界。
分块策略对效果的影响经常被低估。小 chunk(200-300 tokens)适合精确问答,但容易丢失上下文;大 chunk(800-1000 tokens)语义完整,但向量会把整块内容压成一个点,细微信息容易被淹没。实践经验是分块大小跟着知识库的内容结构走:产品说明书可以按章节分,法规条文按条款分,代码文档按函数或模块分。重叠窗口也不能忽视,100 tokens 的重叠能让跨块引用的信息不至于断裂。
4.2 混合检索效果的离线评测方法
没有评测就无法做优化。混合检索的离线评测需要构建一个带标注的评估集。具体做法是:从真实用户日志里抽取 200-500 条查询,人工标注每一条对应的相关文档 ID。然后分别跑 BM25、向量检索和混合检索,计算各自的召回指标。
推荐关注三个指标:
- Recall@5:正文答案是否出现在前 5 条结果里。这是最关键的指标
- nDCG@10:排序质量。强调“正确结果排得越靠前越好”
- 无效召回率:前 10 条结果里不相关内容的比例。这个指标直接影响大模型生成质量
评测集需要持续更新。每一周从线上日志里补充新出现的查询类型,避免评测集跟实际用户需求脱节。很多团队的教训是:评测集跑分一直在涨,线上效果却没有明显提升,最后发现评测集里的查询模式太单一,已经无法代表真实分布了。
4.3 线上压测与性能优化
混合检索链路比纯向量检索多出 BM25 这一路,加上 Rerank 模型,整体延迟预算要重新规划。一个比较典型的延迟分配方案是:BM25 召回 10ms、向量召回 30ms、RRF 融合忽略不计、Rerank 精排 80ms、大模型生成按实际情况计算。检索链路总延迟控制在 150ms 以内,再接受的话就要考虑简化链路。
BM25 的高并发性能比向量检索好得多,但需要注意分词器的效率。中文分词如果用精确模式,长文本的分词耗时会明显上升,建议在索引阶段做一次分词缓存。向量检索的瓶颈通常在 embedding 推理和向量距离计算,常用的优化手段是向量量化(比如把 float32 降成 int8,召回质量损失不大但内存可以省 4 倍)和 IVF/HNSW 索引参数调优。
5. 常见问题排查与效果调优速查表
混合检索的工程链路长,问题定位往往需要逐层排查。下面这份速查表总结了最常遇到的几类问题和排查路径:
| 问题现象 | 可能原因 | 排查方法 |
|---|---|---|
| 精确型号/编号查不到 | 分词器切分错误 | 检查 BM25 召回结果是否为空,打印分词结果 |
| 查询结果全是字面匹配,语义泛化差 | 向量召回失效了,可能是 embedding 模型推理服务异常 | 单独调用向量检索接口,验证输出是否正常 |
| 混合融合后结果反而不如单路 | RRF k 值不合适或两路召回量差距过大 | 打印各路线前 20 条结果,检查融合排序是否符合预期 |
| 重排后正确文档被挤出前 5 | Rerank 模型在领域数据上效果一般 | 用评测集单独评估 Rerank 模型,必要时做领域微调 |
| 检索链路 P95 延迟过高 | Rerank 候选量太大 | 在精排前增加规则粗筛,或者精简分块数量 |
调优顺序很重要。先用单路检索分别定位问题出在哪一路,再调融合参数。如果 BM25 单路效果就很好,但混合后变差了,大概率是向量检索一路在“帮倒忙”——这时候检查向量召回的数据质量或 embedding 模型适配性,不要盲目调融合权重。
另外一个我在实践中反复遇到的坑:不要忽略查询改写环节。用户的问题往往带有口头语、指代词、冗余信息,直接拿原始 query 去做检索效果不稳定。调优流程中加入 query 改写模块(用大模型改写、规则抽取核心实体),虽然多出一轮模型调用,但检索质量的提升幅度通常相当可观。
6. 一个完整的个人实践案例复盘
最后用一个模拟的案例——某中型企业的内部文档问答助手——串起整个方案设计和落地的过程,帮助你把前面几节的内容串成一个整体。
该项目面临的问题包括:知识库涵盖产品手册、技术方案、项目复盘、客户邮件归档等多种文档类型,总计约 18 万篇文档,用户主要用自然语言检索历史项目经验。
初期方案采用了纯向量检索,embedding 模型用的是当时效果不错的通用模型,观察了两周之后问题很典型:文档里的项目代号、客户名称、日期在检索时频繁失效,例如用户问“去年给某客户做的那个支付项目有哪些经验总结”,知识库里有一篇标题为“某客户支付项目复盘”的文档,但向量召回始终无法稳定命中,原因就是“复盘”和“经验总结”在语义空间上并没有想象中那么接近,加上标题里的项目代号干扰了向量表示。
后来调整为混合检索方案,BM25 和向量检索并行召回,RRF 融合后加业务规则加权。同时把分块策略改成了“按文档结构切分”,产品手册按章节、复盘报告按小节、客户邮件按单封切块。Rerank 阶段用内部标注数据微调了一个排序模型,把候选量控制在 20 条以内。整体效果对比如下:
| 指标 | 纯向量检索 | 混合检索方案 |
|---|---|---|
| Recall@5 | 63.2% | 81.5% |
| nDCG@10 | 0.71 | 0.84 |
| 无效召回率(前10) | 18.4% | 9.2% |
| P95 检索延迟 | 85ms | 132ms |
Recall@5 提升了接近 20 个百分点,这个提升直接反映在下游大模型的生成质量上——答案的命中率和引用文档的准确度都有明显改善。代价是检索延迟增加了约 50ms,但这个代价在 RAG 整体链路中完全可接受,毕竟大模型生成阶段通常要耗时 1-3 秒。
这个案例其实想表达一个观点:大厂不用纯向量检索并不是因为拒绝新技术,而是因为生产环境要的是“稳定、可控、可解释”的确定性。向量语义能力作为组件嵌进链路可以发挥很大价值,但作为单一依赖,风险太高。
最后的一点个人体会
如果你刚接触 RAG 不久,千万别被“纯向量检索”的演示效果迷惑。Demo 里那几条漂亮的召回结果,掩盖了大量真实查询场景下的精度问题。我在实际项目里积累下来的建议就三条:第一,先上 BM25 基线再叠加向量路,对比效果差异再决定后续投入;第二,每一层组件都要独立可评测,不然出了问题根本定位不到环节;第三,知识库类场景永远优先保证精确匹配,再考虑语义泛化。想明白这三点,你对检索方案的理解就已经超越大多数把向量数据库当银弹的团队了。