AI个人学习
和实操指南

朴素、有效的RAG检索策略:稀疏+密集混合检索并重排,并利用“提示缓存”为文本块生成整体文档相关的上下文

-1

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


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

在本文中,我们概述了一种能够显著改善 RAG 中检索步骤的方法。这种方法称为“上下文检索”(Contextual Retrieval),并使用了两种子技术:上下文嵌入(Contextual Embeddings)和上下文 BM25(Contextual BM25)。该方法可以将检索失败的数量减少 49%,结合重新排序(reranking)时更可减少 67%。这些改进显著提升了检索的准确性,直接转化为下游任务性能的提升。

本质是语义相似和词频相似的检索结果混合起来,有时语义检索结果并不代表真实意图。注意阅读文本末尾提供的链接,这个“老”策略已经发布有2年,此方法应用依然很少,要么就陷入极度复杂的RAG策略,要么就仅使用嵌入+重排。

本文对这个老策略的微小改善是利用“缓存提示”为文本块低成本的生成符合整体文档背景的上下文。别看改动较小,但效果十分出众!

您可以通过 我们的示例代码 使用 Claude 部署自己的上下文检索解决方案。

 

关于简单使用更长提示的说明

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

几周前,我们为 Claude 发布了 提示缓存,显著加快了此方法的速度并降低了成本。开发者现在可以在 API 调用之间缓存常用的提示,将延迟减少超过 2 倍,成本降低高达 90%(您可以通过阅读我们的 提示缓存示例代码 了解其工作原理)。

然而,随着知识库的增长,您将需要更具可扩展性的解决方案,这就是上下文检索的用武之地。介绍完背景,开始进入正题。

 

RAG 基础知识:扩展到更大的知识库

对于无法放入上下文窗口的大型知识库,RAG 是典型的解决方案。RAG 通过以下步骤对知识库进行预处理:

  1. 将知识库(文档“语料库”)分解为较小的文本片段,通常不超过几百个 Token;(过长的文本块表达含义较多,即语义表达过于丰富)
  2. 使用嵌入模型将这些片段转换为编码意义的向量嵌入;
  3. 将这些嵌入存储在向量数据库中,以便通过语义相似性进行搜索。

 

在运行时,当用户向模型输入查询时,向量数据库会根据查询的语义相似性找到最相关的片段。然后,将最相关的片段添加到发送给生成式模型的提示中(作为大模型引用的上下文回答问题)。

尽管嵌入模型擅长捕捉语义关系,但它们可能遗漏关键的精确匹配。幸运的是,一种较早的技术可以在这种情况下提供帮助。BM25 是一种通过词汇匹配寻找精确词或短语匹配的排序函数。对于包含唯一标识符或技术术语的查询,它特别有效。

BM25 基于 TF-IDF(词频-逆文档频率)概念进行改进。TF-IDF 衡量某个词在文档集合中的重要性。BM25 通过考虑文档长度并对词频应用饱和函数进行优化,防止常见词主导结果。

以下是 BM25 在语义嵌入失效时的工作原理:假设用户在技术支持数据库中查询“错误代码 TS-999”。(向量)嵌入模型可能会找到关于错误代码的通用内容,但可能错过精确的“TS-999”匹配。而 BM25 则会查找该特定文本字符串以识别相关文档。

 

通过结合嵌入和 BM25 技术,RAG 方案可以更准确地检索最相关的片段,具体步骤如下:

  1. 将知识库(文档“语料库”)分解为较小的文本片段,通常不超过几百个 Token;
  2. 为这些片段创建 TF-IDF 编码和语义(向量)嵌入;
  3. 使用 BM25 根据精确匹配找到最佳片段;
  4. 使用(向量)嵌入找到语义相似性最高的片段;
  5. 使用排序融合技术合并并去重步骤(3)和(4)的结果;例如专用的重排模型 Rerank 3.5 。
  6. 将前 K 个片段添加到提示中生成响应。

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

朴素且有效的RAG检索策略:稀疏+密集混合检索并重排,且利用“提示缓存”生成文本块相关上下文-1

一个标准的检索增强生成(RAG)系统,结合嵌入和最佳匹配 25(BM25)检索信息。TF-IDF(词频-逆文档频率)衡量词的重要性,并构成 BM25 的基础。

 

这种方法让您能够以较低成本扩展到远远超出单一提示可容纳的庞大知识库。然而,这些传统 RAG 系统存在一个显著的局限性:它们经常破坏上下文。

讲到这里对基础检索方案做出了合理设计,还没有讲到对截断的文本块看待,被截断的文本块是表达相同内容的,绝不应该截断,但上述RAG方案不可避免的截断了上下文。这是一个既简单又复杂的问题。下面进入本文重点。

 

