Blog/Anthropic - Introducing Contextual Retrieval (RAG)
AIAgent2026-02-12

Anthropic - Introducing Contextual Retrieval (RAG)

Anthropic - 上下文检索解读

简介 本文链接

人工智能模型要想在特定场景下发挥作用,通常需要获取背景知识。例如,客服聊天机器人需要了解其所服务的特定业务,而法律分析机器人则需要了解大量的过往案例。

开发者通常使用检索增强生成(RAG)来增强人工智能模型的知识。RAG 是一种从知识库中检索相关信息并将其附加到用户提示中的方法,从而显著提升模型的响应能力。然而,传统的 RAG 解决方案在信息编码过程中会丢失上下文信息,这往往会导致系统无法从知识库中检索到相关信息。

本文介绍了一种能够显著提升 RAG 检索步骤的方法。该方法名为“上下文检索”,它采用了两种子技术:上下文嵌入和上下文 BM25。该方法可以将检索失败率降低 49%,与重排序结合使用时,可降低 67%。这些显著的提升意味着检索准确率的大幅提高,进而直接转化为下游任务性能的提升。

关于使用更长提示的说明

有时候最简单的解决方案就是最好的。如果你的知识库小于 20 万个词元(大约 500 页材料),你可以直接将整个知识库包含在你给模型的提示中,而无需使用 RAG 或类似方法。

几周前,我们发布了 Claude 的提示缓存功能 ,这使得这种方法速度更快、成本更低。现在,开发人员可以在 API 调用之间缓存常用提示,从而将延迟降低 2 倍,成本降低高达 90%(您可以阅读我们的提示缓存指南了解其工作原理)。

然而,随着知识库的增长,您将需要更具可扩展性的解决方案。这时,上下文检索就派上了用场。

RAG 入门指南:如何扩展到更大的知识库

对于超出上下文窗口范围的大型知识库,RAG 是一种典型的解决方案。RAG 的工作原理是通过以下步骤对知识库进行预处理:

  1. 知识库(文档“语料库”)分解成更小的文本块,通常不超过几百个词元;
  2. 使用嵌入模型将这些块转换为编码含义的向量嵌入;
  3. 将这些嵌入存储在向量数据库中,以便按语义相似性进行搜索。

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

虽然词嵌入模型在捕捉语义关系方面表现出色,但它们可能会遗漏关键的精确匹配。幸运的是,有一种较早的技术可以帮助解决这些问题。BM25(Best Matching 25)是一种排名函数,它使用词汇匹配来查找精确的单词或短语匹配项。对于包含唯一标识符或技术术语的查询,它尤其有效。

BM25 的工作原理基于 TF-IDF(词频-逆文档频率)的概念。TF-IDF 衡量一个词对于某个文档的重要性。BM25 通过考虑文档长度并对词频应用饱和函数来改进 TF-IDF,从而有助于防止常用词主导结果。

以下是 BM25 如何弥补语义嵌入的不足之处:假设用户在技术支持数据库中查询“错误代码 TS-999”。嵌入模型或许能找到关于错误代码的一般性内容,但却可能遗漏“TS-999”这个精确匹配项。而 BM25 则会查找这个特定的文本字符串来识别相关的文档。

RAG 解决方案通过结合嵌入和 BM25 技术,可以更准确地检索最适用的数据块,具体步骤如下:

  1. 将知识库(文档“语料库”)分解成更小的文本块,通常不超过几百个词元;
  2. 为这些数据块创建 TF-IDF 编码和语义嵌入;
  3. 使用 BM25 根据精确匹配查找最佳块;
  4. 利用词嵌入技术,根据语义相似性找到最佳词块;
  5. 使用排序融合技术合并和去重(3)和(4)的结果;
  6. 将前 K 个数据块添加到提示中以生成响应。

通过结合 BM25 和嵌入模型,传统的 RAG 系统可以提供更全面、更准确的结果,在精确的术语匹配和更广泛的语义理解之间取得平衡。

这种方法可以经济高效地扩展到庞大的知识库,远远超出单个提示所能容纳的内容。但这些传统的RAG有一个重大局限性:它们常常会破坏上下文信息。

传统 RAG 中的语境难题

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

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

相关的文本片段可能包含以下内容: “该公司营收较上一季度增长了 3%。” 然而,仅凭这一片段并未具体说明指的是哪家公司或相关的时间段,因此难以检索到正确的信息或有效地利用这些信息。

引入上下文检索

上下文检索通过在嵌入之前为每个块添加特定于块的解释性上下文(“上下文嵌入”)并创建 BM25 索引(“上下文 BM25”)来解决此问题。

让我们回到之前提到的美国证券交易委员会(SEC)文件收集示例。以下是一个数据块转换示例:

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."

值得注意的是,过去也曾有人提出过其他利用上下文信息提升检索效果的方法。其他方案包括: 在文档块中添加通用文档摘要 (我们进行了实验,发现效果非常有限)、 假设文档嵌入以及基于摘要的索引 (我们进行了评估,发现性能不佳)。这些方法与本文提出的方法有所不同。

实现上下文检索

当然,手动标注知识库中成千上万甚至数百万个文本块的工作量实在太大了。为了实现上下文检索,我们采用了 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 个词元)会在嵌入数据块之前以及创建 BM25 索引之前添加到数据块的前面。

