Spec-kit 规范驱动开发实战:从文档脱节到 CI 自动校验

发布时间:2026/11/4 4:04:28
Spec-kit 规范驱动开发实战:从文档脱节到 CI 自动校验

1. 为什么我们需要重新审视“规范”这件事

第一次接触 Spec-kit 是在一个多人协作的后端项目里。当时团队有五个人,接口文档散落在三个不同的地方:有人写在 Notion 里,有人直接写在代码注释里,还有人靠口头同步。结果就是联调阶段每天都在吵架——前端说后端返回的字段和文档不一致,后端说前端根本没按约定传参。那段时间我最大的感受是:代码可以重构,但“规范”一旦失控,整个团队的沟通成本会指数级上升。

Spec-kit 这个工具,本质上就是冲着这个问题来的。它属于SDD(Specification-Driven Development,规范驱动开发)这一方法论下的工程化落地工具,形态是一个 CLI。你可以把它理解成“把项目规范从散落的文档里抽出来,变成可执行、可校验、可版本化的工程资产”。它解决的问题很具体:规范写在哪里、谁来维护、怎么保证代码和规范不脱节、怎么在 CI 里自动拦截违规。

这篇文章适合三类人看:一是正在被“文档和代码两张皮”折磨的团队技术负责人;二是想在自己项目里引入 SDD 但不知道从哪下手的独立开发者;三是已经在用各类 CLI 工具(比如 codex cli、claude cli 这类)做 AI 辅助开发,想让 AI 产出更可控的工程师。我会把 Spec-kit 的设计思路、核心机制、实操流程、踩坑经验全部摊开讲,尽量做到你看完就能在自己项目里跑起来。

需要先说明一点:Spec-kit 目前生态还在快速演进,不同版本的行为可能有差异。我下面讲的内容基于我实际使用过的版本和常见实践,如果你拿到的版本对不上,以官方仓库的 README 为准,但思路是通用的。

2. Spec-kit 的整体设计与思路拆解

2.1 它到底把“规范”放在了什么位置

传统开发流程里,规范是“人读的文档”,代码是“机器执行的文本”,两者之间靠人的自觉来维系。Spec-kit 的核心思路是把规范变成“机器也能读的结构化文件”,然后围绕这个文件构建一整套工具链。这个结构化文件通常以 YAML 或类似声明式格式存在,描述的是接口契约、字段约束、命名规则、目录结构约定这些东西。

为什么选声明式而不是自然语言?因为自然语言没法自动校验。你写“用户名字段必填”,CI 没法判断代码里到底有没有做非空校验;但你写required: true加上类型约束,工具就能扫描代码、比对差异、直接报错。这就是 SDD 和“写文档”最本质的区别——规范要能被程序消费。

Spec-kit 在这个体系里扮演的是“执行者”和“协调者”的角色。它不负责定义规范长什么样(那是你团队的事),它负责的是:读取规范、解析规范、把规范投射到代码检查、生成报告、在流水线里卡口。这种职责划分很关键,因为它意味着 Spec-kit 可以适配不同团队的规范风格,而不是强迫所有人用同一套模板。

2.2 为什么做成 CLI 而不是 IDE 插件或 Web 服务

我一开始也疑惑,为什么不做成 IDE 插件,实时提示不是更爽?后来想明白了:CLI 是唯一能同时覆盖本地开发和 CI 流水线的形态。IDE 插件只能在编辑器里生效,Web 服务需要额外部署和维护,而 CLI 可以在开发者本地跑、可以在 Git hook 里跑、可以在 CI runner 里跑,一套逻辑三处复用。

而且 CLI 天然适合和现有工具链组合。你可以把 Spec-kit 的输出接到 codex cli 或 claude cli 这类 AI 辅助工具里,让 AI 基于规范生成代码;也可以把它的检查结果喂给通知系统。这种“可组合性”是 IDE 插件给不了的。我在实际项目里就是把 Spec-kit 的校验结果作为 AI 生成代码的前置输入,效果比让 AI 自由发挥好太多。

2.3 规范驱动开发和测试驱动开发的关系

很多人会把 SDD 和 TDD 混为一谈,其实两者关注点不同。TDD 关注的是“行为正确性”,先写测试再写实现;SDD 关注的是“契约一致性”,先定规范再写代码。两者可以叠加:规范定义接口长什么样,测试验证接口行为对不对。

