规划(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 | 多条思路并行探索再选择 | 高 | 较弱,分支多 | 强但成本高 | 适合难题,不适合高频任务 |
新手可以这样选:
- 流程比较稳定:用 Plan-and-Execute。
- 每一步都依赖工具返回:用 ReAct。
- 需要探索多个候选方案:用 Tree-of-Thoughts。
- 不确定时,先用结构化计划,不要一上来做复杂搜索树。
这里有个容易踩的坑:不要把三种方式理解成互斥。一个真实 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 | 标记是否需要人工确认 |
状态流可以这样设计:
触发重规划的典型事件:
- 工具失败或返回空结果;
- 用户补充了新约束;
- 某一步结果让原计划不再成立;
- 成本、时间或权限超出限制。
注意,重规划不等于全部推倒重来。用户只是把返程从周五改到周六,就不需要重查出发城市、会议地点和酒店区域;只要重查受影响的酒店晚数、返程交通和预算就够了。规划系统如果不能判断“哪些步骤受影响”,就会把每次小修改都变成全量返工。
五、完整案例:差旅规划 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 有几个明确判断:
- 信息不够时先问,不假装已经知道。
- 没有依赖的步骤可以并行,减少等待时间。
- 预算估算必须等关键结果回来,不能提前编。
- 涉及预订、支付、发送确认邮件时,要让用户确认。
六、按计划执行的伪代码
下面这个示例重点不是具体 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_on、status 和执行结果推进。
如果把这段逻辑翻译成人话,就是:
先找出现在能做的步骤;
能做就执行,不能做就说明被什么卡住;
执行成功就记录结果;
执行失败就判断是重试、跳过,还是重新规划;
所有步骤完成后再给最终答案。生产系统里还要补两类保护:第一是循环上限,避免 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 多想几句,而是把复杂任务变成可执行、可观察、可调整的步骤。
好的规划系统要回答:
每一步做什么?
谁来做?
依赖谁?
失败后怎么办?
什么时候必须让人确认?