高级 12 分钟优化

为其添加一个 reranker pipeline

直接回答

重排序器是一种交叉编码器,会重新评估每个问题与段落的配对,并对向量检索返回的候选段落重新排序:先广泛检索,获取 20 到 100 个段落,再保留最好的 3 到 5 个供模型使用。对于法语,BAAI/bge-reranker-v2-m3(采用 Apache 2.0 许可证,约 5.68 亿参数)是最简单的入门选择,可在本地 GPU 上运行;如果处理量不大,甚至可以在 CPU 上运行。

嵌入向量检索能找到与问题相近的段落,但这些段落不一定能回答问题。重排序器通过一次计算共同评估每个问题与段落的组合,从而修正这一缺陷。本指南将说明在什么情况下它值得付出相应成本、针对法语应选择哪个模型、如何用三十行代码将其接入,以及如何用您自己的文档验证它是否真正改善了结果。

作者: Mohamed Meguedmi·更新于 2026-09-30·已在 Windows、macOS 和 Linux 上测试

#重排序器:它在 RAG 流程中有什么作用

一个重排序器接收问题和一段文本,将二者一起处理并输出相关性分数;随后按分数从高到低对候选段落进行排序,仅将得分最高的段落传递给语言模型。在本地RAG流程中,重排序器被插入到向量数据库(如ChromaDB、Qdrant、Weaviate)和语言模型之间:向量检索例如会返回30个段落,重排序器从中筛选出5个。BAAI官方文档中描述:与嵌入模型不同,重排序器接收问题和文档作为输入,直接输出相似度分数,而非生成向量。当正确答案存在于候选段落中但未排在首位时,效果最为明显:一些涉及正确主题但未准确回答具体问题的段落会占据前几位,导致语言模型生成偏离或虚构的回答。如果正确答案不在候选段落中,重排序器无能为力:它不进行搜索,仅负责排序。

嵌入处理会为每个文档生成一个向量,与所提问题无关,而距离衡量的是主题上的整体接近程度。因此,两个涉及相同主题的段落可能获得相近的分数,即使只有其中一个包含答案。交叉编码器会查看完整的问题与段落配对:它会判断所询问的日期、名称或条件是否出现在段落中。这种局部判断更精确,但计算成本也更高,因为每个问题与段落配对都需要经过一次 transformer 计算,而不是每个文档只计算一次。

i
隐喻
嵌入就像一位图书管理员,带您走到正确的书架前,递给您二十本书。重排序器则像一位专家,带着您的问题翻阅这二十本书,再把能回答问题的三本放到最上面。

#双编码器与交叉编码器:为何要结合使用

本地 RAG 工具包

你的文档,你的 AI:基于你的 PDF、笔记和邮件的可靠本地 RAG——无需向云端发送任何内容。

  • 在线空间,终身可用
  • PDF + 文件
  • 30 天内退款
双编码器(嵌入)
分别对问题和每个文档进行编码;文档向量在建立索引时只需计算一次,检索时只需比较向量。速度快,适用于数百万个文本片段。
交叉编码器(重排序器)
将问题和段落一起编码,并输出一个分数。任何计算都无法复用:每个问题与每个候选段落的组合都必须重新计算。精度高,但无法应用于整个语料库。

Sentence Transformers 的文档说明了这一思路:评估数千或数百万个配对会比较慢,因此先用检索器生成一组候选结果,例如一百个,再由交叉编码器重新排序。这种两阶段架构与传统搜索引擎相同。它也解释了主要参数的作用:检索到的候选数量同时影响召回率(检索范围越大,就越有可能包含正确答案)和延迟(每增加一个候选,都需要交叉编码器再处理一次)。

#用于法语的重排序模型该选哪一个?

选择取决于三个标准:语言、许可证和内存。下方的大小数据来自 Hugging Face 模型页面;请注意,文件大小取决于权重精度:bge-reranker-v2-m3 使用 F32(每个参数约 4 字节),mxbai 使用 F16。