Spec-kit 更偏 SDD 这一侧。它不替代单元测试,但它能在测试之前就拦住一批低级错误,比如字段名拼错、类型不匹配、必填项缺失。我在项目里的实践是:Spec-kit 跑在 pre-commit 阶段,测试跑在 CI 阶段,两层过滤,返工率明显下降。

2.4 方案选型背后的取舍

Spec-kit 选择“规范文件独立于代码”而不是“规范内嵌在代码注释里”,这个取舍值得说一下。内嵌注释的好处是离代码近,不容易脱节;坏处是跨文件、跨模块的全局约束很难表达,而且注释格式五花八门,解析成本高。

独立规范文件的好处是全局视角清晰、格式统一、易于版本管理;坏处是有脱节风险。Spec-kit 用“自动校验”来对冲这个风险——只要 CI 里强制跑校验,脱节就会立刻暴露。这个设计逻辑和“基础设施即代码”是一个路子:把隐式约定显式化,然后用工具保证显式约定不被违反。

3. 核心机制解析与关键细节

3.1 规范文件的结构长什么样

Spec-kit 消费的规范文件,通常包含几个层次:全局配置、模块定义、接口契约、字段约束。我用一个简化例子说明,实际项目会更复杂:

project: name: user-service version: 1.2.0 modules: - name: user path: src/user interfaces: - name: getUser method: GET path: /api/user/{id} params: - name: id type: string required: true response: - name: username type: string required: true - name: age type: integer required: false

这个结构的关键在于:每个字段都有类型和必填标记,接口有明确的路径和方法。Spec-kit 解析这个文件后,就能对照代码做检查。比如代码里getUser返回的username如果可能为 null,而规范里写了required: true,就会报不一致。

注意:规范文件的字段命名要和代码里的实际命名保持一致,否则校验会大量误报。我建议在项目初期就定好命名映射规则,比如规范里用 camelCase,代码里如果用 snake_case,就要在配置里声明转换规则。

3.2 校验是怎么做到的

Spec-kit 的校验分两类:静态结构校验和动态行为校验。静态结构校验是扫描代码文件,提取接口定义、字段声明,和规范文件比对。动态行为校验是跑实际请求,看返回结果是否符合规范。

静态校验的实现方式通常是 AST 解析或者正则匹配。AST 解析更准确但依赖语言生态,正则匹配更通用但容易误判。Spec-kit 一般会提供多种解析器,你根据项目语言选。我在 Node.js 项目里用的是基于 TypeScript 编译器的解析器,准确率很高;在一个 Python 老项目里用的是正则方案,需要手动排除一些误报。

动态校验需要项目能跑起来,通常放在集成测试阶段。Spec-kit 会发请求、拿响应、对照规范检查字段类型和必填项。这个环节能抓到静态检查抓不到的问题,比如运行时类型转换导致的偏差。

3.3 和 AI 辅助工具的配合方式

现在很多人用 codex cli 或 claude cli 做代码生成,Spec-kit 在这里能发挥很大作用。具体做法是:把规范文件作为 AI 的输入上下文,让 AI 基于规范生成代码,生成后再用 Spec-kit 校验。这样 AI 的产出就有了明确的约束边界,不会天马行空。

我实测下来,加了规范约束后,AI 生成代码的返工率能降一半以上。因为 AI 最怕的就是“需求模糊”,而规范文件恰好把模糊地带消除了。你可以把规范文件的内容直接拼进 prompt,也可以让 Spec-kit 生成一个精简版的“约束摘要”喂给 AI,后者 token 消耗更少。

3.4 版本管理和变更追踪

规范文件是要进版本库的,这点很重要。每次规范变更都应该有对应的 commit,这样出问题时可以追溯“是哪次规范变更导致了这次不一致”。Spec-kit 通常会提供 diff 功能,对比当前代码和规范的差异,输出变更报告。

我在项目里定了个规矩:规范文件的修改必须单独提 PR,不能和业务代码混在一起。这样 review 的时候能清楚看到规范变了什么,也方便回滚。这个习惯看起来麻烦,但真出问题时能省大量排查时间。

4. 实操流程与核心环节实现

4.1 安装与初始化

Spec-kit 的安装方式取决于它的分发渠道,常见的是通过包管理器安装。以 npm 生态为例,大致流程是:

npm install -g spec-kit spec-kit init

