1. 从“AI写代码一时爽,维护火葬场”说起
我做了十几年开发,最近这两年最深的感受是:AI编码工具已经把“写代码”这件事的门槛拉到了历史最低点。GitHub Copilot、ChatGPT、Claude,随便一个对话窗口,你描述需求,它给你吐出一大段代码,复制粘贴就能跑。看起来很美好,对吧?
但真正在一线做过项目的人,心里都清楚一个被反复验证的真理:写代码只是整个软件生命周期里最不值钱的那一环。真正烧钱、烧时间、烧头发的是接下来的事情——需求有没有被正确理解?这些代码到底在干什么?过两个月再看,还能不能改?换个新人接手,还能不能维护?
我见过太多团队陷入这种局面:AI把代码生成了,大家都挺高兴,但没人说得清这段代码背后的完整逻辑链路。需求是模糊的,代码是AI生成的,文档是不存在的,最后整个项目变成一个大黑箱。出了问题就靠猜,改功能就靠试,AI补全的代码甚至自己都不知道当初为什么要这么写。
用AI编码工具用得越狠,代码里的“隐性债务”就越多。这几乎成了行业里一个心照不宣的危机。
直到我接触了OpenSpec,才意识到AI编码这场游戏的底层逻辑可以完全不一样。它做的事情,本质上不是帮AI写代码,而是把“猜谜”变成“契约”。
题外话说一句,你可能会问:这跟“代码契约”“设计合同”这些概念有什么关系?别急,下面我会掰开揉碎讲清楚。我保证,这不是又一个包装得很高级的AI工具,而是一套能实实在在改变团队协作方式的方法论。
2. OpenSpec的底牌:AI编码不是魔法,是可验证的流程
刚开始用OpenSpec的时候,我的第一反应是:这不就是给AI编码套了个工程化流程的壳吗?但用了一段时间之后我才意识到,这个“壳”才是最关键的东西。
2.1 为什么AI编码会变成“黑箱”?
先聊个底层问题。传统开发流程里,代码是有来源的——需求文档、设计文档、接口定义、测试用例,一层层下来,每一行代码都能追溯到业务逻辑。这是软件工程这么多年沉淀下来的基本盘。
但AI编码时代,这个追溯链条断了。你打开对话框,输入一句需求,AI返回一段代码。AI是怎么理解你的需求的?它基于什么假设生成了这段代码?边界条件是什么?这些信息全部锁在AI的权重里,你根本看不见。你以为你在指挥AI,实际上你在和黑箱对话。
我举个例子,你让AI写一个“用户注册”的功能,它可能默认邮箱就是用户名,也可能默认需要手机验证码,还可能默认密码要有复杂度要求。这些假设它一个都不会跟你确认,直接写进代码。等测试发现“为什么注册不了”?你回头查,才发现AI在某个判断条件里夹带了一个你根本不知道的预设。这种问题,在传统开发里靠代码评审就能拦住,但在AI编码流程里,评审的人根本无从审起,因为AI生成的时候就已经把假设固化进去了。
OpenSpec的思路恰恰是把这段对话过程外置化。它不管AI最终写出什么代码,它只要求你先把“需求意图”变成“可验证的规格说明”。AI做的所有事情,都必须在这个规格说明的约束下完成。代码可以黑箱,需求不能黑箱。
2.2 OpenSpec到底是个什么样的东西?
通俗地讲,OpenSpec是一套人与AI协同开发的工作协议。它把AI编码流程拆成了几个明确的阶段:
| 阶段 | 产出物 | 核心目的 |
|---|---|---|
| 需求澄清 | 规格说明(Spec) | 把模糊需求变成可验证的约束 |
| 计划生成 | 任务清单(Tasks) | 把大规格拆成可执行的小步骤 |
| 代码执行 | 代码变更(Changes) | 让AI在约束范围内生成代码 |
| 验收验证 | 验证报告(Validation) | 确认代码是否满足规格约束 |
它强制要求你和AI之间先建立“契约”,再动手写码。这个“契约”让AI编码工具从一个“猜谜大师”,变成一个按图施工的工程队。
业界有句话叫“开源即信任”,OpenSpec本身就是一套开放规范,你在GitHub上就能找到并接入自己的项目。它不是哪个大厂闭源的工具链,而是一个社区驱动的协作契约标准。这也是我对它另眼相看的原因——它不绑死某一家AI厂商,GPT、Claude、开源模型都能接入使用。
2.3 契约到底“约”的是什么?
我用一个生活化的类比来帮你理解。
想象你家里装修。传统AI编码方式是什么?你走到装修师傅面前,说一句“给我装个厨房,要现代风格的”,转头就忙别的去了。等装修完你跑回来一看——师傅确实装了厨房,但全屋用了复古风,水槽装在岛台正中,灶台紧贴墙壁,燃气管道绕了一圈。你能说师傅不听指挥吗?人家确实装了厨房啊。问题出在哪儿?出在你没跟师傅把“现代风格”这四个字具体成“柜门无拉手”“台面用石英石”“水槽靠窗”这些可验证的细节。
OpenSpec要你做的,就是在开工之前,先把这些细节写成一份双方都认账的“装修合同”。合同上写清楚:尺寸、材料、位置、验收标准。AI就是那个装修师傅,它负责干活,但活干得对不对,照着合同量一下就知道了。
这背后的核心原则只有一条:需求必须可验证,验证必须可自动化。做不到这两点,AI编码就永远是抽卡游戏,花钱抽到什么看脸。
老实说,我第一次尝试把项目需求转成OpenSpec格式的时候,花了好几个小时,觉得这货实在太啰嗦了。每个功能要点都得写清楚“当什么条件成立时,系统做什么事”,简直像在写法律条文。但跑通第一个完整闭环之后,我真香了。
3. 为什么“契约”比“补全”更香:一个真实的重构案例
光说概念不落地,那是耍流氓。我拿一个自己前阵子做的项目,带你看看OpenSpec实际是怎么工作的。
3.1 项目背景:一个被我写废的订单模块
我手头有个电商后台项目,订单列表、订单详情、状态流转这些逻辑初期开发得很快。但问题是,随着业务规则越来越复杂,订单状态开始失控——同一个订单,在某个页面上显示“已支付”,在另一个接口里却查出来“待发货”,仓库同事天天跑来问“这单到底是发还是不发?”
泥菩萨过江自身难保,我开始着手重构订单状态机。如果是以前,我大概率会打开一个对话窗口,把现有代码粘进去,告诉AI“帮我重构订单状态流转,要支持各种边界情况”,然后祈祷AI不要搞出更多幺蛾子。
这一次,我决定试一下OpenSpec。
3.2 第一步:把“模糊需求”翻译成“可验证规格”
在写任何一行代码之前,我先面对一个残酷的现实:我不知道自己到底要什么。
这话听起来有点蠢,但它是真的。我只知道“订单状态要清晰可控”,但“清晰可控”具体是什么?说不清。
于是我把所有订单状态列出来,跟业务方过了一遍每个状态的前置条件、后置动作、流转边界。然后把它们写成OpenSpec的规格声明。你可以理解为一组组的“约束条款”,每一条都是可测试的:
功能:订单状态流转 约束一:初始状态必须为“待支付” 约束二:仅当支付成功回调到达时,状态才能从“待支付”切换为“已支付” 约束三:已支付订单发起退款并审核通过后,状态切换为“已退款” 约束四:已支付订单超过30天未发货,系统自动标记“异常待处理” 约束五:任何状态下不得跳过中间状态直接切换至终态,除非触发“强制关闭”管理操作你看,这些条款我不需要会设计数据库,也不需要懂设计模式,我只需要把业务规则讲清楚。而这恰恰是写代码之前必须想清楚的东西,以前我老想跳过这一步。
OpenSpec强迫你面对这个问题:你真的知道你的业务在干什么吗?
3.3 第二步:让AI在契约里“戴着镣铐跳舞”
规格写好了,接下来才是AI的活儿。我把这份规格文件交给AI编码工具,告诉它:基于这组约束,设计一套订单状态机实现。
有意思的事情发生了。以前AI是自由发挥,现在AI是在“条文约束”下进行“条文解释”。比如它生成的代码里,每一个状态切换方法都必须声明自己“满足哪一条约束”,同时提供相应的验证用例。
我对代码做了一次抽查,发现AI居然会自己识别规格之间的潜在矛盾,比如某条业务规则说可以退款,但订单实际已经发货了,流程上会产生冲突。它会主动在变更说明里标出来,问你是按“退货退款”处理,还是单独走“售后流程”。这种问题,放在以前黑箱模式里,代码早就生成了,等测试阶段才会暴露出来。
3.4 第三步:把AI生成的代码纳入验证闭环
这一步是整个流程里最有含金量的部分。OpenSpec本身就是一套可执行的规格——规格文件写好了,验证脚本也通过工具半自动生成了。
每次AI修改完代码,我就跑一遍验证套件,检查规格约束是否全部满足。不满足?打回重做。满足了?代码才算真正“被接受”。
这个过程的体验和一个经典的工程概念极其相似——你几乎等于在给AI编码加了一组自动化测试,跑不通就不算完成。这种方式彻底把“AI写了一堆看起来很对的代码”变成了“AI写了一堆每条逻辑都能被证明的代码”。从源代码到业务约束,每个点都可以对齐,黑箱被切开了。
我这边重构订单状态机,规格约束写了十几条,AI生成的代码改动涉及好几个模块,但整个重构过程非常稳。以前AI重构代码,我最怕“改一个bug引出三个bug”,而这次因为约束验证跟得上,遗留问题被压缩到了一个很低的水平。
4. 踩坑实录:OpenSpec不是银弹,这些坑我替你踩过了
任何工具都有它的适应边界和理解成本。OpenSpec用起来有一套自己的心智模式,理解不到位,反而会觉得这东西“又重又难用”。
4.1 坑一:把Spec写成“小学生作文”
这是新手最容易犯的错误。很多人刚开始写规格说明,写着写着就变成了:“页面加载后,点击按钮,弹出提示框,用户输入内容,点击确定,数据提交到后台。”这是流程描述,不是规格约束。
OpenSpec要的是可验证的断言。比如“当用户点击提交按钮时,如果输入内容为空,必须提示‘输入不能为空’且不允许请求后端”。后者才能被测试,前者只能被阅读。
说白了,Occam’s Razor在这里不适用。写Spec的时候宁可啰嗦,也不能模糊。每一个“必须”“禁止”“仅当”都是未来验收时的仲裁依据。
4.2 坑二:希望AI自动演进Spec
我曾经天真地以为,代码重构完之后,Spec就可以扔进仓库吃灰了。结果下一次迭代改需求,代码变了,Spec没变,整个流程的直接崩掉——你辛苦确认过的契约没有跟上实际演进。
后来我才形成了一个习惯:每次改代码前,必先改Spec;代码改了多少,Spec同步多少。这个规则听起来很简单,但实际操作中特别容易被忽略,因为Spec的改动节奏和代码改动节奏并不总是一致——业务变快了,你先改了代码想后面补Spec,结果一忙起来就忘了。
我自己总结了一个小技巧:让Spec文件跟代码文件放进同一个Pull Request,Review的时候先看Spec改动,再看代码改动,确保两者逻辑对齐。这一条基本能从机制上避免“代码与契约脱节”的问题。
4.3 坑三:把Spec当成一次性项目管理文档
有些项目经理看了OpenSpec之后很兴奋,觉得“这不就是PRD吗?让产品经理写不就行了?”——这个理解有偏差。
OpenSpec的规格说明,面向的对象不仅仅是人,更是机器。它设计的初衷,是让这些规格说明能被工具解析、被测试执行、被AI用于推理。与常见的PRD相比,OpenSpec最有价值的招牌能力是:规格说明本身就能参与验证,而不是躺在文档系统里当做一份静态的备忘录。
如果你只是把OpenSpec当换了个模板的产品文档来写,那你就等于拿金锄头刨地,完全没发挥出这套方法论的价值。
| 维度 | 传统PRD | OpenSpec规格 |
|---|---|---|
| 表达形式 | 自然语言 + 原型图 | 结构化断言 + 约束条件 |
| 验证方式 | 人工评审 | 自动化/半自动化验证 |
| 变更管理 | 版本管理重 | 直接参与CI/CD流程 |
| 读者对象 | 产品、开发、测试 | 人 + AI + 测试工具 |
4.4 坑四:试图“一步到位”铺到整个项目
我最初上手OpenSpec,图样图森破地想把整个电商后台所有模块全部纳入规格化管理。结果呢?光写规格就写了一周,项目进度完全停摆,我自己差点先崩掉。
正确姿势是小步快跑——先挑一个你最有痛感、状态最混乱的模块,比如订单状态机,或者权限系统,把这一块儿的Spec写好、代码重构完、验证跑通。等到团队真正体验到“黑箱被打开”的快感之后,再逐步推广到其他模块。
5. 环境实操:从零到一搭建OpenSpec工作流
说一千道一万,不如跑一个真实的流程。我拿自己最常用的一套技术栈来演示,你在自己电脑上就能复现。
5.1 环境准备与最小配置
OpenSpec本身不依赖某个特定的IDE,但我个人推荐在VS Code里通过终端操作,因为CCGui等工具可以帮你在编辑器里直接可视化地查看Spec变更集。当然你不装也行,纯命令行也完全够用。
我这里演示的是Linux环境的流程。很多朋友可能用的是Windows,其实现在的WSL Ubuntu写代码体验已经很接近macOS了,配合一款更接近macOS视觉体验的终端字体,整体观感会好很多。这里顺便提一嘴,如果你在WSL里写C/C++,VS Code默认字体会有一种怪怪的使用感,替换成等宽风格的现代字体(比如“Cascadia Code”“JetBrains Mono”)之后,符号对齐和视觉舒适度都会上来,尤其处理OpenSpec这种大量结构化文本时,眼睛舒服很多。
核心依赖其实就一个:Python 3.10+,因为OpenSpec的命令行工具依赖比较新的Python特性。建议用虚拟环境隔离,别污染系统Python。
# 创建并进入一个虚拟环境 python3 -m venv openspec-env source openspec-env/bin/activate # 安装OpenSpec命令行工具 pip install openspec注意:如果你在Windows上使用WSL,强烈建议所有操作都在WSL的Linux环境内完成。避免在Windows原生环境里混用工具链,文件权限和路径分隔符的问题会让你生不如死,这是我用血泪总结出来的教训。
5.2 初始化一个OpenSpec项目的完整过程
装好工具之后,进入你的项目目录,执行初始化命令:
cd ~/projects/my-ecommerce openspec init这个命令会在项目根目录下生成一个.openspec/目录,里面默认的目录结构长这样:
.openspec/ ├── specs/ │ └── 001-order-status.md ← 规格说明文件 ├── logs/ │ └── changelog.md ← 变更日志 └── config.yaml ← 工具配置specs/目录是我们写Spec的地方,logs/目录记录变更历史,config.yaml控制验证行为。
5.3 用命令行执行一个完整的Spec验证
规格文件写完之后,我们做一次本地验证,看看规格本身有没有描述模糊或冲突的问题:
openspec validate specs/001-order-status.md输出结果类似这样:
Validating specification: 001-order-status ✓ Constraint 1: initial state "PENDING_PAYMENT" ✓ Constraint 2: payment callback transitions ✗ Constraint 3: refund requires shipment cancellation Warning: Constraint 3 conflicts with existing order flow in module `orders/services/status.py`你看,工具会在写代码之前就把规格跟现状的冲突点揪出来。这一步帮我省掉了大量后端的“返工试错”。
建议把这条验证命令直接挂进CI流水线里:
# .github/workflows/spec-validation.yml name: Validate OpenSpec on: [pull_request] jobs: validate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 with: python-version: "3.12" - name: Install OpenSpec run: pip install openspec - name: Run validation run: openspec validate .openspec/specs/有了这一步,每一个Pull Request的开发者都会在合并之前被强制跑一遍规格验证。老代码可以黑箱,但新提交进来的代码,必须跟契约对齐。
5.4 接入AI编码工具(以Claude/ChatGPT为例)
工具链搭好了,AI怎么接进来?其实很简单,OpenSpec把规格定义成了文本文件,你可以直接把Spec内容复制给AI,也可以把.openspec/specs/目录作为当前代码库的上下文让AI工具读取。
我通常用的Prompt参考结构是这样的:
你是一个严格遵守规格说明的编码工程师。 请阅读 .openspec/specs/001-order-status.md 中的约束。 根据这些约束,修改订单状态机相关模块的代码。 要求: 1. 每次修改前,先列举你计划修改的文件和方法,并标注对应满足哪一条约束。 2. 修改完成后,提供可执行的验证用例。 3. 如果发现约束之间存在冲突,禁止自行修改约束,必须先向我指出冲突点。你看,这里的关键是让AI“带着追踪号”写代码。每一段输出都指向具体的契约条款,从机制上避免自由发挥。
5.5 从“验证”到“自动生成代码”的进阶操作
如果你想要更强的自动化,还可以让OpenSpec工具从规格描述直接生成代码草稿。这一步相当于把AI编码从“人审代码”升级成“条条约束可追踪、可验证”的检验。
我实测下来,规格写得越“死”,AI生成的代码越“活”。这不是悖论,而是因为约束越明确,AI不需要浪费算力去猜边界条件,它可以把全部精力放在实现细节的优化上。给你的AI自由,不如给它约束。这句反直觉的话,恰恰是OpenSpec整个方法论最核心的洞察。
6. 当“契约”成为团队共识:OpenSpec对协作模式的深层影响
工具层面的东西聊完了,最后我想聊一个更宏观的话题——OpenSpec真正改变的是什么?
6.1 程序员从“翻译官”变成“制定规则的人”
以前写代码,本质上是在当翻译:把自然语言翻译成编程语言。AI编码普及之后,这个翻译动作已经不需要人了,AI比你翻得还快。那程序员的价值在哪里?
OpenSpec给出的答案是:程序员不再是翻译官,而应该变成制定规则的立法者。最重要的能力不再是“怎么实现”,而是“约定什么”。规格说明的撰写质量,直接决定了代码质量和项目下限。
这不是技能降级,这是技能平移。你从跟机器较劲,变成跟复杂度较劲。以前需要掌握很多编译原理才能写出的高质量代码,现在更需要的是业务洞察力和逻辑建模能力。
6.2 测试与开发的边界被打破
传统分工里,开发写代码、测试写用例,两者之间经常存在敌对关系。开发觉得测试吹毛求疵,测试觉得开发不关心质量。
在OpenSpec模式下,规格说明本身既是开发的输入,又是测试的基线。开发写代码时,脑海里想的不是“这段代码能不能编译通过”,而是“我的实现能不能通过规格约束”。测试人员也不再需要从一团迷雾里设计测试用例,直接从Spec里派生用例就行了。
6.3 代码评审从“看人脸色”变成“对着契约说话”
Code Review是团队质量保障的重要一环。但传统Review高度依赖评审人的经验、状态、熟悉度。你让一个对业务不熟的新人去做Review,他大概率只会说“这代码风格不错”“这里缺个注解”。
有了OpenSpec这层“契约”之后,Review就发生了一个有意思的变化:评审人不再是漫无目的地找茬,而是拿着规格一项项核对实现。代码风格问题反而成了次要矛盾,重点变成了“你的代码是否兑现了契约”。这样一来,评审的客观性大幅提升,新人也可以快速上手做严谨Review。
我自己的体会是,代码评审的氛围也微妙地变好了。以前给同事提修改意见,多少有点“我比你懂”的微妙尴尬。现在是双方对着同一份Spec对齐,意见分歧变成了对规格理解的分歧,理性了不少。
6.4 对个人开发者同样适用
你可能会觉得这套流程是团队协作才用得上,个人项目杀鸡焉用牛刀。但我的真实感受恰恰相反:个人项目才是最容易暴露黑箱危机的。
单人开发时没有队友可以帮你把关,AI写的代码跑过了就算“通过了”,但跑过不代表逻辑正确。等三个月后你回头看这一段,根本记不起来当初为什么这么写。而OpenSpec留下的规格文本,相当于给未来的自己留了一张项目地图。哪怕是给自己写契约,也远比靠记忆靠谱得多。
7. 写在最后的一点真心话
用OpenSpec这半年多,我最大的感受不是“代码质量变高了”这种笼统的结论,而是“我对项目的掌控感回来了”。
做开发最焦虑的时刻从来不是上线时出故障,而是你不敢保证下次改动不会引发新的故障。黑箱代码就像一个不断膨胀的气球,你看着它越来越大,却不知道哪一天会爆。OpenSpec至少给了我一个抓手,让我知道每一处代码背后有哪条契约在兜底。
老实说,这个工具的养成成本不低,前几个项目你可能会觉得很束缚。但一旦形成了“Anything that cannot be verified does not exist”这种思维方式,你的编码习惯、需求分析习惯、Review习惯都会发生质变。
我最后分享一个自己一直在用的小技巧:每个模块的Spec文件,我会在文件头部写一段“这段契约在保护什么”。这段大白话不需要结构化,不需要可执行,它就是写给下一个接手的人看的。比如:
# 这段契约在保护什么? # 订单状态流转模块是整个后台最核心的资产, # 这里的状态错乱会直接导致财务对账不平、仓库发货失误。 # 因此本模块的每个状态流转必须可追踪、可回滚、可验证。工具会过时,方法论会迭代,但搞清楚“你的代码到底在保护什么”这件事,任何时候都不过时。OpenSpec只是帮我把这个问题用工程的、验证的方式落地了。