引入上下文检索:大幅提升RAG系统准确性的新方法

Anthropic:Engineering(事故复盘 + 工程实践 · 网页)·2024-09-19 00:00·710天前
AI 导读

传统RAG系统在编码时易丢失上下文,导致检索失败。新方法“上下文检索”通过“上下文嵌入”和“上下文BM25”两项子技术,在检索前为文本块添加解释性上下文,能将检索失败次数减少49%,结合重排序后降幅可达67%,显著提升了下游任务性能。对于小于20万token的小型知识库,可直接将其完整内容放入提示词,结合Claude的提示词缓存功能,能降低超过2倍的延迟和高达90%的成本。对于大型知识库,上下文检索则提供了可扩展的解决方案。

Anthropic:Engineering(事故复盘 + 工程实践 · 网页)
精选
72AI 编辑部评分,满分 100

引入上下文检索:大幅提升RAG系统准确性的新方法

2024-09-19 00:00· 710天前
AI 导读

传统RAG系统在编码时易丢失上下文,导致检索失败。新方法“上下文检索”通过“上下文嵌入”和“上下文BM25”两项子技术,在检索前为文本块添加解释性上下文,能将检索失败次数减少49%,结合重排序后降幅可达67%,显著提升了下游任务性能。对于小于20万token的小型知识库,可直接将其完整内容放入提示词,结合Claude的提示词缓存功能,能降低超过2倍的延迟和高达90%的成本。对于大型知识库,上下文检索则提供了可扩展的解决方案。

推荐理由

Anthropic 把 RAG 检索失败率砍了 67%,方法不复杂但数据扎实,做知识库的开发者可以直接抄 cookbook 上手,是那种读完当天就能改进生产环境的实用帖。

正文 · AI 翻译

为了让 AI 模型在特定场景中发挥作用,它通常需要获取背景知识。

为了让 AI 模型在特定场景中发挥作用,它通常需要获取背景知识。例如,客服聊天机器人需要了解其服务企业的具体业务,而法律分析机器人则需要掌握大量过往案例。

开发者通常使用检索增强生成(RAG)来增强 AI 模型的知识。RAG 是一种从知识库中检索相关信息并将其附加到用户提示词中的方法,能显著提升模型的回答质量。问题在于,传统的 RAG 方案在编码信息时会移除上下文,这常常导致系统无法从知识库中检索到相关信息。

在本文中,我们概述了一种能大幅改进 RAG 检索步骤的方法。该方法称为“上下文检索”,并使用了两种子技术:上下文嵌入向量和上下文 BM25。该方法可将检索失败次数减少 49%,若结合重排序,则可减少 67%。这些改进显著提升了检索准确率,并直接转化为下游任务中更优的性能表现。

您可以使用我们的操作指南,通过 Claude 轻松部署自己的上下文检索方案。

关于直接使用更长提示词的说明

有时最简单的方案就是最好的。如果您的知识库小于 200,000 个模型 token(约 500 页材料),您可以直接将整个知识库包含在提供给模型的提示词中,无需使用 RAG 或类似方法。

几周前,我们为 Claude 发布了提示词缓存功能,这使得该方法在速度和成本效益上显著提升。开发者现在可以在 API 调用之间缓存常用提示词,从而将延迟降低超过 2 倍,成本降低高达 90%(您可以通过阅读我们的提示词缓存操作指南了解其工作原理)。

然而,随着知识库的增长,您将需要一个更具可扩展性的方案。这正是上下文检索的用武之地。

RAG 入门:扩展到更大的知识库

对于超出上下文窗口容量的较大知识库,RAG 是典型的解决方案。RAG 通过以下步骤对知识库进行预处理来实现其功能:

  1. 将知识库(即文档“语料库”)拆分为较小的文本片段,通常不超过几百个模型 token;
  2. 使用嵌入向量模型将这些片段转换为编码语义信息的向量嵌入;
  3. 将这些嵌入向量存储在支持按语义相似度进行搜索的向量数据库中。

