Plan + Execute Agent Thumbnail

规划执行代理

规划执行代理承诺比以前的代理设计更快、更便宜、更高效地执行任务。在本篇文章中,学习如何在 LangGraph 中构建 3 种类型的规划代理。

阅读时间 5 分钟

我们在 LangGraph 中发布了三种代理架构,展示了“规划执行”式代理设计。这些代理承诺比传统的推理和行动 (ReAct) 式代理有很多改进。

⏰ 首先,它们可以更快地执行多步骤工作流程,因为在每个操作之后不需要咨询更大的代理。每个子任务可以在没有额外 LLM 调用(或仅使用轻量级 LLM 调用)的情况下执行。

💸 其次,与 ReAct 代理相比,它们可以节省成本。如果 LLM 调用用于子任务,它们通常可以使用更小、更特定于领域的模型。然后,更大的模型仅用于(重新)规划步骤和生成最终响应。

🏆 第三,通过强制规划器显式地“思考”完成整个任务所需的所有步骤,它们可以整体上表现更好(就任务完成率和质量而言)。生成完整的推理步骤是一种行之有效的提示技术,可以改善结果。将问题细分也允许更专注的任务执行。

背景

在过去的一年里,语言模型驱动的代理和状态机已成为创建灵活且有效的 AI 驱动的产品的有希望的设计模式。

代理的核心是将 LLM 用作通用问题解决程序,并将它们与外部资源连接起来以回答问题或完成任务。

LLM 代理通常具有以下主要步骤

  1. 提议操作:LLM 生成文本以直接响应用户或传递给函数。
  2. 执行操作:您的代码调用其他软件来执行诸如查询数据库或调用 API 之类的事情。
  3. 观察:通过调用另一个函数或响应用户来对工具调用的响应做出反应。

ReAct 代理是该代理的良好原型设计,因为它使用重复的思考、行动、观察循环提示语言模型

Thought: I should call Search() to see the current score of the game.
Act: Search("What is the current score of game X?")
Observation: The current score is 24-21
... (repeat N times)

典型的 ReAct 式代理轨迹。

这利用了思维链提示,以便在每一步中做出单一的行动选择。虽然这对于简单的任务可能有效,但它也有一些主要缺点

  1. 它需要对每个工具调用进行 LLM 调用。
  2. LLM 每次只为 1 个子问题进行规划。这可能会导致次优轨迹,因为它没有被强制“推理”整个任务。

克服这两个缺点的一种方法是通过显式的规划步骤。以下是我们在 LangGraph 中实现的两种此类设计。

规划执行

🔗 Python 链接

🔗 JS 链接

规划执行代理

该架构松散地基于 Wang 等人关于规划求解提示的论文,以及 Yohei Nakajima 的BabyAGI 项目,它是规划代理架构的象征。它包含两个基本组件

  1. 一个规划器,它提示 LLM 生成完成大型任务的多步骤计划。
  2. 执行器(多个),它们接受用户查询和计划中的一个步骤,并调用 1 个或多个工具来完成该任务。

执行完成后,将再次调用代理,并使用重新规划提示,让它决定是使用响应完成还是生成后续计划(如果第一个计划没有达到预期效果)。

这种代理设计使我们无需对每个工具调用都调用大型规划器 LLM。它仍然受到串行工具调用的限制,并且由于它不支持变量分配,因此使用 LLM 来执行每个任务。

无观察推理

🔗 Python 链接

ReWOO 中,Xu 等人提出了一种代理,该代理消除了始终对每个任务使用 LLM 的需要,同时仍然允许任务依赖于先前任务的结果。它们通过允许规划器输出中的变量分配来做到这一点。以下是代理设计的图表。

ReWOO 代理

它的规划器生成一个计划列表,该列表由交错的“计划”(推理)和“E#”行组成。例如,给定用户查询“今年超级碗竞争者的四分卫的统计数据是什么”,规划器可能会生成以下计划

Plan: I need to know the teams playing in the superbowl this year
E1: Search[Who is competing in the superbowl?]
Plan: I need to know the quarterbacks for each team
E2: LLM[Quarterback for the first team of #E1]
Plan: I need to know the quarterbacks for each team
E3: LLM[Quarter back for the second team of #E1]
Plan: I need to look up stats for the first quarterback
E4: Search[Stats for #E2]
Plan: I need to look up stats for the second quarterback
E5: Search[Stats for #E3]

请注意,规划器如何使用诸如#E2之类的语法引用先前的输出。这意味着它可以执行任务列表,而无需每次都重新规划。

工作器节点循环遍历每个任务,并将任务输出分配给相应的变量。它还在调用后续调用时用结果替换变量。

最后,求解器将所有这些输出集成到最终答案中。

这种代理设计可能比简单的规划执行代理更有效,因为每个任务只能拥有必要的上下文(它的输入和变量值)。

但是,它仍然依赖于顺序任务执行,这会延长运行时间。

LLMCompiler

🔗 Python 链接

LLMCompiler 代理

Kim 等人提出的LLMCompiler是一种代理架构,旨在进一步提高任务执行的速度,超越上面描述的规划执行和 ReWOO 代理,甚至超越 OpenAI 的并行工具调用。

LLMCompiler 具有以下主要组件

  1. 规划器:流式传输任务的 DAG。每个任务都包含一个工具、参数和依赖项列表。
  2. 任务获取单元调度和执行任务。它接受任务流。一旦满足依赖项,此单元就会调度任务。由于许多工具涉及对搜索引擎或 LLM 的其他调用,因此额外的并行性可以显着提高速度(论文声称提高了 3.6 倍)。
  3. 联接器:根据整个图历史(包括任务执行结果)动态地重新规划或完成,这是一个 LLM 步骤,它决定是使用最终答案响应还是将进度传递回(重新)规划代理以继续工作。

这里关键的运行时间提升理念是

  • 规划器输出是流式传输的;输出解析器会急切地生成任务参数及其依赖项。
  • 任务获取单元接收解析的任务流,并在满足所有依赖项后调度任务。
  • 任务参数可以是变量,这些变量是 DAG 中先前任务的输出。例如,模型可以调用search("${1}")来搜索由任务 1 的输出生成的查询。这使代理比 OpenAI 中的“尴尬并行”工具调用运行得更快。

通过将任务格式化为 DAG,代理可以在调用工具时节省宝贵的时间,从而带来更好的用户体验。

结论

这三种代理架构是“规划执行”设计模式的原型,该模式将 LLM 驱动的“规划器”与工具执行运行时分离。如果您的应用程序需要多个工具调用或 API 调用,这些类型的方法可以减少返回最终结果所需的时间,并通过减少对更强大 LLM 的调用频率来帮助您节省成本。