对于AI模型在特定情境下变得有用,往往需要访问背景知识。例如,客户服务聊天机器人需要了解其服务的具体业务,而法律分析机器人需要了解大量过去的案例。
开发人员通常使用增强检索生成(RAG)来提升AI模型的知识。RAG是一种方法,它从知识库中检索相关信息并将其附加到用户的提示之中,从而显著提升模型的响应质量。问题是,传统的RAG解决方案在编码信息时会移除上下文,这往往导致系统无法从知识库中检索到相关的信息。
在本文中,我们概述了一个显著改进RAG中检索步骤的方法。该方法称为“上下文检索”,使用两个子技术:上下文嵌入与上下文BM25。这种方法可以将失败的检索次数减少49%,并且当与重排序结合使用时,可以将其减少至67%。这些显著提升了检索准确性,从而直接转化为下游任务的更好表现。
你可以通过我们的食谱轻松部署你自己的上下文检索方案。
关于使用更长提示的一个注释
有时候最简单的解决方案就是最好的。如果你的知识库小于200,000个标记(约500页资料),你可以直接将整个知识库包含在提供给模型的提示中,无需使用RAG或类似方法。
几周前,我们发布了prompt缓存,这使得这种方法速度更快且更具成本效益。开发人员现在可以在API调用之间缓存常用提示,降低延迟超过2倍,并减少高达90%的成本(你可以通过阅读我们的prompt缓存食谱了解具体详情)。
然而,随着你的知识库的增长,你需要一个更可扩展的方案。这就是上下文检索的作用所在。
RAG入门:扩展至更大的知识库
对于较大的知识库,无法适应上下文窗口时,RAG是典型的解决方案。RAG通过以下步骤处理知识库:
- 将知识库(文档的“语料库”)分解为较小的文本片段,通常不超过几百个标记;
- 使用嵌入模型将这些片段转换为向量嵌入,用来编码意义;
- 将这些嵌入存储在一个向量数据库中,以便根据语义相似性进行搜索。
运行时,当用户向模型输入查询时,向量数据库用于基于语义相似性找到最相关的片段。然后,将最相关的片段添加到发送给生成模型的提示之中。
虽然嵌入模型擅长捕捉语义关系,但它们可能会错过关键的确切匹配。幸运的是,有一种较旧的技术可以在这方面提供帮助。BM25(最佳匹配25)是一个排名函数,使用词汇匹配来查找精确的单词或短语匹配。它特别适用于包含唯一标识符或技术术语的查询。
BM25基于TF-IDF(词频-逆文档频率)概念,对这一概念进行细化。TF-IDF衡量一个词在一个集合中的文档中的重要性。BM25通过考虑文档长度并对词频应用饱和函数来改进这一点,以防止常用词主导结果。
以下是BM25如何在语义嵌入失败的地方成功的例子:假设用户在技术支持数据库中查询“错误代码TS-999”。一个嵌入模型可能会找到关于错误代码的内容,但可能错过确切的“TS-999”匹配。BM25通过寻找这个特定的文字字符串来识别相关文件。
RAG解决方案可以通过结合嵌入和BM25技术,按照以下步骤更准确地检索相关片段:
- 将知识库(“语料库”的文档)分解为较小的文本片段,通常不超过几百个标记;
- 为这些片段创建TF-IDF编码和语义嵌入;
- 使用BM25基于确切匹配找到顶级片段;
- 使用嵌入法根据语义相似性找到顶级片段;
- 根据排名融合技术合并并去重步骤(3)和(4)的结果;
- 添加前K个顶级片段到提示以生成响应。
通过结合BM25和嵌入模型,传统RAG系统可以提供更为全面和准确的结果,平衡精确的术语匹配与更广泛的语义理解。
此标准检索增强生成(RAG)系统结合了嵌入和最佳匹配25(BM25)来检索信息。TF-IDF(词频-逆文档频率)衡量词语重要性并构成BM25的基础。这种方法能够使你以具有成本效益的方式扩展巨大的知识库,远远超出单个提示所能容纳的范围。但这些传统的RAG系统有一个重大缺点:它们往往会破坏上下文。
传统RAG中的上下文问题
在传统的RAG中,文档通常被分为较小的片段以提高检索效率。虽然这种方法适用于许多应用,但在单个片段缺乏足够上下文的情况下,会导致问题。
例如,想象你有一个财务信息(比如说美国证券交易委员会SEC文件)的知识库,并收到了如下问题:“ACME公司在2023年第二季度的营收增长是多少?”
一个相关的片段可能是:“公司的收入比前一季度增长了3%。”但单独来看这段文字并没有指明它所涉及的具体公司或时间区间,使得难以准确检索或有效使用这些信息。
引入上下文检索
上下文检索通过在嵌入之前以及创建BM25索引之前为每个片段添加特定于片段的解释性上下文来解决这个问题(称为“上下文嵌入”与“上下文BM25”)。
让我们回到SEC文件的例子。以下是片段如何变形的一个示例:
原始片段 = "公司的收入比前一季度增长了3%。"
上下文化片段 = "这是来自ACME公司在2023年第二季度业绩报告的一部分;上一季度收入为3亿1400万美元。公司的收入比前一季度增长了3%。"
值得一提的是其他改善检索的方法在过去已经被提出过。其他提案包括:在片段中加入通用的文档摘要(我们尝试后发现效果非常有限),假设文档嵌入,以及基于总结的索引(我们评估后发现性能较低)。这些方法不同于本篇提出的方案。
实施上下文检索
当然,手动标注知识库中的数千乃至数百万个片段显然太多工作。为了实施上下文检索,我们转向Claude。我们编写了一段提示,引导模型提供简明且特定于片段的上下文,解释片段在整个文档中的位置。我们使用的Claude 3俳句提示如下:
文档
{{WHOLE_DOCUMENT}}
</文档>
这是我们希望定位到整个文档中的片段
片段
{{CHUNK_CONTENT}}
</片段>
请给出简短且精准的上下文,以便将此片段定位在整个文档中以提高检索的准确性。仅回答简短的上下文内容,其余部分不要添加。
生成的上下文文本通常为50-100个标记,在嵌入片段以及创建BM25索引之前先附加到片段上。
以下是在实践中预处理流程的样子:
上下文检索是一种预处理技术,提高了检索准确性。
如果你有兴趣使用上下文检索,你可以通过我们的食谱开始。
使用提示缓存来降低上下文检索的成本
上下文检索利用我们上述提到的Claude特有的提示缓存功能可以以极低的成本实现。借助提示缓存功能,您无需为每个片段都传递参考文档。您只需要将文档一次加载到缓存中,随后引用之前已缓存的内容即可。假设800标记的片段,8k标记的文档,50标记的上下文指令和每个片段100标记的上下文,每百万文档标记生成上下文化的片段的一次性成本为$1.02。
方法论
我们在不同的知识领域(代码库、小说、ArXiv论文、科学论文)、嵌入模型、检索策略及评估指标上进行了实验。我们在附录II中包含了一些用于每个领域的示例问题及答案。
下面的图表显示了使用最佳性能嵌入配置(Gemini Text 004)并在检索前20个最相关片段时所有知识领域的平均性能。我们采用1减去Recall@20作为我们的评估指标,该指标衡量在前20个片段内未能检索到的相关文档比例。您可以查看附录中的全部结果 — 在我们评估的所有嵌入源组合中,上下文化都提高了性能。
**性能