WorkBuddy_新建任务与工作模式13_Plan模式的完整流程
Plan模式的完整流程摘要Plan模式是当前主流AI编程助手如Cursor、Claude Code、Cline等中一种非常重要的工作机制在真正动手修改代码之前先让AI产出一份可审阅的执行方案由人类确认或调整后再落地执行。本文将围绕 Plan 模式的完整生命周期——开启 → 补充信息 → 审阅方案 → 确认执行或调整计划——展开深入剖析结合可运行的代码示例手把手带你理解并实现一个最小可用的 Plan 模式工作流。无论你是想理解AI Agent的交互设计还是想在自己的工具中落地类似机制本文都能提供可复用的思路与代码。引言在直接对话式改代码的模式下我们常常遇到这样的问题AI 一上来就大改特改改完才发现方向完全错了需求含糊时AI 自行脑补产出的代码与预期南辕北辙涉及多文件、多步骤的重构AI 边想边改中途逻辑断裂人类失去了对改动范围的把控review 成本极高。Plan 模式正是为了解决这些痛点而诞生的。它的核心思想是把思考和执行分离。先产出一份结构化的计划Plan让人来审阅、补充、调整确认无误后再进入执行阶段。这本质上是一种人在回路Human-in-the-loop的工程设计。下面我们按完整流程逐步拆解。一、开启 Plan 模式从直接执行切换到先规划1.1 为什么要有一个显式的开启动作Plan 模式不应该默认开启也不应该悄悄开启。它需要用户明确表达先给我方案别急着改。原因有三成本考量规划本身要消耗 token 和时间简单任务不值得预期管理用户需要知道当前处于只读/规划状态避免误以为代码已被修改权限边界Plan 阶段通常应禁用写文件、执行命令等有副作用的工具。1.2 用状态机建模一个清晰的实现方式是把整个流程建模为有限状态机fromenumimportEnum,autoclassPlanState(Enum):IDLEauto()# 普通对话模式PLANNINGauto()# Plan 模式正在生成/补充计划REVIEWINGauto()# 计划已生成等待用户审阅EXECUTINGauto()# 用户已确认正在执行DONEauto()# 执行完成1.3 开启时的工具约束在 Plan 状态下必须对 Agent 可用的工具做白名单限制只允许只读工具READ_ONLY_TOOLS{read_file,list_dir,search_code,grep}WRITE_TOOLS{write_file,edit_file,run_command,delete_file}defget_allowed_tools(state:PlanState)-set[str]:根据当前状态返回允许使用的工具集合ifstatein(PlanState.PLANNING,PlanState.REVIEWING):# 规划/审阅阶段只读禁止任何副作用操作returnREAD_ONLY_TOOLSifstatePlanState.EXECUTING:returnREAD_ONLY_TOOLS|WRITE_TOOLSreturnREAD_ONLY_TOOLS|WRITE_TOOLS这样一来即便模型想去改文件工具层也会直接拦截从机制上保证 Plan 阶段是安全的。1.4 触发开启的几种常见方式显式指令用户输入先给方案、“plan first”、“别改代码先说说思路”快捷键/开关IDE 中的 Plan 模式按钮如 Cursor 的 Plan Mode自动升级当检测到任务涉及多文件或高风险操作时Agent 主动建议进入 Plan 模式。二、补充信息让计划建立在充分上下文之上2.1 为什么补充信息是独立的一步一个高质量的计划前提是信息充分。如果需求含糊、代码库上下文缺失模型只能靠猜产出的计划必然空洞。因此 Plan 模式在生成计划前或生成初稿后应主动向用户澄清关键信息。这一步的产物通常包括两类向用户提问范围、约束、优先级、验收标准主动检索代码库读取相关文件、搜索调用链把事实性上下文补齐。2.2 结构化澄清把问题变成数据与其让模型自由发挥地问不如定义一个结构化的澄清对象fromdataclassesimportdataclass,fielddataclassclassClarification:question:str# 要问用户的问题reason:str# 为什么需要这个信息options:list[str]field(default_factorylist)# 可选项可选blocking:boolTrue# 是否阻塞计划生成# 示例模型在规划前提出的澄清项clarifications[Clarification(question这次重构是否需要保持对外 API 完全兼容,reason决定能否修改函数签名影响改动范围,options[必须兼容,可以破坏性变更],blockingTrue,),Clarification(question是否需要同步补充单元测试,reason影响计划中的步骤数量与工作量,options[需要,不需要],blockingFalse,),]2.3 主动检索用只读工具补齐上下文在等待用户回答的同时Agent 可以并行地用只读工具收集事实defgather_context(agent,target_symbol:str)-dict:在 Plan 阶段收集与目标符号相关的上下文只读context{}# 1. 找到定义位置context[definition]agent.call_tool(search_code,{query:fdef{target_symbol}})# 2. 找到所有调用点评估影响面context[callers]agent.call_tool(grep,{pattern:f{target_symbol}(,exclude:tests/})# 3. 读取相关测试文件context[tests]agent.call_tool(search_code,{query:target_symbol,path:tests/})returncontext2.4 补充信息的收敛判断不能无限地问下去。一个实用的收敛策略是只对blockingTrue的问题强制等待回答非阻塞问题给出默认假设并在计划中显式标注假设……当关键上下文定义、调用点、测试都已获取即可进入下一步。三、审阅方案把计划变成可读、可评估的产物3.1 计划的推荐结构一份好的计划不是一段散文而是结构化、可逐步核对的清单。推荐包含以下字段fromdataclassesimportdataclass,fielddataclassclassPlanStep:id:inttitle:strdescription:strfiles:list[str]# 预计涉及的文件risk:str# low / medium / highdone_when:str# 验收标准如何判断这步完成dataclassclassPlan:goal:str# 一句话目标assumptions:list[str]# 明确列出的假设steps:list[PlanStep]out_of_scope:list[str]# 明确不做什么防止范围蔓延open_questions:list[str]# 仍需确认的问题3.2 生成计划的提示词骨架PLAN_PROMPT你正在 Plan 模式禁止修改任何文件。请基于以下上下文产出执行计划。 ## 目标 {goal} ## 已收集的上下文 {context} ## 已确认的信息 {confirmed} ## 输出要求 1. 用结构化步骤描述改动每步标注涉及文件、风险等级、验收标准 2. 明确列出你的假设assumptions与不做的事out_of_scope 3. 若仍有阻塞性问题放入 open_questions不要臆测。 3.3 审阅时人类关注什么审阅阶段人类主要评估四件事我们可以在 UI 上对应地高亮关注点对应字段典型问题方向对不对goal这是我要解决的问题吗范围合不合理steps[].files、out_of_scope改动面是否过大风险可不可接受steps[].risk有没有破坏性变更假设成不成立assumptions这些假设我认可吗3.4 一个渲染示例把 Plan 渲染成人类易读的 Markdowndefrender_plan(plan:Plan)-str:lines[f## 目标\n{plan.goal}\n]lines.append(## 假设)lines[f-{a}forainplan.assumptions]or[- 无]lines.append(\n## 执行步骤)forsinplan.steps:lines.append(f{s.id}. **{s.title}**风险:{s.risk}\nf - 涉及文件:{, .join(s.files)}\nf - 完成标准:{s.done_when})lines.append(\n## 不在本次范围)lines[f-{x}forxinplan.out_of_scope]or[- 无]ifplan.open_questions:lines.append(\n## 待确认问题)lines[f-{q}forqinplan.open_questions]return\n.join(lines)输出的效果大致如下## 目标 将 UserService 中的同步查询改为异步保持对外 API 兼容。 ## 假设 - 调用方均通过 await 调用无同步调用残留 - 数据库驱动支持 async ## 执行步骤 1. **抽取数据访问层**风险: medium - 涉及文件: services/user_service.py, db/repo.py - 完成标准: 新 repo 通过现有单测 2. **改造 UserService 为 async**风险: high - 涉及文件: services/user_service.py - 完成标准: 所有方法标注 async 且调用链更新 ## 不在本次范围 - 不修改 HTTP 层四、确认执行从计划到落地的受控切换4.1 确认动作本身要有契约用户的确认不应只是一个模糊的好的而应是一个明确的信号最好带上是否允许偏离计划的授权范围dataclassclassApproval:approved:boolallow_deviation:boolFalse# 执行中是否允许偏离计划max_files_changed:int|NoneNone# 可选的硬性约束4.2 执行器按步骤推进进入EXECUTING状态后执行器应当逐步推进并在每步完成后对照done_when自检defexecute_plan(agent,plan:Plan,approval:Approval)-dict:ifnotapproval.approved:raiseRuntimeError(计划未获批准禁止执行)results[]forstepinplan.steps:# 1. 执行前再次确认工具权限此时已放开写权限agent.set_allowed_tools(get_allowed_tools(PlanState.EXECUTING))# 2. 执行该步骤outputagent.run_step(step)# 3. 自检对照完成标准checkagent.verify(step.done_when,output)results.append({step:step.id,title:step.title,passed:check.passed,detail:check.detail,})# 4. 若不允许偏离且自检失败立即中止回到审阅ifnotcheck.passedandnotapproval.allow_deviation:agent.set_state(PlanState.REVIEWING)return{aborted_at:step.id,results:results}agent.set_state(PlanState.DONE)return{results:results}4.3 偏差检测执行时守护计划边界即使批准了执行也应监控实际改动是否越界比如改了计划外的文件defcheck_deviation(step:PlanStep,changed_files:list[str])-list[str]:返回计划外被修改的文件列表plannedset(step.files)return[fforfinchanged_filesiffnotinplanned]一旦发现越界就应暂停并向用户报告而不是默默改完——这正是 Plan 模式价值的关键体现。五、调整计划审阅不通过时的回退与迭代5.1 调整不是重新来一遍用户审阅后可能给出三类反馈微调某步拆分/合并、调整顺序、改风险描述范围变更增删步骤、修改out_of_scope方向否定目标本身理解错了需要重来。前两类应当在保留已有上下文的基础上做增量修改避免每次都从头生成。5.2 用 diff 方式修改计划defapply_feedback(plan:Plan,feedback:str)-Plan:根据用户反馈增量修改计划示意# 实际实现中可再次调用模型仅要求输出变更部分delta_promptf现有计划{render_plan(plan)}用户反馈{feedback}请仅输出需要变更的步骤新增/删除/修改保持其余步骤不变。 deltacall_model(delta_prompt)returnmerge_delta(plan,delta)# 将增量合并回原计划5.3 调整后的再确认调整完成后状态回到REVIEWING再次请用户确认。整个流程形成一个可循环的闭环PLANNING ──► REVIEWING ──┬──► EXECUTING ──► DONE ▲ │ └──── 调整计划 ◄──────┘5.4 完整驱动循环示例把前面各部分串起来得到一个可运行的骨架defrun_plan_mode(agent,goal:str):# 1. 开启agent.set_state(PlanState.PLANNING)agent.set_allowed_tools(get_allowed_tools(PlanState.PLANNING))# 2. 补充信息contextgather_context(agent,target_symbolextract_symbol(goal))clarificationsagent.propose_clarifications(goal,context)confirmedask_user(clarifications)# 阻塞式收集回答# 3. 生成并审阅方案planagent.generate_plan(goal,context,confirmed)agent.set_state(PlanState.REVIEWING)whileTrue:print(render_plan(plan))feedbackinput(确认执行(y/调整内容): )iffeedback.strip().lower()y:approvalApproval(approvedTrue)break# 5. 调整计划planapply_feedback(plan,feedback)# 4. 确认执行agent.set_state(PlanState.EXECUTING)returnexecute_plan(agent,plan,approval)六、工程实践中的几个关键细节6.1 计划要可验证每个步骤都必须有done_when否则执行阶段无法自检也无法判断是否需要回退。模糊的完成改造是坏计划所有调用点编译通过且单测绿才是好计划。6.2 显式记录假设把模型的隐含假设摆到台面上是 Plan 模式最有价值的部分之一。用户在审阅时看到假设调用方无同步残留往往能立刻发现模型理解是否有偏差。6.3 权限与状态强绑定安全边界必须由代码保证而非依赖模型自觉。前面get_allowed_tools的设计就是这一原则的体现Plan 阶段物理上无法写文件。6.4 日志与可追溯建议对每个状态迁移、每次计划版本都留痕便于事后复盘为什么走了这条路径importlogging logging.basicConfig(levellogging.INFO)deftransition(agent,from_state,to_state,reason):logging.info(f[PlanMode]{from_state.name}-{to_state.name}|{reason})agent.set_state(to_state)总结Plan 模式的本质是把 AI 的思考与执行解耦通过人在回路的方式在动手之前先对齐目标、范围与风险。本文完整梳理了它的四个核心环节开启用状态机显式建模并在规划阶段用只读工具白名单从机制上禁止副作用补充信息通过结构化澄清 主动检索让计划建立在充分上下文之上并明确收敛条件审阅方案把计划结构化为目标、假设、步骤、范围、待确认问题让人能高效评估方向与风险确认执行或调整计划以明确的审批契约进入执行逐步推进并检测偏差审阅不通过时以增量 diff 方式迭代最终形成闭环。一句话概括好的 Plan 模式让 AI 先说清楚要做什么再在人类的确认下只做说好的事。掌握了这套流程你不仅能更好地使用现有的 AI 编程工具也能在自己的 Agent 系统中落地一套安全、可控、可追溯的规划工作流。