Deconstructing RAG

解构 RAG

7 分钟阅读

背景

最近的大型语言模型 (LLM) 状态概述 中,Karpathy 将 LLM 描述为一种新型操作系统的内核进程。就像现代计算机拥有内存并能够访问文件一样,LLM 拥有一个上下文窗口,可以加载从众多数据源检索到的信息。

检索是新型 LLM 操作系统的核心组件

检索到的信息会加载到上下文窗口中,并用于 LLM 输出生成,这个过程通常被称为检索增强生成 (RAG)。RAG 是 LLM 应用程序开发中最重要 的概念之一,因为它是一种将外部信息传递给 LLM 的简单方法,与更复杂/更复杂的针对需要 事实 召回 的问题进行微调相比,它具有优势。

通常,RAG 系统包含:一个问题(通常来自用户),它决定要检索哪些信息;一个从数据源(或多个数据源)检索该信息的流程;以及一个将检索到的信息直接作为提示的一部分传递给 LLM 的流程(参见 LangChain 集线器中的示例提示 这里)。

挑战

近年来,RAG 方法的格局发生了巨大变化,导致用户在如何开始以及如何思考各种方法方面,在一定程度上感到不知所措或困惑。在过去的几个月里,我们一直努力将 RAG 概念归类到几个类别中,并为每个类别发布了指南。下面,我们将总结这些概念并介绍一些未来的工作。

主要的 RAG 主题

查询转换

在考虑 RAG 时,第一个要问的问题是:如何才能使检索对用户输入的变化具有鲁棒性?例如,用户问题在检索的挑战性任务中,可能措辞不当。查询转换是一组方法,专注于修改用户输入,以提高检索效果。

查询扩展

考虑以下问题:“红袜队和爱国者队谁最近赢得了冠军?”回答这个问题可以从提出两个具体的分问题获益

  • “红袜队上次赢得冠军是什么时候?”
  • “爱国者队上次赢得冠军是什么时候?”

查询扩展将输入分解为分问题,每个分问题都是一个更窄的检索挑战。multi-query retriever 执行分问题生成、检索,并返回检索到的文档的唯一并集。RAG 融合 在此基础上进行了构建,对每个分问题返回的文档进行排名。逐步提示 提供了第三种方法,生成一个逐步问题,将答案合成建立在更高级别的概念或原则之上(参见 论文)。例如,关于物理学的问题可以逐步转化为关于用户查询背后的物理原理的问题(以及 LLM 生成的答案)。

查询重写

为了解决措辞不当或表达不清晰的用户输入问题,重写-检索-阅读(参见 论文)是一种方法,可以 重新编写用户问题,以提高检索效果。

查询压缩

在某些 RAG 应用程序中,例如 WebLang(我们的开源研究助手),用户问题遵循更广泛的聊天对话。为了正确回答问题,可能需要完整的对话上下文。为了解决这个问题,我们使用 此提示 将聊天历史压缩成一个最终问题,用于检索。

进一步阅读


路由

在考虑 RAG 时,要问的第二个问题是:数据存储在哪里?在许多 RAG 演示中,数据存储在一个向量存储库中,但在生产环境中通常并非如此。在跨多个数据存储库进行操作时,需要对传入的查询进行路由。LLM 可以有效地用于支持动态查询路由(参见 这里),正如我们最近对 OpenAI RAG 策略 的综述中所讨论的那样。


查询构建

在考虑 RAG 时,要问的第三个问题是:查询数据需要什么语法?虽然路由后的问题是自然语言,但数据存储在关系数据库或图数据库等需要特定语法才能检索的来源中。即使向量存储库也使用结构化元数据进行过滤。在所有情况下,都需要将来自查询的自然语言转换为检索的查询语法。

文本到 SQL

人们付出了相当大的努力,将自然语言转换为 SQL 请求。文本到 SQL 可以很容易地完成(这里),方法是向 LLM 提供自然语言问题以及相关表信息;开源 LLM 已证明在这种任务中非常有效,从而能够保护数据隐私(参见我们的模板 这里这里)。

关系数据库中混合类型(结构化和非结构化)数据存储越来越普遍(参见 这里);可以使用 开源 pgvector 扩展程序为 PostgreSQL 包含嵌入式文档列。还可以使用自然语言与这种半结构化数据进行交互,将 SQL 的表达能力与语义搜索结合起来(参见我们的 cookbook模板)。

文本到 Cypher

