LangChain计划执行型智能体
计划执行型智能体提供了一种比以往设计更快、更经济且性能更强的任务执行方案。本文将指导您在LangGraph中构建三种规划智能体。
我们在LangGraph平台上推出了三种“计划执行”模式的智能体结构。这些智能体在与经典的推理与行动(ReAct)模式智能体相比,展示了多项改进。
⏰ 首先,这些智能体能够更迅速地执行多步骤任务流程,因为完成每个行动后无需再次请求大型智能体的参与。每一项子任务都能在无需额外大型语言模型(LLM)调用,或者调用较轻量级的LLM支持下完成。
💸 其次,与ReAct智能体相比,它们能有效降低成本。如果需要对子任务进行LLM调用,通常会使用更小的、特定领域的模型。仅在需要进行(重)规划步骤和生成最终应答时,才会调用大型模型。
🏆 最后,通过要求规划器明确地逐步“思考”完成整个任务所需要的流程,这些智能体在任务完成率和质量方面能有更优的表现。制定详尽推理步骤一直是一种验证过的提示技巧,用来提升成果。将问题细分还可以使任务执行更加专注和高效。
背景介绍
在过去的一年里,基于语言模型的智能代理和状态机成为了开发灵活且高效的人工智能产品的一个有前途的设计范式。
代理的核心是以语言模型为通用问题解决工具,将其与外部资源相连接,用以解答问题或执行任务。
通常情况下,基于语言模型的智能代理会经历如下几个主要步骤:
1. 提议行动Propose action:语言模型生成文本,直接对用户作出响应,或者传达给某个功能。
2. 执行行动Execute action:代码调用其它软件,以执行例如查询数据库或者调用API等操作。
3. 观察Observe:根据工具调用的反馈进行反应,或者调用另一功能,或者回应用户。
ReAct 智能代理就是一个很好的范例,它利用重复的思考、行动、观察循环来引导语言模型:
思考: 我该调用Search()来查询当前比赛的分数。
行动: Search(“当前X比赛的分数是多少?”)
观察: 当前分数是24-21
…(重复N次)
这是一种典型的ReAct风格智能代理的轨迹。
这种方法利用Chain-of-thought提示,以便每个步骤只做出单一的行动决策。虽然这对于简单的任务可以很有效,但它也存在一些主要弊端:
1. 每次工具调用都需要一次语言模型的调用。
2. 语言模型每次只计划一个子问题。这可能会导致次优的处理轨迹,因为它并没有被逼着对整个任务进行”推理”。
要克服这两个缺陷,一个有效的方法是加入一个明确的规划步骤。以下是我们在LangGraph实现的两种此类设计示例。
计划执行系统 Plan-And-Execute
这一简易结构基于Wang等人的论文[计划与解决提示]所提出,并借鉴了Yohei Nakajima的[BabyAGI]项目,成为了典型的规划型代理架构。它主要包含两个基础部件:
1. 一个规划器(A planner),负责引导一个语言模型(LLM)生成多步骤计划,以完成复杂的任务。
2. 多个执行器(Executor(s)),可以处理用户的查询需求以及计划中的某一步骤,并调用一个或多个工具来执行该项任务。
任务执行结束后,代理会根据新的规划提示再次被调起,这时它会决定是直接提供回应结束,还是根据需要生成进一步的计划(如果原计划并未达成目标)。
这种代理设计避免了在每次调用工具时都需要依赖大型的规划语言模型。但由于它不支持变量的赋值操作,且必须串行调用工具,因此每项任务都需要单独使用一个语言模型。
独立观察之外进行推理
在 [ReWOO]研究中,徐等人设计了一种新型的代理模型,这种模型颠覆了传统每个任务必须依赖语言模型(Large Language Model, LLM)的方式,允许后续任务依赖前一任务的结果。该模型通过在输出规划中加入变量赋值的功能来实现。下图为该代理模型的设计图。
规划器负责产生一个包括“计划”(推理)与“E#”行交替出现的计划清单。例如,对于用户提出的“今年超级碗争夺者的四分卫统计数据是什么”这一查询,规划器可能生成如下计划:
计划:我需要了解今年参加超级碗的球队
E1:搜索[谁在角逐超级碗?]
计划:我需要了解每支球队的四分卫是谁
E2:LLM[第一支球队的四分卫 #E1]
计划:我需要了解每支球队的四分卫是谁
E3:LLM[第二支球队的四分卫 #E1]
计划:我需要查询第一名四分卫的数据统计
E4:搜索[#E2的四分卫统计数据]
计划:我需要查询第二名四分卫的数据统计
E5:搜索[#E3的四分卫统计数据]
请注意,规划器(planner)如何能通过如`#E2`这样的语法来引用之前的输出。这意味着它可以在不需每次重新制定计划的情况下执行一系列任务。
“工作者(worker)”节点将遍历每个任务,并将它们的输出结果分配给预定的变量。并且,在执行后续任务调用时,用对应的结果来替代这些变量。
最终,“解决器(Solver)”将所有输出整合,得出最终答案。
这种代理设计理念可以比单纯的计划-执行模式更为高效,因为每一个任务都仅仅包含必要的上下文信息(即它的输入和变量值)。
不过,这种设计还是基于顺序任务执行,可能会导致整体运行时间较长。
LLMCompiler
LLMCompiler 是由 [Kim团队]研发的一个代理体系结构,它的设计目的是提升任务执行效率,超过了之前介绍的计划-执行与ReWOO代理,甚至高于OpenAI并行工具调用的速度。
LLMCompiler主要由以下部分组成:
1. 规划器(Planner):它可以生成一个任务的有向无环图(DAG)。每个任务都包括工具、参数和一个依赖关系列表。
2. 任务获取单元(Task Fetching Unit) 负责任务的编排与执行。它可以接受任务流,并在任务的依赖被满足后进行调度。由于许多工具都需要进行额外的搜索引擎或LLM调用,这种并行执行可以显著提升速度(据论文可提高3.6倍)。
3. 连接器(Joiner):这部分可以基于整个任务执行的历史(包括任务的执行结果)动态地重新规划或是结束任务。这是LLM环节的一步,它决定了是直接呈现最终结果,还是将进度返回给规划器以便继续工作。
此架构加速执行的关键点在于:
- 规划器的输出是流式的;它能够即时产出任务参数和它们的依赖关系。
- 任务获取单元 接收流式传输而来的任务,并在所有依赖都满足时开始调度。
- 任务参数可以是变量,也即是在有向无环图中之前任务的输出。比如,模型可以用
search("${1}")
来查询由任务1生成的搜索内容。这种方法让代理的工作效率超过了OpenAI的普通并行工具调用。
通过把任务组织成有向无环图,不仅能节省在调用工具时的宝贵时间,还能带给用户更好的体验。
总结
以上三种代理架构是“计划-执行”设计模式的原型,将 LLM驱动的“规划器”与工具执行运行时分离开来。如果您的应用程序需要多次调用工具或API,这些方法可以缩短得到最终结果的时间,并通过减少对更高级LLM的调用,帮助您降低成本。