欢迎光临
我们一直在努力

RAG 检索后优化实战:Rerank、RAG Fusion 与 HyDE 的原理、代码与选型

摘要:本文聚焦 RAG 检索后的精度优化,系统梳理 Rerank、RAG Fusion 与 HyDE 三种策略。Rerank 用专用重排序模型对初召回候选做二次语义打分,是投入产出比最高、几乎必开的第一道精筛;RAG Fusion 通过多查询生成、多路检索与 RRF 融合扩大并稳定召回,再复用 Rerank 收口;HyDE 借助 LLM 生成假设性文档跨越短 Query 与长文档之间的语义鸿沟,适合作为召回侧补充。文章还给出三种重排序模型横向对比、RRF 计算示例与可运行代码,并以企业 IT 知识库问答为例展示端到端链路,最后用索引表汇总优化措施与选型建议。

  • 1 引言:初召回只是开始
  • 2 Rerank 重排序:检索后的第一道精筛
    • 2.1 核心痛点
    • 2.2 实现方式
    • 2.3 核心价值
    • 2.4 工程注意事项
  • 3 RAG Fusion:多查询 + 多路检索 + 融合重排
    • 3.1 定义与工作流
    • 3.2 为什么需要多查询
    • 3.3 RRF 融合算法
    • 3.4 为什么用 RRF
    • 3.5 代码实现
  • 4 HyDE:用假设文档跨越语义鸿沟
    • 4.1 核心步骤
    • 4.2 核心价值
    • 4.3 问题与工程权衡
  • 5 端到端实战案例:企业 IT 知识库问答优化
  • 6 优化措施索引表
  • 7 总结

1 引言:初召回只是开始

本文是 RAG 优化系列的下篇,承接前两篇已发布的博文:《RAG 检索优化实战:从索引治理到混合检索》系统梳理了索引治理、检索前优化、混合检索与缓存加速,解决的是“能不能召回、召回得全不全”的问题;《RAG 查询理解与重写实践》则聚焦查询纠错、查询规范化、多查询生成与实体消歧,解决的是“Query 表述是否准确、是否覆盖用户真实意图”的问题。本篇在此基础上继续向前推进,聚焦检索之后的精度环节,讨论 Rerank、RAG Fusion 与 HyDE 三种策略如何把“多捞”的候选变成“精筛”的证据。建议按“上篇打基础、中篇理查询、本篇提精度”的顺序阅读,三篇合起来构成一条从索引到查询、再到检索后重排的完整优化链路。

在上一篇文章中,我们完成了索引治理、检索前优化、混合检索与缓存加速的部署。但很多团队发现:检索结果“能召回”了,精度却仍然不够——初召回的 Top-50 里混着大量“表面相似、语义不相关”的噪声,直接送入 LLM 会拉低回答质量、推高幻觉概率。

结论先行:召回阶段要“多捞”,精度阶段要“精筛”。检索后的融合重排(Rerank、RRF、RAG Fusion)与高级检索策略(HyDE),正是把“多捞”变成“精筛”的关键。本文从 Rerank 讲起,逐步展开 RAG Fusion 的完整工作流,并给出 HyDE 的适用边界与工程权衡。

2 Rerank 重排序:检索后的第一道精筛

2.1 核心痛点

向量数据库的相似度评分(如余弦相似度、内积)本质是向量空间距离匹配,只能反映 Query 与文本块在嵌入空间中的整体接近程度,无法精确刻画“这段证据是否真正回答了问题”。因此它难以解决“语义匹配偏差”和“复杂意图理解”问题,导致初召回候选证据中混入大量低相关噪声。

更具体地说,Bi-Encoder 架构(Query 与文档分别独立编码)在离线阶段就把文档压缩成固定维度向量,Query 与文档之间缺乏细粒度的词级交互,遇到否定、限定条件、多实体约束等复杂语义时容易失准。这正是需要引入 Rerank 的根本原因。

2.2 实现方式

