获取开发者新闻通讯
产品更新、操作指南、社区聚焦等。每月发送到您的收件箱。
要让 AI 模型在特定场景中发挥作用,它通常需要访问背景知识。例如,客户支持聊天机器人需要了解其所服务的具体业务,法律分析机器人则需要了解大量过往案例。
开发者通常使用检索增强生成(RAG)来增强 AI 模型的知识。RAG 是一种从知识库中检索相关信息并将其附加到用户提示中的方法,能显著增强模型的响应。问题在于,传统的 RAG 解决方案在编码信息时会移除上下文,这往往导致系统无法从知识库中检索到相关信息。
在本文中,我们概述了一种能大幅改进 RAG 检索步骤的方法。该方法称为“上下文检索”(Contextual Retrieval),使用两种子技术:上下文嵌入(Contextual Embeddings)和上下文 BM25(Contextual BM25)。该方法可将检索失败次数减少 49%,若结合重排序(reranking),则可减少 67%。这些改进显著提升了检索准确率,并直接转化为下游任务中更好的表现。
你可以借助我们的 cookbook,轻松使用 Claude 部署你自己的上下文检索解决方案。
有时最简单的解决方案就是最好的。如果你的知识库小于 200,000 个 token(约 500 页材料),你可以直接将整个知识库包含在提供给模型的提示中,无需使用 RAG 或类似方法。
几周前,我们为 Claude 发布了提示缓存,这使这种方法显著更快、更具成本效益。开发者现在可以在 API 调用之间缓存频繁使用的提示,将延迟降低 2 倍以上,并将成本降低最多 90%(你可以阅读我们的提示缓存 cookbook 了解其工作原理)。
然而,随着你的知识库不断增长,你将需要一种更具扩展性的解决方案。这正是上下文检索的用武之地。
对于无法容纳在上下文窗口中的较大知识库,RAG 是典型的解决方案。RAG 通过以下步骤对知识库进行预处理来工作:
在运行时,当用户向模型输入查询时,会使用向量数据库根据与查询的语义相似度找到最相关的块。然后,将最相关的块添加到发送给生成模型的提示中。
虽然嵌入模型擅长捕捉语义关系,但它们可能会错过关键的精确匹配。幸运的是,有一种更早的技术可以在这些情况下提供帮助。BM25(Best Matching 25)是一种使用词汇匹配来查找精确单词或短语匹配的排序函数。它对于包含唯一标识符或技术术语的查询尤其有效。
BM25 建立在 TF-IDF(词频-逆文档频率)概念之上。TF-IDF 衡量一个词对集合中某个文档的重要程度。BM25 通过考虑文档长度并对词频应用饱和函数来改进这一点,这有助于防止常见词主导结果。
以下是 BM25 在语义嵌入失效时如何成功发挥作用:假设用户在技术支持数据库中查询“错误代码 TS-999”。嵌入模型可能会找到关于错误代码的一般内容,但可能会错过精确的“TS-999”匹配。BM25 会查找这个特定的文本字符串以识别相关文档。
RAG 解决方案可以通过以下步骤结合嵌入和 BM25 技术,更准确地检索最适用的块:
通过同时利用 BM25 和嵌入模型,传统 RAG 系统可以提供更全面、更准确的结果,在精确术语匹配与更广泛的语义理解之间取得平衡。
这种方法允许您以成本效益的方式扩展到庞大的知识库,远远超出单个提示所能容纳的范围。但这些传统 RAG 系统有一个显著的局限性:它们常常破坏上下文。
在传统 RAG 中,文档通常被分割成较小的块以便高效检索。虽然这种方法在许多应用中效果良好,但当单个块缺乏足够的上下文时,可能会导致问题。
例如,假设您的知识库中嵌入了一组财务信息(比如美国 SEC 文件),并且您收到了以下问题:“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>
以下是我们想要放入整个文档中定位的片段
<chunk>
{{CHUNK_CONTENT}}
</chunk>
请给出简短精炼的上下文,以将该片段置于整体文档中,从而提升该片段的搜索检索效果。仅以简短精炼的上下文作答,不要包含其他内容。
生成的上下文文本通常为 50-100 个 token,在嵌入之前以及创建 BM25 索引之前,会被前置到该分块中。
以下是预处理流程在实际中的样子:
如果你有兴趣使用上下文检索,可以通过我们的 cookbook 开始。
得益于我们上面提到的特殊提示缓存功能,上下文检索在 Claude 上可以以低成本独特实现。使用提示缓存,你不需要为每个分块都传入参考文档。你只需将文档加载到缓存中一次,然后引用之前缓存的内容。假设分块为 800 个 token、文档为 8k 个 token、上下文指令为 50 个 token,并且每个分块有 100 个 token 的上下文,生成上下文化分块的一次性成本为每百万文档 token 1.02 美元。
我们在各种知识领域(代码库、小说、ArXiv 论文、科学论文)、嵌入模型、检索策略和评估指标上进行了实验。我们在附录 II 中收录了每个领域所使用的一些问题和答案示例。
下图展示了在表现最佳的嵌入配置(Gemini Text 004)并检索前 20 个分块时,所有知识领域的平均表现。我们使用 1 减去 recall@20 作为评估指标,它衡量的是相关文档未能被检索进前 20 个分块的百分比。你可以在附录中看到完整结果——在我们评估的每一种嵌入来源组合中,上下文化都提升了表现。
我们的实验表明:
在实现上下文检索时,有一些注意事项需要牢记:
始终运行评估: 通过向响应生成传入上下文化分块,并区分什么是上下文、什么是分块,可能会改善响应生成。
在最后一步中,我们可以将上下文检索与另一种技术结合,以带来更多性能提升。在传统 RAG 中,AI 系统会搜索其知识库,以找到可能相关的信息分块。对于大型知识库,这种初始检索通常会返回大量分块——有时是数百个——其相关性和重要性各不相同。
重排序是一种常用的过滤技术,用于确保只有最相关的分块被传递给模型。重排序能提供更好的响应,并降低成本和延迟,因为模型处理的信息更少。关键步骤是:
市场上有多种重排序模型。我们使用 Cohere reranker 进行了测试。Voyage也提供重排序器,不过我们没有时间测试它。我们的实验表明,在各种领域中,加入重排序步骤都能进一步优化检索。
具体来说,我们发现重排序上下文嵌入和上下文 BM25 将前 20 个分块的检索失败率降低了 67%(5.7% → 1.9%)。
关于重排序的一个重要考量是对延迟和成本的影响,尤其是在对大量分块进行重排序时。因为重排序在运行时增加了一个额外步骤,即使重排序器并行地对所有分块进行评分,它也必然会增加少量延迟。在对更多分块进行重排序以获得更好性能与对更少分块进行重排序以降低延迟和成本之间,存在固有的权衡。我们建议针对您的具体用例尝试不同的设置,以找到合适的平衡点。
我们进行了大量测试,比较了上述所有技术(嵌入模型、BM25 的使用、上下文检索的使用、重排序器的使用以及检索到的 top-K 结果总数)的不同组合,并覆盖了各种不同的数据集类型。以下是我们发现的总结:
我们鼓励所有使用知识库的开发者使用我们的 cookbook来试验这些方法,以解锁新的性能水平。
以下是跨数据集、嵌入提供商、在嵌入之外使用 BM25、使用上下文检索以及使用重排序在 Retrievals @ 20 上的结果细分。
有关 Retrievals @ 10 和 @ 5 的细分以及每个数据集的示例问题和答案,请参见附录 II。
研究与撰写:Daniel Ford。感谢 Orowa Sikder、Gautam Mittal 和 Kenneth Lien 提供关键反馈,Samuel Flamini 实现 cookbooks,Lauren Polansky 进行项目协调,以及 Alex Albert、Susan Payne、Stuart Ritchie 和 Brad Abrams 对这篇博客文章的塑造。
产品更新、操作指南、社区聚焦等。每月发送到您的收件箱。
