十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

OpenSpec:AI编程先立规矩,用规格文档治住失控的代码生成

OpenSpec:AI编程先立规矩,用规格文档治住失控的代码生成 OpenSpecAI 写代码先立规矩再动手这几天好几个朋友都在问同一个问题为什么我用 Cursor / Codex 让 AI 写代码改着改着就失控了一开始改得挺快到后面越改越乱甚至把原来的正常功能搞崩了。这个问题我前阵子也遇到过后来接触了 OpenSpec 这套工作流才意识到问题不在 AI 本身而在我们压根没给 AI“立规矩”。OpenSpec 说白了就一句话在让 AI 动手改代码之前先写清楚一份规格说明spec把“要做什么、为什么做、边界在哪、怎么验收”全都定下来然后再让 AI 照着这份规矩执行。它不是什么新编程语言也不是传统意义上某个具体软件而是一套面向 AI 编程时代的工作方法和配套工具链。适合谁适合那些每天跟 AI 结对写代码的人——不管是独立开发者、自由职业者还是团队里的技术负责人只要你发现“AI 改来改去失控”这个问题OpenSpec 就是来治这个病的。1. 核心思路拆解为什么“先立规矩”能治住失控的 AI1.1 直接让 AI 改代码到底出了什么问题先说一个我踩过无数次的坑。以前我用 AI 改代码习惯是直接甩给它一个需求“帮我加一个导出功能”。AI 确实很快唰唰就把代码改完了。但问题很快就来了第一次它把导出按钮加到了完全错误的位置。第二次它为了实现导出顺手重构了我的数据层连带改了三个无关文件。第三次它在导出逻辑里擅自加了一个我没要求的分页功能结果跟原有的筛选逻辑冲突整个页面直接崩了。这不是 AI “笨”而是我压根没给它边界。AI 的本质是概率生成你不给它明确约束它就按自己的“惯性理解”来自由发挥。给它一句宽泛需求它就能自由发挥出一片新天地。等到你发现跑偏已经改了一堆文件找回原状又是一场灾难。还有一个隐藏问题上下文丢失。AI 对话窗口是有限的你跟它聊了四十轮之后它早就忘了第一轮你提的什么需求。你说“把刚才那个改回去”它一脸茫然。每次对话都在重新猜你的意图没有一份固定不变的“规矩文件”它就只能靠猜。1.2 OpenSpec 怎么解决这些问题OpenSpec 的核心逻辑其实非常朴素——把“需求意图”和“代码修改”彻底分离。传统做法需求 → 直接改代码 → 改乱了 → 返工 → 更乱。 OpenSpec 的做法需求 → 写成规格文档 → 人类审核确认 → AI 按规格执行 → 按验收标准检测 → 通过才收工。这个流程里有三个关键转变第一需求被“外置”了。以前需求在脑子里、在对话里现在被落成一份 spec 文件。文件是固定的AI 每轮都能重新读一遍就不用依赖它会“记住”你的早期要求。第二AI 被“限制”了。规格里明确写清楚改动范围、不做的事、验收标准。AI 只能在框里跳舞自由度大大降低自然就不容易产出一堆意外惊喜。第三变更被“拆小”了。OpenSpec 的思路是不搞巨型重构而是把大需求拆成一个个小变更change proposal每个变更独立测试、独立验证减少失控半径。好我准备开始写正文了。1.3 它跟“直接给 Prompt”的本质区别有人可能会说那我写个详细的 Prompt 不就行了比如“请给我加导出功能不要改数据层不要动其他文件注意保留原有逻辑”。这确实比一句“加个导出”强得多但它仍然是“一次性”的。AI 这轮听了下一轮可能就忘了你这次写清楚了下次换个需求又得重新写。而且 Prompt 写得太长AI 的注意力会分散它不一定分得清哪些是核心要求、哪些是背景信息。OpenSpec 用的是结构化文件不是一段即兴发挥的 Prompt。它把需求拆成了固定字段背景、需求描述、任务清单、边界条件、验收标准。AI 每轮开工前都会重新加载这份文件每次只专注于当前任务列表里的下一步。相当于你不是在“指挥”它而是给它一份工作手册让它对照着逐步执行。我自己的感受是这个转变非常关键。以前跟 AI 对话我是“监工”每句话都要盯着生怕它跑偏。现在我是“甲方”我把要求写进合同spec然后验收结果就行。省心程度完全不在一个量级。2. 安装与初始化把规矩文件跑起来2.1 安装方式和环境要求OpenSpec 本身是一套轻量级命令行工具基于 Node.js 生态。老实说它并不是一个“必须装”的工具——你完全可以自己手动建目录、写文档这并不复杂。但既然有现成工具用它来规范流程、校验格式、生成模板能省不少事。安装很简单一行命令搞定以 npm 为例npm install -g fission-ai/openspec安装完之后在项目根目录执行初始化openspec init这个命令会在项目里生成一个openspec/目录我用的版本是spec/如果你用的版本新一些留意一下生成的实际目录名里面预置了几个子目录和示例文件openspec/ ├── spec/ │ └── 000-template/ │ ├── proposal.md │ └── tasks.md ├── agents.md └── project.md它的依赖只有 Node.js 环境。这一点对绝大多数开发者来说基本没有门槛不像有些工具还要配数据库、配 Docker装完折腾半天。OpenSpec 装完就能用核心是接下来的工作流习惯。2.2 初始配置agents.md 和 project.md 写什么初始化生成的两个文件算是 OpenSpec 工作流的“地基”我在不同项目里试过几轮觉得这两份文件一定要认真写别图省事跳过。project.md是给 AI 看的项目概述。写清楚这个项目是什么、技术栈是什么、代码结构大致怎么样。其作用有点像给新入职的同事看的部门介绍——AI 每次加载它都能快速对项目建立基本认知。如果不写AI 每次只能靠猜或者靠你反复在对话里解释这就违背“立规矩”的初衷了。agents.md则是定义“谁来干活”。这个文件用来声明当前项目里有哪些 AI 协作角色比如“执行 Agent”“审查 Agent”“架构 Agent”每个角色负责什么。这个设计在单人项目里可能有点多余但一旦多人协作或者同时启动多个 AI 任务角色划分清晰就很重要了——不然两个 AI 同时改一个文件互相踩踏那场面比一个人乱改还惨。我在实际项目中是这样配置的# agents.md ## role: executor 负责按 tasks.md 执行代码变更 约束只修改任务列表中涉及的文件不得随意重构 ## role: reviewer 负责检查变更是否满足 proposal.md 中的验收标准 约束不直接修改代码只提交审查意见你完全可以按自己的项目情况来定义角色关键是让“执行者”和“检查者”分离避免 AI 既当运动员又当裁判。2.3 为什么要初始化一个模板文件openspec init生成的000-template/是变更提案的模板里面包含proposal.md和tasks.md两份文件。平时不要动这个模板它的作用是给后续新建的变更提案提供参考格式。第一次看到这个目录结构时我觉得有点“重”——就加个小功能还要写两份文档但用了一段时间后我理解这套模板设计的意义了必须保证每个变更提案的信息完整度是一致的。如果每个提案都按模板写AI 每次读到的都是固定字段结构它的理解成本会大幅降低不会出现“这个提案没写验收标准AI 自己猜了一个”的情况。模板其实就是在降低“不确定性”。写代码这件事本身是确定的但 AI 生成代码的过程是不确定的而规格文件就是用来对冲这种不确定性的工具。模板则是让所有规格文件保持同一种“格式感”进一步减少 AI 的误读空间。3. 核心工作流实操写提案、拆任务、跑验证3.1 一个真实的 spec 应该长什么样到现在为止我们还没真正“让 AI 改代码”。别急OpenSpec 的核心恰恰在于“开工之前的准备工作”。按照这套流程每接到一个需求你首先要创建一个变更提案。命令行操作如下openspec create 添加导出功能这个命令会自动在spec/目录下创建一个新文件夹比如spec/001-add-export-function/里面也是proposal.md和tasks.md两个文件。接下来你需要手动编辑这两份文件。proposal.md是整个提案的灵魂它回答的问题是这次变更到底要做什么以及为什么做。我按自己的理解把里面最关键的几个字段拆开讲一下。背景与动机为什么需要这个功能是用户反馈还是产品需求这部分写清楚AI 才知道你做这件事的“上下文”。需求描述要做什么用清晰完整的语言描述清楚尽量不用含糊词汇。行为约束/边界条件本次明确不做什么。这一条极其重要我后面的“避坑”部分会专门展开。验收标准怎么判断这件事做完了、做对了。每条验收标准都要能直接执行比如“导出生成的 CSV 文件能正常打开且字段与页面展示一致”。以导出功能为例我写过的proposal.md大致是下面这个形态# 提案添加导出功能 ## 背景 用户反馈列表页数据多无法离线查看希望增加导出为 CSV 的功能。 ## 需求描述 在列表页右上方新增“导出 CSV”按钮点击后生成当前筛选条件下的数据文件并下载。 支持分页场景下导出全部数据非仅当前页。 ## 行为约束 - 不更改现有列表查询逻辑 - 不引入新的后端接口前端基于已有列表接口数据生成 CSV - 不修改无关组件和页面 ## 验收标准 - 按钮存在于列表页右上方点击后触发下载 - 下载文件为 CSV 格式内容包含全部筛选后的数据 - 当前列表展示逻辑不变翻页、筛选仍正常写完之后务必先自行审一遍确认所有内容都和你的真实需求一致。这一步如果偷懒AI 后续的执行就等于没有参照坐标写出来的东西大概率还是要返工。3.2 tasks.md把大任务拆成 AI 能执行的颗粒度proposal.md描述的是“做什么”tasks.md描述的是“怎么一步步做完”。我刚开始用的时候觉得 proposal 写清楚就够了tasks 随手写几条意思一下。后来发现这个想法太天真了——AI 拿到一个大目标如果中间没有步骤节点它依然会自行发挥挑一条它“觉得合理”的路径走。所以 tasks.md 一定要拆到“看得见完成点”的颗粒度。我会习惯性地把任务拆到每个任务大概 10 分钟左右能完成的程度最长不超过 30 分钟。如果某个任务需要超过半小时说明拆得还不够细。还是导出功能的例子# 任务清单 - [ ] 在列表页头部组件中新增导出按钮含样式 - [ ] 实现获取全量筛选数据的逻辑支持分页自动拼接 - [ ] 实现数据转 CSV 格式工具函数 - [ ] 实现浏览器端下载逻辑 - [ ] 添加基础错误处理导出失败时提示用户 - [ ] 按验收标准进行自查确认无损改动每一行前面都有一个未勾选状态的方括号这个记法很直接——AI 每完成一项就可以勾选方便它在长任务流程中随时确认“我现在到哪了”。另外我在任务描述里尽量写清楚“改的是什么文件、达到什么效果”而不是笼统地写“实现导出”。AI 对模糊指令的处理往往不是追问而是直接按自己的理解开工。你用更具体的话把任务说清楚它跑偏的概率才会降低。3.3 让 AI 在“开发模式”下按规矩执行提案写好了、任务清单拆好了下一步才是真正让 AI 动手。OpenSpec 在不同 AI 工具里的用法略有差异但核心逻辑一致把提案内容作为核心上下文喂给 AI然后让 AI 按任务清单逐步执行。以现在主流的 Cursor 为例你可以把整个openspec/spec/001-add-export-function/目录拖进对话窗口或者直接用“添加文件到上下文”功能把proposal.md和tasks.md都添加上然后在对话里给出明确的指令你是 executor 角色请读取上下文中的 proposal.md 和 tasks.md按照任务清单逐项完成代码修改。每完成一个任务勾选对应项全部完成后再自查一遍验收标准输出结果。我比较推荐以“你是 executor 角色”开头这能触发你在agents.md里定义的行为约束效果确实比默认状态更收敛。如果你用的不是 Cursor比如在终端里用 Codex CLI 或 OpenCode你可以在命令行中直接唤起它让它以文件路径或项目描述的方式加载 spec。思路是共通的AI 必须“读到了”提案而不是只靠对话里的口头描述。3.4 执行中的“人工节点”不能省在 OpenSpec 的完整工作流里有一个环节我强烈建议不要省提案创建后、AI 动手前的人工审核。这个环节看起来“多此一举”却是防止返工最省钱的方式。AI 生成代码很快但它未必理解你的真实业务场景。比如“导出全部数据”这个需求你得先想清楚是直接调后端接口拿全量数据还是前端循环翻页把所有数据拼在一起如果数据量特别大前端拼接方案可能会卡爆浏览器。这些业务层面的权衡AI 大概率不会替你考虑周全。如果你不加这个约束它很可能选了最“粗鲁”的方案验证阶段直接现出原形。所以我的习惯是提案写完 → 自己先看一遍 → 确认或修改 → 再交给 AI 执行。这个过程通常只花几分钟但能把大量隐患扼杀在动手之前非常划算。注意这一步千万别让 AI 自己确认自己的提案。就像写作文的人不能自己判自己满分AI 建模出来的“验收标准”很可能带着它自己的理解偏差需要你用人的业务判断来兜底。4. 与主流 AI 编程工具集成Cursor、Codex、OpenCode 实战经验4.1 在 Cursor 中最顺手的使用方式现在很多人用 Cursor 写代码它的聊天窗口和 Tab 补全确实方便。但 Cursor 默认的工作模式是“对话式修改”你问一句它答一句改完就完事缺少对规格的持续约束。所以我的做法是把 Cursor 当成 OpenSpec 工作流里的“执行终端”而不是“决策大脑”。具体操作如下。新建提案之后在 Cursor 里新建一个 Chat把proposal.md和tasks.md作为上下文文件加进来注意是把文件加进上下文不是粘贴文本然后发送上面提到的那段 executor 指令。Cursor 会按任务清单一步步执行你可以在每个任务节点之间检查代码、跑测试然后再让它继续下一步。这里有个实用技巧每次让它开始新任务之前在对话里重新发送一次指定指令提醒它“按 proposal 中的约束执行”。虽然繁琐一点但实测下来能显著降低中长期任务中 AI “跑偏”的概率。因为对话上下文越到后面越混乱早期的约束早就被挤掉了重发一次指令相当于把规矩重新立起来。4.2 Codex CLI 与 OpenCode 的接入方式如果你更习惯在终端里工作Codex CLI 和 OpenCode 也都可以配合 OpenSpec 使用。Codex CLI 是 OpenAI 推出的命令行编程工具OpenCode 则是一个开源终端 AI 编程助手。它们处理长任务的模式不同但原理大同小异它们能读取本地文件能执行命令能修改代码所以你只需要在提示词里指明让它们先读取相关规格文件。以 Codex CLI 为例我常用的命令格式是codex 请先读取 openspec/spec/001-add-export-function/proposal.md 和 tasks.md严格按照提案要求完成导出功能的实现。每完成一项任务在 tasks.md 中勾选。Codex 会先读取文件内容然后开始实现。注意 —— 如果它中途发现任务描述不清晰它可能会停下来询问。这是一个好现象说明它真的在“照着规矩做”而不是自作主张。遇到这种情况根据问题澄清补充提案即可。OpenCode 的用法类似它一样支持文件读取和执行命令同样需要你将 spec 文件路径直接告知。4.3 用 Opencode 或 Codex 做“审查 Agent”的进阶玩法前面提到agents.md可以定义多个角色。等你把 OpenSpec 工作流跑顺了就可以玩一个更进阶的用法让一个 AI 写代码让另一个 AI 来审查。我在一个中等规模的项目里实测过这个模式。我用 Cursor 充当 executor 执行代码修改用 Codex CLI 充当 reviewer让它重新读取proposal.md的验收标准逐条检查 executor 的改动是否达标。这样能发现很多单模型自查时发现不了的问题比如功能实现了但样式跟设计稿不符数据导出逻辑没问题但异常分支没处理或者改动把某个老接口的兼容性破坏了。两个 AI 角色之间靠什么连接就是agents.md和 spec 目录下的文件。executor 把改动结果写在代码里reviewer 通过 Git diff 查看改动内容并对照提案审查。这就是“规矩”的价值——有了同一个规矩文件不同 AI 才能在同一个坐标系里讨论问题而不是你说你的、我改我的。5. 常见问题与排查技巧实录5.1 一个提案写了 20 条任务AI 执行到一半开始发疯用这套工作流一段时间后我遇到过不少问题挑几个典型场景分享一下。问题现象提案里列了 20 个任务AI 执行到第 8 个任务时突然开始重写其他文件或者完全脱离任务清单自由发挥。原因分析任务清单太长AI 的上下文里装着 20 个任务注意力被分散了。它可能在执行第 8 个任务时“联想”到之前某个任务里提到过的边界情况于是开始主动“优化”。这不是它故意捣乱而是大模型的注意力机制本身就有这个倾向。解决方式把长清单拆成多个短清单。比如把 20 个任务拆成 4 个提案每个提案只含 5 个任务或者保持一个提案但每次对话只让它执行其中 3~5 个连续任务完成后再开新对话继续。有效控制 AI 的“视野半径”它跑偏的概率就小了。5.2 AI 不遵守“行为约束”怎么办问题现象proposal.md里明明写了“不更改现有列表查询逻辑”结果 AI 还是顺手把查询逻辑改了个遍。原因分析行为约束写得不够醒目AI 在执行时把它当作“建议”而不是“红线”。还有一个可能约束描述本身有歧义比如“不更改现有列表查询逻辑”到底是指不改查询的 SQL还是连前端查询参数都不能动AI 理解模糊就容易“灵活处理”。解决方式把行为约束写得更窄、更具体最好能指明“涉及哪些文件、哪些函数不允许改动”。我在实践中会把硬性约束放在proposal.md里单独用加粗标识对话开始时再次口头强调。如果 AI 依然改动了约定外的文件用 Git 回退对应文件的改动并在代码评审时向 AI 明确指出具体是哪个 commit 里的哪几行违规了。多来几次它会慢慢学会把边界当回事。5.3 提案和最终实现不一致问题现象AI 已经完成了代码修改但实现的功能跟提案描述的验收标准有出入。原因分析这个基本上是“人与 AI 对验收标准的理解不同”。比如你写了“导出 CSV 文件”AI 认为是输出一个.csv文件并触发浏览器下载但你的真实需求其实还包括“导出按创建时间倒序排列”——而你没写进提案AI 当然不知道。解决方式验收标准写得越具体越好每种可量化的指标都写上去。我没法强调太多次AI 不会读心术你脑子里觉得“这还用说吗”的事情对 AI 来说就是一个全新的信息黑洞。与其事后返工不如把验收标准当成“期末考试大纲”来写。5.4 常见问题排查速查表为方便查阅我把上面几个问题汇总成一张速查表。问题现象可能原因解决思路AI 执行中途开始改无关代码任务清单过长、上下文被稀释拆分短清单限制 AI 视野半径AI 不遵守行为约束约束表述模糊或不够醒目将约束写得极窄、极具体用 Git 回退越界改动实现结果与验收标准不一致验收标准不够量化把验收标准写成可操作、可验证的具体指标AI 在任务中频繁询问提案信息不够完整回到proposal.md补充背景和需求细节多个 AI 同时改动文件冲突缺少角色分工在agents.md中定义明确角色和文件归属6. 我踩过的坑和攒下的经验最后把这段时间折腾 OpenSpec 的真实体会写出来希望大家少走弯路。第一不要一上来就追求“完美提案”。很多朋友看到要写 proposal、要写 tasks第一反应是“太麻烦了”。但你应该把它看作投资开头多花 10 分钟省的是之后两小时的返工。提案写得再好也会遇到意外但规范化流程至少能让你快、准确地发现意外在哪里。如果项目很小比如只改一个问题、影响范围就一个文件那你完全可以跳过 OpenSpec 直接改。它是一个“尺度工具”不是“仪式道具”。第二把proposal.md当成项目的历史记录而不是一次性草稿。每次变更保留下来项目久了就是一份完整的技术决策文档。回头想查“这个导出功能当初为什么选前端拼接方案”翻出对应的 proposal 一目了然。这种“顺手积累”的价值在项目维护期会越来越值钱。第三最核心的一点OpenSpec 真正改变的不是工具而是你组织和表达需求的方式。它逼着你把模糊的念头变成清晰的文字把所有“隐形假设”暴露到纸面上。这份规矩给 AI 用但到最后受益的是你自己——你对自己项目的理解比任何时候都清楚。这种“想清楚再动手”的习惯值得用到每一行代码上。
返回列表