AI 工具使代码生成便捷,但导致规范文档严重脱离实现;提出持续更新规范的工作流,避免长期维护混乱。
在 Claude Code 和 GitHub Copilot 等 AI 智能体已司空见惯的时代,开发方式发生了巨大变化。只需下达指令,代码便会源源不断地生成。然而,是否仍存在一个挥之不去的问题:你是不是总要通过口头或聊天的方式,反复向 AI 解释自己想构建什么?
这就像给司机(AI)指路,却始终不告诉他最终目的地。虽然拿到的代码当下可能可以正常运行,但一段时间后,你难免会疑惑:“为什么实现采用了这样的结构?”以及“最初的规格到底是什么?”随着代码与规格逐渐偏离,无论项目规模大小,许多团队都会面临这个问题。
现实中,以下情况十分常见:
“从一开始就不存在规格”
“规格虽然存在,但已经过时,无法反映当前状态”
“已经没人能掌握全局;系统变成了黑盒,我们根本不知道任何部分是如何运作的”
规格往往会沦为“一次编写,随后遗忘”的文档。随着实现不断推进,代码与规格之间的差异逐渐累积,最终团队只能陷入“代码就是规格”的状态。
本文将介绍一种组合式方法:规格驱动开发(先编写规格,再用它指导 AI 完成实现),配合代码优先的规格回填开发(先实现代码变更,再更新规格以与代码保持一致)。这两种方法结合使用,可以让代码与规格始终保持最新,并持续对齐为一个统一的事实来源。
注意:“代码优先的规格回填开发”是我为本文创造的术语。如果已经存在采用其他名称的类似方法,欢迎在评论区告诉我!
本文面向这样的读者:
你每天都使用 Claude Code 或 GitHub Copilot 进行开发
你经常发现规格还没准备好,代码就已经写出来了
编写规格让人感觉繁琐,因此总是被降低优先级
你曾想过:“我已经很久没更新规格了……”
规格根本不存在,或者已经过时到无可救药
代码与规格已经脱节,系统成了黑盒
你希望在代码与规格之间建立可追溯性
你刚开始接触开发,不知道该如何编写规格
你可能听说过“凭感觉编程”——向 AI 提供宽泛的需求,让它凭直觉编写代码。这种方法非常适合快速构建原型,但在大型应用中会遇到困难。本文采取相反的立场:以规格为基础开展 AI 开发。不过,这种方法实际上存在两个不同的方向。
第一种是规格驱动开发(Spec-Driven Development,SDD),即预先准备详细规格(需求、设计、详细规格和实施计划),再用这些规格驱动 AI 智能体的工作流程。
其逻辑非常直接:
通过预先准备详细规格,你可以精确控制 AI 的行为。
凭感觉编程是“让 AI 自己想办法”,而规格驱动开发则是“使用设计文档引导 AI”。当你从零开始构建应用、尚无现有代码库时,这种方法最为有效。
另一方面,在实际开发中,如果每个微小变更都必须严格遵循“先更新规格,再实现”的流程,往往会显得约束过多。对于小型修改,更实际的做法通常是直接调整代码,验证其能够正常运行,然后再更新规格,也就是采用相反的工作流程。
这就是代码优先的规格回填开发(Code-First Spec-Backfill Development,CFSD),也是本文介绍的第二条主线。其理念是按照与规格驱动开发相反的“代码 → 规格”顺序开展工作,同时最终确保代码与规格保持一致。
注意:“代码优先的规格回填开发”是我为本文创造的术语。如果已经存在采用其他名称的类似方法,欢迎在评论区告诉我!
这两种方法并不矛盾;你应根据项目的具体情况和所处阶段进行选择:
从零开始构建应用 → 规格驱动开发(规格 → 代码)
维护现有应用,但规格缺失、不完整或已经过时 → 首先分析代码并生成规格文件(spec.yaml)(代码 → 规格)
逐步完善和改进现有应用 → 代码优先的规格回填开发(代码 → 规格)
对于规格缺失或与实现不同步的现有应用,首先让 AI 分析当前代码,并生成一份 spec.yaml 作为起点。经过人工审查和修正后,再转向规格驱动开发或代码优先的规格回填开发。
无论采用哪种方法,最终目标都相同:让代码与规格始终保持同步。
本文使用 YAML 作为规格格式。
近期研究强调,应使用 JSON 或 YAML 等结构化格式向大语言模型提供信息。Elnashar 等人(2025)使用 GPT-4o 比较了三种提示词风格(JSON、YAML 和混合 CSV/Prefix),证明提示词格式会影响输出质量、Token 成本和处理时间。他们发现,YAML 在可读性与效率之间取得了极佳的平衡。
我们采用 YAML 作为规格格式,原因如下:
结构简单,能够清晰表达层级关系
支持注释(与 JSON 不同)
便于人类阅读和维护
可以直接向 AI 传递结构化信息
首先,使用 Claude Code 或 GitHub Copilot 创建一份 spec.yaml 设计文档。
这里最关键的是粒度。规格必须足够详细,使 AI 仅通过阅读它就能实现整个应用。避免使用模糊的表述;应力求让规格不留任何可能使 AI 困惑的空间。
除了 API 和数据库设计,我还建议在规格中包含控制器、服务和仓储层的职责,以及类名和函数或方法名。如此详细的定义可以防止 AI 自行创造命名约定和架构,也能让可追溯性更容易维护。
不过,从零开始编写如此详细的规格确实很有挑战性。我的建议是:与 AI 交互式地共同创建规格。先描述应用的大致轮廓,然后逐一梳理所需组件,并在此过程中编写 YAML。前期看起来可能很耗时,但之后会带来丰厚回报——一旦 AI 获得了清晰的规格,实现指令就会变得简单,返工也会显著减少。
同样的方法也适用于现有应用。如果规格缺失或已经过时,可以让 AI 分析当前代码,并生成一份 spec.yaml 作为起点。不过,不要在生成一次后就认为工作已经完成。相反,应反复与 AI 对话:“这个功能的规格是什么?”“这个 API 的职责是什么?”“这个类结构合理吗?”通过对话迭代完善规格,直到它能够反映真实需求。
换句话说,无论是从零开始,还是维护遗留代码,都不要试图在第一天就得到完美的规格。应通过与 AI 对话进行迭代完善。规格质量越高,实现质量和可维护性也会越好。
在选择语言、框架和数据库时,可以咨询 AI,但不要不加判断地接受它的建议。你需要调查并验证:“这种架构真的合理吗?”“是否存在其他选择?”AI 是设计伙伴,而不是决策者。最终设计和技术选型的责任在你。
至少应记录以下内容:
应用的目的与概述
使用的语言(前端与后端)
数据库(类型、表结构等)
API 设计(端点、请求和响应 Schema)
页面布局和功能列表
类设计(Controllers/Services/Repositories)
函数名(方法名)及其职责
身份认证与授权方案
环境变量
外部服务与 API 集成
测试策略(Unit/Integration/E2E)
编码标准与命名约定
约束条件(非功能性需求、性能要求和安全要求)
尚未实现的功能与未来工作(TODOs/Backlog)
spec.yaml 示例project:
name: TaskManagerApp
version: 1.0.0
purpose: "一个面向个人和团队的简单任务管理应用"
tech_stack:
frontend:
language: TypeScript
framework: Next.js
styling: Tailwind CSS
backend:
language: TypeScript
framework: NestJS
database:
type: PostgreSQL
orm: Prisma
architecture:
pattern: MVC
directories:
controllers: src/controllers
services: src/services
repositories: src/repositories
models: src/models
tests: tests
database_schema:
tables:
- name: users
columns:
- { name: id, type: uuid, primary_key: true }
- { name: email, type: string, unique: true }
- { name: password_hash, type: string }
- name: tasks
columns:
- { name: id, type: uuid, primary_key: true }
- { name: user_id, type: uuid, foreign_key: users.id }
- { name: title, type: string }
- { name: status, type: enum, values: [todo, in_progress, done] }
controllers:
AuthController:
methods:
- login
- register
TaskController:
methods:
- list
- create
- update
- delete
services:
AuthService:
methods:
- authenticate
- createUser
TaskService:
methods:
- getTasks
- createTask
- updateTask
- deleteTask
repositories:
UserRepository:
methods:
- findByEmail
- create
TaskRepository:
methods:
- findAllByUserId
- create
- update
- delete
api:
- method: POST
path: /auth/login
controller: AuthController
action: login
service: AuthService.authenticate
- method: GET
path: /tasks
controller: TaskController
action: list
service: TaskService.getTasks
- method: POST
path: /tasks
controller: TaskController
action: create
service: TaskService.createTask
dto:
LoginRequest:
email: string
password: string
LoginResponse:
accessToken: string
CreateTaskRequest:
title: string
TaskResponse:
id: uuid
title: string
status: string
features:
- 用户注册
- JWT 登录
- 任务 CRUD
- 任务状态管理
coding_rules:
naming:
controller: PascalCase
service: PascalCase
repository: PascalCase
method: camelCase
comments:
language: English
testing:
framework: Jest
unit:
- AuthService
- TaskService
integration:
- AuthController
- TaskController
constraints:
- Passwords must be hashed with bcrypt
- APIs must be implemented as REST
- Controllers must not contain business logic
- Services must be called before Repositories
ai_rules:
- spec.yaml is the single source of truth
- Don't change naming conventions
- Generate test code alongside implementation
- Report differences between spec.yaml and code after implementation
changelog:
- version: 1.0.1
date: "2026-07-20"
author: yamada
summary: "Added priority field"
- version: 1.0.0
date: "2026-07-15"
author: suzuki
summary: "Initial version"
backlog:
- id: TASK-101
title: Task search feature
priority: High
- id: TASK-102
title: Email notifications
priority: Low
这个 YAML 只是一个示例。如果你对更清晰的规范结构或其他有用的部分有想法,欢迎在评论中分享!
关键是要精心记录"要构建什么"、"用什么语言/技术"以及"用什么结构"来构建。有了这样的规范,你就永远不需要重复向 AI 解释——这样也能节省 token。
有了规范后,准备实际的开发环境。
首先,采用 Git 来跟踪和管理代码变更。GitHub Desktop 或类似的 GUI 工具会很方便。
创建一个 GitHub 账户
创建一个仓库(强烈建议设为私密)
有关详细的设置说明,网上有许多优秀的指南,这里我就跳过这些细节了。
GitHub Desktop 文档
在 GitHub 上创建仓库
接下来,安装 Visual Studio Code 等编辑器,以及 Claude Code 或 GitHub Copilot 扩展/CLI。请参考官方文档进行安装:
开发环境准备好后,就该让 AI 根据你的规范实现你的应用了。这就是规范驱动开发真正大显身手的地方。注意:这一步假定你是在构建一个新应用。如果你已经有了一个应用,请跳到第 4 步:"检查规范和实现之间的差异"。
@spec.yaml
读取全部内容,不遗漏地实现该应用。
@spec.yaml
读取全部内容,同时编写测试代码。
提交这个 prompt 后,等待结果。根据规模大小,可能需要相当长的时间——要有耐心。
实现完成后,让 AI 验证规范和实际代码是否完全一致。这是确保可追踪性的关键步骤。
@spec.yaml
报告当前代码与规范之间的任何差异。
当报告出差异时,评估是实现有问题还是规范有问题,然后决定修复哪一个。
如果是实现有问题(代码不遵循 spec.yaml):
修复你刚才识别出的差异。
将代码与 @spec.yaml 对齐。
如果是规范有问题(spec.yaml 与实现不同):
在以下文档中反映你提到的变更。
相应地更新 @spec.yaml。
通过不断地这样同步代码和规范,你就为下一阶段做好了准备。
完成的应用几乎总是与你最初的设想略有不同。这就是你进入循环的地方:
用一次提交记录当前状态。
修改代码以匹配(期望的变更)。
如果修复看起来不错,就为该变更请求测试:
阅读这个变更并为其编写测试代码。
如果实现是正确的(代码是对的,规范需要更新),更新规范端:
阅读这个变更并相应地更新 @spec.yaml。
如果你满意了,也提交这个更新。
继续循环:
更新规范(如果满意)
通过重复这个循环,代码和规范保持永久同步和最新。
虽然上面描述的是初始应用发布,但所有后续功能添加和修订都遵循完全相同的循环。这就是代码优先规范回填开发真正大放异彩的地方。
添加功能或进行改进时,从代码开始:
修改代码以匹配(期望的变更)。
如果修复看起来不错,请求测试:
阅读这个变更并为其编写测试代码。
如果实现是正确的,更新规范:
阅读这个变更并相应地更新 @spec.yaml。
提交,大功告成。
这样,你先在代码中尝试一些东西,然后如果满意就在规范中反映它——反复实践代码优先规范回填开发。对于那些以前觉得编写规范繁琐的人来说,这个框架能自然地在每次功能添加或修复时保持规范更新。不再有单独的"手动更新规范"任务了。每一个变更都同时流入代码和规范,使它们始终保持一致。
对于多人团队,在 README.md 中记录要使用的 prompt:
## AI 指令模板
### 用于功能添加/修复
修改代码以匹配(期望的变更)。
### 用于测试代码创建
阅读这个变更并为其编写测试代码。
### 用于规范更新(当实现超出 spec.yaml 时)
阅读这个变更并相应地更新 @spec.yaml。
### 用于差异检查
@spec.yaml
报告当前代码与规范之间的任何差异。
这确保每个团队成员在同一阶段遵循相同的程序并达到相同的质量水平。无论谁在处理什么,你总是会保持最新的规范和可追踪的代码。这种方法最大的好处是在所有阶段的一致性——新开发、功能和修复。整体项目质量会戏剧性地提高。
规范驱动开发(SDD):在 spec.yaml 指导下用 AI 构建新应用,采用"规范→代码"流程
代码优先规范回填开发(CFSD):用于功能/修复的实用方法,采用"代码→规范"流程
YAML 规范应详细说明目的、语言、前端/后端、数据库、API、类设计、函数名、测试策略等。
对于现有应用,让 AI 分析代码并生成 spec.yaml 基础
用 Git/GitHub + VS Code + Claude Code(或 Copilot)设置
初始阶段:使用 SDD 建立坚实基础
运维/维护阶段:在"代码→测试→规范"循环中使用 CFSD
利用 spec.yaml 跟踪谁在何时更改了什么,以及更改发生在哪个功能层级。
在 README 中总结提示词,让所有团队成员都能以一致的质量进行开发。
通过结合这两种方式,规格会自动跟随代码变更,始终保持最新状态。
许多工程师内心都有一种感觉:我们理解规格的重要性,也知道保持规格更新很重要。然而在实践中,维护规格既繁琐又乏味。原因很简单:代码的行为才是真相;规格只是在事后对其进行描述。直觉上,我们认为应该让规格符合代码,而不是反过来让代码符合规格。传统开发方法始终未能解决这一悖论。
此外,团队开发还暴露了另一个问题:“没有 X,我们就无法理解全貌”——这是一种令人担忧的依赖。要么规格不完整,要么没有人真正理解它们。无论组织规模大小,这些问题都普遍存在。
我们的开发环境已经发生了巨大变化。如今,AI 能够快速生成大量且精确的代码。人类的角色也必然随之演变。过去需要大型工程师团队才能完成的项目,现在可以由更小的团队与 AI 协作推进。盲目沿用现有方法论,将无法跟上这种快速变化。
这并不是说传统方法是错误的——数十年的实践积累了大量知识和案例研究。但“当下的最优方法”与“未来的最优方法”可能并不相同。
有趣的是,敏捷开发最初也曾遭受类似的批评,例如“过度”“缺乏纪律”。如今,它已经成为主流,并衍生出了 Scrum 和 Kanban 等变体。我预计,代码优先、规格回填开发也会经历类似的演变。
有些读者会热情接受“代码优先、规格回填开发”;另一些读者则会持怀疑态度并提出反对意见。这很正常——这种方法论存在薄弱之处,也有改进空间。世上并不存在完美的开发方法。
如果本文能够帮助到那些正面临前述挑战的工程师,我将非常高兴。
什么是规格驱动开发?| IBM
Elnashar 等人(2025):使用 GPT-4o 增强结构化数据生成——评估不同提示词风格下的提示效率
如需采取进一步措施,你可以考虑屏蔽此人和/或举报滥用行为。