Rerank 采用 Cross-Encoder 架构:把 Query 与候选文档拼接成一对输入,让模型在编码时就能进行词级交叉注意力交互,输出一个相关性得分。相比 Bi-Encoder 的向量距离,这种“逐对打分”方式精度更高,代价是无法预先建索引,只能对少量候选在线计算。

工程上通常使用专用重排序模型(如 BGE-Reranker-base、Qwen3-Rerank、Cross-BERT 等),对初步检索到的候选证据进行二次语义相关性打分,按得分重新排序,筛选 Top-K 高相关证据。典型链路是:向量/混合检索初召回 Top-50~100,Rerank 逐对打分后保留 Top-5~10 送入 LLM。

from sentence_transformers import CrossEncoder
加载重排序模型(中文场景推荐 BAAI/bge-reranker-base)
reranker = CrossEncoder("BAAI/bge-reranker-base") # 或 Qwen3-Rerank
def rerank(query: str, candidates: list, top_k: int = 5) -> list:
"""对初召回候选做二次语义相关性打分,返回 Top-K 文档。"""
pairs = [(query, doc) for doc in candidates]
scores = reranker.predict(pairs) # 逐对语义相关性打分
ranked = sorted(zip(candidates, scores), key=lambda x: x[1], reverse=True)
return [doc for doc, _ in ranked[:top_k]]

表 1 三种重排序模型横向对比

对比维度

BGE-Reranker-base

Qwen3-Rerank

Cross-BERT

模型规模

约 2.8 亿参数(base 级),轻量易部署

0.6B / 4B / 8B 多规格可选,按算力弹性选择

约 1.1 亿参数(BERT-base 量级),最轻

支持语言

中英文为主,多语言需选 bge-reranker-v2-m3

100+ 种语言,中英文与多语种混检表现好

取决于底座,英文强,中文需中文预训练版本

输入长度限制

约 512 token,超长 chunk 需切分

约 8192 token,可容纳较长证据片段

约 512 token,长文本需截断或分块

典型延迟

单卡 GPU 下 50 对打分约几十毫秒级

0.6B 接近 base 级;4B/8B 明显更高,需批处理

最低,CPU 也可跑,适合高并发低延迟场景

适用场景

中文 RAG 通用首选,开箱即用、性价比高

多语言、长文档、复杂语义与高精度要求场景

英文场景、资源受限或需自建微调的基线模型

选型建议:如果业务以中文为主、追求开箱即用与低延迟,优先选 BGE-Reranker-base,先用它跑通链路并建立离线评估基线;如果涉及多语言混检、长文档证据或对精度要求更高,且能接受额外算力成本,可选 Qwen3-Rerank,并优先从 0.6B 规格起步、按评估结果再升级;如果资源紧张、以英文场景为主,或希望基于自有标注数据做领域微调,Cross-BERT 是更轻量的基线选择。无论选哪种,都建议先用同一批标注 Query 做离线对比,再结合延迟预算与在线 A/B 结果确定最终方案。

2.3 核心价值

专用重排序模型基于深层语义理解,能捕捉 Query 与文本块的内在语义关联,比传统向量相似度评分更精准,可有效区分“表面相似”与“语义相关”,直接提升最终回答的准确性与连贯性,降低幻觉概率。

示例:Query“苹果公司最新产品有哪些?”初召回 Top-50 中可能包含:A“苹果公司发布 iPhone 16 系列”;B“苹果的营养价值与食用禁忌”;C“苹果公司 MacBook Pro 更新”;D“苹果种植技术指南”。Rerank 模型打分后,A、C 得分高,B、D 被降权过滤,最终 Top-5 只保留与“苹果公司产品”语义相关的证据。

2.4 工程注意事项

  • Rerank 模型有输入长度限制(常见 512 token),过长的 chunk 应切分后再打分,避免关键信息被截断;
  • 多语言场景需选择支持对应语言的 Rerank 模型,中文场景不要直接套用英文底座;
  • Rerank 会增加延迟,需与召回数量、并发量做权衡;初召回多捞(如 Top-50),重排后精选 Top-5~Top-10 送入 LLM,既保证召回率,又控制 LLM 上下文窗口占用;
  • 打分应做批处理(batch predict)并设置超时降级:Rerank 服务异常时回退到初召回排序,保证链路可用;
  • 上线前用标注集评估 NDCG@K、MRR 等排序指标,而不只看最终答案准确率,便于定位是召回问题还是重排问题。

