Plan + Execute Agent Thumbnail

计划与执行 Agent

计划与执行 agent 承诺比之前的 agent 设计更快、更便宜且性能更高地执行任务。 了解如何在此篇文章中使用 LangGraph 构建 3 种类型的计划 agent。

5 分钟阅读

我们将在 LangGraph 中发布三种 agent 架构,展示“计划与执行”风格的 agent 设计。 这些 agent 承诺比传统的推理与行动 (ReAct) 风格的 agent 有许多改进。

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

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

🏆 第三,通过迫使计划器明确“思考”完成整个任务所需的所有步骤,它们可以表现更好(在任务完成率和质量方面)。 生成完整的推理步骤是一种经过验证的提示技术,可以改善结果。 细分问题也有助于更专注的任务执行。

背景

在过去一年中,语言模型驱动的 agent 和状态机已成为创建灵活高效的人工智能驱动产品的有前景的设计模式。

在其核心,agent 使用 LLM 作为通用的问题解决器,将它们与外部资源连接起来以回答问题或完成任务。

LLM agent 通常具有以下主要步骤

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

ReAct agent 是一个很好的原型设计,因为它使用重复的思考、行动、观察循环来提示语言模型

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 风格 agent 轨迹。

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

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

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

计划与执行

🔗 Python 链接

🔗 JS 链接

计划与执行 Agent

基于 Wang 等人的关于 计划与解决提示 的论文,以及 Yohei Nakajima 的 BabyAGI 项目,这种简单的架构是计划 agent 架构的代表。 它由两个基本组件组成

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

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

这种 agent 设计使我们避免了每次工具调用都必须调用大型计划器 LLM。 它仍然受到串行工具调用的限制,并且由于它不支持变量赋值,因此每个任务都使用 LLM。

无观察推理

🔗 Python 链接

在 ReWOO 中,Xu 等人提出了一个 agent,它消除了始终为每个任务使用 LLM 的需要,同时仍然允许任务依赖于先前的任务结果。 他们通过允许在计划器的输出中进行变量赋值来实现这一点。 以下是 agent 设计的图表。

ReWOO Agent

它的 计划器 生成一个计划列表,该列表由交错的“计划”(推理)和“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 等语法引用先前的输出。 这意味着它可以执行任务列表,而无需每次都重新计划。

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

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

这种 agent 设计可能比简单的计划与执行 agent 更有效,因为每个任务都可以只拥有所需的上下文(其输入和变量值)。

然而,它仍然依赖于顺序任务执行,这可能会导致更长的运行时间。

LLMCompiler

🔗 Python 链接

LLMCompiler Agent

LLMCompilerKim 等人 提出,是一种 agent 架构,旨在进一步提高任务执行的速度,超越上述计划与执行和 ReWOO agent,甚至超越 OpenAI 的并行工具调用。

LLMCompiler 具有以下主要组件

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

这里的关键运行时加速思想是

  • 计划器 输出是流式传输的; 输出解析器急切地产生任务参数及其依赖项。
  • 任务获取单元 接收解析的任务流,并在满足所有依赖项后调度任务。
  • 任务参数可以是变量,它是 DAG 中先前任务的输出。 例如,模型可以调用 search("${1}") 来搜索任务 1 的输出生成的查询。 这使 agent 的工作速度甚至比 OpenAI 中“令人尴尬的并行”工具调用还要快。

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

结论

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