当 RAG(检索增强生成)应用给出错误答案,即使正确信息就在你的文档里,检索往往是原因。向量搜索擅长找到主题正确的片段,但它常常被近似命中误导,比如用户问的是 Growth 套餐,却拉取了 Enterprise 套餐的存储桶上限。RAG 中的重排序可以解决这个问题:它取向量搜索的前 30 个候选,让它们通过一个专门的交叉编码器模型,该模型会直接针对问题对每个片段重新打分。

在一个 274 个问题的基准测试中,使用 google/gemini-embedding-2 的标准向量搜索将完全正确的片段排在首位,81%的情况下。加入 voyageai/rerank-3-lite 对前 30 个候选进行重排序后,这一比例提升到97%,成本约为每 1,000 次查询 $0.10。请记住,这是在一个小型合成数据集上测试的,所以你的实际收益将取决于你的文档,但下面的工作流程将帮助你测量自己的基线。

TL;DR
检索约 30 个候选,对它们重排序,然后把前 3 个发送给 LLM。
voyageai/rerank-3-lite 和 voyageai/rerank-3 是最准确的专用重排序模型,也是全部 11 个重排序器中最便宜的,分别为每 1,000 次查询 $0.10 和 $0.26。
一个 LLM 重排序器(openai/gpt-6-luna)在 99.6% 的问题中将正确片段排在首位,但每次调用耗时 4.0 秒,而重排序模型为 1.3 秒。
便宜的 voyageai/voyage-4-lite 加上 voyageai/rerank-3-lite 达到了 96.7% 的 precision@1,而更昂贵的 google/gemini-embedding-2 单独使用为 81.0%。
在嵌入调用中设置 input_type。省略它会损失 7 到 12 个百分点的 precision@1。
cohere/rerank-v3.5 只读取文档的前 4,096 个 token(4K),并且不会报错。

为什么 RAG 会检索到错误的片段?

标准向量搜索之所以吃力,是因为嵌入模型在看到用户问题之前,就把整个片段压缩成单个向量。如果一个 130 词的片段解释存储桶上限,具体的套餐名称只是整个块中的一两个词。结果,Starter、Growth、Scale 和 Enterprise 套餐的向量在向量空间中紧密聚集在一起,检索器很容易把错误的套餐排在首位。

为了在不依赖主观评分的情况下测试检索准确率,我们为一个名为 Fernbank 的虚构存储服务构建了一个受控数据集。该语料库包含 274 个文本块,涵盖文档、错误码、SDK 指南、变更日志条目和噪声内容,其中包括旨在诱骗朴素关键词匹配和向量匹配的未回复论坛帖子和支持工单。我们用 anthropic/claude-sonnet-5.5 从一组固定事实生成每个文本块,并用脚本进行了校验。另一个模型 openai/gpt-6.1-sol 负责编写问题。由于每个问题都映射到一个正确的文本块,我们可以在无需主观判断的情况下对检索进行评分。

在完整测试集中,问题是“在 Growth 套餐下,我可以在单个 Fernbank 账户中创建多少个存储桶?”。google/gemini-embedding-2 将 Starter、Enterprise 和 Scale 套餐的文本块分别排在第 1、2、3 位。一个未回复的论坛帖子排在第 4 位,而真正的 Growth 套餐答案排在第 5 位。如果你的 RAG 流水线只把前三个候选发送给 LLM,模型根本看不到正确的文档。

重排序器通过使用交叉编码器架构解决了这个问题。它不是在孤立地评估文档,而是将用户的问题与每个候选文本块一起处理。在数千个文档上运行交叉编码器对于实时查询来说太慢了,因此向量搜索充当快速检索器,在重排序器排序之前将范围缩小到候选短名单。

如何向你的 RAG 流水线添加重排序器

你不需要替换现有的嵌入搜索。将它保留为第一个检索阶段,增加它返回的候选数量,并在将最终结果传给 LLM 之前添加一次重排序调用。

RAG pipeline with a reranker: question, vector search for the top 30 chunks, rerank model, top 3 chunks, LLM answer

用嵌入检索 30 个文本块,对它们重排序,然后将前 3 个发送给 LLM。

以下 Python 示例使用我们的嵌入和重排序 API。它使用余弦相似度检索候选文本块,用 voyageai/rerank-3-lite 对它们重排序,并返回排名最高的三个结果。