虽然向量存储库可以轻松处理非结构化数据,但它们无法理解向量之间的关系。虽然 SQL 数据库可以建模关系,但模式更改可能会造成破坏并代价高昂。知识图谱可以通过对数据之间的关系进行建模并扩展关系类型来解决这些挑战,而无需进行重大改革。它们适用于具有难以在表格形式中表示的许多对多关系或层次结构的数据。

与关系数据库一样,图数据库也有益于使用文本到 Cypher 的自然语言接口,Cypher 是一种结构化查询语言,旨在以直观的方式提供匹配模式和关系的方法(参见模板 这里这里)。

文本到元数据过滤器

配备了 元数据过滤 的向量存储库能够使用结构化查询过滤嵌入式非结构化文档。 自查询检索器 可以使用向量存储库中存在的元数据字段规范将自然语言转换为这些结构化查询,并带有元数据过滤器(参见我们的自查询 模板)。

进一步阅读


索引

在考虑 RAG 时,要问的第四个问题是:如何设计索引?对于向量存储库,有很大的机会调整参数,例如块大小和/或文档嵌入策略,以支持不同的数据类型。

块大小

在我们对 OpenAI RAG 策略 的综述中,我们强调了他们在文档嵌入期间简单地通过实验块大小而观察到的性能显著提升。这是有道理的,因为块大小控制着我们加载到上下文窗口(或我们 LLM 操作系统类比中的“内存”)中的信息量。

由于这是索引构建中的一个核心步骤,因此我们有一个 开源 Streamlit 应用程序,您可以在其中测试各种块大小以获得一些直觉;特别是,值得检查使用不同拆分大小或策略时文档的拆分位置,以及语义相关的內容是否被不自然地拆分。

文档嵌入策略

索引设计中最简单、最有用的想法之一是将您要嵌入的内容(用于检索)与您要传递给 LLM 的内容(用于答案合成)分离。例如,考虑一个包含大量冗余细节的大段文本。我们可以嵌入该文本的几种不同表示形式,以提高检索效果,例如摘要小块,以缩小嵌入信息的范围。在这两种情况下,我们都可以检索完整文本传递给 LLM。这些可以使用 多向量父文档 检索器分别实现。

多向量检索器也适用于包含文本和表格混合的半结构化文档(参见我们的 cookbook模板)。在这些情况下,可以提取每个表格,生成适合检索的表格摘要,但将原始表格返回给 LLM 以进行答案合成。

MVR.png

我们可以更进一步:随着 多模态 LLM 的出现,可以生成和嵌入图像摘要,作为包含文本和图像的文档的图像检索的一种方法(参见下图)。

这可能适用于多模态嵌入预计无法可靠地检索图像的情况,例如复杂图形或表格。例如,在我们的 cookbook 中,我们使用这种方法处理来自金融分析博客(@jaminball 的 Clouded Judgement)的图形。但是,我们还有另一个 cookbook,使用开源(OpenCLIP)多模态嵌入来检索基于更简单的视觉概念的图像。

进一步阅读


后处理

在考虑 RAG 时,要问的最后一个问题是:如何合并检索到的文档?这一点很重要,因为上下文窗口的大小有限,冗余文档(例如,来自不同来源的文档)将使用令牌,而不会向 LLM 提供独特的信息。已经出现了一些文档后处理方法(例如,提高多样性或过滤最近的信息),我们在关于 OpenAI RAG 策略 的博客文章中讨论了一些方法。

重新排序

可以使用 Cohere ReRank 端点来压缩文档(减少冗余),尤其是在检索大量文档的情况下。类似地,RAG 融合使用互惠排序融合(参见 博客实现)来重新排序从检索器返回的文档(类似于 多查询)。

分类

OpenAI 根据每个检索到的文档的内容对其进行分类,然后根据该分类选择不同的提示。这将 标记 文本 用于分类,并与 逻辑路由(在本例中,用于提示)结合使用,该路由基于标记。


未来计划

展望未来,我们将重点关注至少两个扩展这些主题的领域。

开源

这些用于改进 RAG 的任务中,很多都是狭窄而明确定义的。例如,查询扩展(子问题生成)或用于元数据过滤的结构化查询构建是狭窄而明确定义的任务,这些任务也可能重复执行。因此,它们可能不需要大型(且成本最高)的通用模型来实现可接受的性能。相反,更小的开源模型(可能通过微调)就足够了。我们将发布一系列模板,展示如何在适当的情况下将开源模型应用到 RAG 堆栈中。

基准

与我们测试开源 LLM 的努力相辅相成,我们最近发布了 公共数据集,这些数据集可以作为评估的真实依据。我们将扩展这些数据集,以包括一些更具体的 RAG 挑战,并使用它们来评估上述方法的优点以及开源 LLM 的整合。