3 RAG Fusion:多查询 + 多路检索 + 融合重排

3.1 定义与工作流

RAG Fusion 是一种“多查询生成 + 多路检索 + RRF 融合 + 按评分重排序”的检索增强策略,用于解决单一查询召回不全面、检索结果不稳定的问题。其思想源自论文《RAG-Fusion: a New Take on Retrieval-Augmented Generation》,核心是把“一次检索”扩展为“多视角检索 + 排名融合”。工作流分为五步:

第一步,多查询生成:使用 LLM 从不同角度生成多个与原始 Query 相关的查询;第二步,多路检索:对每个查询分别执行检索(可结合向量检索、关键词检索或混合检索),得到多个候选结果列表;第三步,RRF 融合:使用 RRF 算法将多个结果列表的排名融合为单一统一排名;第四步,重排序:对融合后的候选证据使用 Rerank 模型按语义相关性二次打分排序;第五步,Top-K 筛选:精选高相关证据送入 LLM 生成最终回答。

flowchart TD
A["原始 Query"] –> B["步骤 1:多查询生成(LLM 生成 N 个变体查询)"]
B –> C["步骤 2:多路检索(每个查询分别执行向量 / BM25 / 混合检索)"]
C –> D["步骤 3:RRF 融合(按排名融合为统一排名,k=60)"]
D –> E["步骤 4:Rerank 重排序(Cross-Encoder 二次语义打分)"]
E –> F["步骤 5:Top-K 筛选(保留 Top-5~10 证据)"]
F –> G["送入 LLM 生成最终回答"]

图注:上图展示 RAG Fusion 的五步链路。多查询生成以原始 Query 为输入,输出多个变体查询;多路检索以变体查询为输入,输出多组候选结果列表;RRF 融合以多组列表的排名为输入,输出统一融合排名;Rerank 重排序以融合后的候选证据为输入,输出按语义相关性重排的得分序列;Top-K 筛选以重排结果为输入,输出最终送入 LLM 的高相关证据集合。

3.2 为什么需要多查询

单一查询可能无法完全捕捉用户感兴趣的全部范围,或者可能过于狭窄而无法产生全面结果。从不同角度生成多个查询,不仅与原始查询相似,还提供不同视角或角度,从而扩大召回覆盖面、降低单一查询表述偏差带来的漏召回风险,并为 RRF 融合提供更多有效排名信号。

示例一:用户 Query“推荐手机”过于宽泛,可生成“推荐性价比高的手机”“推荐拍照好的手机”“推荐续航强的手机”“推荐适合打游戏的手机”。不同查询召回不同侧重点的候选文档,RRF 融合后能覆盖“性价比、拍照、续航、游戏”多个维度。

示例二:原始 Query“推荐适合程序员的笔记本”,生成“程序员 编程 笔记本 推荐”“高性价比 开发 笔记本”“内存大 编译快 笔记本”“适合写代码的轻薄本”,分别覆盖“编程场景、性价比、性能、便携性”不同角度,后续通过多路召回与 RRF 融合提升召回率。

3.3 RRF 融合算法

RRF(Reciprocal Rank Fusion,逆向排名融合)是一种将多个搜索结果列表的排名结合为单一统一排名的技术,核心公式如下:

RRF(d) = Σ_{r∈R} 1 / (k + rank_r(d))

其中,d 为文档,R 为多个检索结果列表的集合,rank_r(d) 为文档 d 在列表 r 中的排名(从 1 开始),k 为平滑常数,通常取 60。k 的作用是抑制头部排名的过度影响:k 越大,不同排名之间的得分差异越小,融合结果越平滑。表 1 给出了 k=60 时的计算示例。

表 1 RRF 计算示例(k=60)

文档

L1 排名

L2 排名

RRF 得分

D1

1

3

1/61 + 1/63 ≈ 0.01639 + 0.01587 = 0.03226

