Spec-Driven Development:用 Claude Code 实现大型重构的工程化方法
公众号名称:奇点先锋
作者名称:扶苏
发布时间:2026-06-08 08:00
本文将介绍一种使用 Claude Code 进行大型代码重构的工程化方法——Spec-Driven Development(规范驱动开发)。这种方法通过并行研究、规范编写、任务委派等阶段,将 AI 编码助手当作一个开发团队来协作,而非单打独斗。
划重点
-
传统 AI 编码方式的痛点:上下文污染、会话失忆、bug 追踪困难
-
Spec-Driven Development 的四个核心阶段:并行研究、规范创建、规范细化、任务委派
-
Claude Code 的 Task 系统如何实现跨会话持久化和上下文隔离
-
子代理模式如何让主会话保持轻量,避免上下文溢出
-
原子提交 + 预提交钩子如何构建自动化质量反馈循环
-
规范文档作为恢复点,在会话出错时快速重建上下文
问题背景:为什么需要新方法
在本地优先(local-first)Web 开发中,客户端存储是关键组件。作者正在用 Nuxt 4 构建一个简化版同步引擎,最初使用 sql.js(SQLite 编译为 WASM)作为客户端存储方案。
sql.js 的问题:
-
WASM 包体积大(约 1MB)
-
需要复杂的 COOP/COEP HTTP 头配置
-
不支持原生的跨标签页同步
目标:迁移到 IndexedDB,借鉴 Jazz 框架(一个本地优先框架)的设计模式。但这涉及 15+ 文件的重构,工作量不小。
传统做法是直接让 AI 开始写代码,但这种方式存在明显问题:
传统 AI 编码流程的缺陷:
-
上下文窗口被失败的尝试填满,有效信息被稀释
-
跨会话没有持久化记忆,每次都要重新解释
-
bug 发现得晚,容易被遗忘
-
没有明确的完成标准
核心方法:Spec-Driven Development 的四个阶段
Spec-Driven Development 将 AI 编码助手当作一个开发团队来协作:自己是产品负责人,Claude 是技术负责人,子代理是开发者。

阶段一:并行研究
提示词:
你可以访问 jazz 的源代码仓库,向我解释他们如何在客户端使用
indexdb 来持久化状态。我们的项目目前使用 sqlite,但想改成
indexdb,参考 jazz 的实现方式。你的目标是撰写一份报告,
启动多个子代理来完成你的研究任务
**执行过程:**Claude 启动了 5 个并行研究代理,各自独立调查 Jazz 代码库的不同方面:
| 代理 | 关注点 | 关键发现 |
|---|---|---|
| CRDT | 数据结构 | CoMap、CoList 使用基于操作的 CRDT,采用 LWW 策略 |
| WebSocket | 实时同步 | 4 消息协议:load、known、content、done |
| Push/Pull | 同步策略 | 混合模型,带 known-state 追踪 |
| Storage | 持久化 | IndexedDB 包含 coValues、sessions、transactions 存储 |
| Architecture | 整体设计 | Monorepo 架构,带平台适配器 |
关键点: 这些是 Claude Code 内置的子代理(general-purpose 类型),无需自定义配置。当要求”启动子代理”时,Claude 会自动使用内置的 Task 工具。

