背景
在最近一次关于大型语言模型 (LLM) 状态的概述中,Karpathy 将 LLM 描述为一种新型操作系统的内核进程。正如现代计算机拥有 RAM 和访问文件的权限一样,LLM 拥有一个上下文窗口,可以加载从众多数据源检索的信息。

这种检索到的信息被加载到上下文窗口中,并用于 LLM 输出生成,这个过程通常称为检索增强生成 (RAG)。RAG 是 LLM 应用程序开发中最重要的概念之一,因为它是一种将外部信息传递给 LLM 的简便方法,与在需要 事实 召回的问题上进行更复杂/精细的微调相比,它具有优势。
通常,RAG 系统涉及:一个问题(通常来自用户),它决定要检索哪些信息;一个从数据源(或多个来源)检索该信息的过程;以及一个将检索到的信息直接传递给 LLM 作为提示一部分的过程(参见 LangChain hub 此处的提示示例)。
挑战
RAG 方法的格局在最近几个月里大大扩展,导致用户在从哪里开始以及如何思考各种方法方面存在一定程度的过载或困惑。在过去的几个月里,我们致力于将 RAG 概念分为几个类别,并为每个类别发布了指南。下面我们将提供这些概念的综述,并介绍一些未来的工作。

查询转换
在思考 RAG 时要问的第一个问题:我们如何使检索对于用户输入的可变性具有鲁棒性? 例如,用户问题对于具有挑战性的检索任务来说可能措辞不当。查询转换是一组专注于修改用户输入以改进检索的方法。
查询扩展
考虑问题“红袜队或爱国者队最近谁赢得过冠军?” 回答这个问题可以从提出两个具体的子问题中获益
- “红袜队上次赢得冠军是什么时候?”
- “爱国者队上次赢得冠军是什么时候?”
查询扩展将输入分解为子问题,每个子问题都是一个更狭窄的检索挑战。多查询检索器执行子问题生成、检索,并返回检索到的文档的唯一并集。RAG 融合建立在对来自每个子问题的返回文档进行排序的基础上。回溯提示提供了第三种方法,生成一个回溯问题,以便将答案综合建立在更高层次的概念或原则之上(参见论文)。例如,关于物理学的问题可以回溯为一个关于用户查询背后的物理原理的问题(和 LLM 生成的答案)。
查询重写
为了解决框架或措辞不当的用户输入,重写-检索-阅读(参见论文)是一种重写用户问题以改进检索的方法。
查询压缩
在某些 RAG 应用程序中,例如 WebLang(我们的开源研究助手),用户问题是在更广泛的聊天对话之后提出的。为了正确回答问题,可能需要完整的对话上下文。为了解决这个问题,我们使用此提示将聊天历史记录压缩为用于检索的最终问题。
进一步阅读
路由
在思考 RAG 时要问的第二个问题:数据存储在哪里? 在许多 RAG 演示中,数据存储在单个向量存储中,但在生产环境中通常并非如此。当跨越一组不同的数据存储进行操作时,需要路由传入的查询。LLM 可以有效地用于支持动态查询路由(参见此处),正如我们在最近对 OpenAI RAG 策略的评论中所讨论的那样。
查询构建
在思考 RAG 时要问的第三个问题:查询数据需要什么语法? 虽然路由后的问题是自然语言,但数据存储在关系数据库或图数据库等源中,这些源需要特定的语法才能检索。甚至向量存储也利用结构化元数据进行过滤。在所有情况下,来自查询的自然语言都需要转换为用于检索的查询语法。

