规划(Planning):让 Agent 先想清楚再动手

规划模式的核心很简单:不要让 AI 一上来就直接执行,而是先把目标拆成一组步骤,明确先做什么、后做什么、什么时候需要补信息、什么时候需要重来。

用人话说:

普通 AI:你让我做什么,我马上开始做。
 
有规划能力的 Agent:我先判断这件事要分几步做,哪些信息还缺,哪些步骤有依赖,然后再一步步执行。

这也是 Agent 从“会调用工具的助手”升级成“能处理复杂任务的项目执行者”的关键一步。

比如你说:

下周我要去上海出差三天,帮我安排一下。

没有规划的 Agent 可能马上去查机票、订酒店,做到一半才发现你没说预算、没说出差地点、没说几点要到。
有规划的 Agent 会先判断:

1. 先确认出差目的和地点
2. 再确认预算和时间偏好
3. 根据地点选酒店区域
4. 根据入住时间安排航班
5. 最后整理成行程表给用户确认

这就是规划的价值:不是让 AI 看起来更聪明,而是让它少走弯路、少犯低级错误。

一、什么时候需要规划

很多小任务确实不需要规划。

比如翻译一句话、总结一段文字、查询一个简单概念,直接回答就好。你让 AI 每次都先写一份计划,反而会显得啰嗦。

但一旦任务变成“多步、有依赖、会变化”,规划就不是装饰了。

可以把它想成办一场生日聚会。你不能先随便订餐厅,再发现朋友那天大多没空;也不能先买蛋糕,最后才知道寿星不吃甜食。真正要做的是先确认时间、人数、地点、预算和偏好,再安排后面的动作。

Agent 做复杂任务也一样。它不能只会“调用工具”,还要知道:

什么时候该问用户?
什么时候该查资料?
什么时候该先做 A 再做 B?
什么时候发现计划错了要调整?

所以,规划不是为了让简单问题复杂化,而是为了让复杂任务别靠运气往前推。

任务特征是否需要规划推荐方式原因
单步问答不需要直接回答没有明显执行链路
固定短流程不一定提示词链步骤稳定,不需要动态决策
多工具、多资料、多约束需要Plan-and-Execute先列计划,再逐步执行
环境不断变化需要ReAct每一步根据观察调整
难题需要比较多条思路可能需要Tree-of-Thoughts同时探索多个方案
强实时聊天谨慎轻量计划过长规划会拖慢体验

一个简单判断:

如果任务失败后你需要知道“哪一步错了”,就应该有计划。
如果任务只有一步,规划只是额外负担。

二、Planning 在做什么

Planning 通常包含四个动作。

1. 拆解任务

把目标拆成可执行步骤。

1. 确认出差日期和会议地点
2. 查询交通选项
3. 查询酒店选项
4. 估算预算
5. 生成行程建议
6. 请用户确认关键选择

拆解不是越细越好。好的拆解应该让每一步都有明确产出,而不是把“打开工具、输入关键词、等待结果”也拆成三步。否则计划看起来很认真,执行成本却变高了。

2. 判断依赖关系

不是所有步骤都能乱序执行。

确认会议地点 -> 查附近酒店
确认日期 -> 查交通和酒店价格
交通和酒店都有结果 -> 估算预算

依赖关系是规划里最容易被忽略、也最容易出事故的地方。很多 Agent 失败不是因为不会做某一步,而是把顺序排错了:还没确认会议地点就开始推荐酒店,还没拿到数据就开始写结论,还没让用户确认就执行高风险动作。

3. 分配执行方式

每一步可以交给不同能力:

需要用户补充 -> 追问
需要实时信息 -> 调用工具
需要比较方案 -> 让模型分析
需要高风险确认 -> 暂停等待用户

这一步会直接影响系统边界。模型适合判断、归纳和生成;工具适合查询、计算和写入;人适合补充上下文和确认风险。把三者混在一起,Agent 就容易在该问人的时候瞎猜,在该调用工具的时候编答案。

4. 根据结果调整计划

如果预算超了,计划要改。

如果酒店没房,计划要改。

如果用户临时换日期,计划也要改。

Planning 不是一次性写清单,而是让 Agent 知道何时继续、何时重规划、何时停下来问人。

真正的规划能力,一半在“开始前想清楚”,另一半在“执行中承认计划可能会失效”。

三、三种常见规划方式