传统 RAG 中的上下文难题

在传统 RAG 中,文档通常被拆分为更小的块以便于高效检索。这种方法适用于许多应用场景,但当单个块缺乏足够的上下文时,可能会导致问题。

例如,假设您的知识库中嵌入了一些金融信息(例如,美国 SEC 报告),并收到以下问题:"ACME 公司在 2023 年第二季度的收入增长是多少?"

一个相关的块可能包含以下文本:"该公司的收入比上一季度增长了 3%。" 然而,这个块本身并未明确提到具体公司或相关的时间段,使得检索正确信息或有效使用信息变得困难。

引入上下文检索

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

让我们回到 SEC 报告集合的例子。以下是一个块如何被转换的示例:

original_chunk = "该公司的收入比上一季度增长了 3%。"
contextualized_chunk = "该块来自一份关于 ACME 公司 2023 年第二季度表现的 SEC 报告;上一季度的收入为 3.14 亿美元。该公司的收入比上一季度增长了 3%。"

值得注意的是,过去也提出了一些其他使用上下文改进检索的方法。其他建议包括:为块添加通用文档摘要(我们试验后发现增益非常有限)、假设性文档嵌入 和 基于摘要的索引(我们评估后发现性能较低)。这些方法与本文提出的方法有所不同。

通过实验证明很多改进上下文质量的方法增益有限,就算上述提及的相对最佳方法依然值得怀疑。因为加入解释性上下文这个转换过程就会损失或多或少信息

就算切分了一个完整的段落为文本块,并且在完整段落内容中加入多级标题,这个段落孤立的抛开上下文,可能知识传达并不准确,上述例子已经说梦。

此方法有效的解决文本块内容单独存在时,缺乏上下文背景导致内容孤立无意义问题。

 

实现上下文检索

当然,手动为知识库中成千上万甚至数百万的块注释上下文工作量太大。为实现上下文检索,我们转向使用 Claude。我们编写了一个提示,指示模型根据整个文档的上下文提供简洁、块特定的上下文。以下是我们使用 Claude 3 Haiku 的提示来为每个块生成上下文:

<document> 
{{WHOLE_DOCUMENT}} 
</document> 
这是我们希望置于整个文档中的块 
<chunk> 
{{CHUNK_CONTENT}} 
</chunk> 
请提供一个简短且简明的上下文,以便将该块置于整个文档的上下文中,从而改进块的搜索检索。仅回答简洁的上下文,不要包含其他内容。

生成的上下文文本通常为 50-100 个 Token,嵌入前和创建 BM25 索引前会将其添加到块中。

这个提示词运行要引用文本块对应的完整文档(应该不会超过500页吧?),作为提示缓存,才可以准确生成文本块相对于完整文档相关的上下文。

这依赖Claude缓存能力,完整文档作提示缓存输入并不需要每次都付费,缓存嘛,只需一次付费,所以该方案实现的前提条件是大模型允许长文档缓存。DeepSeek 等模型也有类似能力。

 

以下是实际中的预处理流程:

朴素且有效的RAG检索策略:稀疏+密集混合检索并重排,且利用“提示缓存”生成文本块相关上下文-1

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

如果您有兴趣使用上下文检索,可以参考我们的 操作手册 开始。

 

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

得益于我们提到的特殊提示缓存功能,通过 Claude 上下文检索可以以较低的成本实现。通过提示缓存,您无需为每个块传入参考文档。只需将文档加载到缓存中一次,然后引用先前缓存的内容即可。假设每块 800 个 Token,每个文档 8k Token,每条上下文指令 50 个 Token,每个块的上下文为 100 个 Token,生成上下文化块的一次性成本为每百万文档 Token $1.02

方法论

我们在多个知识领域(代码库、小说、ArXiv 论文、科学论文)、嵌入模型、检索策略和评估指标中进行了实验。我们在 附录 II 中列举了我们为每个领域使用的一些问题和答案示例。

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

性能提升

我们的实验表明:

  • 上下文嵌入将前 20 个片段的检索失败率降低了 35%(5.7% → 3.7%)。
  • 结合上下文嵌入和上下文 BM25 将前 20 个片段的检索失败率降低了 49%(5.7% → 2.9%)。

朴素且有效的RAG检索策略:稀疏+密集混合检索并重排,且利用“提示缓存”生成文本块相关上下文-1

结合上下文嵌入和上下文 BM25 将前 20 个片段的检索失败率降低了 49%。

实现注意事项

