基于Spec Kit的规格驱动开发实践
在本文中,我将介绍什么是规格驱动开发,它如何重塑软件开发生命周期,以及在实践中使用Spec Kit和Claude Code构建一个小型REST API时的具体做法。
微信 ezpoda免费咨询:AI编程 | AI模型微调| AI私有化部署
AI模型价格对比 | AI工具导航 | ONNX模型库 | Tripo 3D | Meshy AI | ElevenLabs | KlingAI | ArtSpace | Phot.AI | InVideo
作为软件开发者,我们在项目中已经无数次看到这样的场景:规格文档在项目初期写好,讨论了几周,然后悄悄地被冲刺看板、Jira工单和"我们在代码审查时再解决"所掩埋。
最终,代码成为了事实来源,而规格则变成了过时的产物。
现在,AI编程代理开始改变这种模式,一个新的术语正在出现——规格驱动开发(Spec-Driven Development,SDD)。其背后的理念很简单,但对于我们这些习惯了以文件和PR为思考单位的人来说,有一点不太舒服:
规格,而不是代码,应该是我们维护的主要产物。代码是我们从中生成的东西。

在本文中,我将介绍什么是规格驱动开发,它如何重塑软件开发生命周期,以及在实践中使用Spec Kit和Claude Code构建一个小型REST API时的具体做法。
1、什么是规格驱动开发?
规格驱动开发是一种构建软件的方式,其中一个结构化的、可执行的规格位于工作流程的中心。
不再是从Jira工单直接跳到代码,我们首先编写一个精确的描述:系统应该做什么、必须遵守什么约束、以及变更的边界是什么。然后AI代理使用该规格来规划、组织和实现工作,重要的是,规格在代码生成之后仍然保持活跃。
这是与许多团队过去两年来使用AI助手的方式的一个重大转变。Tab补全式编程(有时被亲切地称为"氛围编程")对于小型粘合代码来说效果不错,但它在团队规模上有一个众所周知的失败模式:
代理对系统意图没有共享理解,每个开发者用稍微不同的提示来影响它。结果是快速、不一致且难以演进的。
1.1 传统开发 vs 规格驱动开发
SDD直接解决了这个问题。规格不再是隐藏在Confluence页面中的Word文档,
它是仓库中一个有版本控制、可审查的文件,AI代理像新团队成员一样阅读它。
理解这种差异的一个有用方式:
- 传统开发:需求 → 代码(代码是事实来源)
- 规格驱动开发:需求(规格)→ AI代理 → 代码(规格是事实来源)
GitHub的开源Spec Kit是这一理念较为突出的实现之一,Kiro和Tessl等工具也在探索类似的领域。它们并不完全相同,但共享一个共同的骨架:一小套结构化文档和一小套AI驱动的阶段,将这些文档转化为可运行的软件。
1.2 SDD如何改变软件开发生命周期
传统的软件开发生命周期(SDLC)包括分析、设计、实现、测试、部署和维护。每个阶段产生产物(需求文档、设计文档、源代码、测试报告),大多数产物随着时间推移逐渐分离。
SDD并不抛弃SDLC,而是重新组织每个阶段的主要焦点:
分析不再仅仅是为了创建一份供将来阅读的文档,它现在产生的是将直接指导实现的规格。我们的问题变得更加精确,因为不清晰的答案会在几小时内而不是几个月内暴露为缺陷。
设计转变为代理或开发者可以遵循的清晰计划。它明确记录架构决策、技术选型和非功能性约束,通常在一份**"宪章"式**文档中概述项目的强制性规则。
实现是代理完成大部分打字工作的阶段,但开发者仍然对结果负责。角色从"编写每一行代码"转变为"审查意图、验证行为,并在代码暴露缺失细节时根据需要优化规格"。
测试与规格更加紧密地对齐。规格中概述的验收标准作为代理创建的初始测试,使人类和代理都能在回归测试期间参照规格。
维护可能是长期收益最大的领域。当规格保持最新时,入职新工程师或代理会话不再涉及逆向工程代码库。你提供规格,其他一切自然到位。
各阶段保持不变,但现在规格作为全程的主要指南,而不是在实现开始时就被丢弃。
2、规格驱动开发的工具
规格驱动开发主要是一种纪律,但已经出现了一些工具包来降低实践它的摩擦。讨论最多的三个是GitHub的Spec Kit、AWS的Kiro和Tessl。
Spec Kit是开源的、CLI驱动的选项,它与大多数团队已经在使用的代理——Claude Code、Cursor、Copilot、Gemini和Codex——的集成最为顺畅,因此它是我在本文其余部分将依赖的工具。
2.1 安装Spec Kit
Spec Kit以一个名为specify的小型Python CLI发布。使用uv在你的机器上安装一次:
uv tool install specify-cli --from git+https://github.com/github/spec-kit.git
specify --version
然后,在你想使用SDD的项目中初始化它:
specify init . --ai claude
--ai claude标志将Spec Kit的提示模板接入Claude Code,同样的标志也接受其他代理(cursor、copilot、gemini、codex)。执行specify init后,Claude Code的斜杠菜单中会出现五个斜杠命令:
/speckit.constitution:定义项目范围不可协商的规则。/speckit.specify:从自然语言描述生成功能规格。/speckit.plan:从规格和技术约束生成实现计划。/speckit.tasks:将计划分解为有序任务列表。/speckit.implement:执行一个或多个任务。
三个额外的辅助脚本用于审查和优化:
/speckit.clarify:在模糊需求到达计划之前标记它们。/speckit.analyze:交叉检查规格、计划和任务的一致性。/speckit.checklist:生成可交给人工审查者的审查清单。
specify init命令实际上会创建这些文件:

运行"specify init"命令后生成的文件
2.2 Spec Kit命令 vs Claude Code原生命令
我们实际上不需要Spec Kit就能做规格驱动开发。它是一个便利层,类似于其他代理如Claude Code内部的工作流运行,使用常规提示让代理在相同的文件夹中产生相同的文件。
宪章层甚至在Claude Code的/init命令中有一个部分内置的类似物,它在项目根目录创建一个CLAUDE.md,Claude在每次会话中都会读取它。这两个文件位于项目的同一层,但回答的问题略有不同:
CLAUDE.md主要是描述性的("项目是这样布局的,用这个命令运行测试"),而constitution.md主要是规范性的("这些是每个功能必须遵守的不可协商规则")。
其他Spec Kit命令,如/speckit.specify、.plan、.tasks和.implement,在Claude Code中根本没有原生等价物——你要么安装Spec Kit,要么自己写提示。
如果你的团队打算认真使用SDD,安装Spec Kit的小额前期成本是值得的,比依赖Claude Code原生命令和自由格式提示要好。
因为相同的/speckit.*命令无论你指向Claude Code、Cursor、Copilot还是Gemini,都产生相同的产物,如果你切换代理,项目的规格可以干净地迁移。3、实际示例:Spring Boot预订API
让我们开始。假设我们想构建一个小型REST服务来管理会议室预订。在传统流程中,我会创建一个Spring Boot项目,画一个Booking实体,添加一个控制器,连接一个仓库,然后边做边想验证规则。
在规格驱动流程中,第一个产物不是一个类,而是一个与源代码并存并受版本控制的规格文件目录。
.specify/memory/constitution.md文件包含每个功能必须遵守的项目范围规则,包括编码标准、测试策略和安全基线。
specs/<feature>/文件夹存放每个功能的产物。src/下的所有内容都是生成的内容——它是输出,不是事实来源——其中的每一行都应该可以追溯到specs/下的某个文件。
安装了Spec Kit并建立了宪章之后,以下是四步工作流程在预订API中的具体表现。
🚨 新的基于技能的hook架构中存在一个bug,影响Claude Code中的**/speckit-specify技能,这是在较新的Spec Kit版本中构建的。在.specify/extensions.yml中,我们有auto_execute_hooks: true和一个强制的before_specify**hook,它先运行/speckit-git-feature:
before_specify:
- extension: git
command: speckit.git.feature
enabled: true
optional: false # mandatory
我们需要编辑.specify/extensions.yml,将before_specifyhook从optional: false改为optional: true来修复这个错误,然后才能开始。
3.1 规格
这一步从开发者编写一个自然语言提示开始。代理将该提示转换为结构化的spec.md文件。开发者然后审查并编辑它。
💬 我会输入代理(Claude Code)的提示:
/speckit.specify 构建一个服务,让员工可以为定义的时间窗口预订会议室。它必须防止同一房间的重复预订。预订只能由创建它的用户取消。员工还应该能够列出给定房间和日期的预订。
运行"/speckit.specify"命令后Claude Code的结果
代理将结果写入specs/001-meeting-room-bookings/spec.md,内容类似这样:
# Feature Specification: Meeting Room Booking
**Feature Branch**: `001-meeting-room-booking`
**Created**: 2026-05-08
**Status**: Draft
**Input**: User description: "Build a service that lets employees reserve a meeting room for a defined time window. It must prevent double-booking of the same room. Bookings can only be canceled by the user who created them. Employees should also be able to list bookings for a given room and day."
## User Scenarios & Testing *(mandatory)*
### User Story 1 - Reserve a Meeting Room (Priority: P1)
An employee wants to reserve a specific meeting room for a team discussion. They select a room, specify a start and end time, and submit the reservation. If the room is available for that time window, the booking is confirmed. If the room is already booked for any overlapping period, the request is rejected with a clear explanation.
**Why this priority**: This is the core capability of the service — without the ability to create a booking, no other functionality has value.
.
.
.
注意spec.md文件中没有Spring Boot、没有JPA、没有REST动词、没有DTO名称。这是有意的——规格描述的是问题,技术选择属于下一步。
在/speckit-specify写入spec.md之后,该技能还会生成<feature-directory>/checklists/requirements.md,一个规格质量检查清单,同时作为规划前的准备关卡。它是一个固定的markdown结构,包含三个部分(内容质量、需求完整性、功能准备度),涵盖的项目包括"规格中不泄漏实现细节"、"没有遗留的[NEEDS CLARIFICATION]标记"、"成功标准是可衡量且与技术无关的"以及"每个功能需求都有明确的验收标准"。代理逐一检查规格中的每一项,修复任何不符合的内容(最多3次迭代),暂停向你询问任何未解决的澄清问题,并将结果与规格一起提交。

