
1. 从一份 config.yaml 说起SDD 到底在解决什么问题第一次接触 OpenSpec 是在一个多人协作的后端项目里。当时团队里三个人一个习惯先写接口文档再动手一个喜欢直接开干边写边改还有一个偏爱在聊天窗口里把需求讲清楚就开工。结果就是接口字段对不上、边界条件各写各的、联调阶段天天吵架。后来有人甩了一份config.yaml出来说以后所有需求先落到这个文件里再让 AI 按文件生成代码。那份 yaml 就是 OpenSpec 的规范入口而它背后代表的这套方法论就是 SDD——Specification-Driven Development规范驱动开发。说白了SDD 的核心主张只有一句话先把要做什么用结构化、机器可读的方式写清楚再让代码生成或人工实现去对齐这份规范。它跟传统的先写文档再写代码最大的区别在于规范不是给人看的散文而是能被工具解析、能被校验、能驱动生成的结构化数据。OpenSpec 就是把这套理念工程化落地的一个工具集它用config.yaml作为项目级配置用规范文件描述能力、接口、数据模型再配合 Claude Code 这类 AI 编码助手把规范直接翻译成可运行的代码骨架。这套东西适合谁我的判断是三类人最该关注一是中小团队的技术负责人苦于需求传递失真、返工率高二是独立开发者想用 AI 快速起项目但又不希望生成一堆风格混乱的代码三是正在把 AI 编码工具引入工作流的工程师需要一套约束机制让 AI 别乱发挥。如果你只是偶尔写个脚本那 SDD 对你来说是杀鸡用牛刀但只要项目超过两个人、生命周期超过一个月规范驱动带来的收益就会指数级放大。我踩过的第一个坑就是把 SDD 理解成写更详细的文档。不是的。文档是给人读的规范是给工具和人都能读的。这个认知差异决定了你后面所有配置和文件组织的方式。下面我按实际落地的顺序把 OpenSpec 这套东西拆开讲。2. OpenSpec 的整体设计与核心思路拆解2.1 为什么是规范驱动而不是提示词驱动很多人用 Claude Code 的方式是打开终端敲一句帮我写一个用户登录接口然后看它生成什么。这种方式在一次性脚本上没问题但在真实项目里会迅速失控——因为每次生成的风格、命名、错误处理都不一样而且你没法追溯这个函数当初是按什么需求写的。OpenSpec 的思路是把提示词升级成规范。规范是持久化的、版本可控的、结构化的。你不再对 AI 说写个登录接口而是先定义一份规范文件里面写清楚这个能力叫什么、输入是什么、输出是什么、有哪些边界条件、依赖哪些其他能力。然后 AI 基于这份规范生成代码。这样做的好处有三个第一需求变更时改规范而不是改提示词历史可追溯第二多人协作时大家对齐的是同一份规范不是各自的记忆第三规范可以被校验字段缺失、类型不匹配这类问题在生成代码之前就能发现。我实测下来最直观的感受是返工率明显下降。以前联调阶段才发现字段对不上现在在规范评审阶段就暴露了。这个提前量就是 SDD 最大的价值。2.2 config.yaml 在项目里扮演什么角色config.yaml是 OpenSpec 的项目级配置入口它决定了工具怎么理解你的项目结构、规范放在哪、生成物输出到哪、用哪个 AI 后端。一份典型的配置大概长这样project: name: user-service root: ./src specs: dir: ./specs format: openspec-v1 generator: provider: claude-code model: default output: ./src/generated overwrite: false validation: strict: true required_fields: - name - inputs - outputs这里每一项都不是随便填的。specs.dir决定规范文件的存放位置我习惯放在项目根目录下的specs/跟源码平级方便 review。generator.overwrite我强烈建议设成false因为一旦设成trueAI 重新生成时会覆盖你手改过的代码这个坑我踩过一次丢了大半天的改动。validation.strict打开后规范里缺字段会直接报错而不是警告前期严格一点后期省心很多。提示config.yaml建议纳入版本控制但generator.output指向的生成目录是否入库取决于你们团队对生成代码的信任度。我的做法是生成目录也入库但加一条 CI 检查确保生成代码和规范保持同步。2.3 规范文件的结构设计逻辑OpenSpec 的规范文件通常按能力拆分一个能力一个文件。比如用户模块下有user.create.spec、user.login.spec、user.profile.spec。每个文件描述一个独立的能力单元包含名称、描述、输入、输出、边界条件、依赖关系。为什么按能力拆而不是按文件拆因为 AI 生成代码时上下文窗口是有限的。如果你把所有规范塞进一个大文件AI 读的时候会丢失细节。按能力拆分后生成某个接口时只需要加载相关的几个规范文件上下文更聚焦生成质量更高。这是我在实际项目里对比过两种组织方式后得出的结论——大文件方式生成的代码经常漏掉边界条件拆分后明显改善。2.4 与 Claude Code 的协作边界OpenSpec 本身不生成代码它负责规范解析 提示词组装 结果校验真正的代码生成交给 Claude Code。这个分工很重要OpenSpec 是约束层Claude Code 是执行层。约束层保证生成什么是确定的执行层负责怎么生成。这样设计的好处是解耦。哪天你想换个 AI 后端只要 OpenSpec 支持改一行config.yaml就行规范文件不用动。我试过在同一个项目里切换不同的生成后端规范层完全无感这个灵活性在工具选型阶段特别有价值。3. 核心细节解析与实操要点3.1 环境准备Claude Code 的安装与配置在讲 OpenSpec 之前得先把 Claude Code 跑起来因为它是默认的生成后端。安装方式按平台分macOS 和 Linux 下官方推荐的方式是通过包管理器安装。Ubuntu 上我一般用 npm 全局安装npm install -g anthropic-ai/claude-code装完之后用claude --version验证。Windows 下稍微麻烦一点建议在 WSL2 里操作原生 Windows 环境偶尔会有路径解析问题。VS Code 用户可以直接装 Claude Code 扩展在扩展市场搜 Claude Code for VS Code 即可装完在设置里配置好可执行文件路径。注意安装过程中如果遇到网络相关的报错先检查本地环境是否满足官方文档列出的前置条件。官方文档链接建议直接从项目仓库的 README 里找不要从第三方转载页面拿版本容易过期。配置环节有几个关键点。第一是模型选择Claude Code 支持切换不同模型后端具体支持哪些以官方文档为准。第二是终端命令执行权限Claude Code 默认会询问是否允许执行终端命令如果你信任当前项目可以在配置里放开但生产环境项目我建议保持询问模式。第三是工作目录一定要在项目根目录启动否则它找不到config.yaml。3.2 规范文件的编写规范与常见错误写规范文件最容易犯的错是写得太像文档。比如有人会写用户登录时应该验证密码是否正确这句话对人来说很清楚但对工具来说太模糊——什么叫验证密码错误返回什么这些都没说。正确的写法是把每个能力拆成结构化的字段name: user.login description: 用户通过账号密码登录 inputs: - name: username type: string required: true - name: password type: string required: true outputs: - name: token type: string - name: expires_at type: integer errors: - code: INVALID_CREDENTIALS when: 用户名不存在或密码错误 - code: ACCOUNT_LOCKED when: 连续失败超过5次 dependencies: - user.store - token.issue这样写的好处是AI 生成代码时能精确知道要处理哪些错误分支不会漏掉ACCOUNT_LOCKED这种情况。我对比过模糊描述和结构化描述两种规范生成的代码后者在错误处理上的完整度高出一大截。常见错误我整理成了一张表错误类型表现后果修正方式描述模糊用自然语言写需求AI 自由发挥边界遗漏拆成 inputs/outputs/errors字段缺失没写 required生成代码不校验必填打开 strict 校验依赖循环A 依赖 BB 又依赖 A生成顺序死锁梳理依赖为有向无环图命名不一致同一概念多种叫法生成代码命名混乱建立术语表统一命名3.3 生成产物的目录组织与命名约定生成代码放哪、怎么命名这个看似小事实际上影响后续维护。我的约定是生成目录按能力模块分子目录文件名跟规范文件名对应。比如user.login.spec生成的代码放在src/generated/user/login.ts。这样从代码能反查到规范从规范也能定位到代码。命名上我坚持一个原则生成代码和手写代码物理隔离。生成的全在generated/下手写的业务逻辑在src/其他目录。这样重新生成时不会误伤手写代码也方便在 code review 时区分这是 AI 生成的和这是人写的。这个隔离策略是我在第二个项目里才想明白的第一个项目混在一起后来重构时痛苦不堪。3.4 校验机制让规范在生成前就跑一遍OpenSpec 的校验分两层。第一层是语法校验检查 yaml 格式、必填字段、类型合法性。第二层是语义校验检查依赖是否存在、命名是否冲突、错误码是否重复。第一层在保存文件时就能触发第二层需要跑一次openspec validate命令。我强烈建议把校验接进 CI。每次提交规范文件时自动跑一遍不通过就阻断合并。这样能保证主分支上的规范永远是可生成的状态。实测下来这个 CI 检查拦住了不少低级错误比如有人改了错误码忘了同步依赖它的规范。4. 实操过程与核心环节实现4.1 从零搭建一个 OpenSpec 项目的完整流程假设我们要做一个待办事项服务从零开始走一遍。第一步初始化项目结构。在项目根目录执行 OpenSpec 的初始化命令具体命令以你安装的版本为准它会生成config.yaml和specs/目录骨架。如果工具没有初始化命令手动创建这两个东西也行config.yaml按前面给的模板填。第二步编写第一个规范。创建specs/todo.create.spec描述创建待办这个能力。输入是标题和可选的截止日期输出是待办 ID 和创建时间错误包括标题为空、标题超长。第三步跑校验。执行openspec validate确认规范合法。这一步会告诉你缺了哪些字段、依赖是否满足。第四步生成代码。执行openspec generate todo.createOpenSpec 会组装提示词、调用 Claude Code、把生成结果写到generator.output指定的目录。第五步人工 review 生成代码。这一步不能省。AI 生成的代码在结构上通常没问题但业务细节需要人确认。我一般重点看三处错误处理是否完整、边界条件是否覆盖、命名是否符合团队约定。第六步把生成代码接入实际业务。生成的是骨架真正的数据库操作、缓存逻辑还需要手写。手写部分放在generated/之外的目录通过依赖注入或接口实现的方式接进去。4.2 参数选择模型、温度、上下文窗口怎么定生成质量跟参数关系很大。模型选择上复杂业务逻辑用能力强的模型简单 CRUD 用轻量模型即可没必要所有场景都上最强的。温度参数如果后端支持调节我一般设得比较低因为代码生成需要确定性温度高了会生成风格飘忽的代码。上下文窗口是另一个关键。OpenSpec 在组装提示词时会把相关规范文件的内容拼进去。如果依赖链很长提示词会变得很大超出窗口后 AI 会丢失前面的信息。我的应对策略是控制单个能力的依赖数量超过五个依赖就考虑拆分能力。这个数字不是绝对的但超过五个后生成质量下降很明显这是我多次实测的观察。4.3 一次完整的生成现场记录拿创建待办这个能力举例我记录一下实际生成过程。规范文件写好后执行生成命令。OpenSpec 先解析规范输出一份中间表示可以理解为给 AI 看的提示词。这份中间表示大概包含能力描述、输入输出定义、错误分支、依赖的接口签名。然后它调用 Claude Code把中间表示作为上下文传进去。Claude Code 返回的是一段 TypeScript 代码包含函数签名、参数校验、错误抛出、以及一个 TODO 注释标记这里需要接入实际存储。我检查了一遍发现它把标题超长的边界条件处理成了throw new Error但我们团队的约定是用自定义错误类。于是我改了一下规范里的错误定义加上error_class字段重新生成这次就对了。这个过程说明一个点规范不是一次写对的是迭代出来的。第一次生成发现问题改规范而不是改生成代码这样下次生成才不会重蹈覆辙。这个习惯养成后规范会越来越精确生成质量也会越来越高。4.4 与现有代码库的集成方式OpenSpec 生成的是新代码怎么跟已有代码库融合是个现实问题。我的做法是分三步先让生成代码独立存在跑通单元测试再通过适配层接入现有业务逻辑最后逐步替换掉旧的手写实现。适配层的写法取决于你的架构。如果是依赖注入框架把生成代码注册成 provider 即可。如果是简单的函数调用写一个 wrapper 把生成函数的签名转成现有代码期望的签名。这一步不要偷懒直接改生成代码否则下次重新生成又得改一遍。提示集成阶段建议保留旧实现一段时间用 feature flag 控制走新路径还是旧路径。等新路径稳定后再移除旧代码。这个灰度策略在真实项目里救过我好几次。5. 常见问题与排查技巧实录5.1 生成代码不符合预期怎么办这是最高频的问题。排查顺序我总结成三看一看规范是否描述清楚二看依赖是否加载完整三看模型是否选对。大部分情况是规范的问题。比如生成代码漏了某个错误分支回去看规范发现那个分支压根没写。或者生成代码命名奇怪回去看规范发现同一个概念用了两种叫法。规范是源头源头不清下游必乱。如果规范没问题检查依赖加载。OpenSpec 生成时会加载依赖的规范文件如果依赖路径写错AI 拿不到依赖的接口签名就会自己瞎编一个。这种情况生成的代码编译能过但运行时对不上。最后才怀疑模型。换个能力强的模型重试一次如果还是不行那基本可以确定是规范的问题。5.2 规范与代码不同步的检测方法项目跑一段时间后经常出现规范改了但代码没重新生成或者代码手改了但规范没更新的情况。检测方法有两个一是比对生成代码的哈希值OpenSpec 可以在生成时记录哈希重新生成时比对不一致就报警二是定期跑一次全量生成看 diff 有多大diff 大说明规范漂移严重。我倾向于第一种接进 CI 自动跑。第二种作为月度健康检查。两种结合基本能保证规范和代码不脱节。5.3 多人协作时的规范冲突处理多人同时改规范冲突是必然的。我的处理原则是规范文件的粒度要细到一个人一次只改一个文件。如果两个人都要改user.login.spec那说明这个能力该拆了。拆成user.login.password.spec和user.login.token.spec各改各的冲突自然消失。如果实在拆不开那就走正常的代码合并流程人工解决冲突。规范文件是文本合并冲突跟合并代码没区别。关键是合并后要重新跑校验和生成确保合并结果仍然可用。5.4 常见问题速查表问题现象可能原因排查动作解决方式生成命令报错找不到规范specs.dir 配置错误检查 config.yaml修正路径生成代码缺字段规范里没定义该字段打开 strict 校验补全规范生成代码覆盖手写逻辑overwrite 设为 true检查配置改为 false依赖加载失败依赖路径拼写错误看生成日志修正依赖名生成质量突然下降上下文超窗口数依赖数量拆分能力校验通过但生成失败模型后端不可用检查后端配置切换或重试5.5 几个我踩过的坑第一个坑是overwrite配置。前面提过设成 true 后重新生成会覆盖手改代码。我现在的做法是生成目录只读需要改就改规范重新生成绝不手改生成代码。第二个坑是规范文件编码。有次同事用 GBK 编码保存了一个规范文件OpenSpec 解析时中文全乱码生成的代码里注释都是乱码。统一用 UTF-8这个没得商量。第三个坑是依赖循环。A 依赖 BB 依赖 A生成时死锁。后来我加了一条规则依赖关系必须是有向无环图写规范时先在纸上画一遍依赖图确认没环再落文件。第四个坑是模型版本漂移。同一个规范隔了一个月重新生成代码风格变了。原因是后端模型升级了。这个没法完全避免应对方式是锁定模型版本升级时做一次全量回归。6. 规范驱动开发的边界与我的实际体会SDD 不是银弹它有明确的适用边界。我总结下来适合 SDD 的场景有三个特征需求相对稳定、接口边界清晰、团队有规范意识。反过来如果需求天天变、接口还在探索阶段、团队习惯自由发挥那强行上 SDD 只会增加负担。我在实际项目里的体会是SDD 最大的价值不在生成代码而在逼你把需求想清楚。写规范的过程就是一次结构化的需求梳理。很多以前在编码阶段才暴露的问题现在在写规范时就暴露了。这个提前量比生成代码本身值钱得多。另外一点OpenSpec 这类工具还在快速演进配置格式、命令、支持的模型后端都可能变。我的建议是核心方法论规范驱动值得投入具体工具保持关注但不要过度绑定。规范文件用通用的 yaml 写即使哪天换工具迁移成本也可控。最后分享一个小技巧刚开始用 SDD 时不要一上来就全项目铺开。挑一个独立的小模块试点跑通写规范、生成、集成、迭代这个完整闭环再逐步扩大范围。我见过太多团队一上来就全量改造结果规范写了一半发现方向不对进退两难。小步快跑是这套东西落地最稳的姿势。