跳到主要内容

原文:08-contextual-retrieval.md 来源:https://www.anthropic.com/engineering/contextual-retrieval

介绍上下文检索(Contextual Retrieval)

发布于 2024 年 9 月 19 日

让 AI 模型在特定场景中真正有用,往往需要它能访问背景知识。

让 AI 模型在特定场景中真正有用,往往需要它能访问背景知识。例如客服聊天机器人需要知道它服务的具体业务,法律分析机器人需要了解海量过往案例。

开发者通常用**检索增强生成(Retrieval-Augmented Generation, RAG)**增强 AI 模型知识。RAG 从知识库检索相关信息并附加到用户提示中,显著增强模型响应。问题是传统 RAG 方案在编码信息时移除了上下文,常导致系统未能从知识库检索到相关信息

本文介绍一种戏剧性改善 RAG 检索步骤的方法——Contextual Retrieval,使用两个子技术:Contextual EmbeddingsContextual BM25。该方法可将失败检索数减少 49%;与重排序(reranking)结合时,减少 67%。这些是检索准确率的显著提升,直接转化为下游任务的更好表现


关于"用更长提示"

有时最简单方案就是最好。如果知识库小于 200,000 token(约 500 页材料),可以直接把整个知识库放进提示——无需 RAG 或类似方法。

我们几周前发布的 prompt caching 让这种方法显著更快、成本更低。开发者现在可以缓存 API 调用之间频繁使用的提示,延迟降低 >2 倍,成本最多降低 90%

但随着知识库增长,你需要更可扩展的方案——这就是 Contextual Retrieval 的用武之地。


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

对超出上下文窗口的更大知识库,RAG 是典型方案。它通过预处理知识库工作:

  1. 把知识库(文档"语料")拆为较小文本块(chunk),通常每块不超过几百 token
  2. 用嵌入模型把这些块转为编码语义的向量嵌入
  3. 把嵌入存入支持语义相似度搜索的向量数据库

运行时,用户输入查询时,向量数据库基于与查询的语义相似度找最相关块,最相关块被加进给生成模型的提示。

嵌入模型擅长捕捉语义关系,但可能错过关键的精确匹配。幸运的是,有更老的技术能在这种情况下帮忙——BM25(Best Matching 25) 是用词法匹配找精确词或短语匹配的排序函数。它对包含独特标识符或技术术语的查询特别有效

BM25 建立在 TF-IDF(词频-逆文档频率)概念之上。TF-IDF 衡量一个词对文档集合中某文档的重要性。BM25 通过考虑文档长度并应用对词频的饱和函数来精炼这一点,帮助防止常见词主导结果。

BM25 在语义嵌入失败的地方成功的例子:用户在技术支持数据库查询 "Error code TS-999"。嵌入模型可能找到关于错误码的内容,但可能错过 "TS-999" 这个精确匹配。BM25 寻找这个特定文本字符串识别相关文档。

RAG 系统通过结合嵌入和 BM25 能更准确检索:

  1. 把知识库拆为小文本块
  2. 创建 TF-IDF 编码和语义嵌入
  3. 用 BM25 找精确匹配的 top 块
  4. 用嵌入找语义相似的 top 块
  5. 用排序融合技术合并和去重 (3) (4) 的结果
  6. 把 top-K 块加进提示生成响应

利用两者,传统 RAG 系统能提供更全面准确的结果——平衡精确词项匹配和更广语义理解。但这些传统 RAG 系统有显著限制:它们常破坏上下文

传统 RAG 的上下文困境

文档通常被拆分为更小块以高效检索。但当个别块缺乏足够上下文时就会出问题。

例如你有金融信息(如美国 SEC 文件)的集合,收到问题:"ACME Corp 在 2023 年 Q2 的营收增长是多少?"

相关块可能包含:"公司营收较上一季度增长 3%。" 但这个块本身没说明指哪家公司或哪个时期,难以检索到正确信息或有效使用信息


介绍 Contextual Retrieval

Contextual Retrieval 通过在嵌入和 BM25 索引化之前为每个块预先添加块特定的解释性上下文来解决这个问题——分别叫 Contextual EmbeddingsContextual BM25

