Skip to content

第 08 章 精准指令与任务拆分

第 06 章给了可执行闭环和任务 Prompt 骨架的雏形,本章把骨架拆开讲透:什么样的指令算"精准",什么时候该把一个大任务拆成多个子任务,以及拆分后如何用 TaskCreate 与子代理编排它们。这一章是第 09 章全栈开发与第 19 章大规模重构的工程前置。

8.1 结论:精准指令四要素 + 1-3 文件粒度

精准指令的最低门槛是四要素同时到位:

text
位置  → 文件路径:行号(改哪儿)
现状  → 当前问题是什么(为什么改)
目标  → 期望改变成什么(改成什么)
约束  → 不能动什么(边界)

任务拆分的最低门槛是:单个子任务触达 1-3 个文件,且能在一次验证闭环内自证完成。超过这个粒度,要么拆得更细,要么升格为多任务编排。

这两条不是修辞,是抗幻觉的物理约束。LLM 在 200K 上下文里推理时,对"模糊指令"的默认响应是猜测——它会把缺失的位置用最常见路径填上,把缺失的约束用最宽松假设放行,把缺失的验证用一句"已修改"代替。四要素的本质是把猜测空间压缩到机器可检查的最小集。

8.2 精准指令四要素详解

8.2.1 位置(文件路径:行号)

位置必须精确到文件,能到行号就到行号。Claude Code 的工具链对路径敏感:@src/auth 会把整个目录投喂进上下文,@src/auth/login.ts:42 会把焦点收到那一行。焦点越窄,幻觉越少。

text
# 差
> 帮我看看认证那块代码

# 好
> 读 @src/auth/jwt.ts 第 38-67 行的 verifyToken 函数

差指令的后果:Claude 会用 Grep 在整个 src/ 搜 "auth",可能命中 30 个文件,把无关的 auth-config.ts auth-types.ts 都读进来,然后在错误的位置"修复"。

8.2.2 现状(当前问题)

现状不是"它有 bug",是可复现的失败现象。最好的现状是一段错误日志或一个失败的测试:

text
# 差
> parseCSV 有性能问题

# 好
> 运行 `npm test -- parse` 时,parseCSV 处理 test/fixtures/10mb.csv 耗时 32 秒,
> 超出 5 秒预算。profiler 显示 78% 时间花在 String.prototype.split 累积调用上。

现状里埋的是根因线索。你给的越具体,Claude 越不需要自己猜根因——LLM 猜根因的失败率远高于人类。

8.2.3 目标(期望改变)

目标写可观察的结果,不写实现方式。一旦你写了实现方式,就把 Claude 的探索空间锁死了——如果你的实现方式本身不是最优解,Claude 不会替你纠错。

text
# 差(锁死实现)
> 把 parseCSV 改成用 readline 逐行读

# 好(描述结果)
> parseCSV 处理 10MB 文件的耗时降到 5 秒以内,内存峰值不超过 200MB

例外:当你已经确定实现路径(例如团队约定的迁移方案),就把路径写进目标。Claude Code 不是用来颠覆已定架构的工具。

8.2.4 约束(不能动什么)

约束是四要素里最常被省略、也是最容易触发事故的一段。约束要写三类:

  • 兼容性约束:API 签名、返回结构、错误码、配置文件格式
  • 范围约束:不改动哪些目录、不引入哪些依赖、不迁移哪些数据
  • 安全约束:不触碰 .env、不修改 migration、不写入生产配置
text
# 差(无约束)
> 优化 parseCSV

# 好
> 约束:
> - 保持 parseCSV 的函数签名 (input: string) => Row[] 不变
> - 不引入新依赖
> - 不修改 src/utils/ 目录以外的文件
> - 不改动 test/fixtures/ 下的测试数据

约束缺失的直接后果是误删和越界——Claude 在"优化"名义下重命名一个被 30 处调用的函数,或在重构名义下删掉一个它认为"无用"的防御性分支。

8.2.5 好/差对比(扩展 06 章的 parseCSV 例子)

把四要素合起来看,对照第 06 章的例子:

text
# 差(三要素缺失)
> 优化这个函数

