很多 RAG 系统的召回率低,并不是向量模型“不够聪明”,而是检索信号太单一。向量检索擅长语义相似,比如“报销流程”和“费用申请规范”能匹配上;但遇到产品型号、错误码、缩写、专有名词时,它经常失手。一个用户搜“E1101 登录失败”,向量库可能返回“账号异常处理”,却漏掉真正包含 E1101 的排障文档。混合检索的价值就在这里:让语义信号和字面信号同时参与竞争。
混合检索到底混合什么?
典型方案是 Dense Retrieval + Sparse Retrieval。前者使用 embedding 捕捉语义相关性,后者常用 BM25、倒排索引或 SPLADE 捕捉关键词匹配。
- 向量检索:适合口语化问题、同义表达、跨段落语义匹配
- BM25 检索:适合术语、编号、代码、缩写、精确字段
- 重排序模型:负责把两路候选结果重新洗牌,压低“看似相关”的噪声
不少团队只做“向量 topK + BM25 topK 拼接”,这其实只是结果合并,不算真正优化。更稳的做法是用 RRF(Reciprocal Rank Fusion)或归一化分数融合,避免不同检索器的分数尺度互相打架。
权重不要拍脑袋
混合检索最容易被误用的地方,是固定设置 0.7 向量、0.3 关键词。这个比例在知识问答里可能合适,但在运维、医疗、法律条文场景里,关键词权重往往要更高。
一个实际可用的策略是按查询类型动态分流:
- 包含错误码、API 名、版本号:提高 BM25 权重
- 问法偏自然语言,如“为什么审批一直卡住”:提高向量权重
- 查询长度小于 4 个词:增加关键词召回,避免语义漂移
- 包含“区别、原因、流程”:扩大向量 topK,再交给 reranker
某企业客服知识库做过一轮离线评测,纯向量 Recall@10 为 72.4%,加入 BM25 后提升到 84.1%;再接入 cross-encoder 重排序,最终 MRR 提升约 18%。提升不是玄学,而是补上了两类检索器各自的盲区。
召回率提升的关键细节
候选集要敢于放大。生成模型最终只吃 5 到 10 段上下文,但检索阶段可以先召回 40 到 100 条候选,再重排压缩。如果一开始 topK 设得太小,相关文档根本进不了候选池,后面模型再强也救不回来。
还有一个常被忽略的点:字段化索引。标题、正文、标签、文档路径不应混在一个文本块里处理。标题里的“退款失败”权重,显然应该高于正文角落里的同一句话。BM25F 或自定义字段 boost,能把这种业务直觉写进检索系统。
评估别只看命中
召回率要用真实查询集评估,至少准备 200 到 500 条带标注的问题。指标可以看 Recall@K、nDCG@K、MRR。更接地气的做法,是抽样查看“未召回但应该召回”的文档,按原因归类:术语缺失、分块错误、同义词问题、权重偏差。每一类问题,背后对应的改法都不一样。
混合检索不是把两个检索器简单拧在一起,而是让不同信号在合适的位置发力。关键词负责咬住事实钉子,向量负责理解人的含糊表达,中间再放一个重排序裁判。召回率真正起飞,通常就发生在这三者不再各干各的那一刻。

纯向量确实有局限,E1101那个例子太真实了😂
之前做客服问答时就是只靠向量,召回率惨不忍睹,后来加了BM25效果明显多了
动态权重这个思路不错,但具体怎么判断查询类型呢?有没有现成的分类器?