06:Planning & Task State:Claude Code 怎么使用 plan 稳住任务
上一篇讲 Context Management,重点是:Claude Code 每一轮到底让模型看见什么。
06:Planning & Task State:Claude Code 怎么使用 plan 稳住任务
上一篇讲 Context Management,重点是:Claude Code 每一轮到底让模型看见什么。
但模型看见材料以后,还要继续往前走一步。它需要把用户目标、项目上下文、工具结果和已有约束整理成一个可以执行的路径。否则上下文越多,反而越容易变成“看到哪里就追到哪里”。
所以这一篇只抓住一个问题:
Claude Code 是怎么使用 plan,把一个模糊任务变成可执行、可校正、可验证的工作路径?
这里的 plan,不是为了让回复看起来更有条理。它更像动手前临时固定下来的一份工作草稿:当前理解是什么,准备先看哪里,可能改哪里,哪些范围先不碰,最后用什么结果判断完成。

这篇文章要拆的主线:Claude Code 怎么使用 plan
05 讲的是“这一轮看什么”。06 要接着讲“看见以后怎么组织行动”。
Claude Code 做代码任务时,用户给的入口经常很短:
修一下构建失败。
把这个页面样式调一下。
参考前面的讨论改 。
这些话能表达目标,但不一定能直接变成安全的文件改动。真正开始做之前,Claude Code 需要先判断几件事:
- 问题可能在哪些文件或模块里。
- 需要先读哪些上下文。
- 改动会不会牵涉多个位置。
- 哪些地方暂时不该碰。
- 最后用什么方式证明任务完成。
plan 的价值就在这里。它把“我要做什么”先压成一个临时工作假设,让后面的工具调用围绕这个假设推进。
这和上篇讲的上下文管理正好接上。上下文管理负责把材料摆到模型面前,plan 负责把材料变成行动路线。
为什么需要 plan:防止工具调用变成随手反应
Claude Code 的强项是能连续调用工具。它可以读文件、搜代码、改文件、跑命令、看测试结果,再继续下一轮。
这个能力很强,也很容易失控。
如果没有 plan,任务可能变成一串局部反应:
- 看到构建报错,就去改报错文件。
- 改完发现另一个文件类型不匹配,又继续改。
- 搜索时看到旧代码顺手重构。
- 测试失败后开始追另一个问题。
- 最后改了不少东西,却说不清最初目标有没有完成。
每一步单独看都合理,连起来就可能跑偏。
plan 解决的不是“模型会不会思考”,而是“每一步工具调用是不是还服务于原始任务”。它让 Claude Code 在动手前先给任务划出一个临时边界:
| plan 要固定的内容 | 它防止什么问题 |
|---|---|
| 目标 | 防止做着做着换成另一个目标 |
| 范围 | 防止读到哪里改到哪里 |
| 步骤 | 防止工具调用变成随手反应 |
| 边界 | 防止顺手重构和无关改动 |
| 验证方式 | 防止“看起来完成”代替真实完成 |
所以 plan 更像 Agent Loop 里的方向盘。工具让 agent 能动手,plan 让它知道每次动手要朝哪个方向。
plan 出现在什么时候
计划有成本。
它会多占一轮思考,也会多占一些上下文。如果只是修一个错别字、改一行文案、加一个很明确的日志,显式 plan 反而显得笨重。
Claude Code 的最佳实践里也把节奏讲得很清楚:先探索,再计划,再编码。这个节奏主要用于不确定、范围较大、需要先审方案的任务[1]。如果能用一句话说清楚 diff,通常可以直接做。
更适合显式 plan 的场景,大概有几类:
-
多文件改动。 用户需要知道会碰哪些地方,Claude Code 也需要避免漏掉依赖关系。
-
不熟悉代码库。 先读文件、看调用链、理解错误,再计划,能减少“解错题”的概率。
-
重构或迁移。 步骤之间有顺序,先后错了容易留下半成品。
-
验证路径不明确。 不知道该跑哪个测试、看哪个页面、检查哪个输出时,plan 要先把验证方式列出来。
-
需要用户先看范围。 有些任务不是不能做,而是动手前最好让用户确认改动边界。
这也是 plan mode 的位置。它让 Claude Code 可以先研究和提出方案,在没有批准前不改源码。这个能力的重点不是“多一个模式”,而是把研究、计划和编辑拆开:先弄清路线,再进入执行[2]。
plan 怎样生成:先观察,再整理路径
一个有用的 plan 通常不应该凭空生成。
如果用户只说“修构建失败”,Claude Code 一上来就列:
- 检查构建。
- 修改代码。
- 跑测试。
这类计划很整齐,但信息量很低。它没有说明错误可能在哪,准备先看什么,也没有说明验证方式。
更好的顺序是先观察。
Claude Code 会先把 05 讲过的上下文选择用起来:看用户目标,读已有约束,找相关文件,查看命令输出或错误信息。等到有了基本证据,再整理 plan。
可以把这个过程拆成五步:
-
读目标。 确认用户真正要的结果,是修失败、改样式、补文档,还是只做分析。
-
找约束。 包括用户明确说过的边界、项目规则、当前文件结构、前文已经确定的方向。
-
读证据。 看错误、相关文件、搜索命中、测试输出、已有 diff。
-
形成路径。 决定先检查哪里、再改哪里、最后怎么验证。
-
写出边界。 说明哪些东西暂时不碰,哪些风险需要留意。
这样生成的 plan 才会贴着任务走。
它不是“通用开发流程”,而是基于当前上下文的执行假设。
一个有用的 plan 应该包含什么
plan 不需要很长,但要有抓手。
我会把 Claude Code 的 plan 理解成六个小块:
| 小块 | 要回答的问题 |
|---|---|
| 目标 | 这次到底要解决什么 |
| 范围 | 会看或改哪些文件、模块、章节 |
| 步骤 | 先观察什么,再修改什么,再验证什么 |
| 边界 | 哪些地方暂时不碰 |
| 风险 | 哪些判断可能被后续证据推翻 |
| 验证 | 用什么结果说明任务完成 |
比如“修构建失败”的 plan,可以不是一大段流程,而是这样:
- 目标:让当前构建命令重新通过。
- 范围:先检查报错指向的配置和引用文件,不做顺手重构。
- 步骤:复现构建失败,定位第一处真实错误,读取相关文件,做最小修改,再重跑构建。
- 边界:不改无关模块,不为了风格调整扩大 diff。
- 风险:构建失败可能是多个错误连锁触发,需要按第一个根因处理。
- 验证:构建命令退出码为 0,并检查 diff 只覆盖相关文件。
这种 plan 的好处是清楚。
用户能看懂 Claude Code 准备怎么动手,Claude Code 后续也能用它约束自己:读文件是为了定位根因,编辑是为了最小修复,跑命令是为了证明结果。
plan 如何影响后续执行
plan 写出来以后,真正的价值才开始。
它会影响后续每一次工具调用。
读文件,不是漫无目的地浏览仓库,而是为了确认 plan 里的某个判断。编辑文件,不是看到可以优化就顺手改,而是为了完成 plan 里的某个步骤。运行命令,也不是为了“做点验证动作”,而是为了检查 plan 里的完成标准。
可以把执行过程看成一个小闭环:
当前 plan
-> 工具调用
-> 工具结果
-> 判断 plan 是否仍然成立
-> 继续执行或修正 plan
这里最关键的是“修正”。
plan 不是不可修改的合同。它更像一份当前最佳假设。只要工具结果回来,Claude Code 就要重新判断:
- 这个结果支持原计划吗?
- 是否发现了更准确的问题位置?
- 是否有步骤已经不需要了?
- 是否有新风险需要告诉用户?
- 是否需要先停下来重新确认范围?
比如原计划认为构建失败来自 TypeScript 配置,结果读完日志发现真正问题是某个导入路径大小写不一致。此时继续按原计划研究配置,就是在浪费上下文。更好的做法是更新 plan:从“检查配置”改成“修正导入路径并验证构建”。
这个更新动作很重要。
成熟的 plan 系统不是让 agent 死守第一版计划,而是让每次偏离都有理由。工具结果改变了判断,计划就跟着变;用户补充了限制,计划也跟着收窄。
plan 和完成不是一回事
plan 只能说明“准备怎么做”,不能证明“已经做好”。
很多长任务会在这里出问题。Claude Code 完成了 plan 里的几个步骤,就可能产生一种“任务应该结束了”的感觉。但用户真正要的不是步骤被执行,而是结果成立。
所以计划的最后一步一定要回到验证。
验证可以是:
- 测试通过。
- 构建成功。
- lint 或 typecheck 干净。
- diff 只触及预期范围。
- 页面截图和目标状态一致。
- 用户明确确认方案或结果可接受。
Claude Code 最佳实践里也强调,要给 Claude 一个能自己读取的检查信号。没有检查时,“看起来完成”就是唯一信号;有测试、构建、脚本、截图这类可读反馈时,Claude 才能自己闭环迭代[1]。
这里可以轻轻带到 todo 和 goal 的位置。
todo 更像过程记录,告诉当前做到哪一步。goal 或验收条件更像终点判断,告诉任务什么时候可以停。它们都可以服务 plan,但这篇不展开它们的产品机制。
这一篇只保留一个结论:
plan 负责组织执行,验证负责判断结果。
把这两件事分开,Claude Code 才不容易把“我按计划做了”误当成“任务已经完成”。
plan 和长任务交接
短任务里,plan 通常只需要在当前会话里起作用。
长任务会更麻烦。上下文会膨胀,会压缩,会恢复,也可能中途换人或换会话。Anthropic 关于长任务 harness 的文章里提到,长时间运行的 agent 需要进度文件、增量推进、测试验证和清晰交接,不能只依赖上下文压缩[3]。
放到 plan 上,就是一句话:
计划如果要跨阶段继续,就要留下能接手的状态。
这里不需要把每一步都写成正式文档,但至少要保留几类信息:
- 当前目标是什么。
- 已经完成了哪些步骤。
- 哪些判断被工具结果推翻过。
- 哪些文件已经改过。
- 哪些验证已经跑过,结果是什么。
- 下一步应该从哪里继续。
这些信息可以留在会话摘要、任务状态、progress 文件、PR 描述或项目文档里。它们不一定都属于 Claude Code 的长期记忆,但它们是长任务继续推进时的接力棒。
这也解释了为什么 05 讲上下文压缩时,要保留目标、关键文件、已改内容、验证结果、风险和下一步。压缩后的摘要如果没有这些字段,plan 就很难继续工作。
对我写 Agent 的启发
如果自己做一个 coding agent,我会把 plan 当成一个可更新对象,而不是一段一次性文本。
最小字段可以这样设计:
| 字段 | 作用 |
|---|---|
| goal | 当前任务要达成什么 |
| scope | 本轮准备查看或修改的范围 |
| steps | 接下来按什么顺序推进 |
| boundary | 哪些动作或文件暂时不碰 |
| verification | 用什么结果判断完成 |
| risks | 哪些地方可能改变计划 |
| updated_reason | 为什么这次更新计划 |
这里面最重要的是 updated_reason。
计划改变不可怕,悄悄改变才可怕。每次工具结果回来以后,agent 都应该问一句:
这个结果是在支持当前 plan,还是要求我调整 plan?
如果要调整,就把原因写出来。比如“测试失败显示问题不在配置,而在导入路径”,或者“用户补充不要改样式,所以移除 UI 调整步骤”。
我还会给 plan 加三条约束:
-
先观察再计划。 不熟悉代码时,先读关键文件、错误输出和项目规则,再列步骤。
-
计划要有边界。 每个 plan 都应该说清楚暂时不碰什么。边界能减少顺手重构和范围漂移。
-
完成必须靠验证。 plan 执行完以后,还要用测试、构建、diff、截图或用户确认来收尾。
这样写出来的 agent 会更稳一点。它不是每一步都显得很隆重,而是在任务真正复杂时,有一个可以回头看的工作草稿。
我现在对 Claude Code 使用 plan 的理解可以收成一句话:
plan 把上下文里的材料整理成行动假设,再让工具结果不断校正这个假设。
参考资料
Claude Code 文档
-
[1] Best practices for Claude Code
本文主要参考它关于“先探索、再计划、再编码”、小任务可以跳过计划,以及给 Claude 可验证检查信号的说明。 -
[2] Choose a permission mode
本文主要参考它关于 plan mode 的说明:先研究和提出计划,在批准前不修改源码。 -
[3] Effective harnesses for long-running agents
本文主要参考它关于长任务需要进度记录、增量推进、验证和交接材料的分析。
相关机制
-
[4] Todo Lists - Claude Agent SDK
本文只参考它关于复杂任务需要进度追踪的公开行为,不展开 todo 机制。 -
[5] Keep Claude working toward a goal
本文只参考它关于完成条件和跨轮判断的思路,用来区分 plan 和“什么时候可以停”。
下一篇继续追的问题
这一篇先把 plan 理解成 Claude Code 的行动草稿。
它解决的是:
看到上下文以后,准备怎么做。
但计划本身不会执行。真正动手时,Claude Code 还要判断这些动作能不能做、是否需要用户确认、会不会触碰敏感文件、外部系统或不可逆命令。
所以 07 继续追:
Claude Code 如何通过权限、settings、hooks 和 sandbox,把 plan 里的行动变成受控执行?