后续提示词:
继续深入研究,完善方案
这触发了对边界情况和实现细节的更深入调查。
阶段二:规范创建
研究完成后,Claude 编写了一份全面的技术规范,保存到 docs/indexeddb-migration-spec.md:
规范结构:
# IndexedDB 迁移规范
## 第一部分:Jazz 如何使用 IndexedDB
- 数据库模式(coValues、sessions、transactions 存储)
- 事务队列模式
- 实体缓存层
- 基于会话的冲突解决
## 第二部分:当前 SQLite 架构分析
- sql.js WASM 配置
- 现有同步协议
- 痛点和局限性
## 第三部分:迁移计划(4 个阶段)
- 阶段 1:核心 IndexedDB 工具函数
- 阶段 2:Composables 层
- 阶段 3:跨标签页同步
- 阶段 4:清理和测试
## 第四部分:实现清单
- [ ] idb-helpers.ts
- [ ] useIndexedDB.ts
- [ ] useSessionTracking.ts
- ...(共 14 项)
核心价值: 规范成为唯一事实来源(source of truth)。Claude 在实现过程中可以引用这份文档,确保所有任务的一致性。它也是一个”锚点”——当实现过程中出现问题时,可以基于规范快速恢复。
阶段三:规范细化(通过访谈)
在开始实现前,使用 Claude 的 AskUserQuestion 工具确保规范足够完善:
提示词:
使用 ask_user_question 工具,关于
@docs/indexeddb-migration-spec.md 你有什么问题吗?在实现之前,
我们想先完善规范文档
Claude 提出了澄清问题:
-
是否需要支持从现有 SQLite 数据迁移?
-
偏好的冲突解决策略是什么?
-
跨标签页同步应该使用 BroadcastChannel 还是 SharedWorker?
回答问题后,进一步要求 Vue 特定的改进:
提示词:
我们想使用 provide 和 inject,你可以访问 pinia 的源代码,
启动多个子代理研究它们是如何实现的,这样我们就可以使用
相同的模式
Claude 研究了 Pinia 的模式,更新了规范,加入了:
-
基于 Symbol 的注入键
-
带回退模式的 Provider composables
-
正确的卸载清理逻辑
阶段四:任务委派实现
这是 Claude Code 的 Task 系统发挥作用的地方。
提示词:
实现 @docs/indexeddb-migration-spec.md,使用 task 工具,
每个任务只能由一个子代理完成,这样每个任务的上下文都很清晰。
每个任务完成后进行一次 commit,然后再继续。你是主代理,
你的子代理就是你的开发人员
Claude Code 的 Task 系统:解决 AI 编码的两大痛点
Task 系统灵感来自 Beads(Steve Yegge 的分布式 git 支持的问题追踪器),解决了 AI 编码代理的两个关键问题:
问题一:代理失忆(Agent Amnesia)
在任务中途启动新会话会丢失所有进度,除非手动记录剩余工作。
问题二:上下文污染(Context Pollution)
上下文窗口填满后,代理会丢弃已发现的 bug,而不是追踪它们。
之前的 todo 列表存在于会话内存中,重启后消失。新的 Task 系统将任务持久化到磁盘,使其可跨会话和子代理共享。
任务如何持久化
任务存储在 .claude/tasks/{session-id}/ 目录下,格式为 JSON:
```json
{
"id": "task-1", // 任务唯一标识
"subject": "创建 idb-helpers.ts", // 任务主题
"description": "实现 IndexedDB 的 Promise 封装...", // 任务详细描述
"status": "pending | in_progress | completed", // 任务状态:待处理 | 进行中 | 已完成
"blocks": ["task-3", "task-4"], // 本任务阻塞的其他任务
"blockedBy": ["task-0"] // 阻塞本任务的前置任务
}
```
四个任务工具
| 工具 | 用途 |
|---|---|
TaskCreate | 创建新任务,包含主题、描述和依赖关系 |
TaskUpdate | 更新状态(pending → in_progress → completed)或修改依赖 |
TaskList | 查看所有任务、状态和阻塞情况 |
TaskGet | 获取特定任务的完整详情,包括描述 |
任务系统架构

为什么子代理 + 任务 = 上下文效率
通过将每个任务委派给子代理,主会话保持轻量——它只负责协调(创建任务、追踪进度、提交)。每个子代理获得一个全新的上下文窗口,专注于其特定任务,读取所需内容,实现功能,然后返回。
这意味着即使对于包含数十个任务的大型重构,主代理也不会耗尽上下文。
对于真正超大型的项目(跨越数天甚至数周),更适合使用完整的自主代理(如 Ralph)。Ralph 的架构非常简洁——一个 bash 循环,反复将 Markdown 文件输入 Claude Code:

关键区别:Ralph 在每次迭代中都在全新的 Claude 会话中执行,使用 Markdown 文件作为唯一的持久化记忆。这让它真正无状态,可以运行数天。
这种 Spec-Driven 方法介于两者之间:子代理获得新鲜上下文,但主编排器在单个会话中维护状态。足够结构化以保持连贯性,足够灵活以处理复杂性,且无需完整自主系统的额外开销。
执行流程:原子提交与自动化反馈
执行流程
协调器将每个任务委派给子代理,每个任务完成后进行原子提交。

