问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

RAG性能优化杀器,引入上下文检索!

创作时间:
作者:
@小白创作中心

RAG性能优化杀器,引入上下文检索!

引用
1
来源
1.
https://cloud.tencent.com/developer/article/2454901?policyId=1&traceId=

RAG(Retrieval-Augmented Generation)是一种通过从知识库中检索相关信息并将其附加到用户提示词中,从而显著提升模型回答能力的技术。然而,传统的RAG解决方案在编码信息时会丢失上下文,导致系统无法从知识库中检索到相关信息。本文介绍了一种显著提升RAG检索步骤的方法,称为“上下文检索”,它利用两个子技术:上下文嵌入(Contextual Embeddings)和上下文BM25(Contextual BM25)。该方法可将检索未命中率减少49%,结合重新排序后,甚至可减少67%。这些改进显著提高检索准确性,进而提升下游任务表现。

前言

为了让AI模型在特定环境中有用,它通常需要访问背景知识。如客服聊天机器人需要了解它所服务的特定业务,法律分析机器人则需要掌握大量的过往案例。

开发者通常通过RAG扩展AI模型的知识。RAG是一种从知识库中检索相关信息并将其附加到用户提示词中的方法,从而显著提升模型的回答能力。但传统的RAG解决方案在编码信息时会丢失上下文,导致系统无法从知识库中检索到相关信息。

本文介绍了一种显著提升RAG检索步骤的方法,称为“上下文检索”,它利用两个子技术:

  • 上下文嵌入(Contextual Embeddings)
  • 上下文BM25(Contextual BM25)

该方法可将检索未命中率减少49%,结合重新排序后,甚至可减少67%。这些改进显著提高检索准确性,进而提升下游任务表现。

可通过操作指南轻松部署自己的上下文检索解决方案。

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

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

Claude已发布提示词缓存,可显著加快并更实惠。开发者现可在API调用之间缓存常用提示词,减少超过2倍的延迟,降低高达90%的成本(阅读提示词缓存操作指南)。

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

1 RAG 简介:扩展到更大的知识库

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

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

在运行时,当用户向模型输入查询时,向量数据库用于根据查询的语义相似性查找最相关的文本块。然后,将最相关的文本块添加到发送给生成模型的提示词中。

尽管嵌入模型擅长捕捉语义关系,但它们可能会错过重要的精确匹配。幸运的是,有一种较老的技术可以在这些情况下提供帮助。BM25(最佳匹配25)是一种排名函数,使用词汇匹配来查找精确的单词或短语匹配。对于包含唯一标识符或技术术语的查询,它特别有效。

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)的结果;
  6. 将前K个文本块添加到提示词中生成响应。

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

这种方法可以让你以低成本扩展到庞大的知识库,远超单个提示词所能容纳的范围。但传统RAG系统有一个显著的局限:它们往往破坏上下文。

传统 RAG 中的上下文问题

在传统RAG中,文档通常被拆分为较小的块,以便于检索。尽管这种方法在许多应用中表现良好,但当单个文本块缺乏足够的上下文时,可能会导致问题。

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

一个相关的文本块可能包含:“公司收入比上一季度增长了3%。”然而,这个块本身并未指明是哪家公司或哪个时间段,导致很难检索到正确的信息或有效使用这些信息。

2 引入上下文检索

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

让我们回到美国证券交易委员会文件的例子。以下是一个文本块的转换示例:

原始文本块 = “公司收入比上一季度增长了 3%。”
上下文化文本块 = “本块来自 ACME 公司 2023 年第二季度的证券交易委员会文件;上一季度的收入为 3.14 亿美元。公司收入比上一季度增长了 3%。”

值得注意的是,过去曾提出过其他使用上下文改进检索的方法。其他提案包括:为文本块添加通用文档摘要(我们实验后发现效果有限),使用假设文档嵌入(我们评估后发现效果不佳),以及基于摘要的索引(我们实验后表现不佳)。这些方法与本文提出的方案不同。

实现上下文检索