Using Prompt Caching to reduce the costs of Contextual Retrieval 利用提示缓存降低上下文检索的成本

提示缓存指南

得益于我们前面提到的特殊提示缓存功能,Claude 能够以极低的成本实现上下文检索。有了提示缓存,您无需为每个数据块都传入参考文档。您只需将文档加载到缓存中一次,然后引用之前缓存的内容即可。假设有 800 个 token 数据块、8000 个 token 文档、50 条 token 上下文指令,并且每个数据块包含 100 个 token 的上下文信息, 那么生成上下文数据块的一次性成本为每百万个文档 token 1.02 美元 。

Methodology 方法论

我们针对不同的知识领域(代码库、小说、arXiv 论文、科学论文)、嵌入模型、检索策略和评估指标进行了实验。 附录二列出了我们针对每个领域使用的一些问答示例。

下图展示了在所有知识领域中使用性能最佳的嵌入配置(Gemini Text 004)并检索前 20 个数据块的平均性能。我们使用 1 减去 recall@20 作为评估指标,该指标衡量的是未能在前 20 个数据块中检索到的相关文档的百分比。您可以在附录中查看完整结果——上下文关联在我们评估的每种嵌入源组合中都提高了性能。

性能提升:

上下文嵌入将前 20 个数据块检索失败率降低了 35% (5.7% → 3.7%)。

结合上下文嵌入和上下文 BM25,前 20 个数据块检索失败率降低了 49% (5.7% → 2.9%)。

注意事项

  1. 数据块边界: 考虑如何将文档分割成数据块。数据块大小、数据块边界和数据块重叠的选择会影响检索性能

  2. 嵌入模型: 虽然上下文检索提升了我们测试的所有嵌入模型的性能,但某些模型可能受益更多。我们发现 Gemini 和 Voyage 嵌入模型尤其有效。

  3. 自定义上下文提示: 虽然我们提供的通用提示效果不错,但如果您使用针对特定领域或用例量身定制的提示(例如,包含可能仅在知识库的其他文档中定义的关键术语词汇表),则可能会获得更好的结果。

  4. 信息块数量: 在上下文窗口中添加更多信息块可以提高包含相关信息的概率。但是,过多的信息可能会分散模型的注意力,因此信息块的数量应该有所限制。我们尝试了 5 个、10 个和 20 个信息块,发现 20 个信息块的性能最佳

始终运行 evals: 通过向其传递上下文块并区分什么是上下文什么是块,可以改进响应生成。

Reranking 通过重新排名进一步提升性能

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

重排序是一种常用的过滤技术,它确保只有最相关的数据块才会被传递给模型。重排序能够提供更好的响应,并降低成本和延迟,因为模型需要处理的信息量更少。其关键步骤如下:

  1. 执行初始检索,获取最有可能相关的块(我们使用了前 150 个);

  2. 将前 N 个数据块连同用户的查询一起传递给重排序模型;

  3. 使用重排序模型,根据每个块与提示的相关性和重要性给每个块打分,然后选择前 K 个块(我们使用了前 20 个块);

  4. 将前 K 个数据块作为上下文传递给模型,以生成最终结果。

性能提升:

市面上有很多重排序模型。我们使用 Cohere 重排序器进行了测试。Voyage 也提供重排序器 ,但我们没有时间进行测试。我们的实验表明,在各种领域中,添加重排序步骤可以进一步优化检索效果。

具体来说,我们发现重新排序的上下文嵌入和上下文 BM25 将前 20 个数据块检索失败率降低了 67%(5.7% → 1.9%)。

成本和延迟方面的考虑

重新排序时需要考虑的一个重要因素是其对延迟和成本的影响,尤其是在对大量数据块进行重新排序时。由于重新排序会在运行时增加一个额外的步骤,因此即使重新排序器并行对所有数据块进行评分,也不可​​避免地会增加少量延迟。重新排序更多数据块以获得更佳性能与重新排序更少数据块以降低延迟和成本之间存在固有的权衡。我们建议您在具体的使用场景中尝试不同的设置,以找到最佳平衡点。

Conclusion 结论

我们进行了大量测试,比较了上述所有技术(嵌入模型、BM25 算法、上下文检索、重排序器以及检索到的前 K 个结果总数)的不同组合,所有测试均针对各种不同的数据集类型。以下是我们的发现总结:

  1. Embeddings+BM25 比单独使用嵌入更好;

  2. 在我们测试过的芯片中,Voyage 和 Gemini 的嵌入效果最好;

  3. 将前 20 个数据块传递给模型比只传递前 10 个或前 5 个数据块更有效;

  4. 为数据块添加上下文信息可以大大提高检索准确率;

  5. 重新排名总比不重新排名好;

  6. 所有这些好处叠加起来 :为了最大限度地提高性能,我们可以将上下文嵌入(来自 Voyage 或 Gemini)与上下文 BM25 结合,再加上重新排序步骤,并将 20 个块添加到提示中。

对比数据

以下是按数据集、嵌入提供商、除嵌入外还使用 BM25、使用上下文检索以及对检索 @ 20 进行重排序的结果细分。