什么是 RAG 重排序(Rerank)?为什么检索之后还要重排序?


一则或许对你有用的小广告

欢迎加入小哈的星球,你将获得:专属的实战项目(4个项目都能学) / 1v1 提问 / 简历修改 / Java 学习路线 / 社群讨论 / 学习打卡 / 每月赠书

  • 《Spring AI 项目实战(问答机器人、RAG 智能客服、联网搜索)》已完结,基于 Spring AI + Spring Boot 3.x + JDK 21...查看介绍

  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...查看介绍;演示链接:http://116.62.199.48:7070/

  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接:http://116.62.199.48/

  • 新开坑项目:《从零手撸:秒杀系统高并发优化实战》 正在更新中...,查看介绍

截止目前,星球内专栏累计输出 150w+ 字,讲解图 5110+ 张,还在持续爆肝中.. 后续还会上新更多项目,已有 4700+ 小伙伴加入学习,欢迎点击围观

面试考察点

  1. 检索精度意识:面试官不仅仅是想知道 Rerank 是什么,更是想确认你理解向量检索(Bi-Encoder)天然存在的精度天花板,知道 "检索 Top-K 结果" 不等于 "Top-K 都相关"。
  2. 原理深度:你能不能解释清楚 Bi-Encoder 和 Cross-Encoder 的架构差异?为什么 Cross-Encoder 能做更精准的语义匹配?
  3. 工程实践:有没有实际接入过 Rerank 模型?选型依据是什么?对延迟和成本的影响你有没有考虑过?

核心答案

Rerank(重排序)就是在初次检索之后,用一个更 "精细" 的模型对候选文档重新打分排序,把真正相关的结果提到最前面。

为啥要这么做?因为 RAG 系统中常用的向量检索(基于 Bi-Encoder)虽然快,但精度有限。它只能做 "粗筛",返回的 Top-K 结果里经常混入一些看着像、实际不相关的文档。如果直接把这些文档丢给大模型,轻则回答跑偏,重则产生幻觉。

加了 Rerank 之后,一般能把检索准确率提升 15%-30%,这在生产环境里是非常显著的提升。

用一个表格快速对比检索和重排序的关系:

维度 初次检索(Bi-Encoder) 重排序(Cross-Encoder)
速度 快(毫秒级) 较慢(百毫秒级)
精度 中等
处理范围 全量文档库(百万级) 候选集(几十条)
计算方式 Query 和 Doc 分别编码 Query 和 Doc 拼接联合编码
角色 粗筛(召回) 精排

工业标准实践:向量检索粗排 Top-40 → Cross-Encoder 精排 Top-3 → 喂给 LLM。

深度解析

一、为什么向量检索不够用?

向量检索用的是 Bi-Encoder(双编码器)架构:把 Query 和 Document 分别通过同一个 Embedding 模型编码成向量,然后用余弦相似度算匹配度。

问题在于——Query 和 Document 是独立编码的,它们之间没有任何交互。模型在编码 Query 的时候完全不知道 Document 长啥样,反过来也一样。这就像两个蒙着眼的人各自描述一个东西,描述完再比对,精准度肯定有限。

具体来说,Bi-Encoder 有几个典型缺陷:

  • 语义鸿沟:Query 通常很短(几个词),Document 很长(几百上千词),两者的语义空间本身就不太对齐
  • 无法捕捉细粒度关系:比如 "不推荐这款手机" 和 "推荐这款手机",Bi-Encoder 可能觉得语义相近,但意思截然相反。Cross-Encoder 能捕捉到否定词、时间限定等细节
  • 多义词消歧能力弱:"苹果" 是水果还是公司?Bi-Encoder 缺乏上下文,很难准确区分

但 Bi-Encoder 的优势也很明显——。因为 Document 向量可以预计算存储,检索时只需要算一次 Query 向量再做相似度查找,适合在全量文档库中快速召回候选。

所以思路就清晰了:用 Bi-Encoder 做快速粗筛,再用 Cross-Encoder 做精准重排,两阶段各取所长。

二、Rerank 的核心原理:Cross-Encoder

Bi-Encoder 与 Cross-Encoder 架构对比
Bi-Encoder 与 Cross-Encoder 架构对比

上图展示了两种编码器的核心差异,下面展开说:

  • Bi-Encoder:Query 和 Document 分别通过同一个 Encoder 产出向量,然后用余弦相似度算匹配度。因为 Document 向量可以预计算并存入向量库,检索时只需编码 Query 一次,所以速度极快,适合在百万级文档中做粗筛。但代价是精度有限——两边独立编码,缺乏细粒度的语义交互。

  • Cross-Encoder:把 Query 和 Document 拼接在一起([CLS] Query [SEP] Document),作为一个整体送进 Transformer 做联合编码。注意力机制能让 Query 中的每个词和 Document 中的每个词充分交互,所以精度远高于 Bi-Encoder。但每对 (Query, Doc) 都要做一次完整的前向传播,计算量大,不适合全量检索,只适合对少量候选做精排。