在运行时,当用户向模型输入查询时,系统会利用向量数据库根据与查询的语义相似度找到最相关的文本片段。然后,将这些最相关的片段添加到发送给生成模型的提示词中。

虽然嵌入向量模型擅长捕捉语义关系,但它们可能会遗漏关键性的精确匹配。幸运的是,有一种较老的技术可以在这种情况下提供帮助。BM25(最佳匹配 25)是一种利用词汇匹配来查找精确单词或短语匹配的排序函数。它对于包含唯一标识符或技术术语的查询尤其有效。

BM25 的工作原理建立在 TF-IDF(词频-逆文档频率)概念之上。TF-IDF 衡量一个词在文档集合中对某篇文档的重要程度。BM25 通过考虑文档长度并对词频应用饱和函数来改进这一点,这有助于防止常见词汇主导搜索结果。

以下是 BM25 在语义嵌入向量失效时如何成功发挥作用的示例:假设用户在技术支持数据库中查询“错误代码 TS-999”。嵌入向量模型可能会找到关于一般错误代码的内容,但可能会遗漏精确的“TS-999”匹配。而 BM25 会查找这个特定的文本字符串,以识别相关的文档。

RAG 解决方案可以通过结合嵌入向量和 BM25 技术,并采用以下步骤,更准确地检索出最适用的文本片段:

  1. 将知识库(即文档“语料库”)拆分为较小的文本片段,通常不超过几百个模型 token;
  2. 为这些片段创建 TF-IDF 编码和语义嵌入向量;
  3. 使用 BM25 基于精确匹配找出排名靠前的文本片段;
  4. 使用嵌入向量基于语义相似度找到最相关的文本块;
  5. 运用排序融合技术,合并并去重来自(3)和(4)的结果;
  6. 将排名前 K 的文本块添加到提示词中,以生成回答。

通过同时利用 BM25 和嵌入向量模型,传统 RAG 系统能够提供更全面、更准确的结果,在精确的术语匹配与更广泛的语义理解之间取得平衡。

一个同时使用嵌入向量和最佳匹配 25(BM25)进行信息检索的标准检索增强生成(RAG)系统。TF-IDF(词频-逆文档频率)衡量词语重要性,是 BM25 的基础。

这种方法使您能够以经济高效的方式扩展到庞大的知识库,远超单个提示词所能容纳的范围。但这些传统 RAG 系统有一个显著的局限性:它们常常会破坏上下文。

传统 RAG 中的上下文难题

在传统 RAG 中,文档通常被分割成较小的文本块以便高效检索。虽然这种方法对许多应用场景效果不错,但当单个文本块缺乏足够上下文时,可能会导致问题。

例如,假设您的知识库中嵌入了一批财务信息(比如美国证券交易委员会的文件),并且您收到了以下问题:“ACME 公司在 2023 年第二季度的营收增长是多少?”

一个相关的文本块可能包含这样的文本:“该公司营收较上一季度增长了 3%。”然而,这个文本块本身并未指明它指的是哪家公司或相关的时间段,这使得检索到正确信息或有效利用该信息变得困难。

引入上下文检索

上下文检索通过在嵌入(“上下文嵌入”)和创建 BM25 索引(“上下文 BM25”)之前,为每个文本块预先添加特定于该块的解释性上下文,从而解决了这个问题。

让我们回到美国证券交易委员会文件集合的例子。以下是一个文本块可能如何被转换的示例:

original_chunk = "The company's revenue grew by 3% over the previous quarter."

contextualized_chunk = "This chunk is from an SEC filing on ACME corp's performance in Q2 2023; the previous quarter's revenue was $314 million. The company's revenue grew by 3% over the previous quarter."

值得注意的是,过去也曾有人提出过利用上下文来改进检索的其他方法。其他方案包括:向文本块中添加通用文档摘要(我们进行了实验,但收效甚微)、假设性文档嵌入(Hypothetical Document Embedding)以及基于摘要的索引(我们评估后发现性能较低)。这些方法与本文提出的方法有所不同。