可在本地使用的重排序器(Hugging Face 模型卡,2026 年 9 月)
模型语言标称规模许可证法语适用性结论
BAAI/bge-reranker-v2-m3多语言0.6B 参数,F32 权重(约 2.3 GB)Apache 2.0默认选择:支持多语言、轻量、配套工具完善
BAAI/bge-reranker-v2-gemma多语言30亿参数,浮点32位精度(约10GB)Apache 2.0仅适用于要求较高且配备专用 GPU 的场景;基于 Gemma-2B 的重排序模型
mixedbread-ai/mxbai-rerank-large-v1英语0.4B 参数,F16 权重Apache 2.0不建议用于法语语料库:模型卡注明的语言是英语
Cohere Rerank多语言托管服务商业不适用于 100% 本地运行的处理流程:文本片段会离开您的机器

bge-reranker-v2-m3 的模型说明将其介绍为轻量级重排序模型,具备强大的多语言能力,易于部署且推理速度快;bge-reranker-v2-gemma 的模型说明则将其定位于多语言场景,并称其在英语和多语言任务中均有良好表现。针对常见说法,有两点值得纠正:bge-reranker-v2-m3 的文件大小超过 2 GB,并非 560 MB(5.68 亿参数,F32 格式);mxbai-rerank-large-v1 则是英语模型,不应选用于法语文档。以半精度加载后,m3 模型的权重约占用 1.1 GB(5.68 亿参数 × 2 字节,由本指南计算),还需加上所处理批次的激活值占用。

→
嵌入模型和重排序模型相互独立
您可以更换其中一个,而无需为另一个重新建立索引:reranker 仅读取文本片段,从不读取它们的向量。选择嵌入模型时,请参阅专门介绍法语嵌入模型的指南。

#添加重排序器前后的处理流程

前后对比
AVANT :
  Question → Embedding → Base vectorielle (top-5) → LLM

APRÈS :
  Question → Embedding → Base vectorielle (top-20 à top-50)
                       → Reranker (top-5) → LLM

On récupère large, puis on ordonne finement.

两个参数控制整个流程:k_retrieve 是向量数据库返回的候选数量,k_final 是传递给 LLM 的文本片段数量。对于大多数 70 亿至 140 亿参数的本地模型,k_final 设为 3 到 5 即可;再增加只会占用上下文窗口,无法带来净收益,还会增加提示词处理时间。k_retrieve 取决于语料库的难度:20 是一个不错的初始尝试;如果问题比较模糊,或语料库包含大量内容相近的文本片段,可以设为 50 到 100。上下文窗口指南详细说明了在提示词中增加文本片段的成本。

#实现方式:sentence-transformers、FlagEmbedding、llama.cpp

#使用 sentence-transformers

CrossEncoder 类加载模型并评估文本对。其 rank 方法直接接受问题和文档列表,并返回排名最靠前的文档;top_k 参数限制结果数量(不设置该参数时,会返回所有文档)。

CrossEncoder.rank
from sentence_transformers import CrossEncoder

reranker = CrossEncoder("BAAI/bge-reranker-v2-m3", max_length=512)

def retrieve_and_rerank(question, k_retrieve=20, k_final=5):
    # 1. Récupération par embedding (ChromaDB, Qdrant, etc.)
    candidats = embedding_search(question, top_k=k_retrieve)  # liste de textes

    # 2. Scoring par le cross-encoder, tri et coupe en une seule étape
    resultats = reranker.rank(question, candidats, top_k=k_final, batch_size=16)
    # resultats = [{'corpus_id': 3, 'score': 0.91}, ...]
    return [candidats[r['corpus_id']] for r in resultats]

#使用模型作者开发的库 FlagEmbedding

模型说明中使用了 FlagEmbedding 库。该说明指出,设置 normalize=True 后,可通过 sigmoid 函数将原始分数映射到 0 到 1 之间;设置 use_fp16=True 则可加快计算,但会略微降低质量。请记住,原始分数没有绝对标尺,不相关段落的分数通常为负;除非您设置了阈值,否则只需关注排序。

FlagReranker
from FlagEmbedding import FlagReranker

reranker = FlagReranker('BAAI/bge-reranker-v2-m3', use_fp16=True)
score = reranker.compute_score(['ma question', 'un passage'], normalize=True)  # entre 0 et 1

#使用 llama.cpp,无需 Python