"/speckit-specify"命令生成的文件
📋 我们此时的工作是审查。如果缺少某条规则(时区、最大预订时限、什么算作同一"天"),我们直接编辑spec.md或让代理修改它。然后像其他源产物一样将文件提交到仓库。我们也可以审查和更新requirements.md,但设计假设你通常不需要这样做——而当你这样做时,你应该明确知道你真正在修复哪个文件。
3.2 计划
有了spec.md之后,开发者提示代理生成技术计划,提供在规格中刻意省略的技术约束:
💬 规划提示:
/speckit-plan使用Java 25和Spring Boot 4.0.x。使用Spring Data JPA在PostgreSQL上持久化。在 */api/v1/bookings下暴露REST端点。使用Jakarta Bean Validation验证输入。在数据库层面强制防止重叠,不仅是在应用代码中。使用JUnit 5和Testcontainers进行测试。

运行"/speckit-plan"命令后Claude Code的结果
代理读取spec.md加上这个提示,并写入specs/001-meeting-room-bookings/plan.md。使用Spec Kit时,它通常还会在同一文件夹中生成支持文件:
data-model.md描述实体形状contracts/目录存放OpenAPI片段research.md记录为什么选择特定的库或方法

"/speckit-plan"命令生成的文件
生成的plan.md的简短版本:
# Implementation Plan: Meeting Room Booking
**Branch**: `main` | **Date**: 2026-05-09 | **Spec**: [spec.md](./spec.md)
**Input**: Feature specification from `/specs/001-meeting-room-booking/spec.md`
## Summary
Build a RESTful Spring Boot 4.0.x service (Java 25) that lets employees reserve, cancel, and list meeting room bookings via `/api/v1/bookings`. Double-booking prevention is enforced at the PostgreSQL level using an `EXCLUDE USING GIST` constraint on a `tstzrange` column; the application handles concurrent conflicts by catching constraint violations and returning HTTP 409.
## Technical Context
**Language/Version**: Java 25
**Primary Dependencies**: Spring Boot 4.0.x, Spring Data JPA (Hibernate 7), Spring Web MVC, Jakarta Bean Validation (Hibernate Validator), Flyway
**Storage**: PostgreSQL 16+ via Spring Data JPA; EXCLUDE USING GIST constraint for overlap prevention
**Testing**: JUnit 5, Testcontainers (PostgreSQLContainer), Spring Boot Test, Mockito
**Target Platform**: Linux server (JVM / containerized)
**Project Type**: web-service (REST API)
**Performance Goals**: 95% of operations within 2 seconds under organizational load (SC-006); booking listing within 2 seconds (SC-004)
**Constraints**: Zero double-bookings (SC-002); concurrent conflict → exactly one booking succeeds (SC-005)
**Scale/Scope**: Organizational scale — tens of rooms, hundreds of employees
.
.
.
📋 与上一步类似,代理起草,开发者负责。如果计划选择了一个不想要的依赖或做出了我们不同意的架构决策,我用纯文本提出异议,代理修改plan.md。
3.3 任务列表
下一个命令将规格和计划转换为具体的待办列表:
💬 提示:
/speckit-tasks使用Spec Kit时,该命令不需要额外提示——代理已经有了spec.md和plan.md可以工作。它写入specs/001-meeting-room-bookings/tasks.md:
---
description: "Task list for Meeting Room Booking implementation"
---
# Tasks: Meeting Room Booking
**Input**: Design documents from `/specs/001-meeting-room-booking/`
**Prerequisites**: plan.md, spec.md, research.md, data-model.md, contracts/openapi.yml
**Tech Stack**: Java 25, Spring Boot 4.0.x, Spring Data JPA, PostgreSQL, Flyway, Jakarta Bean Validation, JUnit 5, Testcontainers
**Tests**: Included — JUnit 5 + Testcontainers explicitly required by the feature spec.
**Organization**: Tasks are grouped by user story to enable independent implementation and testing.
## Format: `[ID] [P?] [Story] Description`
- **[P]**: Can run in parallel (different files, no dependencies on incomplete tasks)
- **[Story]**: Which user story this task belongs to (US1, US2, US3)
- Each task includes the exact file path to create or modify
## Path Conventions
Single Spring Boot project at repository root:
- Source: `src/main/java/com/example/booking/`
- Resources: `src/main/resources/`
- Tests: `src/test/java/com/example/booking/`
- Test resources: `src/test/resources/`
---
## Phase 1: Setup (Shared Infrastructure)
**Purpose**: Initialize the Spring Boot 4.0.x Maven project with all required dependencies and base configuration.
- [ ] T001 Create pom.xml with Spring Boot 4.0.x parent, spring-boot-starter-web, spring-boot-starter-data-jpa, spring-boot-starter-validation, postgresql driver, flyway-core, spring-boot-testcontainers, testcontainers-postgresql, and junit-jupiter at repository root
- [ ] T002 Create BookingApplication.java at src/main/java/com/example/booking/BookingApplication.java
- [ ] T003 [P] Create application.yml with datasource, JPA (ddl-auto: validate), Flyway, and virtual threads (spring.threads.virtual.enabled: true) at src/main/resources/application.yml
.
.
.