D2

2

2

1/62 + 1/62 ≈ 0.01613 + 0.01613 = 0.03226

D3

1

1

1/61 + 1/61 ≈ 0.01639 + 0.01639 = 0.03279

D4

5

10

1/65 + 1/70 ≈ 0.01538 + 0.01429 = 0.02967

D3 在两个列表都排第 1,融合得分最高;D4 虽然也出现在两个列表,但排名靠后,融合得分最低。这体现了 RRF“多路都靠前才更高权重”的核心思想。

3.4 为什么用 RRF

BM25 分数范围可能是 0~20,向量相似度可能是 0~1,直接加权求和需要归一化且受分数分布影响。RRF 只看排名、不关心原始分数尺度,鲁棒性强,更适合融合“BM25 + 向量检索 + 多查询”的异构结果列表。

此外,RRF 无需训练、无超参数调优负担(k 一般固定 60 即可),对新增检索通道天然可扩展:新增一路检索只需把它的排名列表加入融合,不必重新校准分数权重,这也是它在工程上被广泛采用的原因。

3.5 代码实现

下面给出 RAG Fusion 的完整可运行示例,包含 reciprocal_rank_fusion 与 rag_fusion 两个核心函数。其中 llm.generate_variants、retriever.hybrid_search 与 reranker 均以带类型注解的接口占位形式给出,实际接入时替换为团队自有实现即可。

from typing import List, Tuple, Protocol
============ 接口占位:按需替换为真实实现 ============
class LLM(Protocol):
def generate_variants(self, query: str, n: int = 3) -> List[str]:
"""根据原始 Query 生成 n 个不同角度的变体查询。"""
…
class Retriever(Protocol):
def hybrid_search(self, query: str, top_k: int = 50) -> List[str]:
"""对单条查询执行混合检索(BM25 + 向量),返回按相关性降序的文档 ID 列表。"""
…
class Reranker(Protocol):
def call(self, query: str, candidates: List[str], top_k: int = 5) -> List[str]:
"""对候选文档按语义相关性二次打分,返回 Top-K 文档 ID。"""
…
============ 核心函数 1:RRF 融合 ============
def reciprocal_rank_fusion(
result_lists: List[List[str]], k: int = 60
) -> List[Tuple[str, float]]:
"""
将多个检索结果列表(按相关性降序的文档 ID 序列)融合为统一排名。
:param result_lists: 多路检索结果,每个元素是一个按排名升序的文档 ID 列表
:param k: 平滑常数,通常取 60,抑制单路排名波动
:return: [(doc_id, rrf_score), …],按融合得分降序
"""
scores: dict = {}
for ranked in result_lists:
for rank, doc_id in enumerate(ranked, start=1):
scores[doc_id] = scores.get(doc_id, 0.0) + 1.0 / (k + rank)
return sorted(scores.items(), key=lambda x: x[1], reverse=True)
============ 核心函数 2:RAG Fusion 主流程 ============
def rag_fusion(
query: str,
llm: LLM,
retriever: Retriever,
reranker: Reranker,
n_variants: int = 3,
recall_k: int = 50,
top_k: int = 5,
k: int = 60,
) -> List[str]:
"""
多查询生成 -> 多路检索 -> RRF 融合 -> Rerank 精筛。
:param query: 原始用户 Query
:param llm: 提供 generate_variants 的大模型接口
:param retriever: 提供 hybrid_search 的检索器接口
:param reranker: 重排序模型接口
:param n_variants: 生成的变体查询数量
:param recall_k: 每路检索的初召回数量
:param top_k: 最终送入 LLM 的证据数量
:param k: RRF 平滑常数
:return: 最终 Top-K 文档 ID 列表
"""
# 1) 多查询生成:原始 Query + n 个变体
queries: List[str] = [query] + llm.generate_variants(query, n=n_variants)
# 2) 多路检索:每条查询各跑一次混合检索,初召回多捞
result_lists: List[List[str]] = [
retriever.hybrid_search(q, top_k=recall_k) for q in queries
]
3) RRF 融合:多路排名融合为统一排名
fused: List[Tuple[str, float]] = reciprocal_rank_fusion(result_lists, k=k)
candidates: List[str] = [doc_id for doc_id, _ in fused[:recall_k]]
4) Rerank 精筛:按原始 Query 语义二次打分,只保留 Top-K
return reranker(query, candidates, top_k=top_k)
============ 调用示例:构造 3 个候选列表 ============
if name == "main":
模拟三路检索结果(按相关性降序的文档 ID)
L1 = ["D3", "D2", "D1", "D5"]
L2 = ["D3", "D2", "D1", "D4"]
L3 = ["D3", "D1", "D4", "D2"]
fused = reciprocal_rank_fusion([L1, L2, L3], k=60)
for doc_id, score in fused:
print(f"{doc_id}: {score:.5f}")
预期输出(k=60,得分降序):
D3: 0.04918 # 三路均排第 1:3 * 1/61
D1: 0.04813 # 排名 3 / 3 / 2:1/63 + 1/63 + 1/62
D2: 0.04785 # 排名 2 / 2 / 4:1/62 + 1/62 + 1/64
D4: 0.03125 # 仅 L2、L3 命中:1/64 + 1/63
D5: 0.01538 # 仅 L1 命中且排第 4:1/64</code></pre>
从预期输出可以看到 k=60 时的融合排序规律:D3 在三路检索中都排第 1,融合得分最高;D1 与 D2 虽然单路排名略有差异,但都稳定出现在三路结果中,得分紧随其后;D4 只在两路命中,D5 仅一路命中且排名靠后,得分明显偏低。这正是 RRF“多路都靠前才更高权重”的核心思想——只看排名、不看原始分数尺度,因此可以安全地融合 BM25、向量检索与多查询产生的异构结果列表。
以“推荐适合程序员的笔记本”为例:某文档 D“某款 32GB 内存轻薄本,适合 Java 编译和 Docker 开发”在 L1 排第 3、L2 排第 5、L3 排第 2,RRF 综合三个排名给 D 较高融合分,使其进入最终候选;随后 Rerank 按“程序员笔记本推荐”语义再打分,确保最终 Top-5 聚焦编程场景。