方式核心做法成本可观测性失败恢复适合生产自动化
ReAct思考一步、行动一步、观察一步中到高中等强,能边走边改适合动态任务
Plan-and-Execute先列计划,再按计划执行中等强,步骤清楚中等,需要重规划机制很适合
Tree-of-Thoughts多条思路并行探索再选择较弱,分支多强但成本高适合难题,不适合高频任务

新手可以这样选:

  1. 流程比较稳定:用 Plan-and-Execute。
  2. 每一步都依赖工具返回:用 ReAct。
  3. 需要探索多个候选方案:用 Tree-of-Thoughts。
  4. 不确定时,先用结构化计划,不要一上来做复杂搜索树。

这里有个容易踩的坑:不要把三种方式理解成互斥。一个真实 Agent 可能先用 Plan-and-Execute 生成大步骤,再在某个动态步骤里用 ReAct 边查边调,最后在几个候选方案之间做一次轻量比较。模式不是标签,关键是匹配任务的不确定性。

四、最小工程模型

一个计划不能只是一段自然语言。最好变成结构化步骤。

{
  "goal": "安排三天两晚上海出差",
  "steps": [
    {
      "id": "confirm_details",
      "title": "确认日期、会议地点和预算",
      "depends_on": [],
      "status": "pending",
      "executor": "ask_user"
    },
    {
      "id": "search_hotels",
      "title": "查询会议地点附近酒店",
      "depends_on": ["confirm_details"],
      "status": "pending",
      "executor": "tool"
    }
  ]
}

每个 PlanStep 至少应该有:

字段作用
id程序识别步骤
title人能看懂的步骤名
depends_on依赖哪些步骤
status当前状态
executor谁来执行:模型、工具、人
result执行结果
error失败原因

如果要做得更稳,还可以补两个字段:

字段作用
success_criteria判断这一步是否真的完成
risk_level标记是否需要人工确认

状态流可以这样设计:

流程图画布 · 115%
Mermaid 流程图加载中...

触发重规划的典型事件:

  • 工具失败或返回空结果;
  • 用户补充了新约束;
  • 某一步结果让原计划不再成立;
  • 成本、时间或权限超出限制。

注意,重规划不等于全部推倒重来。用户只是把返程从周五改到周六,就不需要重查出发城市、会议地点和酒店区域;只要重查受影响的酒店晚数、返程交通和预算就够了。规划系统如果不能判断“哪些步骤受影响”,就会把每次小修改都变成全量返工。

五、完整案例:差旅规划 Agent

用户输入:

帮我安排一次三天两晚的上海出差,预算 5000 元以内,要靠近会议地点,并给我一份行程建议。

第一步不是立刻查酒店,而是识别缺失信息:

缺失:
1. 出差日期
2. 会议地点
3. 出发城市

如果信息不完整,Agent 应该先追问:

我可以帮你规划。还需要确认三个信息:出发城市、出差日期、会议地点。

信息齐了以后,再生成结构化计划:

{
  "steps": [
    {
      "id": "search_transport",
      "depends_on": [],
      "executor": "tool",
      "status": "pending"
    },
    {
      "id": "search_hotels",
      "depends_on": [],
      "executor": "tool",
      "status": "pending"
    },
    {
      "id": "estimate_budget",
      "depends_on": ["search_transport", "search_hotels"],
      "executor": "model",
      "status": "pending"
    },
    {
      "id": "ask_confirmation",
      "depends_on": ["estimate_budget"],
      "executor": "human",
      "status": "pending"
    }
  ]
}

交通和酒店可以并行查,预算估算必须等它们都有结果。

这个例子里,真正有价值的不是“能查交通和酒店”,而是 Agent 有几个明确判断:

  1. 信息不够时先问,不假装已经知道。
  2. 没有依赖的步骤可以并行,减少等待时间。
  3. 预算估算必须等关键结果回来,不能提前编。
  4. 涉及预订、支付、发送确认邮件时,要让用户确认。

六、按计划执行的伪代码

下面这个示例重点不是具体 API,而是计划如何驱动执行。

def execute_plan(plan, context):
    while has_pending_steps(plan):
        ready_steps = [
            step for step in plan["steps"]
            if step["status"] == "pending"
            and dependencies_succeeded(step, plan)
        ]
 
        if not ready_steps:
            return {
                "status": "blocked",
                "plan": plan,
            }
 
        for step in ready_steps:
            step["status"] = "running"
 
            try:
                result = run_step(step, context)
                step["result"] = result
                step["status"] = "succeeded"
            except ToolError as error:
                step["error"] = str(error)
                step["status"] = "failed"
 
                if should_replan(step, error):
                    return replan(plan, context, failed_step=step)
 
    return {
        "status": "succeeded",
        "plan": plan,
    }

