Lazy loaded image
Agent丨在 RAG 中,既然向量检索已经计算了相似度,为什么还需要引入交叉编码器进行重排?
Words 4723Read Time 12 min
2026-4-22
type
Post
status
Published
date
Apr 22, 2026
slug
agent16
summary
tags
Agent
category
icon
password

1. 先给结论:向量相似度解决的是“快速召回”,交叉编码器解决的是“精确排序”

在 RAG 系统里,向量检索和交叉编码器重排不是重复劳动,而是两种不同目标的模型:
向量检索:
把 query 和 chunk 分别编码成向量,然后用 cosine、dot product 等方式快速找出一批“可能相关”的候选 chunk。
交叉编码器重排:
把 query 和每个候选 chunk 拼在一起,让 Transformer 同时看见两者,通过 token-level cross-attention 重新判断“这个 chunk 是否真的能回答这个问题”。
SentenceTransformers 官方文档把这套流程称为 Retrieve & Re-Rank:第一阶段用 lexical search 或 bi-encoder/dense retrieval 取回较大的候选集,例如 100 个可能相关结果;第二阶段用 CrossEncoder 对这些候选和 query 成对打分,输出最终排序。官方也明确指出,CrossEncoder 更准,但不能对百万级文档全量打分,所以通常只用于 top-k 候选重排。(SentenceTransformers)

2. 为什么“向量相似度”还不够?

2.1 Bi-Encoder 是“先各自理解,再比较距离”

向量检索常用的是 Bi-Encoder 架构:
它的特点是:
query 被单独编码。
chunk 被单独编码。
二者编码阶段互相看不见。
最后只用一个向量距离判断相关性。
这种方式非常适合大规模召回,因为 chunk embedding 可以提前离线计算并存进向量数据库;线上只需要编码 query,然后做近邻搜索。但是,它也天然存在一个问题:它比较的是两个压缩后的向量,而不是 query 和 chunk 的细粒度语义匹配过程。
SentenceTransformers 的 CrossEncoder 文档明确区分了这一点:CrossEncoder 不产生独立 sentence embedding,而是把两个句子/文本一起送入 Transformer,直接输出回归分数或分类概率,因此更适合 reranking、语义文本相似度等成对判断任务,但也无法提前为单个句子预计算 embedding。(SentenceTransformers)

2.2 Cross-Encoder 是“把问题和文档放在一起审题”

交叉编码器的结构更像这样:
它可以在 Transformer 内部做类似这样的细粒度判断:
query 里的实体,chunk 里是否真的出现?
query 的限定条件,chunk 是否满足?
query 问的是“原因”,chunk 给的是不是“结果”?
query 问的是“如何配置”,chunk 只是介绍概念,是否应该降权?
query 中的否定、时间、版本、范围、单位,chunk 是否匹配?
这类判断通常不是一个全局 embedding 向量能稳定表达出来的。SentenceTransformers 官方也指出,CrossEncoder 的优势来自 query 和 document 之间的 attention 交互,但对大量 pair 打分会很慢,所以工程上通常先召回一批候选,再用 CrossEncoder 重排。(SentenceTransformers)

3. 一个例子:向量相似度高,不代表它真的能回答问题

假设用户问:
“RAGFlow 中如果配置了 rerank model,最终相似度是如何计算的?”
向量检索可能召回:
A. “RAGFlow 支持向量检索、关键词检索和混合检索。”
B. “RAGFlow 的 Retrieval component 中,如果选择 rerank model,会使用 keyword similarity 和 reranking score 的加权组合。”
C. “RAGFlow 支持多种 embedding model 和 rerank model。”
A 和 C 都可能和 “RAGFlow / retrieval / rerank” 在向量空间里接近,但真正能回答“最终相似度如何计算”的是 B。
这就是 reranker 的价值:它不是再做一次粗略相似度,而是在候选集合里做精排,把“看起来像”变成“真的能答”。
RAGFlow 官方文档就体现了这种工程设计:默认检索使用 weighted keyword similarity + weighted vector cosine similarity;如果选择 rerank model,则改为 weighted keyword similarity + weighted reranking score,同时文档也警告启用 rerank 会显著增加响应时间。(RAGFlow)