llama.cpp服务器提供了一个可选的reranking接口,但默认是关闭的。文档指出该接口需要一个reranking模型,以bge-reranker-v2-m3为例,并通过--embedding和--pooling rank选项启用。模型需为GGUF格式。如果您的系统已基于llama.cpp构建,且希望避免安装PyTorch,此选项值得采用。请检查已安装版本中的确切选项:文档提醒该接口可能随版本更新而变化。

llama-server(请根据您的版本进行调整)
llama-server -m bge-reranker-v2-m3-Q8_0.gguf --embedding --pooling rank --reranking --port 8081

#使用 LlamaIndex

SentenceTransformerRerank
from llama_index.core.postprocessor import SentenceTransformerRerank

reranker = SentenceTransformerRerank(model="BAAI/bge-reranker-v2-m3", top_n=5)

query_engine = index.as_query_engine(
    similarity_top_k=20,
    node_postprocessors=[reranker],
)

#代价:延迟、内存、文本片段长度

任何延迟数值都无法保证:延迟取决于显卡、精度(FP16 或 FP32)、候选数量以及文本段落长度。请记住这些比例关系。重排序时间随配对数量线性增长:候选数量从 20 增加到 100,工作量会变为原来的五倍。文本段落越长,重排序时间也越长,因为每个配对都会被完整编码。请在自己的机器上使用自己的文本段落进行测量,而不是依赖博客中的数值:对一百次真实请求进行计时,查看耗时的中位数和最坏情况。

候选数量
首要调节项。从 20 开始,测量召回率;只有仍有好的答案未进入候选集时,才增加到 50。
精度
使用 use_fp16=True(FlagEmbedding)或以半精度加载,可减少内存占用并加快计算,但据模型说明,会伴随轻微的性能下降。
批处理大小
sentence-transformers的rank方法默认每批处理32个文本对。如果内存不足,将批量大小降至8或16;如果GPU利用率偏低,则增大批量大小。
最大长度
每对输入最多 512 个 token(官方示例中的 max_length 值)。更长的文本段落会被截断:如果您的分块超过这个长度,段落末尾就不会被读取。在提高上限之前,请先缩短分块。
CPU或GPU
重排序器可以在CPU上运行,但每次对20到50个候选结果进行重排序都需要数秒;对于内部文档助手,这样的延迟可以接受,但对于交互式聊天就不那么合适了。
→
不需要时跳过 reranker
对于规模较小且整理干净的语料库(几十页经过合理切分的内容),向量检索的前 5 个结果通常已经包含答案。先进行评估,只有召回率提高时才保留重排序器。

#重排序器与分块:两项设置相互影响

交叉编码器会评估整个文本段落。如果一个段落混合了三个主题,它针对这三个相应问题的得分都会处于中等水平;如果段落过短,就会丢失有助于将其识别为答案的上下文。将文本切分为长度适中、略有重叠的片段,可以为重排序器提供足够的内容,同时不超过其最大长度限制。如果您更改片段大小,请重新进行召回测试:最佳 k_retrieve 值和重排序器带来的提升都会随之变化。分块策略指南详细介绍了这些选择。

另一个相互配合的环节是混合检索。将关键词检索(BM25)与向量检索的结果合并后,候选集会更加多样,让重排序模型更有机会找到两种方法单独使用时都会漏掉的好答案。重排序是最后一层,混合检索是第二层:两者相互补充,而不是相互替代。

#测量在文档上的性能提升

博客中宣称的提升幅度因语料库而异,从一倍到五倍不等,任何通用数值都不能直接套用于您的语料库。对于结构非常清晰的语料库(整理良好的技术文档),仅使用向量检索就已经有不错的效果;对于噪声较多的语料库(电子邮件、笔记、提取质量较差的 PDF),差距则更明显。只有进行评估,才能知道实际效果。

  1. 01
    整理 30 到 50 个问题
    使用真实的用户问题,并为每个问题指定包含答案的文本片段(提供一个标识符即可)。
  2. 02
    在不重排序的情况下测量召回率 5
    对于每个问题,检查向量数据库返回的前 5 个结果中是否包含正确的段落。
  3. 03
    使用 reranker 测量召回率 @5
    获取 20 个候选结果,重新排序,再次统计前 5 个结果中相关段落的数量。
  4. 04
    也需比较延迟
    记录端到端耗时的中位数。召回率提高几个百分点,并不一定值得额外等待一秒。
  5. 05
    查看失败案例
    对于每一条未正确回答的问题,请检查正确答案是否在前 20 个候选中。若不在,则问题出在上游环节:分块、嵌入或文本提取。
