智能体架构¶
许多 LLM 应用在调用 LLM 之前和/或之后都会执行特定的控制流程步骤。例如,RAG 会检索与问题相关的文档,并将这些文档传递给 LLM,以便为模型的响应提供依据。
除了硬编码固定的控制流程外,我们有时还希望 LLM 系统能够自行选择控制流程来解决更复杂的问题!这就是智能体的一种定义:智能体是利用 LLM 来决定应用控制流程的系统。 LLM 控制应用的方式有很多种
- LLM 可以选择两个潜在路径中的一个进行路由
- LLM 可以决定调用许多工具中的哪一个
- LLM 可以决定生成的答案是否足够,或者是否需要更多工作
因此,有许多不同类型的智能体架构,它们赋予 LLM 不同级别的控制。
路由器¶
路由器允许 LLM 从一组指定选项中选择一个步骤。这是一种控制级别相对有限的智能体架构,因为 LLM 通常只控制一个决策,并且只能返回一组狭窄的输出。路由器通常会采用一些不同的概念来实现这一点。
结构化输出¶
LLM 的结构化输出是通过提供一个特定的格式或模式来实现的,LLM 在响应时应遵循该格式或模式。这类似于工具调用,但更通用。工具调用通常涉及选择和使用预定义函数,而结构化输出可用于任何类型的格式化响应。实现结构化输出的常用方法包括
- 提示工程:指示 LLM 以特定格式响应。
- 输出解析器:使用后处理从 LLM 响应中提取结构化数据。
- 工具调用:利用某些 LLM 内置的工具调用能力生成结构化输出。
结构化输出对于路由至关重要,因为它们确保 LLM 的决策能够被系统可靠地解释和执行。在此操作指南中了解更多关于结构化输出的信息。
工具调用智能体¶
虽然路由器允许 LLM 做出一个单一的决策,但更复杂的智能体架构通过两种关键方式扩展了 LLM 的控制能力
- 多步骤决策:LLM 可以控制一系列决策,而不仅仅是一个。
- 工具访问:LLM 可以选择并使用各种工具来完成任务。
ReAct 是一种流行的通用智能体架构,它结合了这些扩展,整合了三个核心概念。
工具调用
:允许 LLM 根据需要选择和使用各种工具。记忆
:使智能体能够保留并使用先前步骤的信息。规划
:赋能 LLM 创建并遵循多步计划以实现目标。
这种架构允许更复杂和灵活的智能体行为,超越简单的路由,实现跨多个步骤的动态问题解决。您可以将其与 createReactAgent
一起使用。
工具调用¶
当您希望智能体与外部系统交互时,工具非常有用。外部系统(例如,API)通常需要特定的输入模式或载荷,而不是自然语言。例如,当我们绑定一个 API 作为工具时,我们会让模型了解所需的输入模式。模型将根据用户的自然语言输入选择调用某个工具,并返回符合工具模式的输出。
许多 LLM 提供商支持工具调用,并且 LangChain 的工具调用接口很简单:您可以定义一个工具模式,并将其传递给 ChatModel.bindTools([tool])
。
记忆¶
记忆对智能体至关重要,使它们能够跨多个解决问题的步骤保留和利用信息。它在不同尺度上运作
- 短期记忆:允许智能体访问序列中早期步骤中获取的信息。
- 长期记忆:使智能体能够回忆先前交互的信息,例如对话中的旧消息。
LangGraph 提供对记忆实现的完全控制
State
:用户定义的模式,指定需要保留的记忆的确切结构。Checkpointers
:在不同交互的每个步骤中存储状态的机制。
这种灵活的方法允许您根据特定的智能体架构需求定制记忆系统。有关如何为您的图添加记忆的实用指南,请参阅此教程。
有效的记忆管理增强了智能体维持上下文、从过去经验中学习并随着时间推移做出更明智决策的能力。
规划¶
在 ReAct 架构中,LLM 会在一个 while 循环中被重复调用。在每个步骤中,智能体决定要调用哪些工具,以及这些工具的输入应该是什么。然后执行这些工具,并将输出作为观察结果反馈给 LLM。当智能体决定不再需要调用任何工具时,while 循环终止。
ReAct 实现¶
本论文与预构建的 createReactAgent
实现之间存在一些差异
- 首先,我们使用工具调用让 LLM 调用工具,而论文使用的是提示词加上原始输出的解析。这是因为在撰写论文时工具调用尚不存在,但通常更好、更可靠。
- 其次,我们使用消息来提示 LLM,而论文使用的是字符串格式化。这是因为在撰写时,LLM 甚至没有暴露基于消息的接口,而现在这是它们唯一暴露的接口。
- 第三,论文要求所有工具输入都必须是单个字符串。这主要是由于当时 LLM 的能力不是很强,只能生成单个输入。我们的实现允许使用需要多个输入的工具。
- 第四,论文一次只考虑调用一个工具,这很大程度上是由于当时 LLM 性能的限制。我们的实现允许一次调用多个工具。
- 最后,论文要求 LLM 在决定调用哪些工具之前显式生成一个“思考 (Thought)”步骤。这是“ReAct”中的“推理 (Reasoning)”部分。我们的实现默认不这样做,很大程度上是因为 LLM 已经变得更好了,这不再那么必要。当然,如果您希望提示它这样做,您当然可以。
自定义智能体架构¶
虽然路由器和工具调用智能体(如 ReAct)很常见,但定制智能体架构通常能针对特定任务带来更好的性能。LangGraph 提供了几个强大的功能来构建定制的智能体系统
人机协作 (Human-in-the-loop)¶
人工干预可以显著增强智能体的可靠性,尤其对于敏感任务而言。这可能涉及
- 批准特定操作
- 提供反馈以更新智能体的状态
- 在复杂的决策过程中提供指导
当完全自动化不可行或不可取时,人机协作模式至关重要。在我们的人机协作指南中了解更多信息。
并行化¶
并行处理对于高效的多智能体系统和复杂任务至关重要。LangGraph 通过其 Send API 支持并行化,使得
- 并发处理多个状态
- 实现类似 map-reduce 的操作
- 高效处理独立的子任务
有关实践实现,请参阅我们的 map-reduce 教程。
子图 (Subgraphs)¶
子图对于管理复杂的智能体架构至关重要,特别是在多智能体系统中。它们允许
- 对个体智能体进行隔离状态管理
- 对智能体团队进行分层组织
- 控制智能体与主系统之间的通信
子图通过状态模式中重叠的键与父图通信。这使得灵活、模块化的智能体设计成为可能。有关实现细节,请参阅我们的子图操作指南。
反思¶
反思机制可以通过以下方式显著提高智能体的可靠性
- 评估任务完成度和正确性
- 提供反馈以进行迭代改进
- 实现自我纠正和学习
虽然通常基于 LLM,但反思也可以使用确定性方法。例如,在编程任务中,编译错误可以作为反馈。此方法在使用 LangGraph 进行自我纠正代码生成的视频中得到了展示。
通过利用这些功能,LangGraph 能够创建复杂的、针对特定任务的智能体架构,这些架构能够处理复杂的工作流程、有效协作并持续改进其性能。