做 RAG 时纯向量召回老漏关键词,纯 BM25 又抓不住同义改写,于是想上 Milvus 的混合检索——结果卡在嵌入模型挑哪个、BM25 要不要单独建字段、两路分数怎么加权、调完怎么知道变好了。这篇不讲原理,只给一套能照着落地的搭配与验证流程,以及什么场景下混合反而不划算。
做 RAG 到一定阶段基本都会撞上这个组合需求:纯向量召回老漏掉型号、订单号、人名这类裸露关键词,纯 BM25 又抓不住用户的同义改写。于是想到 Milvus 的混合检索,把密集嵌入和 BM25 两路并起来。想的没错,但真动手时问题全冒出来了——嵌入模型挑哪个、BM25 要不要单独建字段、两路分数怎么加权、调完怎么知道确实变好了。
这篇不讲向量原理也不推导公式,只给一套能照着落地的搭配与验证流程。核心思路是:先把「该不该上混合」判断清楚,再定嵌入与字段,最后用一份可复现的评测集把权重调出来。反过来,如果场景本来就不适合混合,硬上只会让调参和运维成本翻倍。
先判断该不该上混合:三类信号
别一上来就配混合。先看线上日志里有没有这样的样本:向量没召回、但人工一看明显该召回。把这些样本捞出来看它们长什么样,是判断要不要上混合最省钱的办法。
- 查询里带型号、订单号、人名、专有名词,纯向量经常召不回——这是混合最典型的适用信号
- 用户提问是短句、几乎没有语义上下文,向量表示本身就虚,BM25 那一路反而更稳
- 纯口语化长问句、以同义改写为主的场景,BM25 命中率低,加进来只增加调参负担
| 日志里的现象 | 更该动的地方 |
|---|---|
| 漏召回的样本多是裸露关键词 | 值得上混合,BM25 补关键词那一路 |
| 漏召回多是语义漂移、改写没抓住 | 先调分块策略和嵌入模型,不是加 BM25 |
| 两路单独跑都还行,合起来反而变差 | 问题在融合权重或候选条数,先调融合 |
| 库很小、查询类型单一 | 单路加重排往往就够,别急着上混合 |
密集嵌入怎么挑:先对齐语言与维度预算
嵌入模型的选择要落到你自己的库上,而不是榜单上。中文为主的语料优先选中文语料训练过的模型;中英混排的库一定要拿真实混合样本测,别只看单语表现。想横向看同类模型的规格与说明,可以去 嵌入模型(/embeddings) 页面核对,但具体效果以自测为准。
维度是另一个要先想清楚的变量。维度越高,存储和检索开销越大;而且在 Milvus 里维度一旦写进集合 schema 就固定了,换模型基本等于重建集合。所以流程应该是先小样本对比几个候选,定下来再灌全量数据。
- 准备业务配对样本从真实问题里挑几十到上百条,人工标出应该召回的文档,这是后面所有比较的基准。
- 按语言筛候选先按语料语言过滤掉明显不匹配的模型,剩下三到五个候选进下一轮。
- 小样本对比同一批样本分别跑候选模型,看召回情况和前几条命中,别只看一个平均分。
- 定维度再灌数确认模型与维度后建集合,把配置记进版本文件,后面换模型要能追溯。
BM25 那一路在 Milvus 里怎么落
BM25 靠的是文本字段的分词与倒排,所以文档原文必须以可分词字段存进集合,不能只存向量。中文要先定好分词方式,分词一变结果全变。权重也不该一套走天下:短查询、含专名的查询给 BM25 更高权重,长问句给向量更高权重。
- 入库前定分词、停用词、是否需要 n-gram,事后改要重刷数据
- 两路各自出候选后用加权求和或排名融合合并,具体接口参数去官方文档核对
- 站内工程视角可参考 向量检索、全文检索、混合检索(/guides/vector-fulltext-hybrid-search) 这篇
- 字段长度和文本清洗方式会直接影响 BM25 打分,别等上线才发现
BM25 的分数只在同一套分词和字段配置下可比,跨配置比大小没有意义。
调参与验收:别凭感觉,留一条可复现的评测
混合检索最容易犯的错是凭单条体验调权重。今天觉得这条好了就加一点,明天又改回去。要避免这个,就得有一份固定的评测集和固定的配置记录。
- 建评测集准备 50 到 200 条业务问题并标注正确答案。数量不用多,但要覆盖短查询和长问句两类。
- 固定变量把嵌入模型、分词配置、融合权重、候选条数写进配置文件,每次只改一个变量再重跑。
- 两路分开看融合前先各自拉前 N 条人眼看。很多时候是某一路本身召回差,融合只是在给坏结果加权。
- 分层监控上线后短查询和长查询分开统计,混在一起的平均值会掩盖问题。
| 要记录的项 | 为什么 |
|---|---|
| 嵌入模型标识 | 换模型等于换召回分布,不记就说不清变化来源 |
| 分词与字段配置 | 分词一变 BM25 结果全变 |
| 融合方式与权重 | 调参的主要旋钮,必须可回滚 |
| 候选条数 | 影响召回上限和延迟,和权重是一组 |
| 评测集版本 | 样本换了,历史结论就不一定成立 |
什么情况下不该硬上混合
混合不是越复杂越好。下面几种情况更该先收手:库很小、查询语义单一,单路向量加一个重排往往就够,加 BM25 只会让调参和运维成本翻倍;对延迟极敏感,混合要多跑一路、多一次融合,链路更长,压测不过关就退回单路。
- 没有标注数据也抽不出人工样本时,无法判断哪套权重更好,先补评测集再谈混合
- 已有重排环节的,先确认重排调到位没有,它本身就能纠一部分召回噪声
- 纯口语化短问答场景,第二路召回收益有限,先优化分块和提示词
- 团队没有精力维护两套配置时,简单可控比理论上的召回上限更重要
常见问题
Milvus 混合检索里密集嵌入和 BM25 的权重一般怎么定?
没有通用值,取决于查询形态。实践做法是给短查询和含专名的查询调高 BM25 权重,给长问句调高向量权重,然后用自己业务的问题集跑对比。先固定候选条数,只调权重这一个变量,跑几轮看排序变化,别一次改好几项。
BM25 那一路需要把文档原文也存进 Milvus 吗?
需要。BM25 依赖文本字段和分词后的倒排索引,只存向量是跑不起来的。原文要落在可分词字段里,中文还要先定分词方式,因为分词规则一变召回结果就变,改分词往往要重刷数据,所以入库前就要想清楚。
怎么判断加了混合检索确实变好了?
靠可复现的评测集,不靠单条体验。准备一份带标注答案的业务问题集,改动前后各跑一遍,比较召回率和前排命中情况,同时把嵌入模型版本、分词配置、权重都记录下来。只有配置固定,两次结果才有可比性。