4 HyDE:用假设文档跨越语义鸿沟

4.1 核心步骤

HyDE(Hypothetical Document Embeddings)出自论文《Precise Zero-Shot Dense Retrieval without Relevance Labels》,用于解决检索阶段可能遇到的“查询—文档”语义鸿沟问题。核心思路是:不直接用短 Query 去检索,而是先让 LLM 生成一篇“假设的答案文档”,再用这篇文档的向量去检索。核心步骤为:使用 LLM 根据用户查询生成假设性文档;将假设性文档嵌入为向量;使用该向量进行检索。

def hyde_search(query: str, llm, embed, vector_index, top_k: int = 20):
"""HyDE 检索:生成假设文档 -> 嵌入 -> 向量检索。"""
# 1) 用 LLM 生成假设性文档
hypothetical_doc = llm(
f"请用一段 3~5 句的说明性文字回答:{query}"
)
# 2) 将假设文档嵌入为向量
hyde_vec = embed(hypothetical_doc)
# 3) 用假设文档向量检索
return vector_index.search_by_vector(hyde_vec, top_k=top_k)

示例:用户 Query“RAG rerank 有必要吗?”,LLM 生成假设性文档:“Rerank 通过 Cross-Encoder 对初召回候选证据进行二次语义相关性打分,可过滤表面相似但语义不相关的噪声,提升 Top-K 证据精度,降低 LLM 幻觉概率……”。将该假设文档嵌入后检索,更容易召回“Rerank 原理”“Cross-Encoder”“RAG 重排序实践”等文档;而直接用短 Query 检索可能只命中“RAG”泛化内容。

4.2 核心价值

用户 Query 通常较短、口语化,而索引文档通常较长、规范化,二者在向量空间中可能存在语义鸿沟。HyDE 通过生成“假设性答案文档”,使检索向量更接近真实文档分布,从而提升召回效果。