你需要一个 OPENROUTER_API_KEY 环境变量,以及安装好的 numpy 和 requests。

Python

importos

importnumpyasnp
importrequests

API="https://openrouter.ai/api/v1"
HEADERS={"Authorization":f"Bearer{os.environ['OPENROUTER_API_KEY']}"}

defembed(texts, input_type, model="google/gemini-embedding-2"):
r=requests.post(f"{API}/embeddings",headers=HEADERS,timeout=120,
json={"model": model,"input": texts,
"input_type": input_type})
r.raise_for_status()
data=sorted(r.json()["data"],key=lambdad: d["index"])
v=np.array([d["embedding"]fordindata])
returnv/np.linalg.norm(v,axis=1,keepdims=True)

defretrieve(question, chunks, chunk_vectors, n=30):
sims=chunk_vectors@embed([question],"search_query")[0]
return[(sims[i], chunks[i])foriinnp.argsort(-sims)[:n]]

defrerank(question, candidates, top_n=3, model="voyageai/rerank-3-lite"):
r=requests.post(f"{API}/rerank",headers=HEADERS,timeout=120,
json={"model": model,"query": question,
"documents": candidates,"top_n": top_n})
r.raise_for_status()
data=r.json()
ranked=[(res["relevance_score"], candidates[res["index"]])
forresindata["results"]]
returnranked, data.get("usage", {}).get("cost")

# Your knowledge base, already split into chunks
chunks=[
"Starter plan limits: an account on the Starter plan can create up to "
"10 buckets.",
"Scale plan limits: accounts on the Scale plan can hold up to "
"2,500 buckets.",
"Enterprise plan limits: Enterprise accounts can create up to "
"40,000 buckets.",
"Growth plan limits: an account on the Growth plan can hold up to "
"150 buckets.",
"Q: What's the bucket cap on the Growth plan? Reply: I think it "
"changed recently, check the docs.",
"Growth plan object size: a single object on the Growth plan can be "
"up to 50 GB.",
]
chunk_vectors=embed(chunks,"search_document")

question=("How many buckets can I create in a single account "
"on the Growth plan?")
retrieved=retrieve(question, chunks, chunk_vectors)
print("Vector search:")
forsim, textinretrieved:
print(f"{sim:.3f}{text[:60]}")

ranked, cost=rerank(question, [textfor_, textinretrieved])
print(f"Reranked (${cost:.7f}):")
forscore, textinranked:
print(f"{score:.3f}{text[:60]}")

Output

Vector search:
0.832 Growth plan limits: an account on the Growth plan can hold u
0.758 Starter plan limits: an account on the Starter plan can crea
0.741 Scale plan limits: accounts on the Scale plan can hold up to
0.737 Enterprise plan limits: Enterprise accounts can create up to
0.717 Growth 计划对象大小:Growth 计划上的单个对象
0.695 问:Growth 计划的上限是多少?回复:我认为
重排序($0.0000038):
0.922 Growth 计划限制:Growth 计划上的账户可以持有 u
0.793 问:Growth 计划的上限是多少?回复:我认为
0.727 Starter 计划限制:Starter 计划上的账户可以创建

对于这些简短的单句片段,向量搜索已经把正确的 Growth 计划限制排在第一位。余弦相似度分数在 0.695 到 0.832 之间,因此有几个候选片段相对接近。重排序后,正确片段获得 0.922 的相关性分数。那个未获解答的论坛帖子以 0.793 的分数升至第二位,排在 Starter 计划条目之前。

第二个结果说明了一个重要局限:相关性并不等同于正确性。该论坛帖子提出了同样的问题,因此重排序器认为它相关,尽管它并没有回答问题。在这个简化示例中,重排序器没有修正第一个结果,因为它本来就是正确的。在完整的基准测试中,使用 130 词的片段时,向量搜索对 19% 的问题把错误片段排在第一位,包括那个 Growth 计划问题,而使用 voyageai/rerank-3-lite 进行重排序修正了其中大部分问题。

实际经验是:向 LLM 提供几个强有力的候选片段,而不是依赖单一结果。你还应考虑过滤掉未获解答的讨论,以及其他提及问题但并未解决该问题的内容。

