AI Agent 任务规划实战:从 ReAct 到 Plan-and-Execute,让智能体学会"先想后做"
作者:yumking | 2026 年 9 月 1 日 | 技术标签:AI Agent / 任务规划 / Plan-and-Execute / 反思机制
摘要
前六篇我们给 Agent 装上了记忆、团队、工具、知识、安全带和仪表盘——但还缺一样最核心的东西:大脑的计划能力。多数 Agent 默认采用 ReAct 模式"走一步看一步",在 3 步以内的小任务上表现优异,可一旦任务超过 8 步,成功率断崖式下跌至 41%——因为它没有全局地图,每一步都在"局部导航"。本文剖析四种规划范式的适用边界,提出 “规划深度自适应” 策略:简单任务直接执行,复杂任务先规划后执行,执行中动态重规划,失败后结构化反思。实测在 15 步以上的长程任务中,任务成功率从 41% 提升至 83%,平均 Token 消耗反而下降 26%。
一、为什么规划是 Agent 的核心瓶颈?
1.1 ReAct 的"近视"问题
ReAct(Reason + Act)是绝大多数 Agent 框架的默认模式:模型推理一步、行动一步、观察结果、再推理下一步。
ReAct 循环:
思考 → 行动 → 观察 → 思考 → 行动 → 观察 → ...
这种模式的问题在于:每一步决策只基于当前观察和历史轨迹,没有全局视野。
| 任务步数 | ReAct 成功率 | 典型失败模式 |
|---|---|---|
| 1-3 步 | 94% | 几乎不出错 |
| 4-8 步 | 71% | 开始绕路、重复调用 |
| 9-15 步 | 58% | 遗忘目标、陷入循环 |
| 15+ 步 | 41% | 目标漂移、雪崩式失败 |
1.2 三个典型失败案例
案例一:目标漂移
任务:"统计仓库里所有 Python 文件的测试覆盖率,并生成报告"
第 5 步:Agent 发现某个文件有 Bug,开始修 Bug
第 12 步:Agent 在重构另一个模块
第 18 步:用户问"报告呢?"→ Agent:"什么报告?"
案例二:原地打转
任务:"把数据库 A 的数据迁移到数据库 B"
第 3 步:连接 B 失败
第 4 步:重试连接 B 失败
第 5-20 步:以完全相同的方式重试了 16 次
案例三:顺序颠倒
任务:"先备份再升级系统"
Agent 先执行了升级,失败后才发现没有备份可回滚。
根因只有一个:没有先规划,就把第一步当成了全部。
1.3 人类怎么做的?
接到复杂任务时,人类专家的动作是:先在纸上列清单,边做边划掉,遇到意外就修改清单,做完复盘。这个朴素的动作拆开来就是四个能力:
- 分解:大任务拆成可执行的小步骤
- 执行:按步骤推进,保留全局清单
- 重规划:意外发生时更新计划而非硬闯
- 反思:失败后总结教训,避免重蹈覆辙
本文的方案就是把这四个能力工程化。
二、四种规划范式拆解
范式一:ReAct(走一步看一步)
用户任务 → [思考①] → [行动①] → [观察①] → [思考②] → [行动②] → ...
- 适用:1-5 步、路径明确的短任务
- 优点:实现最简单,响应快,上下文占用小
- 缺点:无全局视野,长任务必然失控
- 结论:不要抛弃它——它是短任务的最优解,问题只在"什么时候该用它"
范式二:Plan-and-Execute(先规划后执行)
用户任务 → [规划器:生成完整步骤清单]
↓
[执行器:逐步执行,保留清单]
↓
[重规划器:意外时更新剩余步骤]
↓
结果
- 适用:8 步以上、依赖关系清晰的长任务
- 优点:全局视野,每一步都能对照总目标;计划可审计、可预估
- 缺点:初始计划可能基于错误假设;规划本身消耗一次大 Token
- 结论:长程任务的主力范式
范式三:Reflexion(失败后反思)
第一次执行 → 失败 → [反思器:结构化归因]
↓
教训写入记忆
↓
第二次执行(携带教训)→ 成功
- 适用:允许重试、错误可归因的场景
- 优点:同类错误不犯第二次,越用越聪明
- 缺点:重试有成本;反思质量依赖模型自省能力
- 结论:与 ReAct/Plan-and-Execute 叠加使用,而非独立范式
范式四:分层规划(Hierarchical Planning)
目标层: "上线新功能"(抽象目标)
↓ 分解
计划层: [设计 → 开发 → 测试 → 部署](阶段计划)
↓ 分解
执行层: [写代码文件A] [写测试用例B](具体动作)
- 适用:超长任务(50+ 步)、多阶段项目
- 优点:高层计划稳定、低层灵活调整,兼顾视野与敏捷
- 缺点:架构复杂,层间信息传递需要精心设计
- 结论:与第二篇"分层委派"多 Agent 架构天然契合,大项目才值得上
快速选型表
| 任务特征 | 推荐范式 |
|---|---|
| ≤5 步、路径清晰 | ReAct 直接执行 |
| 8+ 步、依赖清晰 | Plan-and-Execute |
| 允许重试、需积累经验 | 任意范式 + Reflexion |
| 50+ 步、多阶段 | 分层规划(配合多 Agent) |
三、从零搭建规划引擎
3.1 场景:自动化运维任务
任务示例:“检查 15 个微服务的健康状态,对异常服务生成诊断报告,并给出扩容建议。”
这个任务天然分成三个阶段:探活 → 诊断 → 建议,适合 Plan-and-Execute。
3.2 用 Python 实现
#!/usr/bin/env python3
"""
Agent 任务规划引擎
Plan-and-Execute + 动态重规划 + 结构化反思
"""
import json
import time
from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Callable, Optional
# ============ 数据结构 ============
class StepStatus(Enum):
PENDING = "pending"
RUNNING = "running"
DONE = "done"
FAILED = "failed"
SKIPPED = "skipped"
@dataclass
class Step:
step_id: int
description: str
tool: str
args: dict = field(default_factory=dict)
depends_on: list[int] = field(default_factory=list)
status: StepStatus = StepStatus.PENDING
result: Any = None
error: str = ""
@dataclass
class Plan:
goal: str
steps: list[Step] = field(default_factory=list)
version: int = 1
created_at: float = field(default_factory=time.time)
def next_runnable(self) -> Optional[Step]:
"""找到下一个依赖已满足的待执行步骤"""
done_ids = {s.step_id for s in self.steps if s.status == StepStatus.DONE}
for step in self.steps:
if step.status != StepStatus.PENDING:
continue
if all(d in done_ids for d in step.depends_on):
return step
return None
def progress(self) -> float:
finished = sum(1 for s in self.steps
if s.status in (StepStatus.DONE, StepStatus.SKIPPED))
return finished / max(len(self.steps), 1)
# ============ 规划器 ============
PLANNER_PROMPT = """你是任务规划器。把用户目标分解为可执行的步骤清单。
要求:
1. 每步只做一件事,描述具体到可直接调用工具
2. 标注步骤间的依赖关系
3. 总步数控制在 3-10 步:宁可粗粒度,也不要把"调用同一个工具"拆成多步
4. 只输出 JSON
用户目标:{goal}
可用工具:{tools}
输出格式:
{{"steps": [
{{"step_id": 1, "description": "...", "tool": "...", "args": {{}},
"depends_on": []}}
]}}"""
def make_plan(goal: str, tools: dict, llm: Callable) -> Plan:
"""调用 LLM 生成初始计划"""
prompt = PLANNER_PROMPT.format(goal=goal, tools=list(tools.keys()))
raw = llm(prompt)
data = json.loads(raw)
steps = [
Step(
step_id=s["step_id"],
description=s["description"],
tool=s["tool"],
args=s.get("args", {}),
depends_on=s.get("depends_on", []),
)
for s in data["steps"]
]
return Plan(goal=goal, steps=steps)
# ============ 重规划器 ============
REPLAN_PROMPT = """你是重规划器。原计划在执行中遇到了问题,请修订剩余步骤。
原目标:{goal}
原计划(含执行状态):{plan_state}
失败信息:{error}
已完成步骤的结果摘要:{done_results}
要求:
1. 已完成的步骤不要重做,其结果可直接引用
2. 优先修复失败原因;若失败无法修复,给出绕行方案(降级/替代工具)
3. 修订只针对未完成的步骤
4. 只输出 JSON,格式与原计划相同"""
def replan(plan: Plan, error: str, tools: dict, llm: Callable) -> Plan:
"""失败后修订剩余计划(版本号 +1,保留原步骤结果)"""
plan_state = json.dumps(
[{"step_id": s.step_id, "desc": s.description, "status": s.status.value,
"error": s.error} for s in plan.steps],
ensure_ascii=False,
)
done_results = json.dumps(
[{"step_id": s.step_id, "result": s.result}
for s in plan.steps if s.status == StepStatus.DONE],
ensure_ascii=False,
) or "{}"
prompt = REPLAN_PROMPT.format(
goal=plan.goal, plan_state=plan_state,
error=error, done_results=done_results,
)
data = json.loads(llm(prompt))
# 保留已完成步骤,替换未完成的
new_steps = [s for s in plan.steps if s.status == StepStatus.DONE]
for s in data["steps"]:
new_steps.append(Step(
step_id=s["step_id"],
description=s["description"],
tool=s["tool"],
args=s.get("args", {}),
depends_on=s.get("depends_on", []),
))
return Plan(goal=plan.goal, steps=new_steps, version=plan.version + 1)
# ============ 反思器 ============
REFLECTION_PROMPT = """你是反思器。Agent 执行任务最终失败,请做结构化归因。
任务目标:{goal}
共尝试 {attempts} 次。最后一次执行轨迹:
{trajectory}
请输出 JSON:
{{
"root_cause": "根本原因(一句话)",
"lesson": "下次执行时应记住的教训(可执行的建议)",
"should_retry": true/false,
"retry_hint": "重试时应改变的具体策略"
}}"""
def reflect(goal: str, trajectory: str, attempts: int, llm: Callable) -> dict:
"""失败后结构化反思,产出可复用的教训"""
raw = llm(REFLECTION_PROMPT.format(
goal=goal, attempts=attempts, trajectory=trajectory
))
return json.loads(raw)
# ============ 执行引擎 ============
class PlanExecuteAgent:
"""Plan-and-Execute 主引擎"""
def __init__(self, tools: dict, llm: Callable,
max_replan: int = 3, max_attempts: int = 2):
self.tools = tools
self.llm = llm
self.max_replan = max_replan
self.max_attempts = max_attempts
self.lessons: list[str] = [] # 跨尝试的教训池(可持久化)
def execute_step(self, step: Step) -> Step:
step.status = StepStatus.RUNNING
try:
step.result = self.tools[step.tool](**step.args)
step.status = StepStatus.DONE
except Exception as e:
step.error = str(e)
step.status = StepStatus.FAILED
return step
def run(self, goal: str) -> dict:
for attempt in range(1, self.max_attempts + 1):
plan = make_plan(goal, self.tools, self.llm)
if self.lessons:
# 把历史教训注入规划 prompt,避免重蹈覆辙
goal_with_lesson = f"{goal}\n\n【历史教训,务必规避】\n" + "\n".join(self.lessons)
plan = make_plan(goal_with_lesson, self.tools, self.llm)
replan_count = 0
while True:
step = plan.next_runnable()
if step is None:
break # 全部步骤已处理
self.execute_step(step)
if step.status == StepStatus.FAILED:
if replan_count >= self.max_replan:
break # 重规划次数用尽,本尝试失败
plan = replan(plan, step.error, self.tools, self.llm)
replan_count += 1
# 判定本轮成败
failed = [s for s in plan.steps if s.status == StepStatus.FAILED]
if not failed:
return {
"success": True, "attempts": attempt,
"plan_version": plan.version, "progress": plan.progress(),
}
# 失败 → 反思 → 沉淀教训 → 下一轮
trajectory = json.dumps(
[{"desc": s.description, "status": s.status.value, "error": s.error}
for s in plan.steps],
ensure_ascii=False,
)
lesson = reflect(goal, trajectory, attempt, self.llm)
self.lessons.append(lesson["lesson"])
if not lesson.get("should_retry", False):
break
return {"success": False, "attempts": attempt, "lessons": self.lessons}
# ============ 完整流程 ============
if __name__ == "__main__":
tools = {
"check_health": lambda service: {"status": "ok"},
"diagnose": lambda service: {"issue": "cpu_high"},
"suggest_scale": lambda service: {"action": "+2 replicas"},
}
def dummy_llm(prompt: str) -> str:
# 占位:真实场景调用大模型
return json.dumps({"steps": [
{"step_id": 1, "description": "检查服务健康", "tool": "check_health",
"args": {"service": "order"}, "depends_on": []},
{"step_id": 2, "description": "诊断异常", "tool": "diagnose",
"args": {"service": "order"}, "depends_on": [1]},
{"step_id": 3, "description": "给出扩容建议", "tool": "suggest_scale",
"args": {"service": "order"}, "depends_on": [2]},
]}, ensure_ascii=False)
agent = PlanExecuteAgent(tools, dummy_llm)
print(json.dumps(agent.run("检查 order 服务并给出扩容建议"),
ensure_ascii=False, indent=2))
3.3 关键设计要点
要点一:计划粒度要"步数约束"
# ❌ 过细:15 步,其中 8 步都是"调用 query_logs"
# ❌ 过粗:2 步:"检查所有服务" "给出报告"(等于没规划)
# ✅ 合理:3-10 步,每步对应一次独立的工具调用或一次明确的判断
规划 Prompt 里显式写"总步数控制在 3-10 步",比事后裁剪有效得多。
要点二:重规划必须"带状态"
# ❌ 从零重规划:已完成的工作全部作废,Token 爆炸
plan = make_plan(goal, ...) # 重新开始
# ✅ 带状态重规划:已完成步骤直接保留,只修订剩余部分
plan = replan(plan, error, ...) # version+1,done 步骤原样保留
要点三:反思要产出"可执行的教训",不是"情绪总结"
# ❌ 无效反思:"这次失败了,下次要更仔细。"
# ✅ 有效反思:"连接 B 前应先用 check_port 工具探测端口,避免盲目重试。"
教训必须具体到"下一步做什么/不做什么",才能注入下一轮规划。
四、规划深度自适应:什么时候该规划?
4.1 核心矛盾
- 不规划:长任务失控(41% 成功率)
- 全都规划:短任务浪费(一次规划消耗 1-3K Token,延迟 +2s)
4.2 解法:任务复杂度预判
在执行前先用一个轻量判断决定"要不要规划":
COMPLEXITY_PROMPT = """判断以下任务需要哪种执行模式,只输出一个词:
- "direct":1-5 步可完成,路径清晰
- "plan":需要先分解任务再执行
- "hierarchical":超长多阶段任务,需分层规划
任务:{goal}
历史教训参考:{lessons}"""
def route_mode(goal: str, llm: Callable, lessons: list[str]) -> str:
"""复杂度路由:短任务走 ReAct,长任务走规划"""
mode = llm(COMPLEXITY_PROMPT.format(goal=goal, lessons=lessons)).strip()
return mode if mode in ("direct", "plan", "hierarchical") else "plan"
4.3 实测效果
| 策略 | 短任务(<5步) | 长任务(15+步) | 平均 Token |
|---|---|---|---|
| 全部 ReAct | 94% / 快 | 41% / 混乱 | 基准 |
| 全部 Plan-Execute | 92% / 慢 2s | 79% | 基准 ×1.4 |
| 自适应路由 | 94% / 快 | 83% | 基准 ×1.04 |
自适应路由在两类任务上都拿到最优或接近最优的表现,总成本几乎不变。
五、实施成本与可行性评估
按惯例,方案提出后评估落地成本。
5.1 分阶段实施成本
| 阶段 | 工作量 | 依赖 | 可行性 | 建议优先级 |
|---|---|---|---|---|
| L1 步数约束的 Plan-Execute | 3-5 人日 | Agent 框架支持自定义执行循环 | 高 | P0 |
| L2 带状态重规划 | 5-8 人日 | 计划数据结构 + 步骤结果持久化 | 高 | P0 |
| L3 结构化反思 | 3-5 人日 | 反思 Prompt 调优 + 教训池存储 | 中 | P1 |
| L4 复杂度自适应路由 | 2-3 人日 | 路由 Prompt + 模式切换逻辑 | 高(成本低收益大) | P1 |
| L5 分层规划(多 Agent) | 10+ 人日 | 依赖第二篇的多 Agent 基建 | 中低(复杂度高) | P2 |
5.2 可行性结论
- P0 两项合计约 1.5 周,是长任务成功率从 41% → 79% 的最大功臣,ROI 最高。
- L3 反思的真瓶颈是"反思质量":弱模型反思常常流于表面,建议反思器用比执行器更强的模型,成本增加可控(反思只在失败时触发)。
- L5 分层规划不要急着上:90% 的业务任务用 Plan-Execute 就够,分层规划只在多阶段项目(如自动化研发流水线)里才有必要性,先跑通 P0/P1 再评估。
一句话:先用 1 周上"规划 + 重规划"拿到 79%,再用 1 周补"反思 + 自适应"冲到 83%,分层规划等业务真需要时再投入。
六、生态现状(2026 年 9 月)
6.1 主流框架的规划支持
| 框架 | 规划范式 | 特点 |
|---|---|---|
| LangGraph | 状态图 + 自定义循环 | 灵活度最高,Plan-Execute 需自建 |
| LlamaIndex Workflows | 事件驱动步骤 | 适合流水线式任务 |
| OpenAI Agents SDK | handoff + guardrail | 偏多 Agent 委派 |
| AutoGen | 对话式协作 | 规划隐含在对话中 |
| QwenPaw | Plan-Execute 内置 | 支持任务分解 + checkpoint |
6.2 范式学术论文脉络
| 工作 | 年份 | 核心贡献 |
|---|---|---|
| ReAct | 2022 | 推理与行动交替 |
| Reflexion | 2023 | 语言化反思替代梯度更新 |
| Plan-and-Solve | 2023 | 先规划后执行的开山 |
| LATS | 2023 | 蒙特卡洛树搜索式规划 |
| ADaPT | 2024 | 按需递归分解 |
6.3 与本系列其他篇目的关系
规划(本篇)是大脑 ──┬── 调用 ──► MCP 工具(第三篇)
├── 查询 ──► RAG 知识(第四篇)
├── 读写 ──► 分层记忆(第一篇)
├── 委派 ──► 多 Agent(第二篇)
├── 受限 ──► 安全防护(第五篇)
└── 被测 ──► 评估监控(第六篇)
规划是所有能力的调度中枢:前六篇建设的器官,最终都由规划器统一调度。
七、实战中的 5 个坑
坑 1:计划一次性拆太细
现象:规划器生成了 25 步的超细计划,第 3 步的前提假设错了,后面 22 步全部作废。
解法:初始计划只规划到"阶段级"(3-10 步),每步执行完再决定是否细化。粗计划 + 频繁重规划,优于细计划 + 一次崩盘。
坑 2:每步都触发重规划
现象:重规划阈值设得太敏感,一个无关紧要的工具警告就触发全量重规划,Token 消耗暴涨 5 倍。
解法:区分"致命失败"和"可忽略异常"。只有阻塞后续步骤的失败才触发重规划,其余记录后继续。设置 max_replan 上限(如 3 次)。
坑 3:反思变成"自我表扬"
现象:反思器输出"整体执行良好,只是运气不好",毫无信息量,教训池被污染。
解法:反思 Prompt 强制要求"指出至少一个具体的、下次可改变的决策",并给出轨迹中的证据。用更强模型做反思器。
坑 4:计划与执行上下文互相污染
现象:把完整计划 + 全部执行结果 + 重规划历史都塞进每一步的上下文,执行到第 10 步时上下文爆炸,模型开始忽略早期约束。
解法:每步执行只注入三样东西:目标、当前步骤、紧邻依赖的结果摘要。完整计划放外部状态(对照第一篇的分层记忆),按需检索。
坑 5:成功任务不沉淀经验
现象:只对失败做反思,成功的绕路方案(如"超时后改用批量接口")没有沉淀,同样的绕路每次都重走一遍。
解法:成功任务也做轻量复盘——检测"计划版本号 > 1 的成功任务",把重规划中被验证有效的调整写入教训池。
八、未来展望
8.1 从"文本计划"到"结构化计划"
当前计划是一段自然语言清单,模型间传递容易失真。未来计划会全面结构化:步骤依赖图(DAG)、预估成本、回退路径都成为计划的一等公民,计划本身可校验、可仿真、可回放。
8.2 规划与验证的联合
生成计划后先"纸面推演"再执行:用低成本模型模拟每步执行,提前发现依赖死锁、工具不匹配等问题。规划质量从"执行后才知道"变为"执行前可预估"。
8.3 跨任务经验迁移
反思教训目前只服务于同类任务。未来的经验库会做泛化抽象:"先探测再连接"不只是数据库迁移的教训,也是一切网络操作的教训。教训的抽象层级决定复用半径。
8.4 未来预判:规划的尽头是"元认知"
当前规划深度要么全局固定,要么靠一个路由模型二选一。我们的预判是:未来的 Agent 会具备"元认知"——先评估自己对任务的把握程度,再动态决定投入多少规划资源。
当前: 任务 → [路由器:direct / plan 二选一] → 执行
预判: 任务 → [元认知:我有多确定怎么做?]
├── 很确定(见过类似任务+有教训池)→ 直接执行
├── 一般确定 → 粗规划(3 步)→ 边走边细化
└── 很不确定 → 深规划 + 先检索经验 + 纸面推演
这像极了人类专家:老手拿到熟题直接下笔,拿到生题才画草稿。规划资源本身也是成本,元认知就是给"规划"这一个动作再做一次规划。 这与第六篇"分布画像"的预判同源——Agent 工程的下一步,都是让系统学会"对自己建模"。
九、总结
任务规划解决的是 Agent 的"大局观"问题。ReAct 让 Agent 有了手脚,规划让它有了脑子。
核心三条:
- 长短任务分流:短任务 ReAct 直接跑,长任务 Plan-and-Execute 先画地图
- 计划是活的:带状态重规划 + 结构化反思,计划跟着现实走,教训跟着任务走
- 规划深度自适应:规划资源本身是成本,按任务复杂度动态投入
记住:先想后做不是慢,盲人摸象式的"边做边想"才是真正的时间黑洞。 一个会规划、会重规划、会反思的 Agent,才能从"能跑通 demo"进化为"能扛住生产"。
欢迎在评论区交流你的 Agent 任务规划实践!
本文基于 2026 年 Agent 规划范式实战经验撰写,示例代码可在此基础上接入 LangGraph / QwenPaw 等框架替换为生产级执行引擎。
- 点赞
- 收藏
- 关注作者
评论(0)