反压机制:让系统自动捕获错误
原子提交的强大之处在于反压(backpressure)机制。与其手动审查每个变更,不如设置预提交钩子,自动运行测试、lint 和类型检查:
```bash
# .husky/pre-commit
# 预提交钩子:运行类型检查、代码规范和测试
pnpm typecheck && pnpm lint && pnpm test-run
```
当子代理提交时,钩子立即运行。如果测试失败,提交被拒绝,代理看到错误输出——这给了它在继续之前自我纠正的机会。这创建了自动化反馈,在源头捕获问题,而不是让 bug 在多个任务间累积。
结果: 你不再是质量控制的瓶颈。系统自动验证正确性,你可以专注于更高层次的决策。
出错时的恢复机制
第一次执行并不完美——启动项目时遇到了一些错误。但这就是规范的价值所在:打开新聊天,固定规范文档,粘贴错误信息,Claude 立即修复。无需重建上下文,无需重新解释架构。
规范充当恢复点。当会话出问题或上下文被污染时,不会丢失一切——你有一份文档,捕获了完整的意图和设计决策。
实际效果
完成情况
一段时间后:
```bash
$ git log --oneline | head
209dc1c96 重构:整理代码结构
9fce16b 功能(存储):从 SQLite 迁移到 IndexedDB
835c494 功能:集成 IDB 同步引擎提供者
d2cd7b7 重构:移除 SQLite/sql.js 依赖
2fb7656 功能:添加浏览器模式测试桩
... (共 14 次提交)
```
14 个任务完成,14 次提交,15+ 文件变更,一个待审查的 PR。
上下文使用情况
尽管协调了 14 个子代理,主会话的上下文仍然可控:
上下文使用:71%
claude-opus-4-5-20251101:143k / 200k tokens
系统提示词:2.8k(1.4%)
系统工具:16.2k(8.1%)
MCP 工具:293(0.1%)
自定义代理:641(0.3%)
记忆文件:431(0.2%)
技能:1.6k(0.8%)
消息:122.9k(61.4%)
可用空间:22k(11.1%)
自动压缩缓冲:33.0k(16.5%)
这证明了委派模式的有效性——主代理处理协调,子代理在隔离的上下文中完成繁重工作。
关键提示词模式
1. 并行研究
启动多个子代理来完成你的研究任务
触发 Claude 启动并行代理,各自独立调查。比顺序研究快得多。
2. 规范优先开发
你的目标是撰写一份报告/文档
强制 Claude 在写任何代码之前生成书面产物。这成为唯一事实来源。
3. 实现前访谈
使用 ask_user_question 工具……在实现之前
在模糊性和设计决策变成 bug 之前,将它们暴露出来。
4. 任务委派 + 提交
使用 task 工具,每个任务只能由一个子代理完成,
每个任务完成后进行一次 commit,然后再继续
创建带原子提交的协调模式。
5. 角色分配
你是主代理,你的子代理就是你的开发人员
设定期望:Claude 应该作为协调者,而非单独实现者。
对比:传统方式 vs 规范驱动方式
| 维度 | 传统 AI 编码 | 规范驱动开发 |
|---|---|---|
| 流程 | 提示词 → 代码 → 调试 → 重复 | 研究 → 规范 → 细化 → 任务 → 完成 |
| 上下文 | 被失败的尝试填满 | 每个任务获得全新上下文 |
| 记忆 | 跨会话无持久化 | 规范是持久化的唯一事实来源 |
| Bug 追踪 | 发现得晚,容易被遗忘 | Bug 变成新任务 |
| 完成标准 | 没有明确的停止点 | 清晰的完成标准 |
高级用法:跨会话工作流
Task 系统支持跨多个 Claude Code 会话的协调。设置共享任务列表 ID:
```bash
# 设置共享任务列表 ID,启动 Claude Code
CLAUDE_CODE_TASK_LIST_ID=myproject claude
```
或在 .claude/settings.json 中添加:
```json
{
"env": { // 环境变量配置
"CLAUDE_CODE_TASK_LIST_ID": "myproject" // 共享任务列表 ID
}
}
```
一个会话充当协调器;另一个成为检查器,监控已完成的任务,验证实现质量,并为缺失的内容添加后续任务。
适用场景
适合使用这种方法的场景
-
涉及大量文件的大型重构
-
需要研究外部代码库的迁移
-
需求不清晰的功能实现
-
通过研究源代码学习新库
不适合的场景
-
小型 bug 修复
-
单文件变更
-
定义清晰的简单功能
所需工具
-
Claude Code CLI(支持 Task 工具的最新版本)
-
规范文档(Markdown 格式即可)
-
参考代码库(如果从现有实现学习)
-
Git(用于原子提交)
写在最后
Spec-Driven Development with Claude Code 模拟了真实的工程工作流:并行工作、交接、阻塞和依赖。与其将 Claude 视为单独编码者,不如将其视为一个团队。
Beads 的核心洞察在这里同样适用:
“通过让每个交给编码代理的任务都在其独立的上下文窗口中执行,你现在可以让它具备记录 bug 以供后续处理的能力。”
SQLite 到 IndexedDB 的迁移,手动完成需要 2-3 天。使用这种方法,只花了一个下午——而且得益于研究阶段发现了作者自己不会找到的 Jazz 模式,代码质量更好。
尝试方法: 下一个重要功能,从”为 X 编写规范,启动子代理进行研究”开始,看看它如何改变你的工作流。
内容效果不满意?点此反馈