实现上下文检索

当然,手动为知识库中成千上万甚至数百万个文本块添加注释工作量过于巨大。为了实现上下文检索,我们求助于 Claude。我们编写了一个提示词,指示模型利用整个文档的上下文,为每个文本块提供简洁、特定于该块的上下文说明。我们使用了以下 Claude 3 Haiku 提示词来为每个文本块生成上下文:

<document> 
{{WHOLE_DOCUMENT}} 
</document> 
Here is the chunk we want to situate within the whole document 
<chunk> 
{{CHUNK_CONTENT}} 
</chunk> 
Please give a short succinct context to situate this chunk within the overall document for the purposes of improving search retrieval of the chunk. Answer only with the succinct context and nothing else. 

生成的上下文文本通常为 50-100 个模型 token,在嵌入该文本块之前以及创建 BM25 索引之前,会被前置到该文本块之前。

以下是预处理流程的实际操作示例:

上下文检索是一种能够提高检索准确率的预处理技术。

如果您对使用上下文检索感兴趣,可以从我们的操作指南(cookbook)入手。

利用提示词缓存降低上下文检索的成本

得益于我们上文提到的特殊提示词缓存功能,使用 Claude 能够以低成本独特地实现上下文检索。借助提示词缓存,您无需为每个文本块传入参考文档。您只需将文档加载到缓存中一次,然后引用之前缓存的内容即可。假设每个文本块 800 个模型 token、每份文档 8000 个模型 token、上下文指令 50 个模型 token、每个文本块的上下文 100 个模型 token,那么生成带有上下文的文本块的一次性成本为每百万文档 token 1.02 美元。

方法论

我们在多个知识领域(代码库、小说、ArXiv 论文、科学论文)、多种嵌入模型、多种检索策略以及多种评估指标上进行了实验。我们在附录二中包含了每个领域所用的一些问答示例。

下图展示了在性能最优的嵌入配置(Gemini Text 004)下,检索前 20 个文本块时,所有知识领域的平均表现。我们使用 1 减去 recall@20 作为评估指标,该指标衡量的是在前 20 个文本块中未能被检索到的相关文档所占的百分比。您可以在附录中查看完整结果——在我们评估的每一种嵌入与来源组合中,加入上下文信息均能提升性能。

性能提升

我们的实验表明:

  • 上下文嵌入将前 20 个文本块的检索失败率降低了 35%(从 5.7% 降至 3.7%)。
  • 结合使用上下文嵌入与上下文 BM25,将前 20 个文本块的检索失败率降低了 49%(从 5.7% 降至 2.9%)。
结合使用上下文嵌入与上下文 BM25,将前 20 个文本块的检索失败率降低了 49%。

实施注意事项

在实施上下文检索时,有几个注意事项需要牢记:

  1. 文本块边界:请考虑如何将文档分割成文本块。文本块大小、文本块边界以及文本块重叠的选择都会影响检索性能¹。
  2. 嵌入模型:虽然上下文检索能提升我们测试过的所有嵌入模型的性能,但某些模型可能比其他模型受益更多。我们发现 Gemini 和 Voyage 的嵌入效果尤为出色。
  3. 自定义上下文化提示词:虽然我们提供的通用提示词效果不错,但针对您的特定领域或使用场景定制的提示词(例如,包含一个关键术语表,这些术语可能只在知识库的其他文档中才有定义)可能会带来更好的结果。
  4. 文本块数量:在上下文窗口中增加更多文本块,可以提高包含相关信息的几率。然而,过多的信息可能会对模型造成干扰,因此存在一个上限。我们尝试了提供 5 个、10 个和 20 个文本块,发现使用 20 个文本块是这些选项中性能最好的(对比结果见附录),但针对您的具体用例进行实验是值得的。

始终进行评估:通过将上下文化后的文本块传递给模型,并区分哪些是上下文、哪些是文本块本身,可以改善回复生成的质量。

