01 Spec Coding
该节点所属的教程路径尚未上线,仅能预览本节内容。
你有没有过这种经历:让 AI 写个功能,它秒出代码,你一看,跑得挺像那么回事。两周后需求变了,你回去读那段代码,完全不知道它当时为什么这么写。改一个地方,三个地方跟着崩。
你不是不会写代码了。你是拿到了一段“没人画过图纸就盖起来的房子”。
Spec Coding 想解决的,就是这件事:在让 AI 动手之前,先把图纸画清楚。
Vibe Coding
Vibe Coding,说白了就是“凭感觉走”。给 AI 一句模糊的意图,它直接开始输出代码,你顺着感觉不断调。Karpathy 最早提这个词的时候,说的就是这种玩法。
它不是什么原罪。下面这些场景,用它反而效率最高:
- 验证一个想法,先写个 Demo 看看效果
- 写一次性脚本,跑完就扔
- 做内部小工具,影响面很小
- AI 写完后有完整测试兜底,而且不直接暴露给外部用户
这些情况下,硬写一大堆规格文档,确实是给自己找事。
问题出在下一步。 很多人验证完想法之后,顺手就把 Vibe 出来的代码推上了生产。Demo 阶段你可以靠感觉走,错了就改,坏了就删。生产代码不行——它后面要接数据库、接支付、接用户数据、接别人的维护成本。你今天省下来的半小时,可能会变成后面几天的排查时间。
判断标准其实就一条:这段代码要活多久?
两天就扔的脚本,Vibe 够了。3-5 天的中间地带,写个轻量 Spec,只写关键约束和验收标准,半小时能搞定。超过一周的代码,只要需要别人维护、涉及数据持久化、接入外部接口,就别裸 Vibe 了。
轻量 Spec 可以简单到这种程度:
markdown
## 任务目标
实现一个订单导出接口,支持按时间范围导出 CSV。
## 关键约束
- 单次导出最多 5000 条
- 时间范围不能超过 31 天
- 必须校验用户权限,只能导出当前租户的数据
- 查询必须命中 order_tenant_time_idx 联合索引
- 导出失败要记录失败原因,不能只返回 unknown error
## 验收标准
- 正常导出 CSV,字段顺序符合产品约定
- 超过 5000 条时返回明确错误
- 越权租户数据不能被导出
- 单元测试覆盖空时间、越界时间、无权限、无数据四种场景
就这些。不需要画架构图,不需要写完整设计文档。把“不能碰什么”和“怎么算做完了”写清楚,就够 AI 照着干了。
Spec Coding 到底是什么
Spec Coding,全称 Spec-Driven Development,直译过来叫“规范驱动开发”。最早是 AWS 在它的 AI IDE 产品 Kiro 里正式提出的。
核心理念很简单:在让 AI 写代码之前,先写清楚规格说明。 文档是代码的前置条件,不是后置补充。
这里要澄清一个常见的误解。Spec Coding 不是 Vibe Coding 的对立面,而是它的进化。在最终实现阶段,AI 仍然是用 Vibe Coding 的方式在写代码。区别在于:它不再是根据一个模糊的指令去猜,而是拿着一份清晰的文档去执行。
打个比方。Vibe Coding 是你跟装修师傅说“帮我搞一下客厅,要好看”。师傅凭经验给你弄了一版,效果好不好全看运气。Spec Coding 是你先画好图纸:电视墙在哪、插座留几个、地板什么材质、预算多少。师傅拿着图纸干活,你也知道验收的时候该看什么。
图纸不是限制师傅的手艺,是让他的手艺用在正确的地方。
一份完整的 Spec 长什么样
Spec Coding 的工作流通常分成四个阶段,每个阶段产出一份文件,下一份基于上一份。
Requirements(需求) 把用户故事转化为结构化的需求文档,包含明确的 User Story 和验收标准。这一步解决“做什么”。
Design(设计) 基于需求生成技术设计文档,包括数据模型、API 设计、组件设计等。这一步解决“怎么做”。
Tasks(任务) 把设计拆解为可执行的原子任务,按依赖关系排序。这一步解决“分几步做”。
Implementation(实现) AI 按照 Tasks 逐个进行代码实现。这一步才是真正动手。
这个流程看起来有点像传统的瀑布模型,但关键区别在于:每个阶段的产出都是 AI 生成、人审核的,整个过程非常快。 传统模式下写一份详细的技术设计文档可能需要几天,而用 AI 来写,可能一个小时就能完成初稿,人只需要花时间审核和调整。
为什么它更适合复杂项目
第一,给 AI 一个“北极星”。 Spec 把目标、约束、验收标准都固定下来了,AI 在实现的时候有明确的参照,不需要漫无目的地猜你要什么。这大幅减少了“越做越偏”的问题,也减少了返工。
第二,迭代意图比迭代代码便宜得多。 如果发现方向需要调整,修改一份 Spec 文档,比修改一堆已经写好的代码,成本低得多,风险也小得多。在 Requirements 阶段发现问题,改起来几乎是零成本;到了代码阶段才发现,改起来可能要伤筋动骨。
第三,天然的可追溯性。 从 Use Case → Requirements → Design → Tasks → Code,形成了一条完整的链条。任何一行代码都能追溯到它对应的业务意图。出了 bug,你能往回查是哪一步的设计有问题;需求变了,你能快速定位哪些代码需要跟着改。
一个真实案例:退款重试,但不能重复扣款
Spec Coding 的价值,在“一句话说不清楚”的场景里体现得最明显。
假设客服需要在支付渠道超时后重试退款。危险写法是一句话:“让退款可以重试。”这一句话把幂等、客服权限、渠道状态和上线证据全都留给了实现阶段自己猜。
SDD 写法会把决定拆到不同文件里。
spec.md 规定:相同 idempotency key 必须返回已有的 refund_id,退款只能在 90 天窗口内发起。
design.md 决定:渠道确认放到 worker 里做,请求链路只创建一条本地 pending 记录,而不是在请求链路里同步重试。
tasks.md 拆开:存储、worker、客服 UI 和测试分成独立切片,每个切片写明允许修改的文件。
evidence.md 记录:合并前必须附重放测试、客服阻断状态截图和重复退款告警。
这就是“图纸”和“口头描述”的差别。 口头描述里,师傅可能觉得“重试嘛,直接再发一次请求不就完了”,结果线上出现了重复扣款。图纸上写明了“相同 key 必须返回已有记录”,师傅就没有发挥空间,也不会踩坑。
落地时怎么用,别搞成仪式感
Spec Coding 最容易走歪的地方,就是为了写文档而写文档。
一条很实用的原则:只有当某个文件能减少歧义时,才加它。
小的 UI 文案变更,可能只需要一份 spec.md。公开 API 变更,可能需要 design.md、tasks.md 和 evidence.md。如果一个文档不会改变任何决策、测试或发布门禁,它大概率只是仪式。
判断有没有效果,看一件事就够了:评审会不会更快暴露分歧。 如果大家只是读完文档点点头,说明内容还不够具体。如果评审者能指出一个非目标、一个证据缺口或一个需要拆分的任务,Spec Coding 才真正在起作用。
得物技术做过一次 10 天、2.5 万行代码、提效 36% 的实战。他们用的也是 Spec Coding 工作流:先把功能规格定义清楚,再让 AI 基于这份“蓝图”自主编码。80% 的功能代码在这个阶段完成。
他们的经验是,这套流程对复杂功能特别有效——需要跨多个文件、多个层次的功能,tasks 分组让 AI 聚焦在当前步骤,不会一次性把整个项目搅乱。
说到底
Spec Coding 的核心思想,用一句话就能说清楚:在让 AI 动手之前,先把关键决定写下来,写清楚。
它不是要你回到写几十页 PRD 的时代。它是要你把“不能碰什么”“怎么算做完了”“为什么这么做”这几个关键问题,在成本最低的时候回答掉。
Prompt 教你怎么跟 AI 说话。Context 教你怎么让 AI 看到对的东西。Harness 教你怎么让 AI 干得稳。Spec Coding 教你,在 AI 动手之前,先把图纸画好。
图纸画好了,师傅的手艺才能用在正地方。