背景
在过去的一年里,语言模型驱动的 Agent 和状态机已经成为一种有前景的设计模式,可用于创建灵活有效的人工智能产品。
Agent 的核心是使用 LLMs 作为通用问题解决器,将它们与外部资源连接起来以回答问题或完成任务。
LLM Agent 通常有以下主要步骤:
- 建议行动:LLM 生成文本以直接响应用户或传递给函数。
- 执行操作:代码调用其他软件来执行查询数据库或调用 API 等操作。
- 观察:通过调用另一个函数或响应用户来对工具调用的响应做出反应。
ReAct Agent 是上面步骤一个很好的原型设计,因为它使用重复的思想、行为、观察循环来提示语言模型:
# 典型的 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)
这利用了思想链 Prompt,让每一步做出单一的操作选择。虽然这对于简单的任务可能有效,但它有几个主要缺点:
- 每个工具调用都需要 LLM 调用。
- LLM 一次仅计划 1 个子问题。这可能会导致次优轨迹,因为它不会被迫“推理”整个任务。
克服这两个缺点的一种方法是通过明确的规划步骤。
Plan-And-Execute 计划与执行
Plan-and-execute Agent
工作原理
核心思路是基于关于规划和解决提示(Plan-and-Solve Prompting)的论文,BabyAGI 项目是该论文实现架构的产品。该架构主要由两个基本组件组成:
- Planner ,提示 LLM 生成多步骤计划来完成大型任务。
- Executor ,接受用户查询和计划中的步骤,并调用 1 个或多个工具来完成该任务。
一旦执行完成,代理会再次被调用,并发出重新计划提示,让它决定是否完成响应或是否生成后续计划(如果第一个计划没有达到预期效果)。
小结
这种 Agent 设计让我们不必为每个工具调用调用大型规划器 LLM。它仍然受到串行工具调用的限制,并为每个任务使用 LLM ,因为它不支持变量赋值。
ReWOO Agent
为了解决上述问题,ReWOO: Decoupling Reasoning from Observations for Efficient Augmented Language Models 论文中提出了一个 Agent,它消除了每个任务始终使用 LLM 的需要,同时仍然允许任务依赖于先前的任务结果 。他们通过允许在规划器的输出中进行变量分配来实现这一点。下图是代理设计的示意图。
ReWOO Agent
工作原理
规划器生成一个由交错的“Plan”(推理)和“E#”行组成的计划列表。例如,假设用户查询“What are the stats for the quarterbacks of the super bowl contenders this year”,规划器可以生成以下计划:
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]
请注意 planner 如何使用 #E2 等语法引用以前的输出。这意味着它可以执行任务列表,而不必每次都重新计划。
worker 循环遍历每个任务,并将任务输出分配给相应的变量。当调用后续调用时,它还会用变量的结果替换变量。
最后, Solver 将所有这些输出整合为最终答案。
小结
这种代理设计比简单的计划和执行代理更有效,因为每个任务只能具有所需的上下文(其输入和变量值)。然而,它仍然依赖于顺序任务执行,这可能会产生更长的运行时间。
LLMCompiler LLM编译器
LLMCompiler Agent
工作原理
An LLM Compiler for Parallel Function Calling 论文,旨在进一步提高任务执行速度,超越上述计划和执行代理和 ReWOO Agent,甚至超越 OpenAI 的并行工具调用。
LLMCompiler 有以下主要组件:
- Planner :流式传输任务的 DAG。每个任务都包含一个工具、参数和依赖项列表。
- Task Fetching Unit :任务获取单元调度并执行任务。这接受任务流。一旦满足任务的依赖性,该单元就会安排任务。由于许多工具涉及对搜索引擎或 LLMs 的其他调用,因此额外的并行性可以显着提高速度(论文声称提高了 3.6 倍)。
- Joiner :根据整个图历史(包括任务执行结果)动态重新计划或完成是一个 LLM 步骤,决定是否响应最终答案或是否将进度传递回(重新)规划代理人继续工作。
这里关键的运行时间提升想法是:
- 规划器输出是流式传输的;输出解析器急切地生成任务参数及其依赖项。
- 任务获取单元接收解析的任务流,并在满足所有任务的依赖关系后调度任务。
- 任务参数可以是变量,它们是 DAG 中先前任务的输出。例如,模型可以调用
search("${1}")来搜索任务 1 的输出生成的查询。这使得代理的工作速度比 OpenAI 中调用的“令人尴尬的并行”工具更快。
小结
通过将任务格式化为 DAG,代理可以在调用工具时节省宝贵的时间,从而带来更好的整体用户体验。
结论
这些智能体有望比传统的推理和行动 (ReAct) 风格的智能体进行许多改进。
首先,他们可以更快地 执行多步骤工作流程,因为每次操作后不需要咨询更大的代理。每个子任务都可以在没有额外的 LLM 调用(或调用轻量级 LLM)的情况下执行。
其次,与 ReAct 代理相比,它们可以节省成本 。如果LLM调用用于子任务,它们通常可以针对较小的、特定于域的模型进行。然后,较大的模型仅需要(重新)规划步骤并生成最终响应。
第三,通过迫使规划者明确“思考”完成整个任务所需的所有步骤,他们可以整体表现得更好(在任务完成率和质量方面) 。生成完整的推理步骤是一种经过验证的改进结果的提示技术。细分问题还可以更集中地执行任务。
这三种代理架构是“计划和执行”设计模式的原型,它将 LLM 驱动的“计划器”与工具执行运行时分开。如果应用程序需要多个工具调用或 API 调用,这些类型的方法可以减少返回最终结果所需的时间,并通过减少调用更强大的 LLMs 的频率来帮助您节省成本。
推荐阅读:
- 高级 RAG(Self-Reflective RAG)
- 附代码|让检索增强生成(RAG)更快
- Embeddings-based 的搜索进行问答
- LLMs:使用搜索 API 进行问答并重新排名(Re-rank)
参考资料:
ReAct: Synergizing Reasoning and Acting in Language Models (https://arxiv.org/abs/2210.03629)
Chain-of-Thought Prompting Elicits Reasoning in Large Language Models(https://arxiv.org/abs/2201.11903)
Plan-and-Solve Prompting: Improving Zero-Shot Chain-of-Thought Reasoning by Large Language Models(https://arxiv.org/abs/2305.04091)
ReWOO: Decoupling Reasoning from Observations for Efficient Augmented Language Models(https://arxiv.org/abs/2305.18323)
An LLM Compiler for Parallel Function Calling(https://arxiv.org/abs/2312.04511)
Plan-and-Execute Agents(https://blog.langchain.dev/planning-agents/)