当然,手动为知识库中的成千上万个块注释上下文太费力。为实现上下文检索,我们转向了Claude。我们编写了一个提示词,指示模型提供简洁、特定于块的上下文,使用整个文档的上下文来解释该块。我们使用了以下Claude 3 Haiku提示词为每个块生成上下文:

<document>
{{WHOLE_DOCUMENT}}
</document>
这是我们希望在整个文档中定位的块
<chunk>
{{CHUNK_CONTENT}}
</chunk>
请提供简短的上下文,以便在文档中更好地定位此块以改进搜索检索。只回答简短的上下文,别无其他。

生成的上下文文本通常为50到100个token,将其附加到文本块之前进行嵌入并创建BM25索引。

实际预处理流程的示意图:

如果你有兴趣使用上下文检索,可通过我们的操作指南入手。

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

得益于Claude的特殊提示词缓存功能,上下文检索在低成本上具有独特优势。使用提示词缓存,你无需为每个块传入参考文档。你只需将文档一次性加载到缓存中,然后引用先前缓存的内容。假设每个块800个token,文档8,000个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%)。

实施考虑

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

  1. 文本块边界:考虑如何将文档拆分为文本块。文本块大小、边界以及重叠会影响检索表现。
  2. 嵌入模型:尽管上下文检索提高了我们测试的所有嵌入模型的性能,但某些模型可能受益更多。我们发现Gemini和Voyage嵌入特别有效。
  3. 自定义上下文提示词:虽然我们提供的通用提示词效果不错,但你可以通过针对特定领域或用例调整提示词,获得更好的结果(例如,包含知识库其他文档中定义的关键术语词汇表)。
  4. 文本块数量:将更多的文本块添加到上下文窗口中可以增加包含相关信息的机会。然而,过多信息可能会对模型造成干扰,因此有一个限度。我们尝试了5、10和20个块,发现20个块是最有效的选项,但值得根据你的用例进行实验。
  5. 始终进行评估:通过传递上下文化的文本块并区分上下文和块内容,生成的响应可能会得到改进。

3 通过重排,进一步提升性能

最后一步,我们可以结合上下文检索与另一种技术,以进一步提升性能。在传统RAG中,AI系统会在其知识库中搜索潜在的相关信息块。当知识库很大时,这种初始检索往往会返回大量块——有时成百上千块,且相关性和重要性各不相同。

重新排序是一种常用的过滤技术,确保只有最相关的文本块被传递给模型。重新排序能提供更好的响应,并减少成本和延迟,因为模型处理的信息更少。关键步骤如下:

  1. 进行初始检索,获取潜在相关文本块的前N个(我们使用前150个);
  2. 将前N个文本块与用户的查询一起传递给重新排序模型;
  3. 使用重新排序模型,根据每个块与提示词的相关性和重要性给出得分,然后选择前K个块(我们使用前20个);
  4. 将前K个文本块作为上下文传递给模型生成最终结果。

性能提升

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

具体而言,我们发现,重新排序后的上下文嵌入和上下文BM25将前20个块检索未命中率降低了67%(5.7% → 1.9%)。

成本和延迟考虑

重新排序的一个重要考虑因素是对延迟和成本的影响,尤其是在对大量文本块进行重新排序时。因为重新排序在运行时增加了额外的步骤,必然会增加少量延迟,尽管重新排序器会并行对所有文本块进行评分。在检索更多文本块以提高性能与检索较少文本块以降低延迟和成本之间存在权衡。我们建议在你的具体用例上进行不同设置的实验,找到合适的平衡点。

4 结论

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

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

我们鼓励所有使用知识库的开发者通过我们的操作指南进行实验,以解锁新的性能水平。

附录 I

以下是数据集、嵌入提供商、BM25与嵌入结合使用、上下文检索的使用、重新排序的使用以及前20个检索结果的表现细分。关于前10和前5个检索结果的细分以及每个数据集的示例问题和答案,请参见附录II。

参考:

  • 文本块拆分策略的进一步阅读,参考此链接和此链接。
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号