关键点:Cross-Encoder 的优势在于 "Attention"——Query 的每个 Token 都能 attend to Document 的每个 Token,捕捉到 Bi-Encoder 根本看不到的细粒度匹配模式。比如它能识别 "这款手机推荐" 里的否定词,而 Bi-Encoder 很可能把这句话和 "推荐这款手机" 打成差不多的相似度。

三、主流 Rerank 模型选型

截至 2025-2026 年,主流的 Rerank 模型/服务有这几个:

模型/服务 部署方式 特点 适用场景
Cohere Rerank API(云端) 性能领先,支持 100+ 语言,接入最简单 快速集成,多语言场景
BGE-Reranker(BAAI) 本地部署 / API 开源,中英文表现好,社区活跃 私有化部署,数据敏感场景
Jina Reranker v3 本地部署 / API 0.6B 参数轻量高效,架构创新 资源受限场景
Voyage AI API(云端) 高精度,LangChain4j 原生支持 海外业务
阿里云 qwen3-rerank API(云端) 中文优化,Spring AI Alibaba 生态 国内阿里云用户
智谱 AI Rerank API(云端) 中文场景优化 国内业务

选型建议:如果数据安全要求高、需要私有化部署,选 BGE-Reranker;如果追求接入速度和效果,选 Cohere Rerank;如果在国内用阿里云全家桶,选 qwen3-rerank

四、代码实战

方式一:LangChain4j 实现 Rerank

LangChain4j 对 Rerank 有比较好的原生支持,通过 ScoringModel 接口 + ReRankingContentAggregator 来实现:

// --- Maven 依赖 ---
// <dependency>
//     <groupId>dev.langchain4j</groupId>
//     <artifactId>langchain4j-cohere</artifactId>
//     <version>1.0.0-beta24</version>
// </dependency>

import dev.langchain4j.model.cohere.CohereScoringModel;
import dev.langchain4j.rag.content.aggregator.ReRankingContentAggregator;
import dev.langchain4j.rag.DefaultRetrievalAugmentor;
import dev.langchain4j.service.AiServices;

// 1. 构建 ScoringModel(这里用 Cohere,也可以换 Jina / Voyage AI)
CohereScoringModel scoringModel = CohereScoringModel.builder()
    .apiKey(System.getenv("COHERE_API_KEY"))
    .modelName("rerank-v3.5")
    .build();

// 2. 构建重排序聚合器
ReRankingContentAggregator contentAggregator = ReRankingContentAggregator.builder()
    .scoringModel(scoringModel)
    // 可选:设置重排后保留的 Top-K 数量
    .maxSelectedResults(3)
    .build();

// 3. 构建 RAG 增强器
DefaultRetrievalAugmentor retrievalAugmentor = DefaultRetrievalAugmentor.builder()
    .contentRetriever(vectorStoreRetriever)  // 向量检索器(粗筛)
    .contentAggregator(contentAggregator)     // 重排序聚合器(精排)
    .build();

// 4. 构建 AI 服务
Assistant assistant = AiServices.builder(Assistant.class)
    .chatLanguageModel(chatModel)
    .retrievalAugmentor(retrievalAugmentor)
    .build();

LangChain4j 的设计很优雅——ScoringModel 是一个统一接口,底层可以插拔 Cohere、Jina、Voyage AI 等不同供应商,核心代码不用改。

方式二:Spring AI 自定义 Rerank Advisor