运行"/speckit-tasks"命令后Claude Code的结果
💡 实用技巧:在实现之前审查。/speckit-tasks是在问题变成代码之前捕获问题的成本最低的时刻。端到端阅读生成的列表,问问每个任务是否有明确的验收标准,顺序是否合理(数据库迁移在实体之前,契约测试在控制器之前),是否遗漏了什么东西是因为规格遗漏了它(在这种情况下,回去编辑spec.md,而不是tasks.md)。在这里运行/speckit-analyze也值得花那几秒钟——它交叉检查spec.md、plan.md和tasks.md,标记你可能要到实现中途才会发现的不一致之处。
3.4 实现
只有现在代理才开始向src/中写入实际的Java文件。开发者逐任务驱动这一步:
💬 实现提示:
/speckit-implement 只运行 Phase 1 的任务 T001*。*💡 **实用技巧:逐任务实现,开启计划模式。**一次性运行/speckit-implement让代理一口气跑完tasks.md中的每个任务是很诱人的。不要这样做。一个任务一个任务地驱动(Run only task T001 from Phase 1),并在每个任务之前切换到Claude Code的计划模式(按Shift+Tab直到屏幕底部显示plan mode on)。计划模式让代理写出逐文件的计划并等待你的批准后才触碰任何代码——这是规格和差异之间的真正检查点。每个任务完成后,快速审查差异,运行测试,然后才继续。如果一个任务暴露了规格中缺失的细节,停下来先更新spec.md,不要"在代码中修复"就算了。
当未来的变更请求到来时,例如允许重复预订,我们先更新spec.md,然后重新生成plan.md、tasks.md和相关的Java文件中受影响的部分。规格与系统保持同步,因为这是变更进入的唯一方式。
4、结束语
规格驱动开发不是银弹,也不是工程判断的替代品。它把更多的权重放在了AI无法为我们做的工作上——比如澄清意图、选择权衡和验证构建的东西是否真正需要。
代理处理打字。我们处理思考。
如果你想在真实项目上实验SDD,我建议从小处开始——例如一个功能、一个仓库——并抵制在"已经知道要构建什么"时跳过规格的诱惑。那种捷径正是SDD试图打破的习惯。一旦规格到位,SDLC的其余部分就开始感觉不再是一系列脱节的交接,更像是一条从意图到运行代码的单一、可追溯的线索。
我也喜欢使用Spec Kit作为SDD工具包——它作为SDD的一种纪律,强制执行一致的文件布局,将每个步骤包装在经过测试的提示模板中,并在每个功能必须遵守的宪章中捕获架构规则。因为相同的/speckit-*命令无论我们指向Claude Code、Cursor、Copilot还是Gemini都产生相同的产物,工作可以在工具切换时迁移,使我们代理无关。
原文链接: Spec-Driven Development with Spec Kit and Claude Code
汇智网翻译整理,转载请标明出处