最近在折腾 AI 辅助开发发现一件让我挺头疼的事模型写代码越来越快但代码“偏”得也越来越离谱。让它加个功能它顺手把无关模块重构了让它修个 bug它自作主张改了接口命名。后来我开始用 OpenSpec 这套规范来约束整个流程实测了一两个月开发节奏顺了不少。OpenSpec 说白了就是一套面向 AI 编码场景的规范格式核心思路是用结构化的 Markdown 文件把“需求、验收标准、任务拆解、进度状态”写清楚让 AI 拿到的不再是一句模糊的 prompt而是一份它真正能读懂、能照着执行的设计文档。今天我把它拆开揉碎了讲一遍包括我踩过的坑、摸索出来的写法以及怎么跟手头的 Git 工作流、Code Review 流程配合起来。1. 我为什么从“提示词驱动”切到 OpenSpec先说背景我日常维护的是一个中型的业务系统代码量不算小前后端加起来 30 多万行。早先我带团队用 AI 编码流程非常简单粗暴开个对话窗口把需求粘贴进去让模型直接改代码改完人肉看一遍差异就提交。前几次体验确实惊艳但项目复杂之后问题频繁冒出来。1.1 AI 写代码最让人崩溃的三个场景第一个是需求漂移。你说“给订单列表增加一个导出按钮”模型非常敬业顺手把订单状态机、日志上报、权限校验全部重构了一遍。看起来是好意但你根本分不清哪些改动是必须的哪些是它自己脑补的。第二个是重复劳动。同一个小需求今天让 A 模型改一版明天让 B 模型改一版两版实现思路完全不同。代码风格统一不了后面维护的成本全压在人身上。第三个是验收无依据。模型说自己“完成”了你让它在测试环境点一遍发现边界值全是坑。问题出在哪因为需求描述里根本没写清楚什么算完成。1.2 我试过的替代方案为什么不够用一开始我想用注释规范、代码检查规范来兜底比如强制 JSDoc、ESLint 严格模式。确实能拦住一部分低级错误但拦不住“方向错误”。后来试过把需求写成详细的 PRD 文档再喂给 AI文档是写清楚了但模型读起来费劲经常把结论性描述当成可执行步骤效果也不稳定。真正让我下决心换思路的是一次排期很紧的功能开发。我一口气把需求拆成十几个小任务每个任务对着一个明确的验收标准。那一次 AI 的产出质量稳定得惊人我基本只需要做轻微 review 就能合入。后来我才意识到问题不在 AI 能力而在我给它看的材料。AI 编码工具更像一个执行力极强的实习生它需要的是高密度的约束文本而不是散文式聊天记录。OpenSpec 恰好提供了这样一套文本组织格式。2. OpenSpec 的核心机制我是怎么理解它的OpenSpec 的名字虽然带“Spec”但和传统软件工程里的需求规格说明书是两回事。传统规格书是给人看的写得再详细模型依然要从中“二次理解”。OpenSpec 的设计目标是让规范文档同时能被人和模型高效读取。2.1 最基础的目录结构与文件约定我习惯在仓库根目录建一个specs/文件夹下面是所有功能规格的存档区。每个功能都单独建一个子目录目录名就是功能名用短横线连接。比如specs/ order-export/ proposal.md tasks.json progress.mdproposal.md描述这个功能“是什么、为什么做、边界在哪”。tasks.json把实现过程拆成可并行的子任务。progress.md则是执行过程中的状态记录类似任务看板。这套结构的好处是模型拿到specs/order-export目录后不需要我额外讲解就能明白自己要从哪个文件开始看、当前做到哪一步、下一步要产出什么。2.2 写好验收标准的关键可测试、可判定OpenSpec 里我最看重的是proposal.md中的验收标准部分。刚开始我写得特别含糊比如“导出功能应正确工作”。后来我发现这种话写不写没区别。真正有效的验收标准每条都要做到能通过代码或操作直接判定真伪。我一般写成三行格式给定某个前提、执行某个动作、得到某个可观测结果。举个例子## 验收标准 - 给定订单列表中存在 100 条记录且当前筛选条件为“已支付” - 当用户点击“导出当前筛选结果”按钮 - 则浏览器触发一个文件下载文件名格式为 orders_YYYYMMDD_HHmmss.csv且文件内包含且仅包含这 100 条订单数据模型看到这种描述整个思考路径会明确多因为它不需要猜测“正确”是什么意思只需要对着代码一项项验证。2.3 状态流转与版本化记录另一个很实用的机制是progress.md的状态标记。每完成一个子任务就在对应条目后面更新状态。AI 在下一轮继续干活时先读一遍状态记录就能精准接上进度不重复造轮子。这其实和我们平时用 Git 管理代码是一个道理。代码有版本需求描述和任务进度也要有版本。OpenSpec 把“开发过程中的中间产物”——也就是需求理解、任务拆解、验收标准——全部纳入版本管理让整个开发链路可追溯。3. 从零开始用 OpenSpec 驱动一次完整开发说了这么多概念接下来拿一个我实际做过的功能完整走一遍流程。这个功能叫“库存预警通知”核心诉求是当商品库存低于安全阈值时系统自动给运营人员发送站内信和邮件。3.1 第一步先把需求和边界写进 proposal.md我没有直接让 AI 动手写代码而是先花一个小时自己写proposal.md。很多人觉得这一步浪费时间我反而觉得这是整个流程里最值钱的半小时。我在这份文档里写清楚了几件事功能背景库存不足导致超卖投诉率上升需要提前通知运营。功能范围只做后台库存模块的预警监测不做前端展示不做供应商通知。触发条件库存量低于 3 件时触发且同一商品 24 小时内只能通知两次避免轰炸。非目标本期不接入短信渠道不处理赠品库存。特别要注意“非目标”这个字段。开始写的时候我也觉得多余后来发现它极其重要。AI 非常擅长给自己“加戏”没有明确边界它可能顺手把促销活动、价格策略全包进来。边界写清楚模型反而更好理解什么不该动。3.2 第二步把整个功能拆成可验证的任务清单写tasks.json时我遵循一个原则每个任务都能独立验证并且任务之间的依赖清晰。我拆出来的任务大概长这样{ tasks: [ { id: task-1, title: 设计库存预警数据模型, depends_on: [], validation: 新增 inventory_alert_rule 表结构包含商品ID、安全阈值、通知间隔字段并包含对应的数据库迁移脚本 }, { id: task-2, title: 实现库存变更监听逻辑, depends_on: [task-1], validation: 商品库存字段更新时触发一次预警检查单测覆盖低于阈值和恢复阈值两种场景 }, { id: task-3, title: 实现通知去重与限流逻辑, depends_on: [task-2], validation: 同一商品在配置的通知间隔内不会被重复通知有对应的单元测试证明 } ] }depends_on字段很关键它明确告诉 AI 哪个任务要做在前面。没有这个字段的话AI 经常会把数据库变更和业务逻辑同时写掉一旦数据库设计有问题后面全部返工。3.3 第三步让 AI 按任务逐个实现并把进度写回 progress.md任务拆好之后我并没有一次性把所有任务都丢给 AI 处理。一次只丢一个任务让它读完对应的 spec 和当前进度然后开始编码。每完成一个任务我都会强制它在progress.md里更新状态写下“完成了什么、引用了哪些文件、下一步计划”。这一个“每完成一步就写一步”的习惯起初非常反直觉——感觉像是给 AI 增加额外工作。但实际运行一周后好处非常明显中途如果切换模型或者讨论中打断了上下文新的会话只需要读一遍progress.md就能接上不需要我重新解释背景。3.4 验收环节把标准当成测试用例执行所有任务完成后我拿proposal.md里的验收标准挨个过了一遍。其中有一条是“库存低于阈值时预警通知在 5 秒内发出”。第一版实现里通知任务做成了异步队列调度延迟不稳定部分场景下超过 10 秒。如果按照传统开发方式这种问题可能要等上测试环境后才能暴露。但因为在 OpenSpec 里验收标准是写出来的AI 实现阶段就会主动考虑性能问题。后来它给我的第二版方案直接改成了实时内存计算加异步分发测试结果满足 5 秒约束。这个经历让我明白一个道理给 AI 写验收标准本质上就是在做测试驱动开发。只不过 TDD 的测试用例是代码OpenSpec 的验收标准是先写成文档再转化成代码逻辑。4. 用 OpenSpec 流程时我踩过哪些坑、怎么填平这部分是我最想分享的内容。网上讲 OpenSpec 理论的多讲真实踩坑的少。我按踩坑频率排个序把最有代表性的问题列出来。4.1 问题一规范文件写得太全反而让模型手足无措最开始我追求“规范文档越详细越好”一份 proposal 写了几百行把数据库字段、接口路由、前端组件全部定义死了。结果模型确实不敢乱来了但也变得畏手畏脚有些非常普通的逻辑非要回到文件里找依据开发效率明显下降。后来我调整策略把规范分成两层高层规范只写“做什么、边界、验收标准”。低层技术选型只给约束不给具体方案。例如我告诉它“缓存模块必须使用现有 Redis 封装不允许引入新依赖”但到底用哪个 key 格式留给它自己设计。这样模型既不会走偏又有发挥空间。4.2 问题二验收标准里混进了“形容词”AI 无法判断对错早期的proposal.md里我写过“导入速度要快”“界面要美观”这类话。AI 看到这种描述除了瞎猜没有别的办法。后来我给自己定了个硬指标验收标准里不允许出现比较级词汇。凡是形容词必须改成可量化的约束。“速度快”改成“导入 1 万行数据耗时小于 5 秒”。“界面美观”改成“弹窗在 1280 宽度下无横向滚动条按钮间距不小于 8 像素”。这套写法开始觉得别扭但坚持下来之后我发现不仅 AI 产出稳定了连后来做人工 Code Review 都轻松不少。因为验收标准就是最清晰的评审清单我不用自己脑子再过滤一遍“这里到底算不算完成”。4.3 问题三没有机械执行检查AI 也会“自我感觉良好”AI 生成的代码经常出现“看着没问题、一跑就报错”的情况。我一开始过于信任验收标准模型说“已验证通过”我就信了。后来发现不行它所谓的“验证”有时候只是读了读代码。解决办法是我在任务验收阶段加入了一个“必须执行指令”。我在提示词里明确要求完成实现后必须运行对应的测试命令和 lint 命令并把输出结果贴到progress.md里。这一步加上后模型的“自我感觉良好”现象大幅减少。后来又更进一步对关键任务我要求它额外写一个最小复现脚本。脚本不复杂可能只有二三十行但能直接展示核心路径的运行结果。这样一来AI 的产出就不再是“代码片段”而是一堆“可运行证据”。4.4 问题四多专业协作时大家理解同一份规范的方式不一样OpenSpec 刚在团队里推广时不是所有人都接受。后台开发觉得 Spec 文档写得像需求文档前端开发觉得验收标准太技术化测试同事觉得没有直接可用的测试用例。我的折中方案是把proposal.md里的验收标准做成一张“双向映射表”每条验收标准都标注对应的任务 ID 和实现文件路径。这样后端对着任务看代码前端对照验收标准看交互测试同事直接按表转化成测试用例效率反而提升不少。4.5 高频问题速查表为了方便参考我把实践过程中遇到过的最典型问题整理成了表格。问题场景根本原因我的处理方式AI 擅自扩展需求范围非目标没有写明在 proposal 中设“非目标”段明确什么不该做模型实现方向正确但接口设计很怪技术约束不足在 tasks.json 中增加接口约定字段同一功能多次实现代码风格差异大缺少风格基线在 specs 根目录放一份 coding-standards.md 作为全局规范任务依赖混乱导致返工依赖关系没定义严格遵守depends_on未完成前置任务不允许执行后续任务模型报告的进度与实际代码不一致没有强制更新进度文件明确要求每次改动后必须更新 progress.md 并附运行结果文档写得太全开发速度反而慢方案空间被封死区分“硬约束”和“建议”只约束必要项5. 把 OpenSpec 嵌进团队现有的开发流程用了几个月之后我的感受是OpenSpec 的最优解不是取代开发流程而是嵌在现成的 Git 工作流、Code Review 和 CI 流程里。几个人以下的个人项目可以像我一样轻量使用十人以上的团队则需要进一步建立共识。5.1 分支策略与规范文档同时变化我在 Git 工作流上的习惯是从main开一个分支做功能分支跑通后再合并。落到 OpenSpec 上每个功能分支对应一个specs/功能名/目录。分支合并时规范目录跟着代码一起进main保证主干上的规范文档始终和代码状态同步。这里有个细节值得多说几句我不建议在代码合并后再去补规范。因为一旦规范文档落后于代码它就彻底失去意义了——AI 下次读这份规范时会以为旧逻辑还是当前逻辑。5.2 Code Review 时先看 Proposal 再看代码以前 Code Review 我是直接打开 Diff 逐行看费眼睛而且容易漏。现在我的顺序变了先读这个功能的proposal.md验收标准再对照 Diff 检查实现与验收标准之间的对应关系。这其实很像测试人员先看用例再看实现的做法。发现差异的时候我会直接在评审意见里引用 proposal 里的验收标准编号。比如“AC-03 要求 24 小时重复通知次数不超过两次但当前实现完全没有缓存去重逻辑”。评审意见一旦有了编号锚点讨论起来特别高效因为大家都知道在说哪一条。5.3 结合现有检查代码规范的工具链有人问过 OpenSpec 和传统 lint、代码检查工具是什么关系。我的理解是这样的代码检查工具负责“代码长得好不好看、有没有低级错误”OpenSpec 负责“需求理解对不对、任务拆得准不准、验收标准有没有达成”。两者是互补关系不是替代关系。我自己的实践是在 CI 里保留了全部原有的 lint 和类型检查再额外加一道“规范一致性检查”大概的伪代码逻辑是for spec in specs: tasks load_tasks(spec) progress load_progress(spec) for task in tasks: if task.id not in progress.completed_tasks: fail(fTask {task.id} 未完成)这行脚本不复杂但它能保证“流程上的完成”和“代码上的完成”对齐。没有这种硬检查“AI 说完成了、实际上没有”的事情还会反复发生。5.4 个人开发者和小团队的轻量用法如果你现在只是一个人在用 AI 写项目完全不用把流程搞得太重。我建议先保留三个文件就够了proposal.md、tasks.json、progress.md。coding-standards 和更复杂的版本策略等项目变大后再加。我见过一些人把 OpenSpec 用成“写作文大赛”规范文档洋洋洒洒几千字代码倒没写几行。这是走了另一个极端。合理的参考比例是一个中大型功能大概一周开发量规范文档整体控制在 300 到 500 行以内重点写透验收标准和任务边界。6. 关于 OpenSpec我最后的几条心得回到最初的问题我为什么觉得普通开发者应该掌握 OpenSpec因为现在的 AI 编码工具已经足够强了真正稀缺的不是“让模型写更多代码”的能力而是“让模型朝正确方向写代码”的控制力。OpenSpec 提供的就是这种控制力的最小可用实现。我个人在实际操作中的体会是它逼着我养成了两个好习惯。第一个习惯是动手写代码前永远先把“什么叫完成”定义清楚第二个习惯是每个任务做完把运行证据留存下来。这两个习惯看起来朴素但在 AI 驱动开发的时代它们比炫酷的模型选择重要得多。如果你正准备在下一个项目里引入这套思路我建议从一个小功能开始试水。不需要一下子把所有规范流程都铺开先把proposal.md写好、验收标准量化、任务拆细让 AI 按任务清单走一遍。跑通一次你就能直观感受到原来让 AI“听话”不是靠多几个限定词而是靠一份结构严谨、边界清晰的规范文本。最后再分享一个小技巧规范文档本身也可以让 AI 帮你 review。我经常把写好的proposal.md丢给模型问它“这份规范里有哪些验收标准无法被机器判定哪些任务边界存在歧义”。模型给出的意见往往一针见血毕竟它最了解自己这类模型在读文档时会卡在哪些地方。这个逆向思路是我实践下来最受益的点建议你也试试。