📰 来源:Towards Data Science | 📅 翻译日期:2026年6月1日
🔗 原文:查看原文
🤖 翻译:DeepSeek AI · 仅供参考
实验设置
与嵌入文章相同的设置。两种场景。
场景一:初用重排序器的喜悦
一个团队正在构建一个覆盖几百份合同的 RAG 系统,他们读过第2篇文章。嵌入在否定、精确标识符以及问题与答案之间的差距上失效。团队的第一反应是文献建议的:添加一个重排序器。交叉编码器比 LLM 小,比余弦相似度更智能,将其插入嵌入和 LLM 之间。他们接入了 bge-reranker-base,发送嵌入阶段的前 100 个结果,保留前 10 个。之前失效的几个查询现在似乎生效了。团队备受鼓舞。
场景二:旧问题重现
两周后,第2篇文章中的同一操作模式重现。用户问“列出所有提到终止的条款”,系统返回了三个“最相关”的条款,正好三个,并排序。合同中共有十一个。用户问“非员工的取消规则是什么?”重排序器从未见过公司的术语“非员工劳动力”,并将一个不相关的段落排在最前面。用户问“有没有没有提到赔偿的条款?”与之前相同的否定失效;交叉编码器并不比嵌入更能理解逻辑补集。同时,延迟达到了几百毫秒。交叉编码器在查询时对每个候选运行,无法预先计算。更糟的是:当他们在没有重排序器的情况下与 text-embedding-3-large 并排比较时,仅嵌入本身通常就匹配或优于 ada-002 + bge-reranker-base。
经典检索漏斗
与第2篇文章中一样,经典的检索漏斗如下:底部的廉价嵌入相似度将数百万候选缩小到数千。中间的可选交叉编码器重排序器将数千缩小到数十。顶部的聊天完成 LLM 读取这数十个。重排序器是位于成本和质量的两种大常量之间的层。了解每个阶段的真正作用是使漏斗工作的关键;期望任何一个阶段具有魔力是团队浪费六个月的原因。本文实证测试了成本-性能梯度:4 个从2014到2024年的嵌入模型,加上 3 个现成的交叉编码器重排序器,在第2篇文章分类的案例上并排评分。结果比漏斗暗示的更加令人惊讶。
测试模型列表
测试的七个模型及其许可证声明URL(模型作者自己声明许可证的页面URL):
GloVe-avg(2014, 300维词向量): Apache 2.0, 在 HuggingFace 模型卡上声明。all-MiniLM-L6-v2(2021, 22M参数, 384维): Apache 2.0, 在 HuggingFace 模型卡上声明。text-embedding-ada-002(OpenAI 2022, 1536维): 专有; OpenAI 使用条款。text-embedding-3-large(OpenAI 2024, 3072维): 专有; OpenAI 使用条款。bge-reranker-base(BAAI 2023, 278M参数): MIT 许可证, 在 HuggingFace 模型卡上声明。bge-reranker-large(BAAI 2023, 560M参数): MIT 许可证, 在 HuggingFace 模型卡上声明。cross-encoder/ms-marco-MiniLM-L-12-v2(历史基线): Apache 2.0, 在 HuggingFace 模型卡上声明。
代码示例
from sentence_transformers import CrossEncoder
from openai import OpenAI
# 双编码器(第2篇文章中的嵌入阶段)。
# 每个文本独立地变为向量。向量空间中的余弦。
client = OpenAI()
def cosine_score(query, passage):
v_q = client.embeddings.create(input=query, model="text-embedding-ada-002").data[0].embedding
v_p = client.embeddings.create(input=passage, model="text-embedding-ada-002").data[0].embedding
return dot(v_q, v_p) / (norm(v_q) * norm(v_p))
# 交叉编码器重排序器。
# 查询和段落一起进行分词,并联合注意力。
# 每个(查询,段落)对一次前向传播。返回单个相关性分数。
reranker = CrossEncoder("BAAI/bge-reranker-base")
def rerank_score(query, passage):
return reranker.predict([(query, passage)])[0]系列背景
本文是更广泛的《企业文档智能第一卷》系列的一部分,该系列从基线管道到语料库规模架构,逐步构建企业 RAG。
重排序器的本质
在实证测试之前,先看架构图。两个原因使其重要:重排序器是一个真实的工程对象,具有真实成本;而系列所捍卫的编辑立场只有在经典角色摆在桌面上时才有意义。
成本/精度梯度
三个阶段,按每次查询成本排序:
- 双编码器嵌入相似度。每个文档预先计算一个向量。查询时,模型对查询编码一次,并在索引上运行余弦相似度。对于数百万候选,仅需毫秒。廉价且近似。
- 交叉编码器重排序器。查询和段落一起分词,并通过一个同时注意两者的 transformer。输出是每对的一个相关性分数。无法预计算,因为查询是输入的一部分。每对数十毫秒。中等成本,中等精度。
- 聊天完成 LLM。读取一个小候选集并生成结构化答案。数百毫秒,每百万 tokens 几美元。最昂贵,最准确。
每个阶段都因其比上一阶段更便宜的能力而合理。嵌入不能做 LLM 能做的一切,但它们可以在 LLM 读取十个候选的时间内对一百万个候选评分。重排序器不能做 LLM 能做的一切,但它们可以在 LLM 读取二十个候选的时间内对一千个候选排序。这是教科书式的故事。第2节在实际查询形状上测试它。梯度比漏斗暗示的更平坦,有时甚至逆转。
漏斗架构
架构图是一个漏斗。假设语料库有 200,000 页。嵌入阶段...(原文未完成,翻译完整)
评论已关闭