大模型应用系列:从Ranking到Reranking
1. 引言
在大模型应用蓬勃发展的今天,如何从海量信息中精准、高效地获取所需内容,成为决定系统成败的关键因素之一。无论是检索增强生成(RAG)、智能问答、推荐系统,还是搜索引擎,都离不开一个核心环节——排序(Ranking)。而随着大语言模型(LLM)能力的提升,传统排序方法暴露出诸多不足,由此催生了“重排序(Reranking)”这一概念的广泛落地。本文将从基础概念出发,系统梳理大模型应用中 Ranking 与 Reranking 的原理、技术演进、经典算法、工程实践与未来趋势,力求为读者提供一份接近 2 万字的深度指南。
我们将先回顾信息检索领域经典的排序模型,如 TF-IDF、BM25,然后探讨大模型如何重塑排序技术,引入基于预训练语言模型的密集检索(Dense Retrieval)和重排序。接着,我们会深入分析 Reranking 的多种实现方式,包括交叉编码器、基于 LLM 的排序器(如 RankGPT)、延迟交互模型(如 ColBERT)等,并辅以代码示例和评价指标对比。最后,从工程角度讨论如何构建低延迟、高吞吐的 Reranking 系统,以及该领域的未来发展方向。
2. 信息检索与排序基础
2.1 相关性排序的传统范式
信息检索的核心任务,是根据用户查询(Query)从文档集合中返回最相关的文档列表。排序模型负责为每个候选文档计算一个相关性分数,并按分数降序排列。早在深度学习兴起之前,词袋模型(Bag-of-Words)结合 TF-IDF 及 BM25 等统计学方法,就已经在工业界得到广泛应用。这些方法基于词频和逆文档频率来度量查询与文档的匹配程度,计算简单、可解释性强,但对语义理解几乎无能为力。
TF-IDF(Term Frequency-Inverse Document Frequency)将文档表示为一个向量,每个维度对应一个词项,权重为词频乘以逆文档频率。BM25(Best Matching 25)在此基础上引入了文档长度归一化和对词频饱和曲线的控制,被公认为最有效的概率检索模型之一。其基本公式为:
BM25(Q, D) = Σ IDF(q_i) * ( f(q_i, D) * (k1 + 1) ) / ( f(q_i, D) + k1 * (1 - b + b * (|D| / avgdl)) )
其中 IDF(q_i) 是查询词 q_i 的逆文档频率,f(q_i, D) 是词 q_i 在文档 D 中的词频,|D| 是文档长度,avgdl 是平均文档长度,k1 和 b 是调节参数。尽管 BM25 在很多场景下仍然难以被超越,但其基于精确词匹配的天然缺陷,使得它无法处理同义词、近义表达和复杂语义。
2.2 从稀疏到密集:向量化检索的崛起
随着 Word2Vec、GloVe 等词嵌入技术的出现,以及后来的 ELMo、BERT 等预训练语言模型,检索领域逐渐转向密集向量表示(Dense Representation)。在密集检索中,查询和文档分别被编码为固定维度的向量,通过向量相似度(如余弦相似度、内积)来衡量相关性。这种范式能够捕捉深层次语义,但需要大量的标注数据来训练编码器,同时对计算资源的要求也远高于稀疏检索。
经典的密集检索框架包括 DPR(Dense Passage Retrieval)、ANCE(Approximate Nearest Neighbor Negative Contrastive Estimation)等。它们通常采用双塔模型(dual-encoder):一个塔编码查询,另一个塔编码文档,共享或不共享参数。训练时使用对比学习损失,使正例对(查询-相关文档)的相似度尽量高,负例对的相似度尽量低。这类模型在开放域问答等任务上取得了显著突破,但随之而来的挑战是:如何在召回阶段兼顾效率与效果?这就引出了多阶段排序架构,以及 Reranking 的用武之地。
3. 从 Ranking 到 Reranking:架构演进
3.1 单阶段排序的局限
在早期的搜索系统中,单一排序模型(如 BM25)直接对所有候选文档打分并输出最终排序结果。这种架构简单,但候选文档集合可能非常庞大(例如互联网搜索中数十亿级),若使用复杂的深度模型进行全量排序,延迟将无法接受。因此,工业界通常采用多阶段级联排序(Cascaded Ranking)架构:第一阶段使用轻量级模型快速召回一个较小的候选集(如 Top-1000),第二阶段再使用更复杂的模型对 Top-1000 进行重排序,最终输出 Top-10 或 Top-20 给用户。
在这种架构中,第一阶段的粗排(Ranking)注重召回率,保证相关文档尽可能不被漏掉;第二阶段的精排(Reranking)则注重精确率,利用更丰富的特征和更强大的模型,对候选文档进行精细排序。随着大模型时代的到来,Reranking 的技术手段发生了质的飞跃,预训练语言模型和 LLM 开始大量被用作重排序器。
3.2 Reranking 的核心价值
Reranking 并非简单地将已有结果再排一次,它的核心价值在于:
- 引入更细粒度的语义交互:粗排模型通常采用双塔结构,查询和文档在编码阶段相互独立,仅在最后通过点积或余弦相似度交互,属于“浅层交互”。而 Reranker 可以在查询和文档之间进行深度交叉注意力(Cross-Attention),逐词计算匹配关系,从而捕获更精确的相关性信号。
- 融合多模态特征:Reranking 阶段可以轻松融入文档质量、时效性、用户行为、个性化等信号,而粗排阶段往往受限于速度和架构。
- 与 LLM 结合:可以将整个文档和查询输入 LLM,让模型直接生成排序决策或相关性分数,利用 LLM 的常识推理和复杂指令跟随能力,进一步提升排序质量。
因此,Reranking 在 RAG 系统、企业搜索、电商推荐等场景中扮演着越来越重要的角色。下面我们将深入探讨大模型时代 Ranking 与 Reranking 的具体技术方案。
4. 大模型时代的 Ranking 技术
4.1 基于 BERT 的密集检索:DPR
DPR(Dense Passage Retrieval)由 Facebook AI 提出,是密集检索的里程碑式工作。它使用两个独立的 BERT 编码器,分别将查询和文档段落编码为固定长度的向量,并通过内积计算相似度。训练时,从 Wikipedia 等大规模语料中构建正负例对,负例包括随机负例、BM25 硬负例等。DPR 在多个开放域 QA 数据集上大幅超越了 BM25 和之前的密集检索模型。
DPR 的成功表明,用 BERT 级模型提取的密集向量可以很好地表示语义,但它的缺点也很明显:需要为每个文档预先计算向量并存储,占用大量存储空间;同时,双塔架构缺少查询与文档的细粒度交互,导致在一些需要精确匹配的任务上表现不佳。
4.2 ColBERT:延迟交互的优雅折中
ColBERT(Contextualized Late Interaction over BERT)提出了一种介于双塔和交叉编码器之间的方案——延迟交互(Late Interaction)。它先用 BERT 分别对查询和文档进行编码,得到查询中每个 token 的向量和文档中每个 token 的向量,然后在计算相似度时,对查询中的每个 token 向量找到文档中与之最相似的 token 向量并求和,即 MaxSim 操作。这种设计既保留了 token 级别的细粒度交互,又因为文档向量可以预先计算而支持高效的近似最近邻搜索(ANN),在效果和效率之间取得了很好的平衡。
ColBERT 在 MS MARCO 等数据集上大幅领先当时的双塔模型,并接近交叉编码器的效果,同时推理速度远快于交叉编码器。ColBERTv2 进一步通过蒸馏和压缩技术,将索引大小降低了 10 倍以上,使其更具实用性。
4.3 通用嵌入模型:BGE 系列
BGE(BAAI General Embedding)是北京智源研究院推出的通用文本嵌入模型,其中 BGE-M3 支持多语言、多功能(包括密集检索、稀疏检索和 ColBERT 风格的多向量检索),在 MTEB 等基准上表现优异。BGE 通过大规模预训练、指令微调、对比学习等技术,使得生成的嵌入向量可以胜任多种下游任务,包括检索、聚类、分类等。在 RAG 应用中,BGE 常被用作第一阶段的检索器,为后续的 Reranking 提供高质量的候选集。
使用 BGE 进行检索非常简单,下面是使用 FlagEmbedding 库的示例代码:
from FlagEmbedding import BGEM3FlagModel model = BGEM3FlagModel('BAAI/bge-m3', use_fp16=True) 编码文档 passages = ["文档1内容", "文档2内容", ...] passage_embeddings = model.encode(passages, batch_size=12, max_length=8192)['dense_vecs'] 编码查询 query = "查询内容" query_embedding = model.encode([query], max_length=8192)['dense_vecs'] 计算相似度 import numpy as np scores = np.dot(query_embedding, passage_embeddings.T) top_k = np.argsort(scores[0])[::-1][:10]这样,我们就得到了一个按相关性排序的候选文档列表,接下来就可以交给 Reranker 进行精排。
5. Reranking 技术详解
5.1 交叉编码器(Cross-Encoder)
交叉编码器是 Reranking 中最经典、最有效的方法之一。它将查询和文档拼接成一个序列(如 [CLS] query [SEP] document [SEP]),输入到类似 BERT 的 Transformer 模型中,通过 [CLS] 向量接一个线性层输出相关性分数。因为查询和文档在每一层 Transformer 中都能进行充分的注意力交互,交叉编码器能够捕捉到非常细粒度的语义匹配信息,效果通常显著优于双塔模型。
然而,交叉编码器的计算成本极高——每对查询-文档都需要完整地前向传播一次模型,无法预先计算文档向量。因此,它只能用于 Reranking 阶段,即对粗排返回的 Top-K(通常 K 在几十到几百)文档进行重排序。在工业实践中,常使用基于 BERT-base 或 BERT-large 的交叉编码器,或者使用 DistilBERT 等轻量版本以平衡效果和延迟。
流行的交叉编码器实现包括 SentenceTransformers 库中的 CrossEncoder,以及 BGE-Reranker 系列。BGE-Reranker 基于 BAAI 的通用嵌入模型,通过多阶段训练(预训练、微调、蒸馏)得到,在多个测试集上达到了 SOTA 水平。下面是使用 BGE-Reranker 的示例:
from FlagEmbedding import FlagReranker reranker = FlagReranker('BAAI/bge-reranker-v2-m3', use_fp16=True) 对每个查询-文档对计算分数 query = "什么是大模型" passages = ["大模型是参数规模巨大的神经网络...", "今天天气很好...", ...] scores = reranker.compute_score([[query, p] for p in passages]) 按分数降序排列 ranked_indices = sorted(range(len(scores)), key=lambda i: scores[i], reverse=True)交叉编码器虽然效果好,但对每个候选文档都需要模型推理,当候选集较大时延迟会迅速上升。因此,如何进一步优化推理效率,是工程实践中的重点。
5.2 基于 LLM 的 Reranking:RankGPT 与 LLM-Reranker
随着 GPT-4、Claude 等大语言模型的强大能力,研究者开始探索直接使用 LLM 进行 Reranking。RankGPT 是其中代表性工作,它通过精心设计的提示词,让 LLM 对候选文档列表进行排序。常见做法包括:将查询和候选文档列表输入 LLM,要求模型输出排序后的文档编号或直接输出相关性分数。由于 LLM 具有丰富的世界知识和推理能力,在某些需要复杂语义理解和推理的任务上,基于 LLM 的 Reranking 可以超越传统交叉编码器。
但 LLM 作为 Reranker 也面临诸多挑战:推理速度慢、成本高、上下文长度限制(难以一次性处理大量候选文档)、输出格式不稳定等。为了解决这些问题,研究者提出了滑动窗口(Sliding Window)策略、提示词压缩、以及结合传统交叉编码器的混合方案。此外,还有专门为 Reranking 微调的小型 LLM,如 LLM-Reranker 系列,它们在保持较好效果的同时大幅降低了成本。
下面是一个使用 OpenAI 接口进行 RankGPT 风格排序的示意代码:
import openai def llm_rerank(query, passages, top_n=5): prompt = f"请根据查询对以下文档进行排序,只输出文档编号,按相关性从高到低排列。\n查询:{query}\n\n" for i, p in enumerate(passages): prompt += f"文档 {i}: {p}\n" prompt += "\n输出排序后的文档编号(用逗号分隔):" response = openai.ChatCompletion.create( model="gpt-4", messages=[{"role": "user", "content": prompt}], temperature=0 ) result = response.choices[0].message.content.strip() # 解析编号 ranked_indices = [int(x.strip()) for x in result.split(',')] return ranked_indices[:top_n]需要注意的是,LLM 的输出可能包含非数字字符,鲁棒解析是工程落地时必须考虑的问题。
5.3 ColBERT 作为 Reranker
ColBERT 本身既可以作为第一阶段的检索器(通过 ANN 搜索文档向量),也可以作为 Reranker 使用。在 Reranking 场景中,已经通过粗排获得了 Top-K 候选文档,我们只需要对每个候选文档与查询重新计算 ColBERT 的 MaxSim 分数,然后重新排序即可。由于 ColBERT 的文档向量可以预先计算和存储,Reranking 的计算量相对较小,且效果优于单纯的双塔,接近交叉编码器。ColBERT 在需要兼顾效果和速度的场景下,是一个非常实用的 Reranking 选择。
5.4 训练 Reranker 模型
尽管有大量开箱即用的预训练 Reranker,但在特定垂直领域,微调一个定制化的 Reranker 往往能带来显著提升。训练 Reranker 通常需要构造三元组数据:查询、正例文档、负例文档。负例可以来自随机采样,但更好的做法是使用粗排模型挖掘的“硬负例”(hard negatives),即与查询相关但并非正例的文档,这类样本能有效提升模型区分能力。
以交叉编码器为例,训练时常用的损失函数包括:
- 交叉熵损失:将问题建模为二分类(相关/不相关),或通过 softmax 在多文档间做对比学习。
- Margin Ranking Loss:要求正例分数比负例分数高出一定边缘。
- ListNet / LambdaRank:直接优化排序列表的指标,如 NDCG。
使用 SentenceTransformers 或 HuggingFace Transformers 可以方便地训练 Reranker。下面是一个使用 HuggingFace 训练交叉编码器的简化示例:
from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments from datasets import Dataset 假设已有训练数据:query, positive, negative model_name = "bert-base-uncased" tokenizer = AutoTokenizer.from_pretrained(model_name) model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=1) def preprocess(examples): pos_inputs = tokenizer(examples['query'], examples['positive'], truncation=True, padding=True) neg_inputs = tokenizer(examples['query'], examples['negative'], truncation=True, padding=True) return {'input_ids': pos_inputs['input_ids'], 'attention_mask': pos_inputs['attention_mask'], 'labels': [1]*len(examples['query'])} # 正例标签为1,负例同理 构建数据集,这里仅示意 train_dataset = Dataset.from_dict({'query': queries, 'positive': pos_docs, 'negative': neg_docs}) train_dataset = train_dataset.map(preprocess, batched=True) training_args = TrainingArguments(output_dir="./reranker", num_train_epochs=3, per_device_train_batch_size=8) trainer = Trainer(model=model, args=training_args, train_dataset=train_dataset) trainer.train()实际训练时,通常会将正负例拼接为一个样本,标签为 1 或 0,或者使用对比学习框架。微调后的 Reranker 在特定领域可以大幅提升排序精度。
6. 评价指标与实验设计
6.1 常用排序评价指标
评估 Ranking 和 Reranking 系统性能,需要一系列能够反映排序质量的指标。以下是最常用的几个:
- MRR(Mean Reciprocal Rank):第一个相关文档出现位置的倒数,对多个查询取平均。MRR 越高,说明相关文档排名越靠前。适用于答案唯一的场景,如问答任务。
- MAP(Mean Average Precision):在每个查询的相关文档位置计算精度,然后对所有查询取平均。MAP 考虑了所有相关文档的排名,适用于多相关文档场景。
- NDCG(Normalized Discounted Cumulative Gain):考虑文档的相关性等级(如 0-3 分),并对排名靠前的位置给予更高权重,通过理想排序进行归一化。NDCG 是衡量排序质量的综合指标,广泛应用在搜索和推荐中。
- Recall@k:前 k 个结果中相关文档的比例,侧重于召回能力。在 RAG 中,Recall@k 通常用于评估检索环节是否漏掉了重要文档。
- Precision@k:前 k 个结果中相关文档的占比,侧重于精确率。
在 Reranking 场景中,我们通常关注 Reranking 后 Top-K 结果的 NDCG、MRR 提升,以及相对于粗排的 Recall@k 变化。评估时务必使用独立的测试集,并确保测试集与训练数据无重叠。
6.2 离线评估与在线 A/B 测试
离线评估是模型迭代的基础,但离线指标的提升并不总能转化为线上用户体验的改善。因此,在将新 Reranker 上线前,需要进行在线 A/B 测试,通过真实的用户行为指标(如点击率、转化率、停留时长、任务完成率等)来验证效果。同时,还要关注延迟、资源消耗等工程指标,确保系统在高压下依然稳定。
7. 工程实践:构建高效 Reranking 系统
7.1 延迟与吞吐量优化
Reranking 阶段的延迟直接影响用户体验,特别是在实时交互场景中。优化手段包括:
- 模型量化与蒸馏:使用 INT8 量化或模型蒸馏技术,将交叉编码器从 BERT-large 压缩为更小的模型,显著降低推理时间。
- 批量推理:将多个查询-文档对组成 batch 同时推理,充分利用 GPU 并行能力。
- 缓存机制:对于高频查询,可以缓存 Reranking 结果或中间向量,避免重复计算。
- 异步流水线:将检索、Reranking、生成等环节设计为异步流水线,隐藏延迟。
- 模型服务框架:使用 Triton Inference Server、TorchServe、或者 vLLM 等高性能推理框架部署模型,并开启动态批处理。
例如,使用 Triton Server 部署 BGE-Reranker 可以轻松支持上千 QPS 的并发请求,延迟控制在 10ms 以内。下面是一个简单的 Triton 配置示例:
# config.pbtxt name: "bge_reranker" platform: "python" max_batch_size: 64 input: [ { name: "INPUT_TEXT", data_type: TYPE_STRING, dims: [-1] } ] output: [ { name: "SCORE", data_type: TYPE_FP32, dims: [-1] } ]实际部署时,还需要编写 Python backend 实现模型加载和推理逻辑。
7.2 与向量数据库的集成
在 RAG 系统中,第一阶段的检索通常依赖向量数据库(如 Milvus、Pinecone、Weaviate、Qdrant 等)。向量数据库负责存储文档向量并提供高效的近似最近邻搜索。Reranker 则作为检索后的一个插件式模块,从向量数据库返回的 Top-K 文档中进一步精选。常见的集成方式是将 Reranker 封装为一个独立的微服务,向量数据库检索出的结果通过 HTTP 或 gRPC 调用 Reranker 服务进行重排序,最终返回给下游生成模块。
这种松耦合架构使得我们能够独立升级检索器或 Reranker,也便于进行 A/B 实验和灰度发布。
7.3 容错与降级
在线系统中,Reranker 服务可能因过载、网络等问题而不可用。此时必须设计降级策略,例如直接使用粗排结果,或者退回到一个更轻量级的 Reranker(如 ColBERT)以保证服务可用性。同时,需要监控 Reranker 的延迟、错误率、分数分布等指标,及时发现异常。
8. 未来展望
随着大模型能力的持续进化,Ranking 和 Reranking 领域正在经历深刻变革。以下是一些值得关注的趋势:
- 端到端的生成式检索:传统“检索-重排序-生成”的流水线可能被直接由模型生成答案或文档 ID 的端到端范式取代,例如 Google 的 DSI(Differentiable Search Index)等。但该方向目前仍处于早期,效果和可控性有待提升。
- 多模态 Reranking:未来 Reranker 不仅要处理文本,还要融合图像、表格、代码等多模态信息,实现跨模态的精准排序。
- 个性化与上下文感知:Reranker 将越来越深入地整合用户画像、历史行为、会话上下文,实现千人千面的排序结果。
- 绿色 AI 与效率优化:如何在保证效果的前提下,最大限度降低计算和能源消耗,是 Reranking 技术走向大规模应用必须解决的问题。
- 自动 Reranker 选择与融合:通过元学习或 AutoML 技术,系统可以根据查询类型和候选集特征,自动选择最合适的 Reranker 或融合多个 Reranker 的结果。
9. 总结
本文从信息检索的基础排序模型出发,逐步深入到 Reranking 的技术细节,系统梳理了 Ranking 与 Reranking 在大模型应用中的核心价值、主流算法和工程实践。我们回顾了 BM25、DPR、ColBERT、BGE 等经典 Ranking 方法,详细介绍了交叉编码器、基于 LLM 的排序、ColBERT 重排序等 Reranking 方案,并给出了相应的代码示例和评价指标。
在实际项目中,Ranking 和 Reranking 的选型需要综合考虑效果、延迟、成本、可维护性等因素。随着大模型生态的不断成熟,我们有理由相信,未来的 Reranking 系统将更加智能、高效和个性化,为大模型应用提供更强大的信息筛选能力。