代码中还有另外两个细节值得正确处理:

  • 第一,input_type 参数告诉嵌入模型它是在编码搜索查询还是文档。有些模型对这两种输入的处理方式不同,因此省略该参数可能会损害检索效果。在我们的测试中,省略它使 Gemini 的 precision@1 从 81.0% 降至 74.1%,使 voyageai/voyage-4-lite 的 precision@1 从 64.6% 降至 52.9%。参见embeddings API 参考文档,该文档将其作为字符串接收,并记录其取值为 search_query 和 search_document。

  • 其次,top_n 控制的是重排序器返回多少条结果,而不是它评估多少条。模型仍然会对你发送的每个候选进行打分,因此候选数量会同时影响成本和延迟。

你如何知道重排序确实有帮助?

重排序器可以改善结果排序,却不一定能改善用户最终收到的答案。要判断是否值得加入它,请在改动前后分别测量检索准确率,然后再评估最终答案。

1. 从 precision@1 开始:即第一个检索到的片段包含正确答案的问题所占的百分比。你不需要一个庞大的评估集就能开始。从应用日志中取 50 个真实问题,每个都标注其正确的答案片段,就能给你一个初始基线。关于从生产流量构建黄金评估数据集的指南解释了如何搭建一个。

2. 不要只依赖 recall@5:它衡量的是正确片段是否出现在前五名中的任意位置,而不论其位置。在我们的测试中,Gemini 达到了 98.2% 的 recall@5,但 precision@1 只有 81.0%。正确的信息通常出现在结果中的某个位置,但并不总是在最前面。

我们还测试了对最终答案的影响。我们使用 anthropic/claude-haiku-5.5,基于每种检索配置返回的片段来回答全部 274 个问题,然后将回答与已知事实进行对比。

发送给 LLM 的片段数答案正确率上下文中包含正确片段
voyage-4-lite 前 5,无重排序93.1%93.1%
gemini-embedding-2 前 5,无重排序97.1%98.2%
gemini-embedding-2 前 3,无重排序95.6%96.0%
gemini-embedding-2 前 30,重排序至 399.3%100%
voyage-4-lite 前 30,重排序至 399.3%99.6%

我们 2026 年 10 月 8 日的运行包含 274 个问题。重排序使用了 voyageai/rerank-3-lite。

结果表明,重排序帮助 LLM 在使用更少片段的情况下正确回答了更多问题。大多数错误答案都源于信息缺失。在正确片段不在前三名的案例中,有十分之九的情况下模型回复称所提供的段落不包含答案。换句话说,应用告诉用户它不知道某件事,而它自己的文档其实能够回答。

重排序通过改进到达模型的文本块解决了这个问题。它还让我们可以只发送三个文本块而不是五个,将 LLM 回答成本从每 1,000 个问题 $0.22 降至 $0.16。重排序调用增加了 $0.10,因此在我们的设置中,重排序每 1,000 个问题净增加成本 $0.04。

重排序是否能为你省钱取决于你的模型、文档大小和查询量,因此要在整个流水线上衡量成本和准确率,从检索一直到最终答案。

哪个重排序模型最适合 RAG?

我们使用 google/gemini-embedding-2 为 274 个问题各自检索出的相同 30 个候选,比较了 11 个重排序模型。这为我们比较它们的准确率、延迟和成本提供了一致的基础。

在我们测试的专用重排序模型中,Voyage 的重排序模型在准确率和价格之间提供了最佳组合。

重排序模型Precision@1中位秒数(我们的设置)每 1,000 次查询的 $ 成本
无(仅嵌入)81.0%不适用不适用
voyageai/rerank-397.8%1.27$0.26
voyageai/rerank-3-lite97.1%1.26$0.10
voyageai/rerank-2.5-lite96.7%1.50$0.10
voyageai/rerank-2.596.4%1.30$0.26
cohere/rerank-4-pro95.3%1.54$2.50
qwen/qwen3-reranker-8b92.3%1.51$1.49
cohere/rerank-4-fast92.0%1.25$2.00
cohere/rerank-v3.590.5%1.47$1.00
openai/gpt-6-luna(LLM)99.6%4.01$0.70
anthropic/claude-haiku-5.5(LLM)98.9%4.44$0.87
google/gemini-3.8-flash(LLM)100%3.25$4.14

我们的运行时间为 2026 年 10 月 8 日。成本是每次响应的使用成本,与 GET /api/v1/generation 一致。每个中位数中约有 0.9 秒是我们测试机器的网络开销。

