做AI Agent开发这几年我见过太多团队在Planning这个词上栽跟头。第一次做Agent的人往往默认所谓规划就是让模型写出一份步骤清单然后照着清单往下走。直到生产环境里出现各种意外——工具调用失败、中途发现目标理解偏了、步骤之间出现前后依赖却没人管——才意识到AI Agent里真正的Planning远比输出一段计划文本要复杂得多。这篇文章我就围绕我在多个Agent项目里沉淀下来的规划架构、Prompt设计和排查经验把一个能打的Planning系统应该长什么样一层层拆给你看。1. 先搞清楚一件事Agent里的Planning到底在规划什么如果把Agent比作一个能独立干活的小团队那Planning就是这个团队里的项目经理。用户丢过来一句话比如帮我整理一份关于新能源电池行业的投资简报这句话本身是模糊的行业边界在哪里、简报要覆盖哪几个维度、数据截止到什么时间、最终产出什么格式全都没说清楚。规划要做的事情就是把这些模糊意图翻译成一串可执行、可验证、有依赖、有兜底的子任务。很多人第一步就错了直接让模型请一步一步思考。这确实能吐出一个步骤列表但那个列表往往既没有依赖关系也没有验收标准更没有失败后的回退方案。我习惯把真正的规划总结成三个转换把模糊意图转换成清晰目标把清晰目标转换成有序步骤把有序步骤转换成可调用的工具动作三个转换缺一个都算不上是真正意义上的Planning。举个实际例子同样是调研竞争对手不好的规划会写成分析竞品、总结优劣势、给出建议这种话每个子任务都含糊到无法执行好的规划则拆成收集竞品公开产品信息调搜索引擎→ 抓取近半年发布动态调新闻接口→ 用代码统计关键词频次调Python环境→ 生成对比表格调报告生成器每一步都有明确的工具、产出物和验收标准。为什么我这么看重规划因为规划质量直接决定了执行质量和返工成本。执行器再强拿到一个方向错误的计划也白搭反过来规划做得再好没有好的反馈闭环也会在执行中慢慢跑偏。Planning是整个Agent系统的杠杆点这个杠杆撬得动系统的鲁棒性就上来了撬不动后面所有环节都在给前面的错误买单。2. 三种常见的Planning实现范式AI Agent的规划不是只有一种形态。根据任务性质、环境复杂度和token预算我一般把常见实现分成三种范式每种都有明确的适用场景和致命短板。2.1 一次性任务分解把整盘计划在开头全部拆完这是最直观的范式Agent收到目标后先调用规划模型产出一份完整的子任务列表然后按顺序逐个执行执行过程中原则上不修改计划。它的优点很突出——结构清晰、全局视角完整、便于人工在做之前审查一遍计划。业务稳定的时候这种方式特别舒服比如固定流程的离线数据处理、定时报告生成任务边界很清楚几乎不会出现意外。但它的短板也很致命不适应动态变化。一旦执行到第三步发现需要的信息在前两步根本没取到整个计划就得推倒重来。2.2 反馈驱动的循环规划想一步、做一步、看一步这类思路受学术界讨论很多的ReAct启发核心是不追求开局就给出完整计划而是想一步、做一步、观察一步每一步根据执行结果决定下一步动作。我常用边开车边看路来形容不预设整条路线但每到一个路口都重新评估方向。优点是容错性强特别适合开放域任务比如多轮信息检索、开放问答、竞品分析这种前面结果会影响后面行动的场景。缺点是容易迷失方向做几步之后忘了最初目标另外每一步都要重新输入上下文token消耗比一次性规划大不少。如果不加约束Agent可能在一个细小问题上反复横跳。2.3 分层规划高层定路线底层做动作分层规划Plan-and-Execute思路是我个人在生产环境里用得最多的一种。它把一个Agent拆成两层上层是规划器负责产出粗粒度的子目标下层是执行器对每个子目标再拆具体动作。两个角色分开上下文隔离关注点也隔离。这种结构的好处是职责清晰规划器不用关心调用哪个工具、传什么参数这种细节执行器也不用操心整个任务分几步。代价是多了一次模型调用响应延迟更高而且上下层之间传递信息时容易丢上下文。所以在工程上我对分层规划有一个要求上层传给下层的必须是结构化摘要不是一整段自然语言描述。2.4 选型到底怎么定我的建议很明确生产环境不要赌单一范式而是用混合结构。上层做一次性分解保证全局方向不偏下层做反馈式循环保证每个子任务遇到环境变化时能自我修正。选型可以参照下面这张表维度一次性任务分解反馈驱动循环分层规划全局视角强弱强动态容错弱强中Token消耗低高最高延迟低中高适合任务稳定的批处理流程开放式检索与问答多工具长链路复杂任务判断标准就三条任务目标是否可能多步且步骤之间不确定是否严重依赖外部环境反馈才能继续是否需要人工预审整条链路。三条都中优先分层规划只中前两条用反馈驱动循环一条都不中不要上Planning后面我会专门讲什么时候该克制。3. 规划Prompt这样写产出的计划才靠谱规划质量的上限很大程度由Prompt设计水平决定。我见过不少人把规划Prompt写成你是一个聪明的助手请把任务分解成几个步骤这种Soft Prompt在Demo里能跑一上生产就露馅。真正能稳定产出可用计划Prompt里必须有五个要素。3.1 规划Prompt的五要素第一个是角色边界。必须明确告诉模型你是规划器只负责拆解任务不负责执行。否则模型容易在计划里夹带私货把具体动作混进去。第二个是输出协议。要求模型输出严格的结构化内容我一般用JSON字段固定。自然语言计划我第一年吃过太多亏解析困难、字段缺失、格式漂移后来全部改成JSON Schema校验出问题能立刻定位。第三个是约束条件。工具名称必须从预注册列表里选禁止幻觉。这一步是硬约束不是在Prompt里强烈建议而是要在下游用白名单校验兜底。第四个是示例注入。给一正一反两个示例尤其要给出反例——告诉大家这样的计划不合格因为子任务不可执行。few-shot对规划质量的提升比我试过的其他技巧都明显。第五个是质量标准。把好计划的标准写清楚子任务是原子性的、步骤之间存在依赖关系、每个子任务有验收标准。标准越具体模型越容易对齐。3.2 一份可以直接改的规划Prompt下面这份Prompt是我基于多个项目打磨后沉淀下来的基础模板你可以直接拿去改你是一个任务规划器。你的唯一职责是把用户目标拆解为可执行的子任务。 规则 1. 每个子任务必须是原子性的即可以由一次工具调用或一个固定动作完成。 2. 子任务之间需要明确依赖关系dependencies字段引用前面的子任务ID。 3. tool字段必须从以下列表中选择web_search, code_python, data_reading, report_writer, api_call。 4. 每个子任务必须包含acceptance_criteria且该标准必须可以从执行结果中自动判断。 5. 最多输出6个子任务超过请合并同类项。 输出严格JSON格式不要输出任何额外文字 { goal: 用户目标的重新表述, plan: [ { id: task_id_1, description: 这个子任务具体做什么, tool: 使用的工具名称, dependencies: [], acceptance_criteria: 判断该任务是否成功的标准 } ] }每个字段都不是随便设计的。id是为了给dependencies提供引用锚点否则你没法表达任务3依赖任务1和任务2acceptance_criteria是重规划触发的依据执行器完成一个子任务后拿这个标准做自动判定不通过就触发重规划tool限制死是为了在源头切断工具幻觉。3.3 示例注入与反模式配一个反例很重要。我经常在Prompt里放这样一段不合格示例{id: t1, description: 分析市场趋势, tool: web_search, dependencies: [], acceptance_criteria: 完成分析}这种计划看起来没问题实际上完全不可执行。分析市场趋势不是原子动作工具web_search能做的只是检索结果不是分析完成分析也不是可自动判断的验收标准。用这个反例告诉模型模糊描述会被打回它就会自觉往细了拆。还有一个反模式值得特别说一下让模型在输出计划前先输出一大段思考过程然后混着计划一起返回。思考过程是给推理用的不是给执行用的。两者混在一起解析困难不说模型还容易在计划里写我认为应该先...之类的废话。我的做法是把CoT关掉或者明确要求思考过程写在内部推理最终只输出JSON。4. 规划落地从计划文本到真实执行的工程细节Prompt写好了模型能产出漂亮计划了但距离跑起来还差一整个工程链路。规划落地涉及解析、校验、排序、执行、反馈五个环节每个环节都有坑。4.1 计划解析与校验模型返回的JSON先解析解析完立刻做Schema校验。我直接用Python的jsonschema库一步到位from jsonschema import validate, ValidationError plan_schema { type: object, required: [goal, plan], properties: { goal: {type: string}, plan: { type: array, minItems: 1, items: { type: object, required: [id, description, tool, dependencies, acceptance_criteria], properties: { id: {type: string}, description: {type: string}, tool: {enum: [web_search, code_python, data_reading, report_writer, api_call]}, dependencies: {type: array, items: {type: string}}, acceptance_criteria: {type: string} } } } } } try: validate(instanceparsed_plan, schemaplan_schema) except ValidationError as e: # 校验失败重试一次仍失败则降级为自由执行模式 retry_plan call_planner_with_feedback(str(e))校验失败时不要傻傻原地重试。把错误信息拼进重试Prompt告诉模型你的计划没通过校验原因如下请重写成功率会高不少。如果第二次仍失败我一般降级为自由执行模式放弃强制计划让执行器自己看着办——这至少保证任务不会卡死。4.2 执行顺序的确定计划里每个子任务都有dependencies这实际上形成了一张DAG有向无环图。执行顺序需要做拓扑排序。这个不用引第三方图计算库自己维护一个入度表加队列就够了from collections import deque def topo_sort(plan): indegree {task[id]: 0 for task in plan} children {task[id]: [] for task in plan} for task in plan: for dep in task[dependencies]: if dep in children: children[dep].append(task[id]) indegree[task[id]] 1 queue deque([tid for tid, deg in indegree.items() if deg 0]) order [] while queue: tid queue.popleft() order.append(tid) for nxt in children[tid]: indegree[nxt] - 1 if indegree[nxt] 0: queue.append(nxt) if len(order) ! len(plan): raise ValueError(计划中存在循环依赖或孤立节点) return order这里有一个容易被忽略的点如果依赖关系里有环拓扑排序会拿不到完整序列。这时候要么是模型规划错了要么是prompt里依赖规则写得不够清楚。我会在校验阶段就做环检测提前拦截别等到执行时崩。4.3 规划器与执行器分离为什么必须拆开我看到很多Demo把规划器和执行器写在同一次模型调用里看起来省事实际上一旦任务复杂同一个模型又要顾全局又要顾细节效果很拉胯。生产环境里我坚持拆成两个组件Planner负责想Executor负责做。执行器每干完一个子任务不会把完整输出丢给规划器。完整日志太长塞进上下文既贵又会干扰判断。正确的做法是让执行器产出一个结构化摘要任务ID、执行状态、关键结果、是否满足验收标准。规划器只看这个摘要再决定继续执行、局部修复还是整体重来。还有一个非常关键的工程细节触发重规划的条件要明确不是感觉不对就重来。我设置的触发条件是三类——执行异常工具报错、超时、验收不通过结果不满足acceptance_criteria、环境反馈异常比如检索结果为空且无第二步方案。没有这三类信号就按原计划继续不允许模型自作主张改路线。4.4 规划循环上限与防死循环反馈驱动循环最怕什么死循环。Agent在一个失败任务上反复重试烧掉大量token不说还可能把系统拖垮。我的规则很简单直接写死在代码里单个子任务最多尝试3次第三次失败就标记为blocked最多触发2次全局重规划超过后终止并返回部分结果每次重规划后必须比上一版计划更接近目标判断标准是已完成子任务数增加或失败依赖被消除否则强制终止这套硬性数据上限比任何道德感里的聪明Agent都好使。规则的设置完全拦在设计者的预期内不会出现模型认为还有希望所以一直重试的失控场面。我自己最早踩过的坑就是没上限一个Agent在某项目中连续重规划了11次最后像个无头苍蝇一样什么都干不成所以这个教训记得格外牢。5. 常见问题与排查技巧实录如果说规划架构是骨架、Prompt是血肉那排查能力就是这个系统的免疫系统。我把实际运行里最高频的问题整理成了一张速查表希望帮你省掉一些弯路。5.1 排查速查表症状常见原因排查思路解决方案计划能产出但无法执行工具名称幻觉检查tool字段是否在预注册列表白名单校验 失败重试执行到一半卡住死循环检查循环轮次与步骤数上限加最大重规划次数强制终止计划过于空泛缺少验收标准检查acceptance_criteria是否具体Prompt里强制原子化描述执行结果与计划无关上下文丢失检查执行摘要是否传回规划器回传结构化摘要而非完整日志任务拆解遗漏依赖模型只看局部检查依赖字段是否完整拓扑排序 环检测 重试反馈重规划后任务跑飞全局视角丢失diff新旧计划定位改动点限制只允许局部修复5.2 三个我踩过的坑先说第一个坑。早期版本我用自然语言计划让模型输出第一步做什么、第二步做什么结果解析时各种格式漂移有时带重复序号有时混进注释有时连编号都会断掉。改成强制JSON加Schema校验后解析问题几乎绝迹。这个教训可以总结成一句话宁可做一次严格的结构化限制也不要花大量精力去兼容模型的自由发挥。第二个坑跟上下文管理有关。有段时间我为了让规划器更聪明把完整的执行日志全部喂回给规划器模型结果token爆炸而且模型被大量无关信息干扰重规划质量反而下降。后来改成结构化摘要加关键字段回传效果立刻上来了。真实经验是给规划器的不是更多信息而是更相关的信息。第三个坑是整体重规划。最初每次失败我都让模型重新生成完整计划结果发现它经常丢失已完成子任务的上下文把做完的事情又规划一遍甚至给出和之前冲突的方案。现在我的默认策略是局部修复只对失败子任务及其下游受影响的任务重新规划已完成的部分保持不动。这样既保住了全局视角又避免了重复劳动。5.3 调试利器Trace与计划Diff排查Agent问题有工具辅助会省力得多。我每个Agent项目都会做三件事第一完整的Trace日志。每个子任务记录输入摘要、输出摘要、token消耗、耗时、验收结果。一旦用户反馈结果不对先查Trace定位是第几个子任务开始跑偏。第二重规划Diff。每次触发重规划时记录旧计划和新计划的差异。这不只帮你定位问题还能反过来检验你的重规划触发条件是不是设得太激进——如果频繁diff但结果差异很小说明触发条件应该收紧。第三执行序列回放。把最终实际执行的顺序列出来人工抽查两三条链路。很多隐藏问题比如任务A和任务B并行执行但A的结果被B意外覆盖只有回放时才能看到。6. 什么时候不要上Planning这可能是一篇Planning文章里最反直觉的建议不是所有Agent都需要Planning。我见过一个最离谱的设计是一个只需查询天气的Agent团队也给它上了三层规划架构。结果是什么用户问一句今天北京天气怎么样Agent先花5秒生成一个包含识别地理信息、检索天气API、解析数据、生成回答的四步计划再一步步执行多花了一大堆token还经常因为规划错误导致整个查询失败。这种场景一次工具调用就能解决规划纯属添乱。我的经验法则是这样判断的任务目标是否可能需要多步且步骤之间存在不确定性是才考虑Planning。执行过程中是否依赖外部环境的实时反馈才能继续是才需要反馈驱动或分层规划。任务是否是固定流水线步骤早就确定的是那就别用Planning直接用工作流引擎稳定又省钱。还有一个成本维度绕不开。每次调用规划模型做一次完整规划可能消耗1k到5k个token。如果任务本身只需要两步规划成本反而比执行成本还高这怎么算都不划算。我的习惯是上线前先看一个指标规划token占总token的百分比。超过40%就说明规划过度了要么简化规划要么干脆去掉。7. 一点个人经验最后聊几句我自己的使用体会。现在我在项目里默认的组合是上层一次性规划下层反馈式执行这种结构兼顾了全局稳定和执行灵活。但还有一个细节比架构更重要执行计划之前先让模型用一句话复述一遍目标。不要小看这一步我测试下来它能显著降低规划内容与用户真实意图错位的概率。原因很简单模型在规划时很容易被中间步骤带偏复述目标等于强制做了一次目标对齐。另外一个实用技巧是在规划Prompt末尾加一句优先选择步骤数最少的方案但必须保证每个步骤有明确验收标准。这听起来有点矛盾实际上是逼模型在简洁和完备之间做权衡产出的计划往往比默认的长篇大论实用得多。我现在几乎每个Agent项目都带这句话。如果你后续想把这条路走得更深可以关注三个方向规划结果的缓存复用相同目标结构的任务直接复用历史计划省掉大量重复调用跨Agent协同规划多个Agent各自产出计划再由协调层合并用执行成功率的反馈信号自动调优规划Prompt这在长期跑批的Agent里非常管用。Planning这条路的深度远比表面看到的要深但把它真正做扎实之后Agent的整体可靠性会有一个脱胎换骨的提升。