回到 SEC 文件示例。块的转换:

original_chunk = "公司营收较上一季度增长 3%。"

contextualized_chunk = "本块来自 ACME Corp 在 2023 年 Q2 表现的 SEC 文件;上一季度营收为 3.14 亿美元。公司营收较上一季度增长 3%。"

值得注意的是,过去也有用上下文改善检索的其他方法被提出过,包括:给块加通用文档摘要(我们试验,收益非常有限)、假设性文档嵌入、基于摘要的索引(我们评估,性能低)。这些方法与本文提出的不同


实现 Contextual Retrieval

手工注释知识库中的数千乃至数百万个块工作量太大。我们用 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 索引之前预先添加到块。

用 Prompt Caching 降低成本

Contextual Retrieval 在 Claude 上能以低成本实现,得益于 prompt caching。不必为每个块都传入参考文档——只把文档加载进缓存一次,然后引用先前缓存内容。

假设 800 token 块、8K token 文档、50 token 上下文指令、每块 100 token 上下文,生成上下文化块的一次性成本为每百万文档 token 1.02 美元


性能改善

跨各种知识领域(代码库、虚构小说、ArXiv 论文、科学论文)、嵌入模型、检索策略和评估指标实验。所有领域的平均表现:

  • Contextual Embeddings 把 top-20 块检索失败率降低 35%(5.7% → 3.7%)
  • Contextual Embeddings + Contextual BM25 把 top-20 块检索失败率降低 49%(5.7% → 2.9%)

实现考虑

  • 块边界:块大小、边界、重叠的选择影响检索性能
  • 嵌入模型:Contextual Retrieval 在所有测试嵌入模型上都改善性能,但有些模型受益更多。Gemini 和 Voyage 嵌入特别有效
  • 自定义上下文化提示:通用提示工作良好,但针对特定领域定制(如包含只在知识库中其他文档定义的关键术语词汇表)可能取得更好结果
  • 块数量:上下文窗口中加更多块增加包含相关信息的机会,但太多信息可能让模型分心。我们试 5、10、20 个块,发现 20 个块表现最佳
  • 始终运行评估:通过传上下文化块并区分上下文和块本身,可能改善响应生成

用重排序进一步提升

最后一步可以结合 Contextual Retrieval 与另一项技术——重排序(Reranking)

大知识库中,初始检索常返回大量块(有时数百),相关性和重要性各异。重排序是常用的过滤技术,确保只有最相关的块传给模型。重排序提供更好响应、降低成本和延迟(模型处理更少信息)。关键步骤:

  1. 执行初始检索得到 top 潜在相关块(我们用 top 150)
  2. 把 top-N 块和用户查询通过重排序模型
  3. 重排序模型基于相关性和重要性给每块评分,选 top-K 块(我们用 top 20)
  4. 把 top-K 块作为上下文传入模型生成最终结果

性能改善

我们用 Cohere reranker 测试。Voyage 也提供 reranker,但我们没时间测试。

Reranked Contextual Embedding + Contextual BM25 把 top-20 块检索失败率降低 67%(5.7% → 1.9%)

成本和延迟考虑

重排序在运行时增加额外步骤——必然增加少量延迟(即使 reranker 并行评分所有块)。有内在权衡:重排序更多块以更好性能 vs. 重排序更少以更低延迟和成本。建议在你的具体用例上实验找平衡。


结论

我们运行大量测试,跨各种数据集类型对比上述技术的不同组合。总结:

  • 嵌入 + BM25 比单独嵌入好
  • Voyage 和 Gemini 是测试中嵌入最好的
  • 传 top-20 块给模型比 top-10 或 top-5 有效
  • 给块加上下文大幅改善检索准确率
  • 重排序好于不重排序
  • 所有这些好处叠加:要最大化性能提升,可结合 Contextual Embeddings(来自 Voyage 或 Gemini)+ Contextual BM25 + 重排序步骤 + 加 20 个块到提示

我们鼓励所有处理知识库的开发者用我们的 cookbook 实验这些方法,解锁新水平的性能。