在这个数据集上,voyageai/rerank-3 有 97.8% 的时间将正确的文本块排在第一位,而 Lite 版本达到 97.1%。这一差异在我们 274 个问题的测试中仅相当于两个问题,因此太小而无法确定更昂贵的模型始终更好。先从 voyageai/rerank-3-lite 开始,并在你自己的评估集上将其与 voyageai/rerank-3 进行比较。两者使用相同的 /rerank 端点,因此切换模型只需更改模型标识符。

价格差异主要反映了提供商的收费方式,详见我们的重排序模型页面Voyage 和 Qwen 按 token 计费(每百万 token 0.02 至 0.20 美元),而 Cohere 按每次搜索最多 100 个文档收费 0.001 至 0.0025 美元,与文档长度无关。由于我们的 30 个候选文档包含约 5,000 个 Voyage token,Voyage 模型显得尤为便宜。在这些短片段上,Cohere 的重排序器成本约为 Voyage 选项的 4 至 25 倍,具体取决于所比较的模型。在我们的测试中,向 Cohere 发送 101 个文档还触发了第二次搜索收费。

对于涉及特定错误码(如 FB-2411)的问题,重排序带来的差异尤为明显。仅靠嵌入搜索时,voyageai/voyage-4-lite 只有 25% 的情况下将正确条目排在首位,google/gemini-embedding-2 为 53.6%。全部 11 个重排序器在该子集上均达到 100%。由于错误码条目往往讨论相似的错误,它们的嵌入可能看起来很相似。交叉编码器可以将问题中的确切错误码与每个候选中的错误码进行比较,从而区分出正确的条目。

如果你想知道开发者最常使用哪些模型,我们的重排序模型排名提供了另一个有用的参考。截至 2026 年 10 月 20 日,voyageai/rerank-2.5 以截至 10 月 18 日当周的 468 万次请求领先,并在我们的测试中得分 96.4%。使用热度值得考虑,但它不应取代针对你自己的文档测试模型。模型性能、价格和提供商延迟都可能变化。重排序模型集合列出了可用的选项及其当前详情。

你应该对多少个文档进行重排序?

先从对约 30 个候选文档进行重排序开始,然后根据你的评估结果调整数量。

为了解候选数量如何影响性能,我们用 voyageai/voyage-4-lite 检索不同数量的候选文档,测试了 voyageai/rerank-3-lite:

重排序的候选数候选中包含正确片段重排序后的 Precision@1每 1,000 次查询费用
1097.1%94.5%$0.035
2098.9%96.4%$0.070
3099.6%96.7%$0.104
50100%97.1%$0.174
100100%97.1%$0.348

我们于 2026 年 10 月 8 日进行的运行使用了 274 个问题,以 voyageai/voyage-4-lite 作为第一阶段。

将候选数量从 10 增加到 30,使 precision@1 从 94.5% 提升到 96.7%。再次增加到 50 后,precision 达到 97.1%,只多修正了一个问题,却使重排序成本增加约三分之二。从 50 增加到 100 个候选并没有提升 precision。

重排序有其局限,因为只有当第一阶段的检索把相关片段纳入候选集时,它才能将其提升。如果向量搜索完全漏掉了答案,任何重排序器都无法把它找回来。

对于更大的知识库,用你的评估集找到这样一个点:继续检索更多候选不再能显著提升正确片段可被获取的问题占比。这比假设 30 对每个应用都是最优的,是更好的候选数量选择方式。

LLM 可以用作重排序器吗?

在我们的基准测试中,基于 LLM 的重排序器最准确,尽管返回结果耗时更长。我们没有把每个候选送入专门的重排序模型,而是把问题和全部 30 个带编号的片段交给一个聊天模型,然后要求它按顺序返回最相关片段的 ID。我们使用了严格的结构化输出 schema来确保响应符合预期格式。

这两种方法有一个关键区别。专门的重排序器针对问题对每个候选单独打分。LLM 可以同时读取所有候选并进行比较,这在多个文档包含相似信息时很有帮助。

在我们的测试中,openai/gpt-6-luna 以每 1,000 次查询 0.70 美元的成本达到了 99.6% 的 precision@1,处于 LLM 成本区间的低端,而 google/gemini-3.8-flash 则高达 4.14 美元。这比专门的重排序器准确率更高,但在我们的设置中每次调用耗时约 4 秒,而专门模型约为 1.3 秒。

