☰
【RAG 学习笔记 02】在线链路七步走:混合检索与 RRF 为什么有效
2026/9/27 1:55:17 网站建设 项目流程

这是 RAG 学习笔记的第 2 篇,把在线链路走一遍:

问题清洗 → 查询改写 → 混合检索 → Rerank → 组装上下文 → LLM 生成 → 引用后处理

我原本是硬背这串流程,背不下来;后来把它想成"帮朋友查资料回答问题的完整过程",就顺了。


本系列导航

  • 00 开篇:用「开卷考试」理解 RAG 与我的学习方法
  • 01 Chunking 切块与 Embedding 选型
  • 02 在线链路七步走与混合检索 RRF(本篇)
  • 03 Rerank 与查询改写
  • 04 工程化:延迟、缓存、成本与权限
  • 05 评测调优与三个进阶架构

一、七步流程:每一步为什么存在

步骤做什么类比
问题清洗去掉错别字、多余空格、敏感词把朋友含糊的话听清楚
查询改写把口语化、有指代的问题改成适合检索的句子把"它退款怎么算"改成"会员年卡的退款条件是什么"
混合检索同时用关键词(BM25)和语义(向量)找文档同时用"关键字搜索"和"意思相近搜索"
Rerank把找回来的几十篇用更精细的模型重新排序海选后面试,精挑 5 个
组装上下文把挑出来的片段拼成一段话给 LLM把资料整理好放在桌上
LLM 生成大模型根据资料写出答案你根据资料组织语言回答朋友
引用后处理标来源、检查不安全内容告诉朋友"这是从 XX 文件第 3 页看到的"

记忆口诀:清 → 改 → 找 → 排 → 拼 → 答 → 标。

面试口述版:“在线阶段先清洗和改写用户问题,然后混合检索召回候选,再用 Rerank 精排,组装上下文给 LLM 生成,最后做引用和安全后处理。”——这就够了,不需要一字不差背步骤名。


二、混合检索:BM25 管"字面",向量管"意思"

BM25 是什么?

BM25 是一种基于关键词的检索算法,传统搜索引擎(比如 Elasticsearch)默认就用它。

它给每篇文档打分,依据三个因素:

  • 词频:查询词在文档里出现几次,越多分越高(但有上限);
  • 逆文档频率(IDF):一个词在所有文档里越罕见,权重越高——比如"Pod"比"怎么"稀有,所以匹配上"Pod"得分更高;
  • 文档长度:长文档做归一化,避免长文档占便宜。

一句话:BM25 就是"字面匹配打分器"。

向量检索在做什么?

很多人(包括我)以为"向量检索"就是把文字编码成向量——其实它包含两步:

  1. 编码:用 Embedding 模型把用户问题变成向量,约 10–30ms;
  2. 搜索:拿这个向量去向量数据库(Milvus / FAISS)里找最相似的文档向量,约 20–50ms。

类比:你要在图书馆找一本内容相似的书——先把需求翻译成管理员能懂的"索引号"(编码),管理员再去书架按索引号找(搜索)。两步加起来才是向量检索时间。

为什么必须混合?

  • BM25 擅长精确匹配:产品名、错误码、版本号、专有名词;
  • 向量检索擅长语义泛化:同义改写、口语表达。

举例:用户问"K8s Pod 启动失败怎么排查"

方式结果
纯向量召回"Kubernetes 容器无法运行"(意思相近),但可能漏掉精确包含"Pod"的文档
纯 BM25精确命中"Pod"“启动失败”,但漏掉"容器无法运行"这类语义相关文档
混合 + RRF两者互补,Recall@10 从 0.78 提升到 0.91

一句话:BM25 擅长"字面一样",向量擅长"意思一样",合起来才最全。


三、RRF:为什么只看排名、不看分数

RRF = Reciprocal Rank Fusion(倒数排名融合)。

公式很朴素:

score = Σ 1 / (k + rank_i)

意思是:对每一路检索结果,按其排名贡献分数(第 1 名贡献最大,越靠后越小),再把多路分数相加。

为什么不用"加权分数"而是用 RRF?

这是我最没懂、后来最服气的一点:

BM25 的分数范围可能是 0–20,向量相似度是 0–1,量纲完全不一致。直接加权归一化会引入偏差(归一到哪个区间?权重怎么定?)。

而RRF 只看排名,对分数量纲不敏感,所以更稳健。k 值常用默认k=60,对排名差异不敏感。

面试被问到"怎么融合多路检索结果"时,我的答法是:“我用 RRF 而不是加权求和,因为两路分数量纲不同,加权归一化会引入偏差;RRF 只依赖排名,更稳健。”


四、顺带搞懂:什么叫"双塔粗排"

面试文档里写"召回阶段是双塔粗排:Query 和 Doc 独立编码,交互不充分",我一开始完全不懂。

双塔:有两个"塔"(神经网络)——一个塔编码 Query,另一个塔编码 Doc。它们各自独立把文字变成向量,然后算两个向量的相似度。

为什么叫"粗排":因为 Query 和 Doc没有放在一起看,模型不知道它们之间具体的词级交互。

举例:Query 是"苹果价格",Doc 是"苹果手机售价"——双塔只能分别编码,可能忽略"价格"和"售价"的细微对应关系。

精排(Cross-Encoder):把 Query 和 Doc 拼在一起,如[CLS] 苹果价格 [SEP] 苹果手机售价 [SEP],让模型同时看到两边做深度交互——精度更高,但计算慢。

所以标准流程是:双塔粗排召回 Top-50 → Cross-Encoder 精排 Top-5。粗排快但不够准,精排准但慢,所以只对少量候选做。


五、检索为空怎么办:三层兜底

举例:保险理赔 RAG,用户问"2025 年新增的宠物医疗险报销比例"

  1. 第一层——放宽重试:降阈值、去过滤、启用 BM25 兜底;
  2. 第二层——明确拒答:Prompt 约束"上下文无相关信息时直接说未找到";
  3. 第三层——追问澄清:追问"您是指哪一款宠物险?"

核心原则:宁可拒答,不可幻觉。

这一条我后来在评估部分又见到一次(无答案样本、受监管行业设 Faithfulness 门槛 0.98)。"会拒答"是 RAG 系统成熟的标志,只会答不会拒的系统在真实业务里很危险。


六、这一篇的记忆卡

概念一句话
在线七步清 → 改 → 找 → 排 → 拼 → 答 → 标
BM25基于关键词的字面匹配打分器(词频 + IDF + 长度归一)
向量检索编码(文字→向量)+ 搜索(向量库找相似)
混合检索BM25 管字面、向量管意思,Recall@10 可从 0.78 → 0.91
RRF只看排名不看分数,避免量纲不一致
双塔粗排Query/Doc 独立编码,快但不准
检索为空放宽重试 → 明确拒答 → 追问澄清

七、我的复盘

这一篇最大的收获是搞清了**"召回"和"排序"是两个不同的目标**:

召回阶段要的是"别漏"(高 Recall),排序阶段要的是"把对的放前面"(高精度)。

一句话想通后,很多设计就顺了:

  • 为什么召回想多要几路?——为了 Recall;
  • 为什么召回了还要 Rerank?——为了把对的排前面;
  • 为什么 RRF 只看排名?——因为在"排序"这个目标上,排名比原始分数更可比。

下一篇讲 Rerank 和查询改写:为什么 Cross-Encoder 更准却更慢、HyDE 什么情况下会把检索带偏、以及为什么多轮对话里每一轮的 Query 都必须"自包含"。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询