评估召回率
def rappel_a_k(pipeline, questions, cibles, k=5):
    ok = 0
    for q, cible in zip(questions, cibles):
        ok += cible in [p.id for p in pipeline(q)[:k]]
    return ok / len(questions)

sans = rappel_a_k(pipeline_sans_reranker, questions, cibles)
avec = rappel_a_k(pipeline_avec_reranker, questions, cibles)
print(f"Sans : {sans:.0%}   Avec : {avec:.0%}")
!
重排序器的局限性
它无法修正从 PDF 中提取不当的文本、把答案拆成两半的分块方式,也无法消除问题本身的歧义。它还可能让一些短片段处于不利位置:这些片段虽然包含正确的数字,得分却很低。因此,请检查失败案例,而不要依赖平均值。

#是否需要重排序器?决策依据

何时添加 reranker
情况决策
几十份干净文档组成的语料库,top-5向量检索已表现良好不,先测量一下
正确答案往往排在第 6 至第 30 位是的:这就是典型的使用场景
问题模糊,语料库噪声较多或内容差异很大是的,候选数量为 30 到 50 个
无 GPU 设备的交互式聊天谨慎处理:测量在 CPU 上运行时的延迟,将候选数量减少到 10 至 20 个
前 50 个候选项中都找不到正确答案否:先修正切分、嵌入或提取部分

#关于重排序的常见问题

FAQ
重排序器能否替代向量搜索?+
不。它不会遍历语料库,而是对向量检索提供的几十个候选结果重新排序。如果没有快速的第一阶段检索,就必须对数据库中的每个段落运行重排序器,这会慢得多,难以接受。这两个阶段相互补充:向量检索保证召回率,重排序器则提高排名靠前的结果的精确率。
处理法语文档应选择哪种重排序模型?+
BAAI/bge-reranker-v2-m3 是合理的起点:支持多语言,采用 Apache 2.0 许可证,参数量约为 6 亿,因此在配置不高的显卡上也能使用。避免使用 mxbai-rerank-large-v1,其模型说明标注的语言是英语。bge-reranker-v2-gemma 更庞大,只有当前一个模型无法满足您的问题集需求时,才值得选用。
需要重新排序多少候选结果?+
先从 20 个候选片段开始,保留其中 5 个。如果评估时发现正确答案仍落在这 20 个候选片段之外,就增加到 50 个。每增加一个候选片段,就多一次计算,因此延迟大致呈线性增长。超过 100 个后,通常很难再有收益:这往往表明分块或嵌入存在问题。
使用 reranker 是否需要 GPU?+
不一定需要,但 GPU 会有帮助。在 CPU 上,m3 模型可以运行;处理一批候选项的延迟约为一秒或更长,具体取决于机器:需要在您自己的设备上测量。对于内部文档使用场景,这仍然可以接受。若要获得流畅的聊天体验,即使是性能不高的 GPU,或更轻量的模型,也能改变使用感受。
可以将 reranker 与 Ollama 配合使用吗?+
Ollama 提供生成模型和嵌入向量服务,但重排序需要单独进行:可以使用 Python 中的 sentence-transformers 或 FlagEmbedding,也可以使用提供重排序接口的 llama.cpp 服务器。重排序器是一个独立模型,在自己的进程中加载;如果内存允许,它可以与生成模型同时运行。
如何判断重排序器是否真的改善了我的检索结果?+
构建30至50条真实问题并配合预期段落,然后比较前5个结果中启用与不启用reranker的召回率以及中位延迟。在干净的语料库上,差异可能较小;在噪声语料库上,差异则更为明显。随后分析失败案例,以判断问题是否源于上游环节。
这份指南对您有帮助吗?

有反馈、发现了错误,或想补充说明?请告诉我们,让这份指南对每个人都更有帮助。