很多人搭 RAG 到一半会发现:纯向量召回对型号、编号、专有名词老是漏,改成关键词加向量又不知道两路分数怎么合。这篇不聊原理图,只讲落地顺序——先定召回策略,再定融合与并发,最后用固定评测集验证是不是真的变好。
搭 RAG 搭到一半,很多人会撞上同一个现象:纯向量召回对自然语言问句挺好使,可用户一开口就是型号、编号、人名缩写,检索结果里就是没有那一段。于是想把关键词检索也加进来,两路一起召。但真动手又会卡在下一个问题上:一路是余弦相似度,一路是 BM25 分数,量纲根本不一样,怎么合?
这篇不讲原理图,只讲落地顺序:先定召回策略,再定融合方式和并发,最后用固定评测集验证是不是真的变好了。顺序乱了很容易调半天权重,最后发现瓶颈压根不在融合那一步。
先判断该不该上混合检索
混合检索不是默认选项。它换来的是召回率,付出的是链路复杂度、延迟和排障成本。判断要不要上,先看用户查询里是不是高频出现型号、编号、专有名词、缩写这类向量模型不敏感的 token,以及同一份文档里同一个概念是不是有多个写法。
- 用户查询带型号、编号、人名、缩写,纯向量召回经常整段漏掉,加关键词那一路才有救
- 文档里同一概念有多种写法(简称、全称、英文名),纯关键词又召不全,这时候才需要两路互补
- 先做一次归因:把最近答错的一批 query 捞出来,看正确 chunk 是排序靠后还是压根没进候选集
- 排序靠后是排序问题,先上 rerank 更划算;压根没进候选集才是召回问题,才轮到混合检索
融合与分发:两路怎么合并、几路并行
融合有两条常见路线。一条是把两路分数归一化到同一区间再加权求和,好处是直观,坏处是权重要调,而且两路分布会随语料变化漂移。另一条是按排名做倒数排序融合,只看名次不看分数,对打分尺度不一致的两路更省心,代价是丢掉了分数里的置信信息。
| 对比项 | 加权求和 | 倒数排序融合 |
|---|---|---|
| 要不要调参 | 需要定权重,语料一变可能要重调 | 基本不用调,只看名次 |
| 对分数尺度敏感 | 敏感,归一化方式影响很大 | 不敏感 |
| 信息利用 | 用上了分差,强弱能区分 | 只保留相对顺序 |
| 适合场景 | 两路分数可比、有人盯调参 | 两路打分口径不一致、想快速上线 |
rag-fusion 的思路是同一 query 生成多个改写,各跑一遍检索,再对多路结果做倒数排序融合。它本质上是拿调用次数换召回率。落地前先算清楚:一次问答会打几次检索,查询量会翻几倍,向量库扛不扛得住。
- 改写数量不要贪多,先从小批量试起,看召回增量是否随改写数线性上涨,通常很快见顶
- 多路检索尽量并发,但并发会放大下游压力,先确认向量库连接数和限流上限
- 两路都做同样的归一化处理(分词、大小写、去停用词),否则等于在查两个不同的库
超时、降级与成本口径
混合检索最容易出事的地方不是融合算法,是超时。一路检索卡住,整个请求跟着挂,用户侧看到的是全部失败。所以每一路检索要单独设超时,再设一个整体预算,某一路超时就退回单路结果,把这次降级记进日志。
- 分路超时加整体预算每一路检索单独设超时阈值,再给整个检索阶段设一个总预算,两者都要有
- 定好降级顺序改写多路 → 单路改写 → 原始查询单路检索 → 原始 query 直接交模型并标注无检索结果,逐级退,不让整链失败
- 记录实际检索次数把每类检索消耗的调用量和一次问答实际打了多少次检索写进日志,不然评估成本只能靠猜
- 横向对照数量级用量口径可以到站内的用量页面看,拿自己的每请求检索次数和常见水平对照,判断是不是明显偏高
成本这块建议换个口径看:不要只算单次请求贵不贵,要算每答对一次的平均检索次数。答对率上不去,再便宜的检索也是浪费。要横向参照行业用量水平,去站内页面核对当时的数字,不要凭印象拍脑袋。
怎么证明它真的变好了
改召回策略最大的风险是凭手感。今天调完感觉好一点,明天语料一更新又回去了,没人说得清到底哪一步起了作用。解决办法是固定一批 query 加标准答案组成的评测集,每次改动都跑一遍,留一份可对比的记录。
| 层次 | 看什么 | 不涨说明什么 |
|---|---|---|
| 召回层 | 命中率、正确 chunk 的命中排名 | 候选集没改善,问题在分词、索引或改写 |
| 生成层 | 答对率、引用是否与答案对得上 | 召回到了但拼装或提示词有问题 |
| 工程层 | 单路延迟、整体超时率、降级触发次数 | 收益被工程开销吃掉了 |
上线别一把梭。先对小部分流量开混合检索,同一时段对比两边的延迟和答对率,再决定要不要放量。灰度期间重点盯降级触发次数,它比平均延迟更能反映链路稳不稳。
几个常见坑
- 只对一路做分词或大小写归一化,两路实际查的不是同一份内容,融合结果自然乱
- 改写生成的查询和原 query 语义跑偏,越检索越偏,要限制改写数量并设相似度下限
- 语料更新后只重建了向量索引,忘了关键词索引,两路数据长期不同步,漏召回还很难发现
- 把融合权重写死在代码里,语料一换就失准,权重至少要能配置化调整
混合检索能救的是「正确内容压根没进候选集」,救不了「进了候选但排得太后」——前者加一路,后者上重排。下一步如果你正在选向量库或检索服务,先拿自己的真实 query 跑一遍命中情况,再决定要不要上混合检索;具体服务在并发、限流、超时上的表现,可以到站内目录对照着看当时的数据。→
常见问题
混合检索和 rag-fusion 是一回事吗?
不是一层的东西。混合检索说的是「用两种以上召回方式同时查」,重点是召回路径;rag-fusion 说的是「同一问题生成多个查询、分别检索后再融合」,重点是查询扩展加结果合并。两者可以叠:先多查询扩展,再在每一路查询里同时跑关键词和向量。
小团队有必要上吗?
先看有没有真实痛点。如果现在的错答里,大部分是「资料明明有但没检索到」,那值得试;如果主要是「检索到了但模型答歪」,加一路检索帮助有限,先改拼装顺序和提示词更划算。可以先在一路关键词检索上验证一周,再决定要不要上融合。
两路检索的分数差很多,怎么合?
别直接相加。要么各自归一化到同一区间再按权重加,要么干脆丢掉分数只用排名做倒数排序融合。后者更好上手,因为不用反复调权重,也不受向量相似度和关键词打分尺度不一致的影响。