它的另一个价值是零样本适配:HyDE 不需要相关性标注,也不需要针对新领域重新训练检索模型,只要换一个生成模型就能迁移到新语料,因此在冷启动或标注稀缺的场景下性价比较高。

4.3 问题与工程权衡

HyDE 的主要问题在于:假答案质量依赖 LLM 能力,假设性文档可能包含错误或幻觉内容,易引入噪声;专业领域知识场景下,LLM 还需经过领域知识微调;同时需要额外调用 LLM 生成假设性文档,增加延迟与成本。

风险示例:在医疗场景中,Query“二甲双胍禁忌证”,若 LLM 生成假设文档时错误加入“所有肾功能不全患者均禁用”等不准确表述,可能将检索引向错误证据。因此专业领域应优先使用领域微调模型或权威词典增强,或将 HyDE 结果与原始 Query 检索结果做 RRF 融合,降低单一假文档噪声影响。

  • 对高时效、高风险场景谨慎使用 HyDE;
  • 可将 HyDE 与原始 Query 检索并行,使用 RRF 融合,降低假答案噪声影响;
  • 对专业领域,优先使用领域微调模型或领域词典增强,而非直接依赖通用 LLM 生成假设文档;
  • 对假设文档做长度与格式约束(如 3~5 句、只输出正文),并缓存高频 Query 的生成结果,控制额外 LLM 调用带来的延迟与成本。

5 端到端实战案例:企业 IT 知识库问答优化

以企业 IT 知识库为例,用户 Query:“VPN 连不上咋办,提示认证失败。”

优化前存在的问题:Query 口语化,直接检索可能召回“VPN 产品介绍”而非排障文档;单一向量检索可能漏掉“认证失败”精确关键词;Top-K 中混入“网络拓扑”“采购流程”等噪声。

优化后链路:

  • 查询重述:“VPN 连接失败 认证失败 排查方法”与“VPN 认证失败 解决方案”;
  • 混合检索:BM25 精确召回“认证失败错误码”,向量检索召回“VPN 排障步骤”;
  • RRF 融合:两路结果融合,排障文档在两路都靠前,综合排名提升;
  • Rerank:过滤“VPN 采购”“网络架构”等低相关证据,保留“检查账号密码、重置 MFA、查看客户端日志”Top-5;
  • 缓存:高频 Query“VPN 连不上”缓存 Embedding 与 Top-20 结果,TTL 30 分钟;
  • LLM 生成:基于 Top-5 证据输出分步骤排障方案。

优化效果:召回率提升,噪声证据减少,回答更聚焦“认证失败”排障步骤,有效降低幻觉。

下面把上述链路串成一段可运行的 Python 示例,依次完成查询重述、混合检索、RRF 融合、Rerank 精筛四个环节。示例中的 LLM、BM25 索引、向量索引与 Rerank 模型均以可替换的接口形式给出,实际接入时替换为团队自有的实现即可。