# 中(只有位置和目标,缺现状和约束)
> 优化 src/utils/parse.ts 的 parseCSV,目标降到 5 秒以内

# 好(四要素齐全)
> 优化 src/utils/parse.ts:12-58 的 parseCSV 函数。
> 现状:处理 test/fixtures/10mb.csv 耗时 32 秒,profiler 显示 78% 时间在 split 累积调用。
> 目标:耗时降到 5 秒以内,内存峰值不超过 200MB。
> 约束:保持 (input: string) => Row[] 签名不变,不引入新依赖,
>       不修改 src/utils/ 以外文件,不改动 test/fixtures/。
> 验证:运行 `npm test -- parse` 全绿,用 10MB 文件测耗时给基准对比。
> 完成输出:diff 摘要 + 基准对比表 + 仍未覆盖的风险。

"好"版本比"差"版本多出的信息量,直接决定了 Claude 是否需要猜。每一段缺失,都会被一次猜测填补;每次猜测,都是一个失败风险。

8.3 任务 Prompt 骨架五段详解

第 06 章给过骨架,这里逐段拆开讲:

text
目标:
<用户可观察到的结果,而非实现方式>

范围:
<允许读取和修改的目录/文件>

约束:
<兼容性、安全、风格、禁止事项>

验证:
<必须运行的测试、Linter、类型检查、运行态检查>

完成输出:
<变更摘要、验证结果、剩余风险>

目标段

写用户可观察到的结果,不写实现方式(见 8.2.3)。一句话能写清就一句,写不清说明你自己还没想清楚——这时候不该下发任务,该先回 Plan Mode(第 07 章)。

范围段

范围段是给 Claude 的"读权限"和"写权限"清单。范围越窄,幻觉越少。常见写法:

text
范围:
- 读取:src/auth/、src/utils/jwt.ts、test/auth/*.test.ts
- 修改:src/auth/jwt.ts、src/auth/verify.ts
- 不修改:src/auth/middleware.ts(他人正在改,有未合并 PR)

显式声明"不修改"比只声明"修改"更安全——它能防止 Claude 出于"顺便修一下"的冲动越界。

约束段

见 8.2.4。约束段是事故防线,不是可选润色。

验证段

验证段把"完成"变成机器可检查的状态。这一段直接决定 Claude 能否自跑步骤 4-6(运行验证 → 读取失败 → 自我修正)。验证命令必须是可在终端直接执行的,不能是"检查一下性能":

text
验证:
- 单元测试:`npm test -- auth --runInBand`
- 类型检查:`npm run typecheck`
- Lint:`npm run lint -- src/auth/`
- 运行态:`node scripts/bench-parse.js test/fixtures/10mb.csv` 耗时 < 5s

四类验证各管一头:测试管行为正确,类型管接口正确,Lint 管风格一致,运行态管真实表现。一个任务至少要有前两类。

完成输出段

完成输出段规定 Claude 交付什么。这一段常被省略,但它的价值是强制 Claude 做自我审查:

text
完成输出:
- diff 摘要(改了哪些文件、每个文件改了什么)
- 验证结果(每条验证命令的实际输出)
- 剩余风险(哪些场景没覆盖、哪些假设没验证)

"剩余风险"这一项尤其重要。它逼 Claude 把"我没把握的地方"说出来,而不是用"已修复"掩盖。人类审查 git diff 时,这部分就是重点。

8.4 TaskCreate:任务拆解与依赖编排

8.4.1 何时拆

拆分的触发条件是三条之一:

  1. 单任务触达超过 3 个文件——上下文负担过重,验证闭环会拉长
  2. 任务内部存在明显阶段边界——例如"先加类型,再加实现,最后加测试"
  3. 部分子任务可并行——文件间低耦合,串行执行浪费时间

不满足以上任一条件,就别拆。拆分本身有协调成本(见 8.7),过度拆分比不拆更糟。

8.4.2 拆多细:1-3 文件粒度

每个子任务触达 1-3 个文件,且能在一次验证闭环内自证完成。这个粒度是经验值,背后逻辑是:

  • 1 个文件:子任务有明确单一职责,验证命令简单
  • 2-3 个文件:实现 + 测试 + 类型声明这类天然耦合的组合
  • 超过 3 个文件:上下文负担过重,Claude 容易顾此失彼

8.4.3 blocks / blockedBy 依赖

TaskCreate 的依赖字段用来表达子任务间的先后顺序(以下为 Claude Code Agent SDK 与编排工具的通用字段语义,具体 API 以 code.claude.com/docs 为准,核对日期 2026-07-08):

  • blocks:本任务完成后,哪些任务可以被解除阻塞
  • blockedBy:本任务在哪些任务完成前不能开始

无依赖的任务会被调度器并行启动,有依赖的任务按拓扑序串行。这条机制是"并行拆分策略"(8.5)的执行基础。

8.4.4 拆分工作流

text
命令(在 Plan Mode 或交互会话中下发给 Claude):
> 把"重构认证系统"拆成子任务,用 TaskCreate 创建,每个任务触达 1-3 个文件,
> 标注 blocks/blockedBy 依赖,先不要执行。

预期输出:

text
Task #1  类型定义:src/auth/types.ts                    blocks: [#2, #3]
Task #2  JWT 实现:src/auth/jwt.ts                      blockedBy: [#1]  blocks: [#4]
Task #3  验证中间件:src/auth/verify.ts                 blockedBy: [#1]  blocks: [#4]
Task #4  回归测试:test/auth/*.test.ts                  blockedBy: [#2, #3]
Task #5  旧代码清理:src/auth/legacy.ts(删除)          blockedBy: [#4]

验证:

  • 每个任务的 范围 段触达文件 ≤ 3
  • 依赖图无环(拓扑序可解)
  • Task #1 是根,无 blockedBy
  • Task #5 是叶,无 blocks

失败边界:

  • 拆出环形依赖(#1 blockedBy #2#2 blockedBy #1)→ 调度器死锁,需要人工介入解开
  • 任务粒度过细(单文件拆成 5 个任务)→ 协调成本超过并行收益,合并
  • 任务粒度过粗(单任务 8 文件)→ 上下文爆炸,拆开

8.5 并行拆分策略:子代理 vs 主上下文

拆分之后,执行路径有两条,选错就会出事。

8.5.1 文件间低耦合 → 子代理并行

判定条件:

  • 每个子任务修改的文件集合不重叠
  • 子任务之间没有"我改完你才能改"的实时依赖(只有拓扑依赖)
  • 每个子任务的验证可以独立运行

满足以上条件,用 Agent 工具派发子代理并行执行。每个子代理有独立上下文,完成后只返回摘要,主上下文负责汇总:

text
命令:
> 用 Explore 子代理并行执行 Task #2 和 Task #3,各自完成后返回 diff 摘要和验证结果。
> 主上下文汇总后,再串行执行 Task #4。

预期输出:

text
[Agent #2] 修改 src/auth/jwt.ts:verifyToken 改为流式校验
           验证:`npm test -- auth.jwt` 通过
[Agent #3] 修改 src/auth/verify.ts:中间件复用新 verifyToken
           验证:`npm test -- auth.verify` 通过
[主上下文] 汇总两个 diff,串行执行 Task #4 全量回归测试

验证:主上下文跑 npm test -- authnpm run typecheck 全绿。

失败边界:

  • 子代理之间有未声明的隐式依赖(例如都改了 types.ts)→ 后提交者覆盖先提交者,类型冲突
  • 子代理返回的摘要遗漏了"我顺手改了 X"→ 主上下文漏审,git diff 才会暴露

8.5.2 跨文件一致性 → 主上下文操作,不用子代理

判定条件之一即触发:

  • 多个子任务修改同一文件(例如都改 types.ts)
  • 子任务之间需要实时互相参照(例如实现和接口声明要同步演进)
  • 修改涉及全局命名空间或共享 schema(数据库迁移、API 契约)

这种情况下,子代理的独立上下文反而是负担——它们看不到彼此的修改,会各自做不同的假设。正确做法是在主上下文里串行执行,让 Claude 在同一个上下文里维护一致性:

text
命令:
> Task #2 和 Task #3 都要改 src/auth/types.ts,不要用子代理,
> 在主上下文里按 #2 → #3 顺序串行执行,每次改完跑一次 typecheck。

预期输出:主上下文连续完成两个任务,每次 Edit 后立即 npm run typecheck,失败则自我修正。

验证:git diff src/auth/types.ts 显示单次一致的类型演进,无回退痕迹。

失败边界:

  • 误用子代理并行改同一文件 → 两个子代理各改一版,合并时冲突或丢失修改
  • 主上下文串行执行时上下文窗口溢出 → 用 /compact 压缩,或把已完成任务的 diff 提交后再开新会话

8.5.3 决策矩阵

场景文件重叠实时依赖执行方式
批量给 20 个组件加同一类型注解子代理并行
重构 JWT 签发 + 验证 + 中间件无(各管一文件)无(拓扑依赖即可)子代理并行
实现新接口 + 同步更新类型声明有(都改 types.ts)主上下文串行
数据库 schema 迁移 + 代码适配有(共享 schema)主上下文串行
跨 50 个文件重命名一个全局符号无(各文件独立)子代理并行,但需先在主上下文定义符号映射

8.6 大规模重构:Agent 并行 + worktree 隔离

当任务规模上升到几十个文件、多个子任务需要独立的 git 分支保护时,裸用子代理并行会失控——子代理在主工作区直接改文件,彼此修改会污染,失败时回退困难。

正确做法是 Agent 工具配合 isolation: "worktree" 参数,让每个子代理在独立的 git worktree 里工作。worktree 是 git 原生能力,为每个子代理分配一个独立的工作目录和分支,修改互不干扰,完成后通过 merge 或 PR 汇总。

这条路径涉及 worktree 创建、子代理派发、合并策略、冲突处理等工程细节,是第 19 章"大规模重构与批量操作"的主题。本章只给出预告:

text
命令骨架(详细在第 19 章):
> 用 worktree 隔离的方式,派发 5 个子代理并行重构 5 个模块,
> 每个子代理在自己的 worktree 里完成 Edit + 验证,返回 worktree 路径,
> 主上下文汇总后逐个 merge。

适用边界:

  • 文件数 > 10 且模块间低耦合 → worktree 并行
  • 文件数 < 10 → 主上下文串行更简单
  • 模块间有强耦合 → 不用 worktree,回到 8.5.2 主上下文操作

8.7 实战:把"重构认证系统"拆成 5 步精准任务

接一个模糊需求:

text
> 重构认证系统,现在太乱了,JWT 和 session 混在一起,想统一成 JWT。

这个需求下不来直接执行——"太乱"是现状描述,"统一成 JWT"是方向,但位置、约束、验证全缺。先进 Plan Mode(第 07 章)做事实建模,再拆任务。

步骤 1:Plan Mode 事实建模

text
命令:
> 进入 Plan Mode。读 @src/auth/、@src/middleware/、@test/auth/、@package.json。
> 输出:
> 1. 当前认证入口与调用图
> 2. JWT 与 session 各自的使用位置(文件:行号)
> 3. 外部 API 契约中不能变的部分
> 4. 测试覆盖现状
> 不要改任何文件。

预期输出:一份带文件路径和行号的事实清单,标识出 src/auth/jwt.ts src/auth/session.ts src/middleware/auth.ts 三个核心文件,以及 12 处调用点。

验证:清单里的每个引用都能在代码里找到对应。

步骤 2:设计目标架构与约束

text
命令:
> 基于事实清单,设计统一为 JWT 的目标架构。
> 约束:
> - HTTP 头部 Authorization: Bearer <token> 格式不变
> - 现有 /api/login 返回结构不变
> - 不引入新依赖
> - session 模块在 Task #4 完成前不删除(保留回退能力)
> 输出目标架构与文件级改动计划。

验证:改动计划里的每个文件都在事实清单的范围内,没有越界。

步骤 3:TaskCreate 拆解

text
命令:
> 把改动计划拆成 5 个子任务,用 TaskCreate 创建,每个触达 1-3 个文件,
> 标注 blocks/blockedBy,先不执行。

预期输出:

text
Task #1  类型重构:src/auth/types.ts
         blockedBy: []  blocks: [#2, #3]

Task #2  JWT 实现:src/auth/jwt.ts
         blockedBy: [#1]  blocks: [#4]

Task #3  中间件适配:src/middleware/auth.ts
         blockedBy: [#1]  blocks: [#4]

Task #4  回归测试:test/auth/jwt.test.ts、test/auth/middleware.test.ts
         blockedBy: [#2, #3]  blocks: [#5]

Task #5  旧 session 清理:src/auth/session.ts(删除)
         blockedBy: [#4]

验证:依赖图无环;#2 和 #3 文件不重叠,可并行;#4 触达 2 文件,符合粒度。

步骤 4:并行执行 + 串行收口

text
命令:
> 执行 Task #1(主上下文,因为后续都依赖它)。
> 完成后,用子代理并行执行 Task #2 和 Task #3(文件不重叠)。
> 两个子代理返回后,主上下文串行执行 Task #4 和 Task #5。
> 每步完成后跑对应验证。

预期输出:5 个任务按拓扑序完成,每步有 diff 摘要和验证结果。

验证:npm test -- authnpm run typechecknpm run lint 全绿;git diff 显示 session.ts 在最后一步才删除。

步骤 5:人工审查

text
命令:
> git diff main..HEAD --stat
> /code-review --effort high
> /security-review

验证:diff 范围与计划一致;/code-review 无 HIGH 级别问题;/security-review 确认 JWT 校验未引入算法降级、密钥硬编码等常见漏洞。

8.8 失败边界

三种典型失败模式,每种都有对应的防御措施。

8.8.1 指令过笼统 → 幻觉

症状:Claude 在错误文件里"修复"了一个不存在的问题,或引入了未要求的依赖。

根因:位置或现状段缺失,Claude 用最常见路径填补猜测。

防御:四要素强制齐全;位置精确到行号;现状附可复现的失败现象或错误日志。进 Plan Mode 先做事实建模,再下发修改任务。

8.8.2 拆分过细 → 协调成本

症状:一个本来 30 分钟能完成的小重构,拆成 8 个子任务后,主上下文花在调度、汇总、解决子代理冲突上的时间超过实际编码时间。

根因:把"单一职责"过度解读为"单一文件",把本应在同一上下文里完成的耦合修改强行拆开。

防御:1-3 文件粒度是下限不是目标;有实时依赖的任务合并到主上下文串行;子任务数 ≤ 5 时收益最高,超过 8 时重新评估是否真需要拆。

8.8.3 约束缺失 → 误删越界

症状:Claude 在"优化"或"清理"名义下删除了防御性分支、重命名了被多处调用的公共函数、或修改了 .env / migration 等敏感文件。

根因:约束段省略,或只写了"不引入新依赖"这一条,没写范围约束和安全约束。

防御:约束段必填三类(兼容性、范围、安全);.env、migration、secrets 通过 .claude/settings.jsondeny 规则硬阻断(见第 05 章);git diff 审查时重点看新增/删除的 import 和被改动的敏感文件。

8.9 小结

精准指令四要素(位置、现状、目标、约束)把猜测空间压缩到最小;任务 Prompt 骨架五段(目标、范围、约束、验证、完成输出)把"完成"变成机器可检查的状态;TaskCreate 按 1-3 文件粒度拆解,用 blocks / blockedBy 编排依赖;文件低耦合并行用子代理,跨文件一致性用主上下文;大规模重构交给 worktree 隔离(第 19 章)。

一句话:把模糊需求翻译成机器可检查的任务,是 Claude Code 工程化的核心手艺。这层手艺到位,后面的全栈开发(第 09 章)、调试(第 18 章)、大规模重构(第 19 章)才能跑起来;这层手艺缺位,任何高阶功能都会退化为时灵时不灵的聊天。


上一章:Plan Mode:计划优先
下一章:全栈开发实战


下一章:遗留代码重构与 Bug 修复 | 返回目录