第 08 章 精准指令与任务拆分
第 06 章给了可执行闭环和任务 Prompt 骨架的雏形,本章把骨架拆开讲透:什么样的指令算"精准",什么时候该把一个大任务拆成多个子任务,以及拆分后如何用
TaskCreate与子代理编排它们。这一章是第 09 章全栈开发与第 19 章大规模重构的工程前置。
8.1 结论:精准指令四要素 + 1-3 文件粒度
精准指令的最低门槛是四要素同时到位:
位置 → 文件路径:行号(改哪儿)
现状 → 当前问题是什么(为什么改)
目标 → 期望改变成什么(改成什么)
约束 → 不能动什么(边界)任务拆分的最低门槛是:单个子任务触达 1-3 个文件,且能在一次验证闭环内自证完成。超过这个粒度,要么拆得更细,要么升格为多任务编排。
这两条不是修辞,是抗幻觉的物理约束。LLM 在 200K 上下文里推理时,对"模糊指令"的默认响应是猜测——它会把缺失的位置用最常见路径填上,把缺失的约束用最宽松假设放行,把缺失的验证用一句"已修改"代替。四要素的本质是把猜测空间压缩到机器可检查的最小集。
8.2 精准指令四要素详解
8.2.1 位置(文件路径:行号)
位置必须精确到文件,能到行号就到行号。Claude Code 的工具链对路径敏感:@src/auth 会把整个目录投喂进上下文,@src/auth/login.ts:42 会把焦点收到那一行。焦点越窄,幻觉越少。
# 差
> 帮我看看认证那块代码
# 好
> 读 @src/auth/jwt.ts 第 38-67 行的 verifyToken 函数差指令的后果:Claude 会用 Grep 在整个 src/ 搜 "auth",可能命中 30 个文件,把无关的 auth-config.ts auth-types.ts 都读进来,然后在错误的位置"修复"。
8.2.2 现状(当前问题)
现状不是"它有 bug",是可复现的失败现象。最好的现状是一段错误日志或一个失败的测试:
# 差
> parseCSV 有性能问题
# 好
> 运行 `npm test -- parse` 时,parseCSV 处理 test/fixtures/10mb.csv 耗时 32 秒,
> 超出 5 秒预算。profiler 显示 78% 时间花在 String.prototype.split 累积调用上。现状里埋的是根因线索。你给的越具体,Claude 越不需要自己猜根因——LLM 猜根因的失败率远高于人类。
8.2.3 目标(期望改变)
目标写可观察的结果,不写实现方式。一旦你写了实现方式,就把 Claude 的探索空间锁死了——如果你的实现方式本身不是最优解,Claude 不会替你纠错。
# 差(锁死实现)
> 把 parseCSV 改成用 readline 逐行读
# 好(描述结果)
> parseCSV 处理 10MB 文件的耗时降到 5 秒以内,内存峰值不超过 200MB例外:当你已经确定实现路径(例如团队约定的迁移方案),就把路径写进目标。Claude Code 不是用来颠覆已定架构的工具。
8.2.4 约束(不能动什么)
约束是四要素里最常被省略、也是最容易触发事故的一段。约束要写三类:
- 兼容性约束:API 签名、返回结构、错误码、配置文件格式
- 范围约束:不改动哪些目录、不引入哪些依赖、不迁移哪些数据
- 安全约束:不触碰
.env、不修改 migration、不写入生产配置
# 差(无约束)
> 优化 parseCSV
# 好
> 约束:
> - 保持 parseCSV 的函数签名 (input: string) => Row[] 不变
> - 不引入新依赖
> - 不修改 src/utils/ 目录以外的文件
> - 不改动 test/fixtures/ 下的测试数据约束缺失的直接后果是误删和越界——Claude 在"优化"名义下重命名一个被 30 处调用的函数,或在重构名义下删掉一个它认为"无用"的防御性分支。
8.2.5 好/差对比(扩展 06 章的 parseCSV 例子)
把四要素合起来看,对照第 06 章的例子:
# 差(三要素缺失)
> 优化这个函数
# 中(只有位置和目标,缺现状和约束)
> 优化 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 章给过骨架,这里逐段拆开讲:
目标:
<用户可观察到的结果,而非实现方式>
范围:
<允许读取和修改的目录/文件>
约束:
<兼容性、安全、风格、禁止事项>
验证:
<必须运行的测试、Linter、类型检查、运行态检查>
完成输出:
<变更摘要、验证结果、剩余风险>目标段
写用户可观察到的结果,不写实现方式(见 8.2.3)。一句话能写清就一句,写不清说明你自己还没想清楚——这时候不该下发任务,该先回 Plan Mode(第 07 章)。
范围段
范围段是给 Claude 的"读权限"和"写权限"清单。范围越窄,幻觉越少。常见写法:
范围:
- 读取: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(运行验证 → 读取失败 → 自我修正)。验证命令必须是可在终端直接执行的,不能是"检查一下性能":
验证:
- 单元测试:`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 做自我审查:
完成输出:
- diff 摘要(改了哪些文件、每个文件改了什么)
- 验证结果(每条验证命令的实际输出)
- 剩余风险(哪些场景没覆盖、哪些假设没验证)"剩余风险"这一项尤其重要。它逼 Claude 把"我没把握的地方"说出来,而不是用"已修复"掩盖。人类审查 git diff 时,这部分就是重点。
8.4 TaskCreate:任务拆解与依赖编排
8.4.1 何时拆
拆分的触发条件是三条之一:
- 单任务触达超过 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 拆分工作流
命令(在 Plan Mode 或交互会话中下发给 Claude):
> 把"重构认证系统"拆成子任务,用 TaskCreate 创建,每个任务触达 1-3 个文件,
> 标注 blocks/blockedBy 依赖,先不要执行。预期输出:
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 工具派发子代理并行执行。每个子代理有独立上下文,完成后只返回摘要,主上下文负责汇总:
命令:
> 用 Explore 子代理并行执行 Task #2 和 Task #3,各自完成后返回 diff 摘要和验证结果。
> 主上下文汇总后,再串行执行 Task #4。预期输出:
[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 -- auth 与 npm run typecheck 全绿。
失败边界:
- 子代理之间有未声明的隐式依赖(例如都改了
types.ts)→ 后提交者覆盖先提交者,类型冲突 - 子代理返回的摘要遗漏了"我顺手改了 X"→ 主上下文漏审,
git diff才会暴露
8.5.2 跨文件一致性 → 主上下文操作,不用子代理
判定条件之一即触发:
- 多个子任务修改同一文件(例如都改
types.ts) - 子任务之间需要实时互相参照(例如实现和接口声明要同步演进)
- 修改涉及全局命名空间或共享 schema(数据库迁移、API 契约)
这种情况下,子代理的独立上下文反而是负担——它们看不到彼此的修改,会各自做不同的假设。正确做法是在主上下文里串行执行,让 Claude 在同一个上下文里维护一致性:
命令:
> 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 章"大规模重构与批量操作"的主题。本章只给出预告:
命令骨架(详细在第 19 章):
> 用 worktree 隔离的方式,派发 5 个子代理并行重构 5 个模块,
> 每个子代理在自己的 worktree 里完成 Edit + 验证,返回 worktree 路径,
> 主上下文汇总后逐个 merge。适用边界:
- 文件数 > 10 且模块间低耦合 → worktree 并行
- 文件数 < 10 → 主上下文串行更简单
- 模块间有强耦合 → 不用 worktree,回到 8.5.2 主上下文操作
8.7 实战:把"重构认证系统"拆成 5 步精准任务
接一个模糊需求:
> 重构认证系统,现在太乱了,JWT 和 session 混在一起,想统一成 JWT。这个需求下不来直接执行——"太乱"是现状描述,"统一成 JWT"是方向,但位置、约束、验证全缺。先进 Plan Mode(第 07 章)做事实建模,再拆任务。
步骤 1:Plan Mode 事实建模
命令:
> 进入 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:设计目标架构与约束
命令:
> 基于事实清单,设计统一为 JWT 的目标架构。
> 约束:
> - HTTP 头部 Authorization: Bearer <token> 格式不变
> - 现有 /api/login 返回结构不变
> - 不引入新依赖
> - session 模块在 Task #4 完成前不删除(保留回退能力)
> 输出目标架构与文件级改动计划。验证:改动计划里的每个文件都在事实清单的范围内,没有越界。
步骤 3:TaskCreate 拆解
命令:
> 把改动计划拆成 5 个子任务,用 TaskCreate 创建,每个触达 1-3 个文件,
> 标注 blocks/blockedBy,先不执行。预期输出:
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:并行执行 + 串行收口
命令:
> 执行 Task #1(主上下文,因为后续都依赖它)。
> 完成后,用子代理并行执行 Task #2 和 Task #3(文件不重叠)。
> 两个子代理返回后,主上下文串行执行 Task #4 和 Task #5。
> 每步完成后跑对应验证。预期输出:5 个任务按拓扑序完成,每步有 diff 摘要和验证结果。
验证:npm test -- auth、npm run typecheck、npm run lint 全绿;git diff 显示 session.ts 在最后一步才删除。
步骤 5:人工审查
命令:
> 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.json 的 deny 规则硬阻断(见第 05 章);git diff 审查时重点看新增/删除的 import 和被改动的敏感文件。
8.9 小结
精准指令四要素(位置、现状、目标、约束)把猜测空间压缩到最小;任务 Prompt 骨架五段(目标、范围、约束、验证、完成输出)把"完成"变成机器可检查的状态;TaskCreate 按 1-3 文件粒度拆解,用 blocks / blockedBy 编排依赖;文件低耦合并行用子代理,跨文件一致性用主上下文;大规模重构交给 worktree 隔离(第 19 章)。
一句话:把模糊需求翻译成机器可检查的任务,是 Claude Code 工程化的核心手艺。这层手艺到位,后面的全栈开发(第 09 章)、调试(第 18 章)、大规模重构(第 19 章)才能跑起来;这层手艺缺位,任何高阶功能都会退化为时灵时不灵的聊天。
上一章:Plan Mode:计划优先
下一章:全栈开发实战
下一章:遗留代码重构与 Bug 修复 | 返回目录