init命令会在项目根目录生成一个规范文件模板和配置文件。模板里有一些示例内容,你需要根据项目实际情况修改。配置文件里通常包含解析器选择、检查规则开关、忽略路径等。

提示:初始化后先别急着写完整规范,先跑一次spec-kit check看看默认配置下的输出。这样你能了解工具的报错风格,再决定哪些规则要开、哪些要关。

如果你用的是其他语言生态,安装命令可能是pip install spec-kit或go install,具体看官方文档。安装完成后建议先验证版本:

spec-kit --version

这一步能确认工具装对了,也能避免后面因为版本差异导致的困惑。

4.2 编写第一版规范文件

第一版规范不要追求大而全,先把核心接口和关键字段写进去。我的经验是:从最容易被违反的约定开始写。比如团队经常搞错的字段命名、经常漏掉的必填校验、经常不一致的返回结构。

写规范文件时要注意几点:一是字段类型要写清楚,string、integer、boolean、array、object 这些基本类型要明确;二是必填和可选要区分,不要所有字段都写 required;三是嵌套结构要展开,不要用“详见文档”这种偷懒写法,因为工具解析不了。

写完第一版后,跑一次校验,看看报错数量。如果报错太多,说明规范定得太严或者代码确实问题多,这时候要分批次修,不要一次性全改,容易引入新问题。

4.3 接入本地开发流程

本地开发阶段,最有效的接入方式是 Git hook。在 pre-commit 里跑 Spec-kit 校验,不通过就不让提交。这样能把问题拦在本地,不会污染远程仓库。

配置方式是在.git/hooks/pre-commit里加一行:

#!/bin/sh spec-kit check --staged

--staged参数表示只检查暂存区的文件,速度更快。如果项目大、全量检查慢,这个参数很关键。我试过全量检查要几十秒,只查暂存区就一两秒,体验差别很大。

注意:Git hook 不会自动同步到团队其他成员,每个人都要手动配置。如果团队人多,建议用 husky 这类工具统一管理 hook,避免有人漏配。

4.4 接入 CI 流水线

CI 阶段是 Spec-kit 发挥最大价值的地方。在流水线里加一个校验步骤,不通过就阻断合并。这样能保证主分支的代码始终和规范一致。

以常见的 CI 配置为例,大致是这样:

steps: - name: Install dependencies run: npm install - name: Spec validation run: spec-kit check --all --format json > spec-report.json - name: Upload report run: upload-artifact spec-report.json

--format json让输出变成结构化数据,方便后续处理。你可以把报告上传成 artifact,也可以解析后发通知。我在项目里是把报告解析后,把违规项按模块分组,发给对应的负责人,这样责任清晰。

4.5 和 AI 工具联动的实操

如果你在用 codex cli 或 claude cli,可以这样联动:先用 Spec-kit 生成一份“约束摘要”,再把摘要和需求一起喂给 AI。约束摘要的生成命令大致是:

spec-kit export --format prompt > constraints.txt

这个文件里包含了当前项目的核心规范约束,token 量比完整规范文件小很多。把它作为 AI 的 system prompt 或上下文,AI 生成代码时就会自觉遵守这些约束。

我实测的流程是:需求描述 + 约束摘要 → AI 生成代码 → Spec-kit 校验 → 不通过则把报错喂回 AI 让它修 → 再校验。这个循环跑两三轮,基本就能得到符合规范的代码。比人工写快,比纯 AI 生成可控。

4.6 参数计算与规则调优

Spec-kit 的检查规则通常有严格程度分级。太松了没效果,太严了误报多。我建议的做法是:先全开,跑一遍,统计每类规则的报错数量;然后按“报错多且修复成本低”的优先级逐步收紧。

比如“字段命名不一致”这类规则,报错多但修复简单,可以优先开;“返回类型不匹配”这类规则,报错少但修复复杂,可以放后面。这个调优过程要结合项目实际情况,没有万能配置。

另外,忽略规则要慎用。有些团队为了快速通过校验,大量加 ignore,结果规范形同虚设。我的原则是:ignore 必须写清楚原因和负责人,定期 review,能修的就修掉。

5. 常见问题与排查技巧实录

5.1 校验报错太多怎么办

这是新手最常见的问题。第一次跑校验,报几百个错,直接劝退。我的处理方式是分三步:第一步,先看报错分类,统计每类有多少;第二步,挑一类影响最大、修复最简单的先修;第三步,修完后把这类规则设为强制,其他规则暂时设为警告。

