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