llm范式和多agent架构(ReAct、Plan-and-Execute)
论文:《ReAct: Synergizing Reasoning and Acting in Language Models》
链接:https://arxiv.org/pdf/2210.03629
背景:
经过适当提示的大型语言模型(LLMs)已经展现出进行推理步骤以推导出算术、常识和符号推理任务中问题的答案的涌现能力,但“思维链”推理是一个静态的黑盒,因为模型使用其内部表示来生成思考,并且没有与外部世界建立联系,这限制了其反应式推理或更新知识的能力。这可能导致事实幻觉和推理过程中的错误传播等问题。
目标:以协同的方式将推理和行动结合起来进行一般任务解决 。
人类智能的核心在于推理与行动的紧密结合。例如做饭时,人们会根据当前状态调整计划、搜索外部信息、反思并修正行为。这种“边想边做”的机制在 LLM 中尚未被充分建模。
提出一种统一的框架 ReAct,使 LLM 能交错生成推理轨迹和动作,实现“边推理边行动”,提升任务解决能力、可解释性和鲁棒性。
ReAct,一种结合推理和行动的通用范式,用于解决各种语言推理和决策任务(图1)。ReAct以交错的方式提示大型语言模型生成与任务相关的语言推理轨迹和行动,这允许模型进行动态推理,以创建、维护和调整行动的高级计划(为行动而推理),同时还可以与外部环境(例如Wikipedia)交互,以将额外信息纳入推理(为推理而行动)。
大型语言模型(LLMs)在推理(reasoning)和行动(acting)方面表现出强大能力,但现有研究通常将两者割裂开来:
推理:如 Chain-of-Thought (CoT) 提示,仅依赖模型内部知识进行静态推理,容易幻觉(hallucination)和错误传播。
行动:如 WebGPT、SayCan 等,通过语言模型生成动作与环境交互,但缺乏高层抽象推理和工作记忆支持。
1.提示词工程
CoT(Chain of Thought,思维链)---- prompt engineering
标准CoT:
# 伪代码示例 def chain_of_thought(prompt): # 1. 在提示中加入推理步骤要求 enhanced_prompt = f"""请按步骤推理: 问题:{prompt} 让我们一步步思考:""" # 2. 模型生成包含推理步骤的回复 response = model.generate(enhanced_prompt) # 3. 提取最终答案 answer = extract_final_answer(response) return answer
Few-shot CoT(少样本示例COT):
给模型提供几个(通常是2-5个)带有完整推理步骤的示例,让模型学会模仿这种“一步一步思考”的方式来解决新问题。
# 使用示例演示推理过程 few_shot_examples = """ Q: 小明有5个苹果,吃了2个,又买了3个,现在有几个? A: 小明原来有5个苹果,吃了2个后剩下5-2=3个。 然后买了3个,现在有3+3=6个。 所以答案是6。 Q: 如果一本书30元,打8折后多少钱? A: 原价30元,8折就是乘以0.8。 30 × 0.8 = 24元。 所以答案是24元。 """
关键技术点:
-
步骤分解:将复杂问题分解为多个推理步骤
-
中间结果:明确展示每一步的计算或推理过程
-
自然语言格式:用自然语言描述推理过程
2.执行策略/范式/思维模式
1)ReAct(Reasoning + Acting)
-
思想:边想边做,即时决策
-
过程:思考→行动→观察→再思考(循环)
实现推理和执行的交错进行,伪代码如下:
class ReActAgent: def __init__(self, model, tools): self.model = model self.tools = tools # 可用工具集(搜索、计算器、API等) def run(self, question): context = f"问题:{question}\n" max_steps = 5 for step in range(max_steps): # 1. 思考下一步 thought = self._think(context) # 2. 决定行动(如果需要) action = self._decide_action(thought) if action.type == "FINISH": return action.answer elif action.type == "TOOL": # 3. 执行工具调用 observation = self._use_tool(action.tool, action.params) # 4. 观察结果并继续 context += f"观察:{observation}\n" def _think(self, context): prompt = f"""{context} 现在我需要思考下一步该做什么。我应该:""" return self.model.generate(prompt)
差异对比
| 方面 | CoT | ReAct |
|---|---|---|
| 核心 | 纯推理链 | 推理+行动交互 |
| 外部交互 | 无 | 支持工具调用 |
| 错误处理 | 内部修正 | 通过观察结果调整 |
| 结构 | 线性推理 | 循环决策 |
| 适用场景 | 纯推理问题 | 需要外部信息的任务 |
2)混合ReAct/CoT实现
def react_with_cot(agent, question): # 初始推理步骤(CoT风格) initial_reasoning = agent.think(f"分析问题:{question}") # ReAct循环 while not task_complete: # 1. 推理当前状态(CoT) thought = agent.think(f""" 当前状态:{current_state} 需要解决:{sub_problem} 我的推理:""") # 2. 决定行动 action = agent.decide_action(thought) if action == "USE_TOOL": result = agent.use_tool() # 3. 基于结果的进一步推理(CoT) reflection = agent.think(f""" 工具返回:{result} 这意味着:""")
工程实现:
CoT优化:
- 使用few-shot示例指导推理格式
- 明确要求"逐步思考"
- 加入自我验证步骤
ReAct优化:
- 限制最大循环次数防止死循环
- 设计清晰的工具描述
- 实现回退和错误处理机制
混合策略:
- 复杂任务先用CoT分解
- 需要外部信息时切到ReAct
- 关键步骤加入反思和验证
性能考量:
- CoT:增加token消耗,但提升准确率
- ReAct:需要多次模型调用,延迟较高
- 缓存策略:缓存常用推理结果
- 并行处理:并行工具调用优化
langChain agent实现:
from langchain.agents import initialize_agent, Tool from langchain.agents import AgentType # 定义工具 tools = [ Tool(name="Search", func=search_tool, description="搜索信息"), Tool(name="Calculator", func=calculator, description="数学计算") ] # 创建ReAct代理 agent = initialize_agent( tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True )
3)Plan-and-Execute(计划与执行)
-
思想:先规划,再执行
-
过程:总体规划→分解任务→顺序执行
Plan-and-Execute中的 Plan 和 Execute 可以由同一个Agent的不同思维模式来实现
伪代码:
问题:北京今天天气如何?我想知道是否适合户外运动 【规划阶段】 计划: 1. 获取北京今日天气数据 2. 获取户外运动适宜条件标准 3. 对比天气数据与运动条件 4. 给出建议 【执行阶段】 → 执行步骤1:调用天气API → 结果:25°C,晴朗,PM2.5=30 → 执行步骤2:查询运动适宜条件 → 结果:适宜温度20-28°C,PM2.5<50 → 执行步骤3:对比 → 结果:符合条件 → 执行步骤4:生成建议 def plan_and_execute(problem): # 第一阶段:制定计划 plan = model.generate(f""" 制定解决这个问题的计划: 问题:{problem} 请输出分步骤的计划:""") # 第二阶段:按计划执行 steps = parse_plan(plan) results = [] for step in steps: # 专注于当前步骤 result = execute_step(step, previous_results=results) results.append(result) # 第三阶段:整合结果 final_answer = synthesize_results(results) return final_answer
| 维度 | ReAct | Plan-and-Execute |
|---|---|---|
| 决策时机 | 即时决策,动态调整 | 预先规划,按计划执行 |
| 灵活性 | 高,可根据反馈实时调整 | 较低,需重新规划 |
| 复杂度 | 更适合开放性问题 | 更适合结构化任务 |
| 资源消耗 | 可能多次工具调用 | 工具调用更有计划性 |
| 错误处理 | 内嵌在循环中 | 需要额外错误处理机制 |
| 透明度 | 思考过程可见 | 计划阶段清晰可见 |
| 适用场景 | 探索性任务、动态环境 | 复杂多步任务、有明确步骤 |
langchain中plan-and-execute实现:
from langchain_experimental.plan_and_execute import ( PlanAndExecute, load_agent_executor, load_chat_planner ) # 1. 规划器 planner = load_chat_planner(llm) # 2. 执行器 executor = load_agent_executor(llm, tools, verbose=True) # 3. 组合 agent = PlanAndExecute( planner=planner, executor=executor, max_iterations=3 ) # 运行 - 先规划再执行 result = agent.run("帮我写一份关于AI发展的市场报告")
3. Multi-Agent系统架构
Multi-Agent 协作从字面意思上来理解就是”多个Agent协同的工作,目的是通过系统工程的方法,为大模型的不稳定性与不可控性提供结构化解法,寻求更可控、更稳定、更工程化。
Multi-Agent 协作是将大模型的推理过程拆解、组织、结构化,让智能具备可控性、可维护性,并能通过工程化手段真正落地。
Multi-Agent并不是 AI 应用开发的万能解法。在应用场景为所有智能体必须共享同一上下文、或智能体之间存在密集依赖关系的场景,多智能体反而会带来额外复杂度,此时采用单一智能体或更集中化的架构更为合适。
在Anthropic内部,采用的多智能体架构是协调者-工作者模式:由一个主导智能体(a lead agent)来协调流程,同时将任务委派给并行运作的专用子智能体(subagents)。
实际的运作模式是:主导智能体来处理分析用户的查询,并且定制策略,然后同时生成(spawns)子智能体来探索不同维度的信息。
1)集中式架构(Controller-Agents)
[控制器/协调器]
↙ ↓ ↘
[Agent A] [Agent B] [Agent C]
↘ ↓ ↙
[结果聚合器]
特点:
-
中央控制器协调所有Agent
-
适用于任务分解明确的场景
2)去中心式架构(Peer-to-Peer)
[Agent A] ↔ [Agent B] ↔ [Agent C]
↕ ↕ ↕
[共享内存/消息队列]
特点:
-
Agent之间直接通信
-
没有单一控制点
-
更灵活,适合动态协作
3)分层架构(Hierarchical)
[管理Agent]
↓
[协调层Agent]
↙ ↓ ↘
[执行层Agent] [执行层Agent] [执行层Agent]
特点:
-
不同层级的Agent承担不同的业务功能
-
适用于企业级应用
多Agent系统的核心在于如何设计高效的协作机制,而不是简单地堆叠多个LLM调用。包括通信协议、错误处理、监控和可观测性、agent的启动和销毁、资源管理、安全认证和权限控制。
Agent 编排:指的是如何协调、调度和管理多个 Agent 来共同完成一个复杂任务。包括顺序编排、并行编排、条件分支/循环、竞争/评审等。
主流编排框架:
-
LangGraph / LangChain:基于有向图(状态机)定义 Agent 工作流,天然支持循环、分支,是目前最流行的编排范式。
通信协议:定义了 Agent 之间 如何交换信息。良好的协议是确保 Agent 有效协作的基础。
1. 通信内容:消息格式json
2. 通信模型
- 直接对话:两个 Agent 直接进行“对话”。
- 发布-订阅:Agent 向特定“频道”发布消息,关心该主题的 Agent 会自动接收。
-
中央调度/消息总线:所有消息都通过一个中央枢纽(如消息队列)路由。编排器通常兼任此角色,便于监控和控流。
3. 传输层协议
-
HTTP/REST & WebSocket:最通用。Agent 作为 Web 服务暴露 API,通过 HTTP 请求/响应或 WebSocket 长连接通信。简单易实现,适合云原生部署。
- 消息队列:如 RabbitMQ、Apache Kafka、Redis Pub/Sub。用于异步、解耦、高吞吐的场景,确保消息不丢失。适合生产级系统。
- gRPC:基于 HTTP/2,性能更高,支持双向流,适合对延迟敏感的内部服务通信。需要定义 Protobuf 接口。
优势:
-
消息总线解耦:Agent 之间不直接调用,只与总线交互,新增 Agent 非常容易。
-
异步处理:Agent 可以并行工作,提高效率。
论文解析:https://blog.csdn.net/bylander/article/details/152733528

浙公网安备 33010602011771号