Deconstructing RAG

解构 RAG

阅读时长 7 分钟

背景

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

检索是新型 LLM 操作系统的一个核心组成部分

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

通常,RAG 系统包括:一个问题(通常来自用户),它决定了要检索什么信息;一个从数据源(或多个数据源)检索该信息的过程;以及一个将检索到的信息直接作为提示的一部分传递给 LLM 的过程(可以在 LangChain hub 此处查看示例提示)。

挑战

近几个月来,RAG 方法的范围已大大扩展,导致用户在如何开始和如何看待各种方法上都感到有些不知所措或困惑。在过去的几个月里,我们一直致力于将 RAG 概念归入几个类别,并为每个类别发布了指南。下面我们将对这些概念进行总结,并介绍一些未来的工作。

主要 RAG 主题

查询转换

在思考 RAG 时要问的第一个问题是:我们如何才能使检索对用户输入的变异性具有鲁棒性?例如,对于检索的挑战性任务,用户的问题可能表述不当。查询转换是一组专注于修改用户输入以改进检索的方法。

查询扩展

考虑问题“红袜队还是爱国者队最近赢得过冠军?” 回答这个问题可以通过问两个具体的子问题来完成

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

查询扩展将输入分解为子问题,每个子问题都是一个更狭窄的检索挑战。多查询检索器执行子问题生成、检索,并返回检索到的文档的唯一并集。RAG fusion 则在此基础上对每个子问题返回的文档进行排序。Step-back prompting 提供了第三种类似的方法,它生成一个“step-back”问题,以更高层次的概念或原则为基础来综合答案(参见论文)。例如,关于物理学的问题可以“step-back”成一个关于用户查询背后物理学原理的问题(和 LLM 生成的答案)。

查询重写

为了处理表述不当或措辞不佳的用户输入,重写-检索-读取(Rewrite-Retrieve-Read,参见论文)是一种重写用户问题以改进检索的方法。

查询压缩

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

进一步阅读


路由

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


查询构建

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

文本到 SQL

已有大量工作致力于将自然语言转换为 SQL 请求。文本到 SQL 可以轻松完成(此处),方法是将自然语言问题以及相关的表信息提供给 LLM;开源 LLMs 在此任务中已被证明非常有效,从而实现了数据隐私(请参阅我们的模板此处此处)。

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

文本到 Cypher

虽然向量库可以很好地处理非结构化数据,但它们不理解向量之间的关系。虽然 SQL 数据库可以模拟关系,但模式更改可能会造成干扰和高成本。知识图谱可以通过模拟数据之间的关系并扩展关系类型而不进行重大改造来解决这些挑战。它们对于具有难以在表格形式中表示的多对多关系或层级结构的数据非常有用。

与关系数据库一样,图数据库也受益于自然语言界面,使用文本到 Cypher,这是一种结构化查询语言,旨在提供一种可视化匹配模式和关系的方式(参见模板此处此处)。

文本到元数据过滤器

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

进一步阅读


索引

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

块大小

在审查 OpenAI 的RAG 策略时,我们强调了他们仅仅通过在文档嵌入过程中试验块大小就看到了显著的性能提升。这是有道理的,因为块大小控制着我们加载到上下文窗口(或我们 LLM OS 类比中的“RAM”)中的信息量。

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

文档嵌入策略

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

对于包含文本和表格混合的半结构化文档,多向量检索器也能很好地工作(参见我们的烹饪书模板)。在这些情况下,可以提取每个表格,生成一个适合检索的表格摘要,然后将原始表格返回给 LLM 进行答案综合。

MVR.png

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

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

进一步阅读


后处理

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

重排序

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

分类

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


未来计划

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

开源

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

基准测试

与我们测试开源 LLMs 的努力相辅相成,我们最近推出了公共数据集,这些数据集可以作为评估的地面实况。我们将扩展这些数据集,以包含更多具体的 RAG 挑战,并利用它们来评估上述方法的优点以及开源 LLMs 的集成。

© . This site is unofficial and not affiliated with LangChain, Inc.