截至 2026 年中,Spring AI 还没有内置的 Rerank 模块(社区在 GitHub Issue #4343 推进中),但可以通过自定义 Advisor 来实现:

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.ChatClientRequestSpec;
import org.springframework.ai.chat.client.advisor.api.*;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.web.client.RestTemplate;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 自定义 Rerank Advisor
 * 在向量检索之后,调用 Rerank API 对结果重新排序
 */
public class RerankAdvisor implements CallAroundAdvisor {

    private final VectorStore vectorStore;
    private final RestTemplate restTemplate;
    private final String rerankApiUrl;
    private final int topK;           // 初始检索数量
    private final int rerankTopN;     // 重排后保留数量

    public RerankAdvisor(VectorStore vectorStore, String rerankApiUrl,
                         int topK, int rerankTopN) {
        this.vectorStore = vectorStore;
        this.restTemplate = new RestTemplate();
        this.rerankApiUrl = rerankApiUrl;
        this.topK = topK;
        this.rerankTopN = rerankTopN;
    }

    @Override
    public AdvisedResponse aroundCall(AdvisedRequest request, CallAroundAdvisorChain chain) {
        String userQuery = request.userText();

        // 第一步:向量检索,多召回一些候选(粗筛)
        // 比如 topK=40,为后续重排序留足空间
        List<Document> candidates = vectorStore.similaritySearch(
            SearchRequest.builder()
                .query(userQuery)
                .topK(topK)
                .build()
        );

        // 第二步:调用 Rerank API 进行精排
        List<Document> reranked = rerank(userQuery, candidates);

        // 第三步:取重排后的 Top-N 结果,拼装到 Prompt 中
        String context = reranked.stream()
            .limit(rerankTopN)
            .map(doc -> doc.getText())
            .collect(Collectors.joining("\n\n"));

        // 将上下文注入到用户消息中
        String enhancedQuery = "基于以下参考资料回答问题:\n\n"
            + context + "\n\n问题:" + userQuery;

        AdvisedRequest newRequest = AdvisedRequest.from(request)
            .withUserText(enhancedQuery)
            .build();

        return chain.nextAroundCall(newRequest);
    }

    /**
     * 调用外部 Rerank API(如 Cohere / 阿里云 qwen3-rerank)
     */
    private List<Document> rerank(String query, List<Document> candidates) {
        // 构建请求体(以 Cohere Rerank API 为例)
        Map<String, Object> requestBody = Map.of(
            "query", query,
            "documents", candidates.stream()
                .map(Document::getText)
                .toList(),
            "top_n", rerankTopN,
            "model", "rerank-v3.5"
        );

        // 调用 API 并解析返回的重排序结果
        Map<String, Object> response = restTemplate.postForObject(
            rerankApiUrl, requestBody, Map.class
        );

        // 按 relevance_score 降序排列,返回重排后的文档列表
        // ...解析逻辑省略...
        return candidates; // 简化示例
    }

    @Override
    public String getName() {
        return "RerankAdvisor";
    }

    @Override
    public int getOrder() {
        return 100; // 确保在检索 Advisor 之后执行
    }
}

然后在 ChatClient 里注册这个 Advisor:

ChatClient chatClient = ChatClient.builder(chatModel)
    .defaultAdvisors(
        new RerankAdvisor(vectorStore,
            "https://api.cohere.com/v2/rerank",
            40,   // 粗筛 Top-40
            3     // 精排后取 Top-3
        )
    )
    .build();

五、生产环境的坑和最佳实践

聊几个我在实际项目中踩过的坑:

1. 粗筛数量要留余量

粗筛 Top-K 不要设太小。如果只检索 5 条再做 Rerank,那 Rerank 能做的优化空间非常有限。建议粗筛 20-50 条,再精排到 3-5 条喂给 LLM。

2. 延迟权衡

Rerank 会增加一次额外的模型调用,延迟大概 50-200ms。对于实时性要求高的场景(如客服对话),需要权衡精度和延迟。可以考虑:

  • 用轻量级 Rerank 模型(如 Jina Reranker v3,0.6B 参数)
  • 减少粗筛候选数
  • 用 GPU 部署本地 Rerank 模型,避免网络开销

3. Rerank 不是万能药

如果 Embedding 模型本身就很拉胯,或者 Chunk 切分策略有问题,Rerank 也救不了。先把地基打好(好的 Embedding + 合理的 Chunk),再加 Rerank 才是锦上添花。

4. 混合检索 + Rerank 效果最佳

单独的向量检索容易漏掉精确匹配的关键词(比如产品型号、专有名词)。生产环境推荐 Hybrid Search(向量检索 + 关键词检索如 BM25),把两路结果合并后一起做 Rerank。业界数据显示,混合检索 + Rerank 的组合能减少约 25% 的 Token 用量和成本。

面试高频追问

  1. Rerank 模型和 Embedding 模型有什么区别?

    Embedding 模型(Bi-Encoder)负责把文本编码成向量,用于快速检索;Rerank 模型(Cross-Encoder)负责对候选结果做精细化的相关性评分。两者是 RAG 流水线中不同阶段的组件,互补关系。

  2. 能不能用 LLM 做重排序?

    可以,但成本高、延迟大。LLM Reranker(如让 GPT-4 判断相关性)灵活度更高,能理解复杂语义,但每条文档都要消耗大量 Token。适合离线评估或对精度要求极高的场景,不适合在线实时服务。Cross-Encoder 是更好的在线选择。

  3. Rerank 对 RAG 效果的提升有多大?

    普遍能提升 15%-30% 的检索准确率(NDCG、MRR 指标)。具体效果取决于 Embedding 模型质量和候选文档分布。如果初次检索已经很好,Rerank 的边际收益会减小;但如果初次检索噪声大,Rerank 的提升会非常明显。

常见面试变体

  • "RAG 系统中,为什么两阶段检索(粗筛 + 精排)比单阶段检索效果好?"
  • "Bi-Encoder 和 Cross-Encoder 有什么区别?各适合什么场景?"
  • "你在项目中是怎么做 Rerank 的?选的哪个模型?为什么?"
  • "除了 Cross-Encoder,还有哪些重排序策略?"

记忆口诀

Rerank 核心就三句话:Bi-Encoder 快但粗(各编各的,缺交互),Cross-Encoder 精但慢(拼在一起,充分交互),工业实践 = 粗筛 Top-40 + 精排 Top-3。

总结

Rerank 的本质是用 Cross-Encoder 对 Bi-Encoder 的检索结果做精细化二次排序,弥补向量检索精度不足的问题。面试中重点讲清 "为什么需要"(Bi-Encoder 的精度天花板)、"怎么做"(Cross-Encoder 的联合编码原理)、"怎么选"(主流模型对比)这三个层面,基本就能拿高分。