4. 成熟 RAG 项目都是怎么放 reranker 的?

4.1 标准两阶段架构

这套结构的核心思想是:
召回阶段宁可多拿一点,保证 recall。
重排阶段再精挑细选,保证 precision。
SentenceTransformers 官方示例也是这个思路:先用 lexical search 或 bi-encoder 找候选,再用 CrossEncoder 给每个 query-document pair 打分,最后输出排序后的结果。(SentenceTransformers)

5. 从源码看 reranker 到底做了什么

5.1 LlamaIndex:NodePostprocessor 里重写 node.score

LlamaIndex 的 SentenceTransformerRerank 是一个典型的 postprocessor。官方文档说明它使用 sentence-transformers 的 cross-encoder 对 nodes 重新排序,并返回 top N nodes;示例中常用 cross-encoder/ms-marco-MiniLM-L-2-v2 这类模型。(Developer Documentation)
抽象后的逻辑如下:
LlamaIndex 源码中能看到几个关键点:初始化时加载 CrossEncoder;重排时构造 (query, node content) pair;调用模型 predict 得到分数;把原来的 node score 替换为 rerank score;最后按新分数排序并截断 top_n。(GitHub)
这说明 reranker 并不是“补充一个标签”,而是直接参与最终上下文选择。

5.2 LangChain:ContextualCompressionRetriever + CrossEncoderReranker

LangChain 的典型用法是:
LangChain 文档示例中,先构造 FAISS 向量检索器并设置 k=20,再用 ContextualCompressionRetriever 包装基础 retriever,使用 CrossEncoderRerankerHuggingFaceCrossEncoder 对返回结果重新排序,最后只保留 top 3。(AiDocZh)
源码层面也很直观:
LangChain 的源码实现就是对每个 (query, document) pair 打分,然后按 score 倒序排序并截断 top_n。(AiDocZh)

5.3 Haystack:Ranker 通常放在 Retriever 之后

Haystack 的 SentenceTransformersSimilarityRanker 也体现了同样的工程模式:它通常放在返回 document list 的 Retriever 之后,用于 RAG 或文档搜索 pipeline 中提升结果排序质量。Haystack 文档还建议,当和 Retriever 一起使用时,可以把 Retriever 的 top_k 设置得小一些,从而减少 Ranker 需要处理的文档数量,提高速度。(docs.haystack.deepset.ai)
Haystack 的 Ranker API 里默认模型是 cross-encoder/ms-marco-MiniLM-L-6-v2,支持设置 top_k、score_threshold、batch_size,以及 torch、onnx、openvino 等后端。(docs.haystack.deepset.ai)
这反映了生产系统里的一个重要事实:
reranker 不是越多越好。
reranker 是一个成本较高的精排层,应该只处理第一阶段召回出来的一小批候选。

5.4 RAGFlow:rerank 分数进入混合相似度

RAGFlow 的 Retrieval component 文档说明:如果没有 rerank model,检索时使用 keyword similarity 和 vector cosine similarity 的加权组合;如果选择 rerank model,则使用 keyword similarity 和 reranking score 的加权组合。(RAGFlow)
从 RAGFlow 源码看,它在启用 rerank 模型时会限制候选数量,例如把外部 reranker 的候选上限约束到 provider-safe 的规模;之后调用 rerank_by_model,把 query 和候选 docs 送给 rerank 模型得到 vtsim,再与 token similarity、rank feature 做加权融合,最后按综合分排序并过滤。(GitHub)
抽象后可以理解为:
RAGFlow 这个设计很有代表性:它不是简单地把 reranker 当成唯一分数,而是把 keyword、rerank、标签/特征等信号融合起来。这类设计在企业 RAG 里很常见,因为纯向量、纯关键词、纯 rerank 都各有盲区。(GitHub)

6. 向量检索和交叉编码器的本质差异

