跳到内容

Agent 架构

许多 LLM 应用程序在 LLM 调用之前和/或之后实现特定的控制流步骤。例如,RAG 会检索与用户问题相关的文档,并将这些文档传递给 LLM,以便模型的响应基于提供的文档上下文。

我们有时不希望硬编码固定的控制流,而是希望 LLM 系统能够自行选择控制流来解决更复杂的问题!这是 agent 的一个定义:agent 是一个使用 LLM 来决定应用程序控制流的系统。LLM 可以通过多种方式控制应用程序

  • LLM 可以在两个潜在路径之间进行路由
  • LLM 可以决定调用众多工具中的哪一个
  • LLM 可以决定生成的答案是否足够,或者是否需要更多工作

因此,有许多不同类型的agent 架构,它们赋予 LLM 不同程度的控制权。

Agent Types

路由器

路由器允许 LLM 从指定的选项集中选择一个步骤。这种 agent 架构的控制级别相对有限,因为 LLM 通常只专注于做出一个决策,并从有限的预定义选项集中生成特定输出。路由器通常采用几种不同的概念来实现此目的。

结构化输出

使用 LLM 的结构化输出是通过提供 LLM 在其响应中应遵循的特定格式或模式来实现的。这类似于工具调用,但更通用。虽然工具调用通常涉及选择和使用预定义函数,但结构化输出可用于任何类型的格式化响应。实现结构化输出的常见方法包括

  1. Prompt 工程:通过系统 prompt 指示 LLM 以特定格式响应。
  2. 输出解析器:使用后处理从 LLM 响应中提取结构化数据。
  3. 工具调用:利用某些 LLM 内置的工具调用能力生成结构化输出。

结构化输出对于路由至关重要,因为它们确保 LLM 的决策能够被系统可靠地解释和执行。在此操作指南中了解更多关于结构化输出的信息

工具调用 Agent

虽然路由器允许 LLM 做出一个决策,但更复杂的 agent 架构通过两种关键方式扩展了 LLM 的控制

  1. 多步决策:LLM 可以连续做出一系列决策,而不仅仅是一个决策。
  2. 工具访问:LLM 可以选择并使用各种工具来完成任务。

ReAct 是一种流行的通用 agent 架构,它结合了这些扩展,整合了三个核心概念。

  1. 工具调用:允许 LLM 根据需要选择和使用各种工具。
  2. 记忆:使 agent 能够保留和使用先前步骤的信息。
  3. 规划:使 LLM 能够创建并遵循多步计划来实现目标。

这种架构支持更复杂、更灵活的 agent 行为,超越了简单的路由,能够进行多步动态问题解决。您可以将其与 create_react_agent 一起使用。

工具调用

无论何时您希望 agent 与外部系统交互,工具都非常有用。外部系统(例如 API)通常需要特定的输入模式或负载,而不是自然语言。例如,当我们绑定一个 API 作为工具时,我们就让模型了解所需的输入模式。模型将根据用户的自然语言输入选择调用工具,并返回符合工具所需模式的输出。

许多 LLM 提供商支持工具调用,并且 LangChain 中的工具调用接口很简单:您只需将任何 Python function 传递给 ChatModel.bind_tools(function) 即可。

Tools

记忆

记忆对于 agent 至关重要,它使 agent 能够在多步问题解决过程中保留和利用信息。它在不同尺度上运作

  1. 短期记忆:允许 agent 访问在序列早期步骤中获取的信息。
  2. 长期记忆:使 agent 能够回忆起先前交互中的信息,例如对话中的历史消息。

LangGraph 提供对记忆实现的完全控制

  • State:用户定义的模式,指定要保留的记忆的精确结构。
  • Checkpointers:一种机制,用于在不同交互的每个步骤中存储状态。

这种灵活的方法允许您根据特定的 agent 架构需求定制记忆系统。有关如何将记忆添加到您的图的实用指南,请参阅本教程

有效的记忆管理增强了 agent 保持上下文、从过去经验中学习并随着时间推移做出更明智决策的能力。

规划

在 ReAct 架构中,LLM 在一个 while 循环中被重复调用。在每一步,agent 决定调用哪些工具以及这些工具的输入应该是什么。然后执行这些工具,并将输出作为观察结果反馈给 LLM。当 agent 决定它有足够的信息来解决用户请求并且不再值得调用任何工具时,该 while 循环终止。

ReAct 实现

这篇论文与预构建的 create_react_agent 实现之间存在一些区别

  • 首先,我们使用工具调用让 LLM 调用工具,而论文使用的是 prompt + 解析原始输出。这是因为工具调用在撰写论文时还不存在,但通常更好、更可靠。
  • 其次,我们使用消息来 prompt LLM,而论文使用的是字符串格式化。这是因为在撰写本文时,LLM 甚至没有暴露基于消息的接口,而现在这是它们唯一暴露的接口。
  • 第三,论文要求工具的所有输入都是一个单一字符串。这很大程度上是因为当时的 LLM 能力不是很强,只能生成一个单一输入。我们的实现允许使用需要多个输入的工具。
  • 第四,论文当时只考虑一次调用一个工具,这主要是由于当时 LLM 性能的限制。我们的实现允许一次调用多个工具。
  • 最后,论文要求 LLM 在决定调用哪些工具之前明确生成一个“Thought”步骤。这是“ReAct”中的“Reasoning”部分。我们的实现默认不这样做,这主要是因为 LLM 已经变得更好,不再那么必要。当然,如果您希望它这样做,您肯定可以 prompt 它。

自定义 Agent 架构

虽然路由器和工具调用 agent(如 ReAct)很常见,但定制 agent 架构通常会带来更好的特定任务性能。LangGraph 提供了几个强大的功能来构建定制的 agent 系统

人工回路

人工参与可以显著提高 agent 的可靠性,特别是对于敏感任务。这可以包括

  • 批准特定行动
  • 提供反馈以更新 agent 的状态
  • 在复杂决策过程中提供指导

当无法实现或不希望实现完全自动化时,人工回路模式至关重要。在我们的人工回路指南中了解更多信息。

并行化

并行处理对于高效的多 agent 系统和复杂任务至关重要。LangGraph 通过其 Send API 支持并行化,从而实现

  • 并发处理多个状态
  • 实现 Map-Reduce 类操作
  • 高效处理独立子任务

有关实际实现,请参阅我们的map-reduce 教程

子图

子图对于管理复杂的 agent 架构至关重要,尤其是在多 agent 系统中。它们允许

  • 独立 agent 的独立状态管理
  • agent 团队的层次化组织
  • agent 与主系统之间的受控通信

子图通过状态模式中的重叠键与父图通信。这实现了灵活的模块化 agent 设计。有关实现细节,请参阅我们的子图操作指南

反思

反思机制可以显著提高 agent 的可靠性,通过

  1. 评估任务完成度和正确性
  2. 提供反馈以进行迭代改进
  3. 实现自我纠正和学习

虽然通常基于 LLM,但反思也可以使用确定性方法。例如,在编码任务中,编译错误可以作为反馈。此方法在使用 LangGraph 进行自我纠正代码生成的此视频中有所演示。

通过利用这些功能,LangGraph 能够创建复杂的、针对特定任务的 agent 架构,这些架构可以处理复杂的工作流、有效地协作并持续改进其性能。

评论