文本到 SQL
大量精力集中在将自然语言翻译成 SQL 请求上。通过向 LLM 提供自然语言问题以及相关的表格信息,可以轻松地完成文本到 SQL 的转换(此处);开源 LLM 已被证明在此任务中非常有效,从而实现了数据隐私(请参阅我们的模板此处和此处)。
关系数据库中混合类型(结构化和非结构化)数据存储越来越普遍(参见此处);可以使用开源pgvector PostgreSQL 扩展包含嵌入式文档列。也可以使用自然语言与这种半结构化数据进行交互,将 SQL 的表达能力与语义搜索相结合(请参阅我们的cookbook和模板)。
文本到 Cypher
虽然向量存储可以轻松处理非结构化数据,但它们不理解向量之间的关系。虽然 SQL 数据库可以建模关系,但模式更改可能会造成破坏且成本高昂。知识图谱可以通过建模数据之间的关系并在不进行重大改造的情况下扩展关系类型来应对这些挑战。对于具有多对多关系或难以用表格形式表示的层次结构的数据,它们是理想的选择。
与关系数据库一样,图数据库也受益于使用文本到 Cypher 的自然语言界面,Cypher 是一种结构化查询语言,旨在提供一种可视化方式来匹配模式和关系(请参阅模板此处和此处)。
文本到元数据过滤器
配备元数据过滤的向量存储能够进行结构化查询,以过滤嵌入的非结构化文档。自查询检索器可以使用向量存储中存在的元数据字段的规范,将自然语言转换为带有元数据过滤器的这些结构化查询(请参阅我们的自查询模板)。
进一步阅读
- 请参阅我们关于查询构建的博客文章
索引
在思考 RAG 时要问的第四个问题:如何设计我的索引? 对于向量存储,有很多机会可以调整参数,例如块大小和/或文档嵌入策略,以支持可变数据类型。
块大小
在我们对 OpenAI RAG 策略的评论中,我们强调了他们仅通过在文档嵌入期间试验块大小而看到的性能显着提升。这是有道理的,因为块大小控制了我们加载到上下文窗口(或 LLM OS 类比中的“RAM”)中的信息量。
由于这是索引构建的核心步骤,我们有一个开源Streamlit 应用程序,您可以在其中测试各种块大小以获得一些直觉;特别是,值得检查文档在使用各种拆分大小或策略时在何处拆分,以及语义相关的内容是否被不自然地拆分。
文档嵌入策略
索引设计中最简单且最有用的想法之一是将您嵌入的内容(用于检索)与您传递给 LLM 的内容(用于答案合成)分离。例如,考虑一大段包含大量冗余细节的文本。我们可以嵌入几个不同的表示形式来改进检索,例如摘要或小块以缩小嵌入信息的范围。在任何一种情况下,我们都可以检索全文以传递给 LLM。这些可以使用多向量和父文档检索器分别实现。
多向量检索器也适用于包含文本和表格混合的半结构化文档(请参阅我们的cookbook和模板)。在这些情况下,可以提取每个表格,生成适合检索的表格摘要,但将原始表格返回给 LLM 以进行答案合成。

我们可以更进一步:随着多模态 LLM 的出现,可以使用生成和嵌入图像摘要作为文档中包含文本和图像的图像检索的一种手段(见下图)。
这可能适用于多模态嵌入预计无法可靠检索图像的情况,例如复杂图形或表格的情况。例如,在我们的cookbook中,我们将这种方法与来自财务分析博客(@jaminball 的 Clouded Judgement)的图形一起使用。但是,我们还有另一个cookbook,它使用开源 (OpenCLIP) 多模态嵌入来检索基于更直接视觉概念的图像。

进一步阅读
- 请参阅我们关于多向量检索器的博客文章
后处理
在思考 RAG 时要问的最后一个问题:如何组合我检索到的文档? 这很重要,因为上下文窗口的大小有限,并且冗余文档(例如,来自不同来源)将利用令牌,而不会向 LLM 提供唯一信息。已经出现了一些文档后处理方法(例如,为了提高多样性或过滤最新性),我们在关于 OpenAI RAG 策略的博客文章中讨论了其中一些方法。
重新排序
Cohere ReRank 端点可用于文档压缩(减少冗余),在我们检索大量文档的情况下。相关地,RAG 融合使用倒数排名融合(参见博客和实现)来重新排序从检索器返回的文档(类似于多查询)。
分类
OpenAI 根据每个检索到的文档的内容对其进行分类,然后根据该分类选择不同的提示。这结合了标记的文本以进行分类,以及基于标签的逻辑路由(在本例中,用于提示)。
未来计划
展望未来,我们将至少关注扩展这些主题的两个领域。
开源
许多改进 RAG 的任务都是狭窄且定义明确的。例如,查询扩展(子问题生成)或用于元数据过滤的结构化查询构建是狭窄、定义明确的任务,也可能重复执行。反过来,它们可能不需要大型(且成本最高)的通用模型来获得可接受的性能。相反,较小的开源模型(可能经过微调)可能就足够了。我们将发布一系列模板,展示如何在适当的情况下将开源模型整合到 RAG 堆栈中。
基准
与我们测试开源 LLM 的努力相配合,我们最近推出了公共数据集,这些数据集可以作为评估的真实依据。我们将扩展这些数据集,以包括一些更具体的 RAG 挑战,并使用它们来评估上述方法的优点以及开源 LLM 的整合。