能从 Claude Code 获得可靠输出的开发者和花半天时间撤销代理刚构建内容的开发者之间,差距正在扩大。这种差异不在于天赋、经验或什么秘密的 prompt engineering 技巧。这是方法论的问题。用 AI 代理交付生产软件的开发者已经收敛到一个模式上,不管他们怎么称呼它:在代理开始写代码之前,定义你想要什么。
这篇文章给这个模式命名。Spec-first 开发是 AI 辅助软件工程的方法论。不是模糊的"最佳实践"。一个结构化的、可重复的生命周期,有定义的阶段、清晰的检查点和每一步的具体产出物。如果你一直在寻找让 Claude Code 的输出可预测到足以押上你的发布计划的方法,这就是那个框架。
Vibe Coding 的天花板
"Vibe coding" 在 2025 年初进入了词汇表。提议是:用自然语言描述你想要什么,让 AI 写,迭代直到看起来对了。对于原型、周末项目和一次性脚本,vibe coding 有效。你快速得到功能性的东西,如果之后坏了,风险也低。
生产软件在不同的约束下运行。代码必须集成到现有代码库,满足特定需求,并经受住其他维护者的接触。当 vibe coding 遇到这些约束时,失败模式是可预测的。
第一个失败是漂移。你模糊地描述一个功能,代理实现它的理解,你调整,代理重新实现调整后的理解。三次迭代后,你有了不满足任何原始需求的可工作代码,因为每次迭代都移动了目标。你在收敛于代理认为你想要的东西,而不是你实际需要的。
第二个失败是不可见的决策。你描述中的每个空白都是代理默默做出的决策。数据库 schema、错误处理策略、API 形状、验证规则、库的选择。你在代码审查中发现这些决策,或者更糟,在生产中。代理没有做出坏决策。它做出了未被指示的决策,而你没有机制在它们被嵌入实现之前捕获它们。
第三个失败是审查瘫痪。代理选择了架构、数据模型、错误码和边缘情况处理的 600 行 diff,在传统意义上是无法审查的。你不是在对 spec 审查代码。你是从代码中逆向工程出 spec,然后决定你是否同意。这比写 spec 花的时间更长。
Vibe coding 触及天花板,因为它混淆了两个不同的活动:决定构建什么和构建它。Spec-first 开发将它们分开。
作为方法论的 Spec-First
Spec-first 开发是一个四阶段生命周期。每个阶段产生一个具体的产出物。每个转换有一个清晰的门控条件。该方法论适用于任何 AI 编码代理,但本文的示例使用 Claude Code,因为那是社区迭代最快的地方。
阶段 1:头脑风暴
你和代理(或只有你)探索问题空间。约束是什么?存在哪些方法?权衡是什么?这是对话式的。你不承诺任何事情。你在绘制地图。
门控条件:你有一个首选方法,能说清为什么选择这个方法而不是替代方案。
与 Claude Code 头脑风暴很有价值,因为代理对模式和库有广泛的知识。错误是从头脑风暴直接跳到代码。头脑风暴浮现选项。它不在选项之间做选择。那是你做的。
阶段 2:Spec
你写下决定。这是代理将据以实现的合同。Spec 不是用户故事,不是 Jira 工单,不是一段散文。它是一个结构化文档,包含:
- 问题陈述:什么坏了或缺少什么,用具体术语
- 建议的方法:头脑风暴阶段选择的解决方案
- 受影响的文件:代理应该触碰哪些文件(隐含地,哪些不应该)
- 验收标准:定义"完成"的可测试条件
- 范围之外:代理应明确避免什么
验收标准是最重要的元素。每个必须是有可观察结果的具体动作。"认证应该能工作"不是标准。"提交有效凭据返回 200 和会话令牌;提交无效凭据返回 401 且无令牌"才是。
范围之外部分防止镀金。没有它,代理会"改善"相邻代码,重构它们注意到的凌乱文件,或添加看似相关的功能。代理在未请求工作上花的每一分钟都是你审查未请求工作花的一分钟。
门控条件:没参加头脑风暴的人能读这个 spec 并构建正确的东西。
阶段 3:实现
代理对 spec 执行。不是对一段对话。不是对你讨论过什么的记忆。对一个有可测试标准的具体文档。
写代码之前,代理产出一个计划:它打算做的变更的编号列表,将修改哪些文件,以及如何验证结果。这个计划是两分钟的检查点。你读它,确认它匹配你的意图,给实现开绿灯。或者你捕获一个误解并纠正它。无论哪种方式,你花了两分钟而不是二十分钟。
Plan-before-code 模式不是官僚主义。它是整个工作流中杠杆最高的单一干预。大多数实现错误不是编码错误。它们是理解错误:代理误解了 spec。在计划中捕获理解错误的成本是两分钟。在 400 行 diff 中捕获是二十分钟。在生产中捕获是一天。
门控条件:代理发布了完成报告,其中有关于构建了什么和如何验证的具体声明。
阶段 4:验证
你或 QA 流程对 spec 确认实现。不是"看起来对吗?"而是"它满足每个验收标准吗?"
验证是机械的。你从 spec 中取每个标准,执行测试(运行命令、打开浏览器、触发事件),记录结果:通过或失败。失败的标准回到阶段 3。验证与实现一起记录,这样六个月后读这个任务的任何人都能看到确切测试了什么。
门控条件:每个验收标准有记录的通过/失败结果。
这就是完整的生命周期。四个阶段,四个产出物(方法理由、spec、实现计划、验证记录),四个门控条件。阶段是顺序的但轻量。对于中等大小的功能,阶段 1 和 2 需要 15-20 分钟。阶段 3 需要实现多长时间就多长。阶段 4 需要 5-10 分钟。
为什么代理比人类更需要这个
写 spec 的每个论点都早于 AI。"写代码之前先写需求"是我们大多数人出生之前就有的建议。那为什么将其定位为 AI 辅助开发特有的东西?
因为代理改变了成本函数。
收到模糊需求的人类开发者会停下来问问题。"你说的是密码认证还是 SSO?""这需要在手机上工作吗?""令牌过期时会发生什么?"每个问题都是把实现推向正确目标的迷你检查点。人类开发者面对模糊 spec 的成本是几个 Slack 线程,也许一个下午的返工。
收到模糊需求的代理不会停下来。它会默默做出每个模糊的决定,锁定一种方法,给你呈现完成的实现。代理面对模糊 spec 的成本是一个可能完全错误的完成实现,加上你发现它错误的时间,加上重做的时间。
不对称是鲜明的。代理在执行上比人类开发者快,在判断上更差。Spec 中的每个模糊之处都是判断调用,代理在没有指导下做出的每个判断都是结果是否匹配你意图的抛硬币。Spec 消除抛硬币。
有第二个更微妙的原因。代理不会反驳。收到坏 spec 的高级工程师会说"因为 X 这没有意义。"代理会忠实地实现坏 spec,产出忠实的错误结果。Spec-first 开发迫使你在将其交给一个会不加质疑地执行的实体之前,压力测试你自己的思维。Spec 不仅是给代理的。它是给你的。
Plan-before-code 检查点
如果你从这篇文章中只带走一个实践而忽略其余的,带走这个。
在代理写代码之前,要求它发布实现计划。不是代码。不是 diff。一个它打算做什么的结构化大纲。
计划看起来像这样:执行顺序的编号步骤,要修改的文件,每个文件中的逻辑更改,和验证方法。代理大约三十秒产出这个。你大约两分钟读完。在那两分钟里,你可以捕获:
- 范围违规:代理计划修改 spec 中未列出的文件
- 架构不匹配:代理选择了与现有模式冲突的方法
- 缺失步骤:计划没有涉及某个验收标准
- 过度工程:代理计划构建不合理的抽象
2 分钟的计划审查取代了 20 分钟的 diff 审查,在后者中你在它们已经建好之后才发现这些问题。这是软件工程中最便宜的质量门控。
我在 Claude Code 的 Spec 驱动开发 中写了 plan-before-code 模式的详细演练,包括 spec 模板和完成报告格式。这篇文章聚焦于模式为什么有效;那篇聚焦于如何实施。
作为一等步骤的验证
大多数开发者工作流中投入最少的阶段是验证。代理说"完成了。"开发者瞄了一眼 diff。合并发生了。两天后用户碰到验收标准中的边缘情况第三条时,bug 浮现了。
Spec-first 开发将验证视为有自己产出物的正式步骤。完成报告将每个验收标准映射到一个具体检查:
- 标准:"切换工作区恢复保存的过滤器状态。"
- 检查:打开应用,在工作区 A 设置过滤器,切换到工作区 B,切回工作区 A,观察过滤器已恢复。
- 结果:通过。
这不是开销。这是决定实现是否真正满足 spec 的步骤。没有它,spec 是愿望清单,验收标准是美好愿望。
验证记录还解决了一个下游问题:代码审查。当审查者打开 pull request 时,他们读 spec,读验证记录,用完整上下文审查 diff。审查时间缩短,因为审查者在确认一个已验证的声明,而不是在进行调查。
当你并行运行多个代理,每个实现不同的 spec 时,验证纪律是受控管道和"大概能用"的代码堆之间的区别。每个 spec 有标准。每个实现有完成报告。每个完成报告将标准映射到检查。没有记录的验证,什么都不发布。
异议和诚实的权衡
Spec-first 开发不是免费的。异议是真实的,值得正面回应。
"写 spec 拖慢了我。" 孤立来看,是的。为一个功能写 spec 需要 15-20 分钟。但你在实现和审查阶段收回那些时间(甚至更多)。有清晰 spec 的代理比有模糊 prompt 的代理更频繁地产出正确实现。更少的迭代,更少的返工,更短的审查。对任何有实质内容的功能来说,净效果是更快的交付,不是更慢。
对于琐碎的变更(重命名变量、修复错字、升版本号),spec 是不必要的开销。Spec-first 是给需要决策的实现工作的。如果变更是机械的和明确的,跳过 spec。
"我的代理不用 spec 就足够好了。" 对某些任务来说,可能是真的。Claude Code 从简短描述中推断意图的能力非常强。问题不是代理能不能从模糊指令产出好输出。是它是否可靠地这样做。如果你能接受偶尔的返工和不可预测的审查时间,vibe coding 可能足够用于你的场景。Spec-first 在一致性和可预测性重要时回报最大:功能复杂时,代码进入生产时,别人会维护时。
"Spec 会过时。" 合理的担忧。头脑风暴中写的 spec 可能经不住现实的考验。解决办法不是跳过 spec。而是当计划揭示新信息时更新 spec。如果代理的计划显示 spec 中的方法行不通,在继续之前修改 spec。Spec 在实现期间是活文档。验证后变成历史记录。
"这就是瀑布。" 不是。瀑布的失败是为大项目写大 spec,有长反馈周期。Spec-first 开发在任务级别运作:每个功能或修复一个 spec,15-20 分钟写完,几小时实现,当天验证。反馈循环紧凑。每个 spec 的投入很小。如果 spec 错了,你在计划审查中就发现了,不是六个月后。
为 Spec-First 生命周期配备工具
该方法论与任何任务系统配合工作:GitHub Issues、Linear、Notion、纯文本文件。重要的是 spec、计划、实现笔记和验证结果都在一个地方,附在一个任务上。
如果你在找为这个工作流设计的系统,beads 是一个开源的、Git 原生的 issue tracker,承载完整的生命周期。每个 "bead" 携带一个描述(你的 spec)、评论线程(计划和完成报告)、状态(open、in_progress、ready_for_qa、done)以及依赖和优先级等元数据。bd CLI 从终端操作,这意味着代理可以读 spec、发布计划和报告完成,而不离开工作环境。
bd create --title "Persist filter state across workspaces" \
--description "## Problem ..." --type feature --priority p2
bd update bb-a1b2 --claim --actor eng1
bd comments add bb-a1b2 --author eng1 "PLAN: ..."
# After implementation:
bd comments add bb-a1b2 --author eng1 "DONE: ... Commit: a1b2c3d"
bd update bb-a1b2 --status ready_for_qa
整个生命周期在 CLI 中完成。六个月后,bd show bb-a1b2 返回什么被规格化、计划、构建和验证的完整历史。
当你让一个代理走过这个生命周期时,CLI 就够了。当你并行运行五个或十个,每个在 spec-implement-verify 管道的不同阶段时,你需要一眼看到管道的状态。Beadbox 是一个实时仪表盘,显示哪些 spec 是开放的,哪些有计划等待审查,什么在进行中,什么被阻塞,什么准备好验证了。它监控代理写入的同一个 beads 数据库,状态变化时实时更新。
你不需要 Beadbox 来实践 spec-first 开发。方法论是工具无关的。但当并行工作流将你的管道变成一个仅靠记忆无法追踪的任务队列时,可视层改变了你审查、解除阻塞和发布的速度。
更广泛的转变
Spec-first 开发不是对 AI 编码代理不好的反应。它是对它们在没有指导时擅长错误事物的认识。代理是非凡的执行者。他们写出正确的语法,遵循模式,处理样板代码,产出没有人类能匹敌的量。他们缺的是对构建什么做出好决策的上下文。那个上下文来自你,spec 是载体。
在 AI 辅助工程中蓬勃发展的开发者不是写最好 prompt 的人。是写最好 spec 的人。Prompt 是短暂的。Spec 是持久的。Prompt 为单次交互优化。Spec 为生命周期优化:头脑风暴、定义、实现、验证。
这不是等代理变聪明之前的临时变通。即使模型改进,根本的不对称仍然存在:人类知道业务需要什么;代理知道怎么写代码。Spec 连接两者。更好的模型会更快地执行 spec,但对 spec 本身的需求不会消失。随着规模扩大它变得更重要,因为更多代理对模糊指令执行会产出更发散的输出。
如果你一直在运行 Claude Code 代理并发现结果不一致,或在审查上花太多时间,或难以协调并行工作流,试试这个:在下一个功能之前,花 15 分钟写一个有可测试验收标准的 spec,要求代理在编码前发布计划,逐条验证输出。一个周期就能看到差别。
如果你正在构建这样的工作流,请给 Beadbox 在 GitHub 上点个星。
Like what you read?
Beadbox is a real-time dashboard for AI agent coordination. Free during the beta.