对比项
向量检索 / Bi-Encoder
交叉编码器 / Cross-Encoder
输入方式
query 和 chunk 分别编码
query + chunk 一起输入
是否可预计算
chunk embedding 可离线预计算
不可为单个 chunk 预计算最终相关性
计算成本
低,适合百万级召回
高,适合 top-k 精排
匹配粒度
向量级整体相似
token-level 交互匹配
主要目标
recall,找候选
precision,排顺序
典型位置
Retriever
Reranker / Postprocessor
常见问题
“看起来像”但不一定能回答
慢,吞吐成本高
工程用法
top_k=50/100/200
rerank top_k 后取 top_n=3/5/8
SentenceTransformers 官方也把 CrossEncoder 的特点总结为:给输入 pair 计算相似度分数,通常性能优于 SentenceTransformer/Bi-Encoder,但由于需要对每个 pair 单独计算,所以更慢,因此常用于重排 SentenceTransformer 召回的 top-k 结果。(SentenceTransformers)

7. 为什么 RAG 特别需要 rerank?

7.1 RAG 的错误往往发生在“上下文选择”阶段

很多 RAG 幻觉并不是 LLM 本身完全乱编,而是因为传给 LLM 的上下文质量不够:
检索到了相似但不支持答案的 chunk。
真正相关的 chunk 排在第 12 位,但只取了 top 5。
chunk 里有关键词,但语义方向不对。
检索结果里有多个相互冲突的版本。
长文档切块后,关键条件被切散了。
reranker 的核心作用就是把“真正能回答问题”的 chunk 往前推,把“只是语义相近”的 chunk 往后压。

7.2 RAG 的上下文窗口有限,top N 的顺序非常重要

即使模型支持长上下文,也不意味着可以无脑塞入所有召回结果。上下文越长,成本越高,干扰越多,而且重要证据可能被淹没。
因此 RAG 的最终质量通常高度依赖:
top 3 有没有正确证据?
top 5 有没有覆盖关键约束?
top 8 是否包含互相冲突或低质量内容?
排在前面的 chunk 是否比后面的 chunk 更适合生成答案?
LlamaIndex、LangChain、Haystack、RAGFlow 都把 reranker 放在 retriever 之后,本质上就是为了优化这个“有限上下文选择”问题。(Developer Documentation)

8. 什么场景最应该上交叉编码器重排?

8.1 强烈建议使用 reranker 的场景

场景
原因
企业知识库问答
文档相似内容多,版本多,容易召回相似但错误内容
法律、金融、医疗、合规类 RAG
query 条件细,错一个限定词就可能答错
技术文档问答
API 名称、版本、参数、错误码相似度高
多文档长文档检索
chunk 噪声多,top_k 排序不稳定
Hybrid Search
BM25 和 vector 分数量纲不同,需要更强精排
多语言检索
embedding 可能召回语义近似内容,但精确回答仍需验证
Agent 工具文档检索
工具名相似、参数相似,误选工具代价高

8.2 可以暂时不使用 reranker 的场景

场景
原因
文档规模很小
可以直接让 LLM 阅读较多上下文
问题非常简单
向量 top_k 已经足够稳定
延迟极敏感
reranker 会增加额外推理时间
成本极敏感
API rerank 或 GPU rerank 都有成本
已有高质量领域 embedding
如果评测显示 top_n 命中率足够高,可先不上
RAGFlow 文档也明确提醒,使用 rerank model 会显著增加系统响应时间;它的 FAQ 中也把“留空 Rerank model”作为降低响应时间的手段之一。(RAGFlow)

9. 工程参数怎么取?

9.1 推荐的两阶段参数

参数
常见取值
说明
retriever_top_k
30 - 200
第一阶段召回候选,偏 recall
rerank_top_n
3 - 10
最终给 LLM 的 chunk 数
chunk_size
300 - 1000 tokens
太短缺上下文,太长影响 rerank 精度和速度
reranker_batch_size
8 - 32
GPU/CPU 资源决定
score_threshold
按评测定
不同 reranker 分数不可盲目跨模型比较
timeout
必设
防止 rerank 模型拖垮主链路
一个比较稳妥的生产默认值:
Haystack 文档建议,当 Ranker 跟 Retriever 一起使用时,可以让 Retriever 的 top_k 小一些,以减少 Ranker 处理的文档量。RAGFlow 源码里也能看到启用外部 reranker 时会限制候选数量,避免对过多候选调用 rerank。(docs.haystack.deepset.ai)