from typing import List, Dict, Tuple
============ 环节 1:查询重述 ============
def rewrite_query(query: str, llm, n_variants: int = 2) -> List[str]:
"""
输入:原始口语化 Query,如 "VPN 连不上咋办,提示认证失败。"
输出:原始 Query + N 个规范化/多角度变体查询,用于后续多路检索
关键参数:n_variants=2,控制变体数量,过多会放大延迟与噪声
"""
prompt = (
f"请把下面的用户问题改写成 {n_variants} 条适合检索的规范化查询,"
f"保留关键实体与错误信息,每行一条,不要解释:\\n{query}"
)
variants = [line.strip() for line in llm(prompt).splitlines() if line.strip()]
# 原始 Query 也保留,避免重述偏差导致漏召回
return [query] + variants[:n_variants]
============ 环节 2:混合检索 ============
def hybrid_search(query: str, bm25_index, vector_index, top_k: int = 50) -> List[str]:
"""
输入:单条查询
输出:按相关性降序的文档 ID 列表(BM25 与向量两路结果合并去重)
关键参数:top_k=50,初召回多捞,为后续 RRF 与 Rerank 留足候选
"""
bm25_hits = bm25_index.search(query, top_k=top_k) # 精确关键词召回,如 "认证失败错误码"
vector_hits = vector_index.search(query, top_k=top_k) # 语义召回,如 "VPN 排障步骤"
merged, seen = [], set()
for doc_id in bm25_hits + vector_hits:
if doc_id not in seen:
seen.add(doc_id)
merged.append(doc_id)
return merged
============ 环节 3:RRF 融合 ============
def reciprocal_rank_fusion(result_lists: List[List[str]], k: int = 60) -> List[Tuple[str, float]]:
"""
输入:多路检索结果列表(每个列表是按相关性降序的文档 ID 序列)
输出:[(doc_id, rrf_score), …],按融合得分降序
关键参数:k=60,平滑常数,抑制单路排名波动对融合结果的影响
"""
scores: Dict[str, float] = {}
for ranked in result_lists:
for rank, doc_id in enumerate(ranked, start=1):
scores[doc_id] = scores.get(doc_id, 0.0) + 1.0 / (k + rank)
return sorted(scores.items(), key=lambda x: x[1], reverse=True)
============ 环节 4:Rerank 精筛 ============
def rerank(query: str, candidates: List[str], reranker, top_k: int = 5) -> List[str]:
"""
输入:原始 Query + RRF 融合后的候选文档 ID 列表
输出:按语义相关性重排后的 Top-K 文档 ID,直接送入 LLM
关键参数:top_k=5,控制送入 LLM 的证据数量,兼顾精度与上下文成本
"""
pairs = [(query, doc) for doc in candidates]
scores = reranker.predict(pairs) # Cross-Encoder 逐对语义相关性打分
ranked = sorted(zip(candidates, scores), key=lambda x: x[1], reverse=True)
return [doc_id for doc_id, _ in ranked[:top_k]]
============ 端到端串联 ============
def answer_it_query(query: str, llm, bm25_index, vector_index, reranker) -> List[str]:
# 1) 查询重述:1 条原始 + 2 条变体
queries = rewrite_query(query, llm, n_variants=2)
# 2) 混合检索:每条查询各跑一次 BM25 + 向量,初召回 Top-50
result_lists = [hybrid_search(q, bm25_index, vector_index, top_k=50) for q in queries]
3) RRF 融合:多路排名融合为统一排名,取前 50 作为 Rerank 候选
fused = reciprocal_rank_fusion(result_lists, k=60)
candidates = [doc_id for doc_id, _ in fused[:50]]
4) Rerank 精筛:按原始 Query 语义二次打分,保留 Top-5 证据
return rerank(query, candidates, reranker, top_k=5)
if name == "main":
query = "VPN 连不上咋办,提示认证失败。"
top_docs = answer_it_query(query, llm, bm25_index, vector_index, reranker)
print("最终送入 LLM 的证据:", top_docs)

运行说明:示例中 llm、bm25_index、vector_index、reranker 为依赖注入的接口对象,分别对应大模型调用、BM25 索引、向量索引与 Cross-Encoder 重排序模型。四个环节的输入输出与关键参数已在注释中标注:查询重述控制变体数量,混合检索控制初召回 Top-50,RRF 融合控制平滑常数 k=60,Rerank 精筛控制最终 Top-5。实际部署时可按延迟预算调整这些参数,并用离线评估集对比调整前后的召回率与答案准确率。

6 优化措施索引表

表 2 汇总了上、下两篇涉及的全部优化措施,可作为团队实施与评审的速查索引。

表 2 RAG 优化措施索引表

优化点

示例 Query/场景

优化动作

预期效果

文本切块

产品手册参数表

按标题/段落/表格切分,overlap 50~100

保留语义完整性

查询纠错

“今田天气”

改为“今天天气”

减少错别字漏召回

查询规范化

“咋查明天成都天气”

改为“查询明日成都天气”

提升检索规范性

多查询

“推荐手机”

生成性价比/拍照/续航/游戏多查询

扩大召回覆盖面

HyDE

“RAG rerank 有必要吗”

生成假设性解释文档再检索

缓解短 Query 语义鸿沟

混合检索