这样分批推进,既能快速看到效果,又不会一次性压垮团队。我在一个老项目里就是这么干的,第一周只修了字段命名,第二周修了必填校验,一个月后规范覆盖率就到了八成以上。

5.2 规范文件和代码脱节怎么防

脱节的根源是“规范改了但代码没改”或者“代码改了但规范没改”。防脱节的核心是让校验成为强制环节。本地 hook 加 CI 卡口,两层保险。另外,规范文件的修改要单独 review,确保改规范的人知道自己在改什么。

我还见过一种情况:规范文件写得太细,代码实现有合理偏差,导致大量误报。这时候要反思规范是不是定得过死。规范应该约束“对外契约”,而不是“内部实现细节”。把边界划清楚,脱节问题会少很多。

5.3 和现有工具链冲突怎么处理

Spec-kit 可能和现有的 lint 工具、格式化工具产生重叠或冲突。比如 ESLint 也在检查命名规范,Spec-kit 也在检查,两边规则不一致就会打架。处理方式是明确分工:lint 管代码风格,Spec-kit 管接口契约,各管各的,规则不要重叠。

如果确实有重叠,以 Spec-kit 为准,把 lint 里的对应规则关掉。这样职责清晰,维护起来也简单。

5.4 性能问题怎么优化

项目大了之后,全量校验可能很慢。优化方向有几个:一是只校验变更文件,用--staged或--diff参数;二是开启缓存,把上次校验结果缓存起来,没变的文件跳过;三是并行校验,Spec-kit 一般支持多进程,配置里开一下。

我在一个上万文件的项目里,通过缓存加并行,把校验时间从几分钟压到了十几秒。关键是要让校验足够快,快到开发者愿意在本地跑,否则大家就会绕过它。

5.5 常见问题速查表

问题现象可能原因排查方向解决方式
报错数量异常多规范定得太严或解析器不匹配检查规则配置和解析器选择分批收紧规则,换解析器
校验结果和实际不符缓存过期或路径配置错误清缓存,检查 ignore 路径清缓存重跑,修正路径
CI 通过但本地失败环境差异或版本不一致对比本地和 CI 的工具版本统一版本,锁定依赖
AI 生成代码仍违规约束摘要不完整或 prompt 太长被截断检查摘要内容,精简 prompt补全约束,分段喂给 AI
校验速度慢全量检查或未开缓存看是否用了 diff 模式开缓存,用增量检查

5.6 几个我踩过的坑

第一个坑是规范文件用了中文注释,结果解析器报编码错误。后来统一改成英文注释,问题消失。如果你的项目有国际化需求,规范文件本身建议用英文,注释可以另开文档。

第二个坑是 ignore 规则写得太宽,把整个目录忽略了,结果那个目录下的问题一直没被发现。后来改成精确到文件,定期 review ignore 列表。

第三个坑是没锁定 Spec-kit 版本,CI 上自动装了新版本,行为变了导致流水线突然失败。后来在 package.json 里锁死版本,升级时手动改,改完先本地验证再上 CI。

6. 把规范变成团队资产的一些体会

Spec-kit 这类工具的价值,不在于它本身多复杂,而在于它强迫团队把“隐式约定”变成“显式资产”。这个过程一开始会有点痛,因为要把脑子里想的东西写下来,还要接受工具的无情检查。但坚持一段时间后,你会发现沟通成本明显下降,新人上手也快了很多。

我现在带项目,第一件事就是搭 Spec-kit,把核心接口和关键约束写进去。哪怕项目还很小,这个习惯也值得养成。因为规范这东西,越早建立越省事,等到代码烂成一团再补,成本会高得离谱。

如果你也在用 AI 辅助开发,强烈建议把 Spec-kit 和 codex cli、claude cli 这类工具串起来用。规范给 AI 划边界,AI 在边界内发挥,产出质量和速度都能兼顾。这个组合我用了大半年,是目前我觉得最顺手的开发方式之一。

最后分享一个小技巧:Spec-kit 的校验报告可以定期归档,每个月看一次趋势。如果违规数量在下降,说明规范在落地;如果一直居高不下,说明要么规范不合理,要么执行不到位,需要调整策略。数据不会骗人,比感觉靠谱。