在实施上下文检索时,需要注意以下几点:

  1. 片段边界: 考虑如何将文档拆分为片段。片段大小、边界和重叠的选择会影响检索性能 ^1^。
  2. 嵌入模型: 虽然上下文检索提高了我们测试的所有嵌入模型的性能,但某些模型可能受益更多。我们发现 Gemini 和 Voyage 嵌入特别有效。
  3. 自定义上下文提示: 尽管我们提供的通用提示效果良好,但通过针对特定领域或用例定制提示(例如,包含知识库中其他文档中可能定义的关键术语表),可以获得更好的结果。
  4. 片段数量: 将更多片段添加到上下文窗口中可以提高包含相关信息的几率。然而,过多信息可能会分散模型的注意力,因此需要控制数量。我们尝试了 5、10 和 20 个片段,发现使用 20 个片段在这些选项中表现最佳(详见附录),但根据您的用例进行实验是值得的。

始终运行评估: 通过传递上下文化的片段并区分上下文和片段,可以改进响应生成。

 

使用重排序进一步提升性能

在最后一步中,我们可以结合上下文检索和另一种技术,以进一步提高性能。在传统的 RAG(Retrieval-Augmented Generation)中,AI 系统在其知识库中搜索可能相关的信息片段。对于大型知识库,初始检索通常返回大量片段——有时多达数百个,相关性和重要性各不相同。

重排序是一种常用的过滤技术,可以确保仅将最相关的片段传递给模型。重排序提供了更好的响应,同时降低了成本和延迟,因为模型处理的信息更少。关键步骤如下:

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

 

朴素且有效的RAG检索策略:稀疏+密集混合检索并重排,且利用“提示缓存”生成文本块相关上下文-1结合上下文检索和重排序最大化检索准确性。

性能提升

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

具体而言,我们发现重排序上下文嵌入和上下文 BM25 将前 20 个片段的检索失败率降低了 67%(5.7% → 1.9%)。

朴素且有效的RAG检索策略:稀疏+密集混合检索并重排,且利用“提示缓存”生成文本块相关上下文-1重排序上下文嵌入和上下文 BM25 将前 20 个片段的检索失败率降低了 67%。

 

成本和延迟的考虑

重排序的一个重要考虑因素是对延迟和成本的影响,特别是在重排序大量片段时。由于重排序在运行时增加了一个额外步骤,它不可避免地增加了一些延迟,即使重排序器是并行为所有片段打分的。在为更高性能重排序更多片段与为更低延迟和成本重排序更少片段之间存在权衡。我们建议针对您的具体用例实验不同设置,以找到最佳平衡点。

 

结论

我们运行了大量测试,比较了上述所有技术(嵌入模型、BM25 的使用、上下文检索的使用、重排序器的使用以及前 K 个检索结果的数量)的不同组合,并跨各种数据集类型进行了实验。以下是我们的发现摘要:

  1. 嵌入+BM25 比仅使用嵌入更好;
  2. Voyage 和 Gemini 是我们测试中效果最好的嵌入模型;
  3. 将前 20 个片段传递给模型比仅传递前 10 或前 5 个更有效;
  4. 为片段添加上下文极大地提高了检索准确性;
  5. 重排序比不重排序更好;
  6. 所有这些优势可以叠加: 为了最大化性能改进,我们可以结合使用上下文嵌入(来自 Voyage 或 Gemini)、上下文 BM25、重排序步骤,并将 20 个片段添加到提示中。

我们鼓励所有使用知识库的开发者使用 我们的实践手册 实验这些方法,以解锁新的性能水平。

 

附录 I

以下是跨数据集、嵌入提供商、BM25 与嵌入结合使用、上下文检索的使用和重排序的使用的 Retrievals @ 20 结果分解。

有关 Retrievals @ 10 和 @ 5 的分解以及每个数据集的问题和答案示例,请参见 附录 II

 

朴素且有效的RAG检索策略:稀疏+密集混合检索并重排,且利用“提示缓存”生成文本块相关上下文-11 减去 recall @ 20 的数据集和嵌入提供商结果。

脚注

  1. 有关片段划分策略的更多阅读,请查看 此链接 和 此链接
未经允许不得转载:首席AI分享圈 » 朴素、有效的RAG检索策略:稀疏+密集混合检索并重排,并利用“提示缓存”为文本块生成整体文档相关的上下文

首席AI分享圈

首席AI分享圈专注于人工智能学习,提供全面的AI学习内容、AI工具和实操指导。我们的目标是通过高质量的内容和实践经验分享,帮助用户掌握AI技术,一起挖掘AI的无限潜能。无论您是AI初学者还是资深专家,这里都是您获取知识、提升技能、实现创新的理想之地。

联系我们
zh_CN简体中文