“iPhone 16 电池续航”

BM25 + 向量并行

兼顾精确匹配与语义召回

RRF

多路检索结果

按排名融合,k=60

多路靠前文档权重更高

Rerank

“苹果公司最新产品”

过滤水果苹果证据

提升 Top-K 精度

实体消歧

“小米最新产品”

标注“小米科技”

避免粮食小米误召回

缓存

“如何重置 VPN 密码”

缓存 Embedding 与 Top-20

降低延迟

数据更新

产品价格文档

每日增量更新,过期下线

保证时效性

表 3 聚焦本文重点讨论的三种检索后策略,从问题、核心手段、关键参数与适用场景四个维度做横向对照,便于按需选型。

表 3 三种检索后策略对照表

策略

解决的问题

核心手段

关键参数

适用场景

Rerank

初召回结果中混入“表面相似、语义不相关”的噪声,Top-K 精度不足

用 Cross-Encoder 类重排序模型对 Query-候选对做二次语义相关性打分,按分重排后截取 Top-K

初召回数量(如 Top-50)、重排后保留数(Top-5~10)、模型输入长度(512/8192 token)、批处理大小

对答案精度要求高、噪声明显的通用 RAG 问答;中文场景优先 BGE-Reranker-base,多语言长文档选 Qwen3-Rerank

RAG Fusion

单一查询表述过窄或存在偏差,导致召回不全面、结果不稳定

LLM 从多角度生成多个查询,分别多路检索,再用 RRF 按排名融合为统一排名,最后接 Rerank 收口

生成查询数(如 3~5 个)、每路召回数(如 Top-50)、RRF 平滑常数 k(通常 60)、融合后候选数

查询宽泛或口语化、需要多维度覆盖的推荐与咨询类场景;异构检索结果(BM25 + 向量)需要融合时

HyDE

短 Query 与长文档之间存在语义鸿沟,直接检索命中率低

用 LLM 生成假设性答案文档,将其嵌入为向量后检索,使查询向量更接近真实文档分布

假设文档长度(如 3~5 句)、生成模型能力与领域适配度、检索 Top-K、是否与原始 Query 结果做 RRF 融合

Query 极短、口语化且文档规范化的开放域问答;高时效、高风险或强专业领域需谨慎,建议与原始检索并行融合

使用建议:三种策略并非互斥,而是分层协作。Rerank 是几乎必开的基础精筛;RAG Fusion 在查询宽泛、召回不足时叠加;HyDE 仅在语义鸿沟明显且能接受额外 LLM 调用成本时启用,并优先与原始 Query 检索做 RRF 融合以控制噪声。

7 总结

Rerank 是检索后的第一道精筛,用 Cross-Encoder 类专用重排序模型对初召回候选做二次语义打分,把“表面相似”的噪声挡在 LLM 之外,是投入产出比最高、几乎必开的一环。

RAG Fusion 负责“扩大并稳定召回”,通过多查询生成、多路检索与 RRF 融合让不同角度的结果互补,再复用 Rerank 收口,形成“先多捞、再精筛”的闭环。

HyDE 则用于跨越短 Query 与长文档之间的语义鸿沟,通过生成假设性文档改善检索向量分布,适合作为召回侧的补充手段,而非替代精筛环节。

三者配合的逻辑是:HyDE 与多查询负责把候选池做宽,RRF 负责把多路结果融合成统一排名,Rerank 负责把最终 Top-K 做准,层层递进地提升证据质量;同时这些策略都会带来额外的 LLM 调用与延迟成本,需要结合业务场景、延迟预算与评估数据做取舍,用“离线评估 + 在线 A/B”的迭代机制让每一项优化都可量化、可回退。

落地顺序建议:先上 Rerank 建立精度基线,再按需叠加 RAG Fusion 扩大召回,最后在语义鸿沟明显的场景谨慎引入 HyDE;每一步都用同一套评估集验证收益,避免为优化而优化。

赞(0)
未经允许不得转载:171主机测评 » RAG 检索后优化实战:Rerank、RAG Fusion 与 HyDE 的原理、代码与选型
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址