这才是规划 Agent 和普通顺序脚本的区别:它不是写死每一步,而是根据 depends_onstatus 和执行结果推进。

如果把这段逻辑翻译成人话,就是:

先找出现在能做的步骤;
能做就执行,不能做就说明被什么卡住;
执行成功就记录结果;
执行失败就判断是重试、跳过,还是重新规划;
所有步骤完成后再给最终答案。

生产系统里还要补两类保护:第一是循环上限,避免 Agent 一直重试;第二是幂等设计,避免失败重跑时重复下单、重复发信、重复写数据库。

七、生产注意事项

设计点为什么重要简单做法
计划结构化程序才能执行和恢复JSON plan + step status
停止条件防止 ReAct 无限循环最大步数、最大时间、最大成本
重规划现实结果会打破原计划失败后生成新 plan
人工确认高风险决策不能自动做支付、删除、发送前暂停
日志监控方便复盘哪一步错了记录 step、tool、status、cost
成本控制规划会增加调用次数限制分支和重试

Planning 最容易犯的错误,是把计划写成漂亮文字,却没有状态、依赖和失败处理。

还有一个常见错误,是把规划交给模型之后就完全相信它。更稳的做法是让模型生成候选计划,再由程序做结构校验:步骤 id 不能重复,依赖不能形成环,executor 必须在允许范围内,高风险步骤必须有人工确认。这样计划既保留了模型的灵活性,又不会完全失控。

八、规划、工具调用、反思之间的关系

模式解决的问题和 Planning 怎么组合
工具调用执行真实动作计划步骤可以指定要调用的工具
反思检查结果是否合格每个关键步骤后做质量检查
并行化同时执行独立步骤没有依赖的 plan step 可以并行
路由判断进入哪种任务流程先路由,再生成对应计划

真实 Agent 往往会组合这些模式:先路由识别任务,再规划步骤,执行时调用工具,关键节点用反思检查结果。

可以把它理解成一条很朴素的工作链路:

路由:这是什么类型的任务?
规划:这件事分几步做?
工具调用:每一步怎么拿到真实结果?
反思:结果是否满足目标?
重规划:如果不满足,改哪一部分?

只讲工具调用,Agent 会变成“会按按钮的模型”;只讲反思,它会变成“做完再检查的模型”;加入规划之后,它才开始像一个能安排任务、追踪状态、处理意外的执行者。

九、什么时候不要用复杂规划

规划不是万能药。用错了,反而会拖慢系统。

以下几类任务要谨慎:

场景更合适的做法原因
单步问答直接回答没有执行链路
固定短流程写死业务流程稳定规则比动态规划可靠
强实时聊天轻量内部计划用户不需要看完整计划
高频低价值任务限制步骤和重试规划成本可能高于收益
权限不清的任务先问人不能靠规划绕过确认

一个简单标准是:规划应该让任务更可控,而不是让交互更沉重。如果计划本身比任务还复杂,多半是用错了。

十、可复制的规划提示词模板

你是任务规划器。
 
请根据用户目标生成一个可执行计划。
 
要求:
1. 如果信息不足,先列出需要追问的问题;
2. 每个步骤只做一件事;
3. 写出步骤依赖;
4. 标出执行方式:model、tool、human;
5. 高风险动作必须设置 human confirmation;
6. 输出 JSON。
 
JSON 格式:
{
  "goal": "...",
  "missing_info": ["..."],
  "steps": [
    {
      "id": "...",
      "title": "...",
      "depends_on": ["..."],
      "executor": "model|tool|human",
      "status": "pending"
    }
  ]
}
 
用户目标:
{{user_goal}}

这个模板适合做“规划器”的最小起点。真正接入系统时,不要只把它当提示词,还要配合 schema 校验、状态记录、工具权限和人工确认。否则模型虽然输出了 JSON,但系统依然不知道哪些步骤能自动执行,哪些步骤必须停下来。

十一、一句话记住规划模式

Planning 不是让 AI 多想几句,而是把复杂任务变成可执行、可观察、可调整的步骤。

好的规划系统要回答:

每一步做什么?
谁来做?
依赖谁?
失败后怎么办?
什么时候必须让人确认?