在用户等待答案的交互式应用中,这额外的耗时很重要。LLM 重排序可能更适合批处理,或那些检索正确信息尤为重要、且可以接受额外延迟的应用。

请记住,我们的基准测试使用的是干净的、由模型生成的文本。真实的知识库存在格式不一致、文档不完整以及其他复杂情况,因此我们不能假设 LLM 重排器在更杂乱的现实世界数据上也能保持同样的优势。

在有了混合搜索或更好的嵌入模型之后,你还需要重排器吗?

混合搜索和更好的嵌入模型都能改善检索,但我们的基准测试表明,两者的效果都不如加入重排器。混合搜索将向量相似度与基于关键词的检索相结合,通常使用 BM25。我们用倒数排名融合(RRF)合并结果,它会把两个排名融合在一起。

在我们的测试集上,混合搜索将 voyageai/voyage-4-lite 的 precision@1 从 64.6% 提升到 69.3%。然而,使用 google/gemini-embedding-2 时,precision@1 从 81.0% 下降到 78.8%,尽管 recall@5 有所提升。能力更强的嵌入模型胜过了更便宜的替代方案。Gemini 达到了 81.0% 的 precision@1,而 Voyage 4 Lite 为 64.6%。但 Gemini 的嵌入价格为每百万 token 0.20 美元,而 Voyage 4 Lite 为 0.02 美元。将更便宜的嵌入模型与 voyageai/rerank-3-lite 结合使用,precision@1 达到了 96.7%。

混合搜索和更好的嵌入仍然有用,因为它们承担不同的职责。混合搜索可以帮助检索出向量搜索遗漏的候选,而更强的嵌入模型可以改善初始排名。重排器则增加了另一层,将每个候选与问题直接进行比较。

为了获得最佳效果,请分别以及组合评估这些选项。你可以使用我们的嵌入模型对比来帮助为第一阶段的检索选择嵌入模型。

什么会破坏重排?

当文档超出模型的上下文限制时,重排可能会悄无声息地失败。例如,cohere/rerank-v3.5 具有4,096 token 的上下文限制,因此它可能永远看不到文档中包含答案的那部分。

我们用两份 11,000 token 的文档做了测试,它们仅最后一句不同。其中一份包含答案,但两份获得了相同的相关性分数:0.2703。模型实际上漏掉了区分二者的那个细节。相比之下,voyageai/rerank-3-lite 给这两份文档分别打了 0.7812 和 0.3242,正确地把包含答案的那份排在前面。Cohere 4 系列模型、voyageai/rerank-3 和 qwen/qwen3-reranker-8b 也都把正确的文档排得更靠前。检查你的重排序模型的上下文上限,并让分块舒适地控制在该上限之内。

另一个问题是模型兼容性,因为 /rerank 端点只接受重排序模型。把聊天模型 openai/gpt-6-luna 发过去会返回 400 Model openai/gpt-6-luna does not exist,这与模型标识符拼错时得到的错误相同。在发起请求之前,请确认该模型出现在重排序模型集合中。

后续步骤

常见问题

RAG 中的重排序是什么?

RAG 中的重排序是第二个检索步骤,重排序模型会针对问题对向量搜索返回的每个分块打分并重新排序,使最相关的少数几个进入 LLM。重排序模型会同时阅读问题和分块,因此能捕捉到近似命中,例如正确额度配错了套餐。在我们 274 个问题的测试中,它把正确分块排在首位的比例从 81% 提升到了 97%。

RAG 的最佳重排序模型有哪些?

在我们 2026 年 10 月的测试中,voyageai/rerank-3 和 voyageai/rerank-3-lite 是最准确的专用重排序模型,也是最便宜的重排序模型,在 274 个问题中分别有 97.8% 和 97.1% 把正确分块排在首位。LLM 重排序模型得分更高,但每次调用约需 4 秒。

我应该对多少份文档进行重排序?

对约 30 个候选进行重排,对于更大的知识库,则增加数量,直到正确的片段可靠地出现。在我们的测试中,从 30 增加到 50 使 precision@1 从 96.7% 提升到 97.1%(在噪声范围内仅多答对一道题),并使重排成本增加了三分之二。

参考资料