做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和任务2";acceptance_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(instance=parsed_plan, schema=plan_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的整体可靠性会有一个脱胎换骨的提升。
做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和任务2";acceptance_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(instance=parsed_plan, schema=plan_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的整体可靠性会有一个脱胎换骨的提升。