Clipping 微信公众号

Spec-Driven Development:用 Claude Code 实现大型重构的工程化方法

by 扶苏 原文 ↗
Created: 2026-06-11

公众号名称:奇点先锋

作者名称:扶苏

发布时间: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 包含 coValuessessionstransactions 存储
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 编写规范,启动子代理进行研究”开始,看看它如何改变你的工作流。


内容效果不满意?点此反馈

输入关键词开始搜索