通过重排序进一步提升性能

在最后一步,我们可以将上下文检索与另一项技术结合,以获得更显著的性能提升。在传统 RAG 中,AI 系统会搜索其知识库以查找可能相关的信息片段。对于大型知识库,这种初始检索通常会返回大量片段——有时多达数百个——且这些片段的相关性和重要性参差不齐。

重排序是一种常用的过滤技术,用于确保只有最相关的片段被传递给模型。重排序能提供更好的响应,同时由于模型处理的信息量减少,还能降低成本和延迟。关键步骤如下:

  1. 执行初始检索,获取最可能相关的片段(我们使用了前 150 个);
  2. 将前 N 个片段连同用户查询一起,传递给重排序模型;
  3. 使用重排序模型,根据每个片段与提示词的相关性和重要性为其打分,然后选择前 K 个片段(我们使用了前 20 个);
  4. 将前 K 个片段作为上下文传递给模型,以生成最终结果。
结合上下文检索与重排序,以最大化检索准确率。

性能提升

市场上有多种重排序模型。我们使用 Cohere 的重排序器进行了测试。Voyage 也提供重排序器,但我们没有时间进行测试。我们的实验表明,在不同领域,增加重排序步骤都能进一步优化检索效果。

具体来说,我们发现,经过重排序的上下文嵌入向量和上下文 BM25 将前 20 个片段的检索失败率降低了 67%(从 5.7% 降至 1.9%)。

经过重排序的上下文嵌入向量和上下文 BM25 将前 20 个片段的检索失败率降低了 67%。

成本与延迟考量

重排序的一个重要考量因素是对延迟和成本的影响,尤其是在对大量文本块进行重排序时。由于重排序在运行时增加了一个额外步骤,即使重排序器并行对所有文本块进行评分,也难免会带来少量延迟。在重排序更多文本块以提升性能,与重排序更少文本块以降低延迟和成本之间,存在固有的权衡。我们建议针对你的具体用例尝试不同的设置,以找到合适的平衡点。

结论

我们进行了大量测试,比较了上述所有技术(嵌入模型、是否使用 BM25、是否使用上下文检索、是否使用重排序器以及检索的 Top-K 结果总数)的不同组合,并涵盖了多种不同的数据集类型。以下是我们发现的总结:

  1. 嵌入向量+BM25 的效果优于单独使用嵌入向量;
  2. 在我们测试的模型中,Voyage 和 Gemini 的嵌入向量效果最佳;
  3. 将前 20 个文本块传递给模型比仅传递前 10 个或前 5 个更有效;
  4. 为文本块添加上下文能显著提高检索准确性;
  5. 使用重排序优于不使用重排序;
  6. 所有这些优势可以叠加:为了最大化性能提升,我们可以将上下文嵌入向量(来自 Voyage 或 Gemini)与上下文 BM25 结合使用,再加上一个重排序步骤,并将 20 个文本块添加到提示词中。

我们鼓励所有从事知识库工作的开发者使用我们的 cookbook 来尝试这些方法,以解锁新的性能水平。

附录 I

以下是按数据集、嵌入提供商、是否在嵌入基础上使用 BM25、是否使用上下文检索以及是否使用重排序,针对检索召回率 @ 20 的结果细分。

关于检索召回率 @ 10 和 @ 5 的细分,以及每个数据集的示例问题和答案,请参见附录 II。

各数据集和嵌入提供商在检索召回率 @ 20 上的 1 减去召回率结果。

致谢

研究和撰写由 Daniel Ford 完成。感谢 Orowa Sikder、Gautam Mittal 和 Kenneth Lien 提供关键反馈,Samuel Flamini 实现 cookbook,Lauren Polansky 负责项目协调,以及 Alex Albert、Susan Payne、Stuart Ritchie 和 Brad Abrams 为这篇博文定稿提供指导。

来源:Anthropic:Engineering(事故复盘 + 工程实践 · 网页)· anthropic.com