10. 一个完整的 RAG + rerank 代码骨架

下面是一个接近真实工程的抽象版本:
关键点不是“有没有相似度”,而是不同阶段的相似度承担不同职责:
dense score:负责从海量 chunk 中快速找候选。
sparse score:负责关键词、专有名词、编号、错误码等字面匹配。
rerank score:负责 query 与 chunk 的精确语义匹配。
final score:可以融合业务权重、时间、权限、文档质量、点击反馈等信号。

11. 常见误区

误区一:reranker 会提升召回率

严格来说,reranker 不能找回第一阶段没有召回的文档
如果正确 chunk 没有进入 candidate_top_k,reranker 再强也没用。所以第一阶段 top_k 不能太小,embedding、chunking、hybrid search 仍然很重要。

误区二:reranker 分数可以直接当概率

很多 reranker 输出的是 logit 或模型内部相关性分数,不一定是 0 到 1 的概率。SentenceTransformers 文档也提醒,部分 MS MARCO 模型返回 logits;可以用 Sigmoid 得到 0 到 1 的分数,但这不影响排序。(SentenceTransformers)
工程上更稳妥的做法是:
同一模型内部比较排序。
不同模型不要直接比较绝对分数。
threshold 必须通过验证集调参。
线上变更 reranker 后要重新校准阈值。

误区三:reranker top_n 越大越好

reranker top_n 变大,LLM 拿到的上下文更多,但也可能引入噪声。RAG 的目标不是“塞最多材料”,而是“塞最能支持答案的证据”。

误区四:用了 reranker 就不需要优化 embedding

reranker 只能重排候选,不能替代召回。一个健康的 RAG 系统应该同时优化:
chunk 策略
embedding 模型
hybrid retrieval
query rewrite
metadata filter
rerank
answer grounding
evaluation

12. 如何评估 reranker 是否真的有用?

不要只看主观感觉,建议至少做三类评测。

12.1 Retrieval 指标

指标
关注点
Recall@K
正确 chunk 是否进入候选集
MRR
正确 chunk 排得是否足够靠前
NDCG@K
多个相关 chunk 的排序质量
Hit@K
top K 是否命中答案证据
reranker 主要应该提升 MRR、NDCG@K、Hit@small K,例如 Hit@3、Hit@5。

12.2 RAG 生成指标

指标
关注点
Faithfulness
答案是否被上下文支持
Answer Relevance
答案是否回答问题
Context Precision
提供给 LLM 的上下文是否精确
Context Recall
上下文是否覆盖答案所需证据
如果 reranker 有效,通常会看到 Context Precision 和 Faithfulness 上升。

12.3 线上指标

指标
关注点
用户追问率
答得不准时用户会继续追问
引用点击率
用户是否点击引用来源
答案采纳率
用户是否接受答案
延迟 P95/P99
rerank 是否拖慢系统
token 成本
top_n 减少后是否降低上下文成本

13. 生产系统里的推荐架构

推荐策略:
第一阶段用 hybrid retrieval 保证候选覆盖。
第二阶段用 cross-encoder reranker 提升排序精度。
第三阶段用 context builder 控制上下文长度和结构。
第四阶段用引用、证据检查、拒答策略降低幻觉。

14. 最后总结

在 RAG 中,向量检索已经计算了相似度,但这个相似度主要是为了 快速召回候选,不是为了完成最终精排。
向量检索解决的是:
从百万级 chunk 中快速找到可能相关的几十个。
交叉编码器重排解决的是:
在这几十个候选中判断谁真的能回答当前问题。
二者的关系不是替代,而是分工:
所以,成熟 RAG 系统一般不会问“有了向量相似度还要不要 rerank”,而会问:
第一阶段应该召回多少候选?
reranker 应该处理多少候选?
最终给 LLM 几个 chunk?
延迟和精度之间如何平衡?
是否通过评测证明 rerank 带来了收益?
这也是 LangChain、LlamaIndex、Haystack、RAGFlow 等项目都把 reranker 放在 retriever 后面的原因:RAG 的质量,往往不取决于你有没有检索到相似内容,而取决于你有没有把真正有证据价值的内容排到最前面。
回到首页