OpenSpec 实战手册:用规范驱动 AI 编码的完整工作流
你有没有遇到过这种场景让 AI 帮忙改一个老接口它五分钟后交出一版“看起来没问题”的代码你 review 的时候才发现它把其他模块依赖的返回结构也悄悄改了甚至把单测里依赖的 mock 数据也顺手“修正”了。更麻烦的是当你追问它为什么这么改它会给你一段逻辑自洽的解释让你一时分不清是它对了还是你原来的设计对了。这不是模型能力不行而是我们在把需求丢给 AI 之前少做了一步非常关键的工作把模糊的意图翻译成 AI 能执行、能自检、能验收的规范。AICoding 发展到今天真正拉开差距的地方已经不是“会不会写提示词”而是“能不能像管理一个远程工程师一样管理 AI 的执行过程”。OpenSpec 就是围绕这个问题设计的一套工作流框架它把规范驱动开发的思路引入了 AI 编码场景先写规格再生成计划最后让 AI 按单子干活。这篇文章是我的 OpenSpec 完整实战手册 v1.0会从核心原理一直讲到命令使用、spec 写法、踩坑经验最后还会聊一个很实际的话题AICoding 笔试里怎么用 OpenSpec 打出差异化。无论你是在项目里已经用过 Aider、Claude Code、Cursor还是正在准备 AICoding 相关的面试应该都能从里面拿走一些直接能用的东西。1. 先搞清楚OpenSpec 解决的是 AICoding 里最贵的问题1.1 AI 编码为什么“写出来快、改不动”如果你经常用 AI 写代码一定会有一种体感从零开始生成一个功能AI 非常快快到让人觉得编程已经不存在门槛了。但一旦进入已有项目让 AI 改一个被多处依赖的函数问题就来了。原因其实不复杂大模型能看到的上下文是有限的它不会像人类老员工一样脑内自动加载“这个函数的三个调用方、两个历史变更原因、一个性能约束”。它只能依据当前对话里你给它的信息加上它自己读取的一小部分文件去做一个局部最优的判断。这个局部最优放在全局视角下往往就是灾难。比如你让它“把用户列表接口加上分页”它可能只改了接口本身没有改前端约定好的返回格式或者它在实体类上加了一个字段却忘了同步数据库迁移脚本。模型不是不聪明是它根本不知道这些约束存在。所以 AI 编码的真正瓶颈不是写代码的速度而是“让 AI 在正确的边界内写代码”的成本。这个成本恰好是 OpenSpec 想解决的。1.2 OpenSpec 的定位把需求变成 AI 可验证的契约OpenSpec 做的事情可以概括成一句话把一次代码变更从“一段对话”变成“一份契约”。你不再在对话框里零散地说“帮我改一下”“这里优化优化”“那边看着不对”而是先产出一份结构化的规格文件里面明确写清楚这次为什么要改、改哪些范围、不碰哪些范围、技术方案是什么、验收条件有哪些。有了这份契约AI 的角色就从一个“自由发挥的结对程序员”变成了“按设计文档施工的工程师”。更关键的是验收条件写清楚之后AI 可以在完成每一步之后对照条件自检而不是自我感觉良好地交卷。这在工程上是一个很本质的转变以前我们靠人肉 review 来兜底现在我们把 review 的标准前置到了 AI 的执行指令里让它在产出代码的同时产出“我为什么说做完”的证据。1.3 它和 Aider、Claude Code、Cursor 不是竞争关系我经常被问OpenSpec 是不是要取代 Cursor完全不是。OpenSpec 不是编辑器也不是模型客户端它更像是一个需求与计划管理层。你可以把它理解为施工总包Aider、Claude Code、Cursor 这类工具是下面的施工队。OpenSpec 负责把需求拆成任务清单施工队负责按清单改代码。所以一个典型的 AICoding 步骤是这样的先由人或 AI 把需求写成 spec再由 OpenSpec 生成 plan任务计划然后让 Claude Code 这类 agent 按 plan 逐步执行最后再依据 spec 里的验收标准做回归确认。整个过程里OpenSpec 管的是“做什么、做到什么程度算完”编码工具管的是“具体怎么改”。2. 落地准备从 OpenSpec 官网开始初始化一个干净的项目骨架2.1 获取 CLI官网和安装方式先说明一下OpenSpec 本身是一个开源项目最权威的信息来源就是它的官网和官方 GitHub 仓库。官网上通常会有 Getting Started 页面提供两类安装路径一类是直接下载编译好的 CLI 二进制适合 macOS 和 Linux 用户另一类是从源码构建适合需要二次定制的人。如果你拿不准选哪种优先用官方推荐的安装方式通常也就是一条命令的事。装好之后先跑一下版本命令确认环境没问题openspec --version如果你的 shell 提示找不到命令优先检查两件事一是安装路径是否加进了 PATH二是当前目录是否在 Git 仓库内。OpenSpec 的工作流跟 Git 绑定得很紧很多命令都依赖 Git 根目录来定位项目所以不要在随便一个临时目录里初始化它。2.2 初始化openspec init 会生成什么进入你的项目根目录执行初始化命令openspec init用 OpenSpec 官网文档里的术语来说这一步会帮你建立一个“spec 工作区”。我基于常见开源实践解释一下它生成的目录结构不同模板可能在细节上有差异但核心逻辑一致docs/ specs/ proposals/ # 存放变更提案也就是每个功能或修复的 spec 文件 decisions/ # 记录架构决策类似 ADR tasks/ # 存放可执行的任务计划 agents.md # 给 AI 看的项目说明描述角色、约束、工作流如果你看到的模板是项目根目录下直接生成openspec/目录也不用慌原则一样proposals 是“想改什么”的说明书tasks 是“怎么改”的施工图decisions 是“为什么这么定”的历史记录。这里有一个经验分享agents.md值得花 15 分钟认真写。它是 AI 进入仓库后第一个会读的文件相当于给 AI 的入职手册。我在项目里会固定写三个部分项目技术栈、代码风格约束、执行 spec 时必须遵守的验收流程。这一步做扎实了后面 AI 的“自觉性”会高很多。2.3 把 spec 纳入 Git 版本管理初始化完成之后建议立刻把整个 specs 目录提交进 Git。很多人会忽略这一点觉得 spec 只是临时文档。实际上spec 是你和 AI 之间最重要的沟通记录。如果 spec 不进版本库你就无法追溯某个功能当初为什么这么设计也无法在 AI 执行到一半时精准回滚到某个需求版本。我的习惯是每个 spec 文件对应一个分支。比如我要做“给文章列表加标签过滤”我会先切一个分支feat/tag-filter在这个分支里写好 spec然后让 AI 执行计划。这样 spec 的变更历史就是需求的历史代码的变更历史就是实现的历史两者对得上review 会轻松很多。3. 第一次实战把模糊需求写成 AI 能执行的任务3.1 需求拆解三步法边界、输入输出、验收条件写 spec 最忌讳的是一上来就写“我要一个标签筛选功能”。这种描述给人类同事都容易产生歧义给 AI 更是一场灾难。我习惯用三步法把一个模糊需求拆清楚。第一步是划边界。明确写清楚“这次改什么、不改什么”。比如做标签过滤边界是“只在文章列表接口新增 query 参数”明确不碰“文章管理后台的筛选 UI”。边界划得越清楚AI 越不会自作主张去重构别的模块。第二步是定输入输出。把数据流讲明白入参是什么类型、取值空间是什么、出参长什么样、异常情况怎么表达。不要只写“支持按标签过滤”要写“GET /api/articles?tagtech 返回文章列表tag 参数为可选空值时返回全部文章不存在该标签时返回空列表而不是 404”。第三步是写验收条件。这是最容易偷懒但也最值钱的部分。验收条件要能被程序判断比如“所有被返回的文章都包含 tagtech 这个标签”“单测新增 fileter_by_tag_test.py 并通过”。AI 执行完任务后会逐条对照这些条件自检比你说一百句“仔细点”都管用。3.2 一个可以直接抄的 spec 文件模板下面是我在实际项目里常用的 spec 模板基于 OpenSpec 的 proposals 结构做了简化# Change: 文章列表接口支持按标签过滤 ## Why 内容详情页需要展示同标签文章当前接口不支持按标签筛选 前端只能拉全量数据再在内存里过滤数据量大时性能问题明显。 ## Scope - 修改article_service.py 中的列表查询逻辑、article_api.py 中的接口层 - 修改新增 tests/test_tag_filter.py - 不修改数据库表结构、文章推荐算法、管理后台 UI ## Plan 1. 在 article_api.py 的 GET /api/articles 中新增可选参数 tag 2. 在 article_service.py 中新增 filter_by_tag(tag) 查询方法 3. 当 tag 为空时保持原有返回逻辑 4. 新增测试覆盖有标签、无标签、标签不存在三种场景 ## Acceptance Criteria - [ ] 请求 /api/articles?tagtech 只返回包含 tech 标签的文章 - [ ] 不传 tag 参数时行为与修改前完全一致 - [ ] 不存在该标签时返回空列表状态码保持 200 - [ ] pytest tests/test_tag_filter.py 通过注意看我加了“Why”之外还加了“不修改”这个显式声明。这件事对 AI 执行非常关键因为大模型天生倾向于“顺手优化”而“顺手优化”恰恰是破坏既有行为的主要来源。有了这个声明AI 会把自己限制在清单内。3.3 措辞规则哪些话能说哪些话绝对不能说写 spec 本质上是在跟 AI 沟通措辞直接影响执行质量。我把自己的经验总结成一张对照表不要写要写原因优化一下列表查询性能保持原分页逻辑不变将标签过滤条件下推到 SQL WHERE前者给了 AI 自由发挥的空间处理好边界情况tag 为空、tag 为超长字符串、tag 含特殊字符时按 XX 处理边界条件要具体到可测试代码风格保持一致遵循项目里 black isort 的格式化规则可验证AI 可以自查尽量别破坏现有功能不修改article_service.py里已被三处调用的get_articles()签名指明“不要动”比“尽量别”有效得多这里面的核心逻辑是AI 对模糊指令的补全能力很强但这种补全未必符合你的真实意图。你必须把关键约束写成显式条件而不是指望它“悟”出来。4. 让 AI 照着单子干活plan 生成与执行闭环4.1 从 spec 到 plan谁负责拆步骤spec 写完之后下一步是把它变成可执行的任务计划。OpenSpec 在常见版本里会提供 plan 相关的命令比如openspec plan这个命令的具体形态取决于你安装的版本运行openspec --help就能看到实际命令。它做的事情是读取 proposals 目录里的当前 spec结合仓库现状生成一份任务清单。你可以把每个 spec 文件想象成一道菜谱plan 就是后厨的备菜顺序先切什么、再炒什么、最后装盘以及每一步的验证方式。我个人的建议是第一二次用 OpenSpec 时不要盲目信任自动生成的 plan打开看一遍。重点关注三点任务顺序是否合理、有没有遗漏测试步骤、文件改动清单是否超出了 spec 的 Scope。如果 plan 里出现了 spec 明确说“不修改”的文件那就说明 spec 写得还不够强势或者 AI 理解偏了趁早纠正。4.2 执行阶段的喂给策略一次只给一个任务当 plan 确认无误后就可以让编码 agent 开工了。这里有一个我踩过好几回才学乖的经验不管你用的是 Claude Code 还是 Aider尽量不要一次性把整个 plan 扔给它让它“全做掉”。模型在一个超长上下文里连续执行多个子任务时注意力会逐渐涣散越往后越容易偏离原始约束。正确做法是一次只交代一个任务。比如第一步只让它“在 article_api.py 新增可选参数 tag”然后停下来检查这一步的 diff确认没问题再让它做第二步。虽然看起来多花了几轮交互但整体返工率会显著下降。OpenSpec 的 tasks 目录在这里的价值就体现出来了每个 task 文件就是一个独立的、可单独喂给 AI 的执行单元你只需要说“读取 docs/specs/tasks/003_add_tag_param.md然后开始改”。4.3 验证与回归AI 自检、测试、人肉 review 三层关卡执行完之后验证环节绝不能省。我的流程是三层第一层是 AI 自检。在 task 文件的结尾固定写一句“完成后逐条对照 Acceptance Criteria输出每次检查的证据测试命令输出、相关代码片段”。AI 会自己跑测试并把结果贴出来。这能让很多“我以为改好了”的情况在提交前就暴露。第二层是自动化测试。spec 里写了验收条件代码里就应该有对应的测试。我会要求 AI“先写失败测试再实现功能”这样测试的覆盖范围就跟验收条件焊死了。等到测试全绿基本上功能就完成了一大半。第三层才是人肉 review。人不需要再逐行看代码而是重点看 AI 有没有越界改动。我通常用git diff --stat扫一眼改动文件清单凡是 spec 的 Scope 里没出现的文件都要问一句为什么。很多次AI 会“贴心”地帮你格式化了一个无关文件或者补了一个“看起来更优雅”的公共方法这时候你就知道 scope 声明为什么重要了。5. 高频踩坑现场我遇到的五个 OpenSpec 实战问题5.1 spec 写得太细导致上下文爆炸第一次用 OpenSpec 的人很容易走另一个极端把每个函数的内部实现都写进 spec。比如“第 42 行用一个 for 循环遍历字典key 用变量 k”这种写法摧毁了 AI 的所有判断力还让整个 spec 文件变得巨长消耗大量上下文导致 AI 读到关键验收标准时反而“遗忘”了前面的细节。正确做法是只约束接口与行为不约束内部实现。你告诉它“新增 filter_by_tag 方法参数 tag: str返回 List[Article]”这就够了。至于它是用列表推导式还是 for 循环无所谓。OpenSpec 定位是需求契约不是代码生成器它管住“做什么”和“怎样算完成”把“怎么做”留给编码 agent。5.2 命令失效先查三件事有朋友问我说用了 OpenSpec 命令但 AI agent 总是不执行或者执行了也读不到 spec 文件。我通常让他按顺序排查三件事。第一确认 OpenSpec CLI 是否真的在 PATH 里。很多 agent 是在非交互式 shell 里启动的不会加载你 shell 配置文件里的路径。第二确认当前工作目录是否在 Git 仓库根目录OpenSpec 对 Git 根目录敏感子目录里跑命令经常找不到 spec 文件。第三确认 agent 的系统提示词里有没有告诉它“先读 agents.md 和当前 spec”。Agent 默认只知道“你是编程助手”并不知道你的项目有一套 spec 流程所以你得在项目说明里显式声明。5.3 多个 agent 同时操作同一个仓库的合并冲突当你开始把任务并行化让 agent A 改接口、agent B 改前端时冲突几乎无法避免。我的解决方式很朴素一个 spec 对应一个分支多个 spec 绝不共享分支。在此基础上plan 阶段就要注意文件隔离尽量让两个任务改不同的文件。如果实在改到同一个文件比如都会动到一个公共模型类那就别并行改成串行。还有一种更隐蔽的冲突两个 agent 各自往不同文件里加了 import结果引入循环依赖。这类问题靠 merge 是看不出来的必须跑一遍测试。所以我的建议是任何并行任务合并前都要在集成分支上完整跑一次测试套件不要只看 git 有没有冲突。5.4 测试驱动 vs 规范驱动不是二选一有人问我们团队已经用 TDD还需要 OpenSpec 吗这两者完全可以共存而且顺序上有讲究。规范驱动管的是“做什么”测试驱动管的是“怎么做”。OpenSpec 把验收标准写清楚TDD 把这些验收标准转成可执行测试。我给 AI 的 task 里通常会同时包含两类指令先写测试再实现最后用 spec 的 Acceptance Criteria 兜底。实际效果是测试保证了实现与预期的匹配程度spec 保证了实现没有超出范围。缺了测试spec 的验收条件只是纸面承诺缺了 spec测试可能覆盖了正确的东西但遗漏了边界。两件事配合起来AI 编码的稳定性才会真正上一个台阶。5.5 spec 过期问题需求变了但 AI 还在执行旧规范最容易被忽略的坑是需求在 AI 执行到一半时变了。如果你只是在对话框里说“等等改成另一种方案”这没问题但如果你没有同步更新 spec 文件AI 在下一步读取任务清单时会继续按照旧 spec 工作。它会用它自己的方式把新旧指令“融合”一下产出一个两边都不靠的方案。所以我的铁律是需求变更必须先改 spec再让 AI 干活。哪怕只是改一个字段名也要把对应的 spec 文件同步更新并在 plan 里标记出这次变更。你可以理解为spec 是 AI 的唯一事实来源你口头说的临时指令只能影响当前这一轮不能影响后续任务。如果发现某个计划已经执行到一半且旧 spec 被大量实现最简单的方式是新开一个 spec 并注明“Supersedes: 旧 spec 名称”让 AI 在新的上下文中重新规划而不是在旧计划的尾巴上打补丁。6. AICoding 笔试与面试用 OpenSpec 打出差异化6.1 “aicoding 笔试题怎么写”的一种高分思路最近不少公司开始把 AICoding 作为笔试题型而且越来越多地考察一个点你如何组织和拆解任务。以前大家以为 AICoding 笔试就是比谁 prompt 写得好现在实际考的是你能不能控制 AI 的行为边界。OpenSpec 恰好把这种能力外化成了看得见摸得着的工作流。拿到一道 AICoding 笔试题我的建议是不要急着让 AI 写代码。先花几分钟做一次“需求形式化”题目要求什么、输入输出是什么、隐藏约束有哪些、验收标准怎么定义。不需要真的建一个完整的 OpenSpec 工程哪怕是在答题区写一个简化版的 spec 结构都能立刻向面试官传达一个信号你不是在碰运气你是在按工程方法驾驭 AI。举个例子题目是“用 Python 实现一个 LRU Cache”。大多数人的答案可能是直接写一段标准解法。如果你能在实现之前先写三行说明“约束容量由初始化参数指定get 和 put 时间复杂度 O(1)并发安全不做要求验收随机读写 10 万次后缓存命中率符合预期”然后让 AI 按这个约束去实现你的答案会立刻在“工程化程度”上和别人拉开差距。6.2 30 分钟最小 OpenSpec demo 流程如果你想在面试里展示“我真的会 OpenSpec”在本地准备一个 30 分钟能跑完的最小 demo。我在线下分享时用的流程是这样的先花 5 分钟初始化一个临时项目和 OpenSpec 工作区然后写一个很小的 spec比如“给一个 Python 脚本新增 --verbose 参数”。接着用 AI 生成 plan检查任务顺序再花 10 分钟让 AI 按 plan 执行并补一个测试。最后 5 分钟跑测试展示 spec 的 Acceptance Criteria 逐条勾选。这个 demo 的关键不是功能多复杂而是完整展示“需求 → spec → plan → 执行 → 验证”的闭环。面试官看到的不只是你会用某个工具而是你清楚 AICoding 的步骤是怎么样的先约束再放手先验收后交付。6.3 面试官想从你身上看到的四个信号站在一个参与过技术面试的人的角度我总结一下 OpenSpec 这类经历能传递的四个能力信号。第一个是结构化拆解能力。你能不能把一个模糊需求拆成边界、数据流、验收条件这跟日常工作中的需求分析是一模一样的。第二个是控制 AI 的能力。你说出来的约束是不是可验证的决定了 AI 产出的稳定性。第三个是工程闭环意识。你会不会主动写测试、跑回归、检查 diff 范围这些习惯是装不出来的。第四个是迭代与复盘能力。当 AI 执行失败时你是直接重试还是会去修改 spec 里的歧义描述后者才是真正会用 AI 驱动开发的人。如果面试官问“你怎么保证 AI 生成的代码质量”用 OpenSpec 的实战经历来回答比空谈“我会严格 code review”要有说服力得多。你可以直接说我会先定义可执行的验收条件要求 AI 逐条自检并贴出证据然后在提交前检查文件变更范围是否越界。我在实际项目里用了大半年 OpenSpec 之后最大的体会是它并没有让 AI 变得更聪明但让 AI 变得更好用了。以前我总在对话里反复强调“注意保持原有逻辑”“别动别的文件”“记得跑测试”效果依然时好时坏。现在我把这些要求写进 spec写进 agents.md写进每个 task 的验收清单AI 的执行稳定性明显上了一个台阶。最后分享一个小技巧我会在最后一个任务里额外加一条验收项叫“self review对照整个 spec 检查自己有没有越界改动”。就这一条让 AI 在交卷前主动发现并撤回了很多次“顺手优化”。你不如也在自己的项目里试试哪怕不用完整的 OpenSpec只是把这一条加进你的 AI 编码工作流也能少生不少闷气。