Self-Reflective RAG with LangGraph

使用 LangGraph 的自反思 RAG

6 分钟阅读

动机

由于大多数 LLM 仅定期使用大型公共数据语料库进行训练,因此它们缺乏最新的信息和/或无法用于训练的私有数据。Retrieval augmented generation (RAG),即检索增强生成,是 LLM 应用程序开发中的核心范例,旨在通过将 LLM 连接到外部数据源来解决此问题(请参阅我们的视频系列博客文章)。基本的 RAG 流程包括嵌入用户查询,检索与查询相关的文档,并将文档传递给 LLM 以生成基于检索到的上下文的答案。

基本 RAG 流程

自反思 RAG

在实践中,许多人发现实施 RAG 需要围绕这些步骤进行逻辑推理:例如,我们可以询问何时检索(基于问题和索引的组成)、何时重写问题以获得更好的检索,或者何时丢弃不相关的检索文档并重新尝试检索?术语自反思 RAG (论文) 已被引入,它捕捉了使用 LLM 自我纠正低质量检索和/或生成的想法。

基本 RAG 流程(如上所示)仅使用:LLM 根据检索到的文档确定要生成的内容。一些 RAG 流程使用路由,其中 LLM 例如根据问题在不同的检索器之间进行选择。但是自反思 RAG 通常需要某种反馈,重新生成问题和/或重新检索文档。状态机是第三种认知架构,它支持循环,非常适合这种情况:状态机只是让我们定义一组步骤(例如,检索、评估文档、重写查询)并设置它们之间的转换选项;例如,如果我们的检索文档不相关,则重写查询并重新检索新文档。

RAG 的认知架构

使用 LangGraph 的自反思 RAG

我们最近推出了 LangGraph,这是一种实现 LLM 状态机的简便方法。这为我们提供了在各种 RAG 流程的布局方面的很大灵活性,并支持更通用的 RAG “流程工程”过程,其中包含特定的决策点(例如,文档评分)和循环(例如,重试检索)。

状态机使我们能够设计更复杂的 RAG “流程”

为了突出 LangGraph 的灵活性,我们将使用它来实现受两篇有趣且最新的自反思 RAG 论文 CRAGSelf-RAG 启发的想法。

纠正性 RAG (CRAG)

纠正性 RAG (CRAG) 引入了一些有趣的想法 (论文)

  • 采用轻量级检索评估器来评估检索到的文档对于查询的整体质量,并为每个文档返回置信度评分。
  • 如果向量存储检索被认为模棱两可或与用户查询无关,则执行基于网络的文档检索以补充上下文
  • 通过将检索到的文档划分为“知识条”,对每个条进行评分,并过滤掉不相关的条,来执行知识提炼
Screenshot 2024-02-04 at 2.50.32 PM.png
CRAG 的图表

我们可以将此表示为图表,为了说明目的进行了一些简化和调整(当然,可以根据需要进行自定义和扩展)

  • 作为第一步,我们将跳过知识提炼阶段。它代表了一种有趣且有价值的后处理形式,但对于理解如何在 LangGraph 中布置此工作流程并非必不可少。
  • 如果任何文档不相关,我们将使用网络搜索补充检索。我们将使用Tavily Search API 进行网络搜索,它快速且方便。
  • 我们将使用查询重写来优化网络搜索的查询。
  • 对于二元决策,我们使用 Pydantic 对输出进行建模,并将此函数作为 OpenAI 工具提供,该工具在每次 LLM 运行时都会被调用。这使我们能够对条件边的输出进行建模,其中一致的二元逻辑至关重要。
Screenshot 2024-02-04 at 1.32.52 PM.png
CRAG 的 LangGraph 实现

我们在示例 notebook中对此进行了布局,并索引了三篇 博客 文章。我们可以在此处看到一个 trace,突出显示了当被问及博客文章中找到的信息时的用法:我们节点之间的逻辑流程清晰地列举了出来。

相比之下,我们提出了一个超出博客文章领域的问题。 此处的 trace 显示,我们调用了条件边的下部路径,并从 Tavily 网络搜索中收集了补充文档,用于最终生成。

Self-RAG

Self-RAG 是一种相关的方法,具有其他几个有趣的 RAG 想法 (论文)。该框架训练 LLM 生成自我反思 token,这些 token 控制 RAG 过程的各个阶段。以下是 token 的摘要

  • Retrieve token 决定使用输入 x (问题) OR x (问题), y (生成) 检索 D 个 chunk。输出为 yes, no, continue
  • ISREL token 决定段落 D 是否与输入 (x (问题), d (chunk)) 中的 x 相关,其中 dD 中。输出为 relevant, irrelevant
  1. ISSUP token 决定 LLM 从 D 中每个 chunk 生成的内容是否与该 chunk 相关。输入为 x, d, y,其中 dD 中。它确认 y (生成) 中所有值得验证的陈述都得到 d 的支持。输出为 fully supported, partially supported, no support
  2. ISUSE token 决定从 D 中每个 chunk 生成的内容是否是对 x 的有用响应。输入为 x, y,其中 dD 中。输出为 {5, 4, 3, 2, 1}.

论文中的此表补充了以上信息

Self-RAG 中使用的四种 token 类型

我们可以将其概述为简化的图表,以了解信息流

Screenshot 2024-02-02 at 1.36.44 PM.png
Self-RAG 中使用的流程的示意图

我们可以用 LangGraph 表示这个,为了说明目的进行了一些简化/调整(可以根据需要进行自定义和扩展)

  • 如上所述,我们对每个检索到的文档进行评分。如果任何文档相关,我们将继续生成。如果所有文档都不相关,那么我们将转换查询以制定改进的问题并重新检索。注意:我们可以采用上面来自 CRAG(网络搜索)的想法,作为此路径中的补充节点!
  • 论文将从每个 chunk 执行生成并对其进行两次评分。相反,我们从所有相关文档执行单次生成。然后根据文档(例如,为了防止幻觉)以及如上所述的答案对生成进行评分。这减少了 LLM 调用的次数并提高了延迟,并允许将更多上下文整合到生成中。当然,如果需要更多控制,则可以轻松地适应每个 chunk 生成并单独对其进行评分。
Self-RAG 的 LangGraph 实现

此处是一个示例 trace,突出显示了主动 RAG 自我纠正的能力。问题是 Explain how the different types of agent memory work?。所有四个文档都被认为是相关的,生成与文档的检查通过了,但生成被认为对问题没有完全用处。

然后我们看到循环重新启动,并在此处重新制定查询:How do the various types of agent memory function?。四个文档中有一个因不相关而被过滤掉 (此处)。然后生成通过了两次检查

代理内存的各种类型包括感觉记忆、短期记忆和长期记忆。感觉记忆将感觉信息的印象保留几秒钟。短期记忆用于上下文学习和提示工程。长期记忆允许代理在较长时间内保留和回忆信息,通常通过利用外部向量存储。

整个 trace 非常容易审计,节点清晰地排列出来

结论

自反思可以极大地增强 RAG,从而能够纠正低质量的检索或生成。最近的几篇 RAG 论文都侧重于这个主题,但实现这些想法可能很棘手。在这里,我们展示了 LangGraph 可以轻松用于自反思 RAG 的“流程工程”。我们为实现两篇有趣论文 Self-RAGCRAG 中的想法提供了 cookbook。