news 2026/9/8 21:04:20

SDD+AI协作开发:从规格文档到发布npm包的完整实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SDD+AI协作开发:从规格文档到发布npm包的完整实践

这几天我干了一件挺有意思的事:用 SDD(Specification-Driven Development,规格驱动开发)的方式,跟 AI 协作开发了一个中文排版用的 npm 包,并且真的发布到了 npm 上。

整个过程走下来,我对“AI 协作开发”这几个字的理解彻底变了。以前总觉得 AI 就是个高级代码补全器,让它写段函数、改个 bug 可以,正经做项目不靠谱。现在我发现,只要流程设计对路,AI 完全可以像一支外包团队那样,拿着规格文档按契约交付,而我要做的就是写好需求、拆好任务、审好代码。

这篇文章会把 SDD 的核心思路、规格文档怎么写、六步实践具体怎么落地、以及发布 npm 包时踩到的各种坑全部写出来。想认真尝试 AI 协作开发、又不想停留在“帮我写段代码”聊天阶段的朋友,这篇应该能给你不少能直接抄作业的参考。

1. SDD 是什么,为什么它跟 AI 协作是绝配

1.1 从“对话式编程”到“规格驱动”,中间差的是契约

大多数人和 AI 协作的方式是这样的:打开聊天窗口,输入“帮我写一个函数,实现某某功能”,AI 啪一下给你一段代码,你复制粘贴,跑一下,报错,再贴回去让它改,如此反复。

这种“对话式编程”不是不能用,但它有几个很要命的问题。第一,需求是聊出来的,不是写下来的,聊到后面你自己都忘了最初要什么;第二,AI 每次生成的代码只对当前对话负责,没有全局约束,改着改着就面目全非;第三,没人验收,AI 说“完成了”你就真信了,功能到底对不对、边界情况处理没处理,全靠运气。

SDD 的思路正好相反:先写规格,再写代码。规格文档就是人和 AI 之间的“合同”,里面写清楚输入是什么、输出是什么、有哪些功能要求、哪些边界情况必须处理。AI 的活儿不是“自由发挥写代码”,而是“照着合同交货”。代码写得不对,不是让 AI “修一下”,而是对照规格一条条检查,哪条没满足改哪条。

我在做这个排版 npm 包的时候,最深的一个体会就是这个:把需求写成规格之后,整个项目突然变得可控了。AI 不再是一个“话痨结对程序员”,而是一个“按单交付的承包商”,我作为项目负责人,只需要管好规格和验收。

1.2 三级分类框架:认清 AI 协作的三种水位

说到这儿,就得提一下 ThoughtWorks 的 Birgitta Böckeler 提出的 AI 结对编程分类框架。这个框架把 AI 在开发中的角色分成了三级,我理解下来大概是这样的。

第一级是“编辑器内联补全”,就是 IDE 里那种灰色提示,你写个函数名,它帮你补完。这个阶段 AI 是提词器,它只对“当前正在敲的这行代码”负责,没有能力理解整个项目。

第二级是“任务级 Agent”,像 Claude Code、Codex 这类工具已经能做到:你给它一个任务,它能自己翻代码、改文件、跑命令,甚至提交 commit。这个阶段 AI 已经从“提词器”进化成了“初级程序员”,但它依然缺乏对需求的完整理解,你说一步,它做一步。

第三级才是真正的“规格驱动开发”。这个阶段,人负责写规格文档、拆任务、做评审,AI 负责在规格约束下批量实现代码。Birgitta 那套分类框架的核心启示就是:AI 能力越强,人越应该往“上游”走——把精力花在定义问题而非实现细节上。

我这次做排版 npm 包,就是按第三级来实践的。说实话,刚上手的时候我也怀疑过:就一个小工具,用得着搞这么正式吗?结果真的做下来才发现,规格驱动带来的收益不是“写代码更快”,而是“返工更少”。

1.3 为什么“写规格”比“写代码”更值钱

很多人一听 SDD 就觉得是“多了写文档的负担”。但我的实际体验正好相反:写规格省下的时间,远远大于写规格花掉的时间。

原因很简单。跟人协作,需求不清晰你还可以开会扯皮,跟 AI 协作,需求不清晰它真的会给你编。你只说“处理一下标点”,它可能把英文句号全给你替换成中文句号,把 URL 里的斜杠也改了,甚至把小数点的含义都搞乱。AI 是语言模型,不是读心术,需求文档里没写的东西,它只会用“最可能的理解”去实现,而这个“最可能”往往跟你要的不是一回事。

规格文档的意义,就是把“最可能的理解”变成“唯一的约束”。我这次写的规格里,连“URL 和邮箱地址不处理”“小数点和版本号里的点号不转换”这种细节都写进去了。正是因为写清楚了,AI 一次实现就基本对了,后面只做了很少的修正。

2. 项目需求与规格设计:动手之前先想明白“做什么”

2.1 为什么选“排版工具”当 SDD 的练手项目

先说一下我做的是什么。这是一个叫 cjk-compose 的小工具,核心功能是文本级的中文排版规范化。听起来有点抽象,举几个例子你就明白了。

“Hello世界,这是一段测试text。”——这句话里,中文和英文之间缺空格,逗号用的是半角的,读起来很挤。经过排版工具处理之后,会变成:“Hello 世界,这是一段测试 text。”——中英文之间自动补空格,中文语境下的标点换成全角,整体清爽很多。

这类需求在中文内容生产场景里特别常见。公众号编辑器、文档平台、内容中台,很多都在用类似的能力做文本清洗。我选择这个项目练手,一是因为它的边界相对清晰,适合验证 SDD 流程;二是因为它规模适中,可以用 AI 快速实现,又不至于小到一个函数就搞定;三是因为它有明确的“对错标准”,好验收,不像某些业务逻辑,对错全凭感觉。

当然,最核心的原因是:这个工具足够老实地覆盖“规格文档应该覆盖的那些事”。中文和英文之间怎么加空格、全角半角怎么转换、禁则处理做不做、HTML 输出怎么兼容——每个决策点都是写规格的好素材。

2.2 功能清单与 API 设计

写规格之前,我先把功能范围圈定了。第一版只做四件事:

  • 中文与英文之间自动插入半角空格
  • 中文与数字之间自动插入半角空格
  • 中文语境下错误使用的半角标点转全角
  • 连续空格压缩与基础空白整理

HTML 输出和禁则处理放到第二版,但规格里要把接口预留好,免得以后升级 break API。

API 设计我参考了 pangu 这类成熟库的用法,但做了一点简化。核心就一个函数:

import { format } from 'cjk-compose'; const output = format(input, { spacing: true, // 中英文/数字间加空格 punctuation: true, // 标点标准化 output: 'text' // 输出格式:'text' | 'html' });

CLI 也配上,方便在终端里直接处理文件:

cjk-compose -i input.txt -o output.txt --format text

为什么 API 要这么设计?因为一个排版工具最忌讳的,就是“一把梭”式地替用户做全部决定。有的用户只想加空格,不想动标点;有的用户处理的是 Markdown 源码,里面全是半角标点,动标点反而坏事。所以每个能力都要做成独立开关,默认全开,但用户可以按需关闭。这个决策如果不在规格阶段定下来,等 AI 帮你写完了再改,改起来就是伤筋动骨。

2.3 边界情况清单:把蛋疼场景提前列出来

这部分是我觉得 SDD 最有价值的地方。跟 AI 协作,边界情况不说清楚,它一定会踩雷。我在规格里直接列了一个“禁区清单”:

第一个坑是 URL 和邮箱。你写一段英文 URL,比如https://example.com/path,如果排版工具在里面乱插空格,链接就废了。所以规格里明确写:凡是匹配 URL 或邮箱模式的内容,整体跳过,不处理内部任何字符。

第二个坑是小数点和版本号。3.14里面的点,v2.0.1里面的点,都不能转成中文句号。如果 AI 傻乎乎地把所有英文句号全替换成中文句号,那这份文本基本就不能要了。

第三个坑是 HTML 标签。如果用户传进来的是It's <strong>important</strong>,你处理的应该是文本节点,而不是标签内部的内容。这个在纯文本场景下可以简化,但一旦开了 HTML 输出模式,就必须考虑。

第四个坑是中文引号。很多人打字习惯用直引号",但在中文排版规范里应该用弯引号“”。这个转换规则比标点转换复杂,因为引号是成对出现的,不能简单地按字符替换,得做配对处理。

这些边界情况,如果在开发过程中才发现,你只能在代码里打补丁,很容易补出一个 bug 又带出另一个 bug。但写在规格里,AI 在一开始实现的时候就会主动处理,这就是“前置约束”和“后置补救”的区别。

2.4 一份可用的规格文档长什么样

我把我那份规格文档的结构简化一下,放在这儿,想照着做的人可以直接参考:

# cjk-compose 排版工具规格 v0.1.0 ## 1. 项目目标 输入任意混合中英文、数字、标点的文本,输出符合中文排版规范的文本。 ## 2. 输入输出 - 输入: string - 输出: string - 异常: 非字符串输入抛出 TypeError ## 3. 功能需求 1. 中英文之间插入半角空格 2. 中文与数字之间插入半角空格 3. 中文语境下半角标点转全角(逗号、句号、问号、感叹号、冒号、分号、括号) 4. 连续空格压缩为单个空格 5. 直引号配对转换为弯引号 ## 4. 边界与例外 1. URL、邮箱地址整体跳过 2. 小数点(3.14)、版本号(v2.0.1)中的点号不转换 3. HTML 模式下手标签内容不处理 4. 连续 3 个及以上全角标点不追加转换 ## 5. 非目标(第一版不做) - 不做分词 - 不做字体嵌入 - 不做完整的中文排版引擎 ## 6. 验收标准 对给定 fixture 文件逐条断言,覆盖上述所有功能与边界。

注意第 5 节“非目标”,这个是很多人写规格容易漏掉的。明确“不做什么”,比明确“做什么”还重要。AI 是生成模型,你不限制它,它就喜欢“超额完成”,加一些你没要求的东西,反而引入风险。

3. 六步实践指南:从规格到 npm 发布

3.1 第一步:把规格文档当作“唯一事实来源”

这次项目我采用的就是社区里流传的 SDD 六步实践流程。第一步很简单:把上面那份规格写完整,存成SPEC.md,放进项目仓库根目录。

为什么强调“放进仓库”?因为规格只有在版本管理里才是活的。AI 实现的每一版代码都对应某个版本的规格,代码和规格要能对得上。如果规格只在聊天窗口里存在,翻几条消息就没了,AI 改着改着就“自由发挥”了。

写规格的时候我还有个习惯:同时把验收用例写好。不是严格意义上的测试代码,而是“当输入是 X,输出应当是 Y”这样的断言清单。这个习惯帮我省了很多事——因为后续 AI 实现完,我只要拿这份断言清单去验证就行,不用每次重头想“它写得对不对”。

3.2 第二步:把规格拆成一批可交付的小任务

规格文档是给 AI 看的总纲,但 AI 一次处理不了太多上下文,所以我把它拆成了 5 个小任务:

  1. 初始化 npm 包结构(package.json、目录、基础类型定义)
  2. 实现中英文空格插入功能
  3. 实现标点标准化功能
  4. 实现引号配对与边界情况过滤
  5. 编写测试与 CLI 入口

每个任务的描述都直接引用规格里的条款。比如任务 3 的描述是:“参照 SPEC.md 第 3.3 条,实现中文语境下半角标点转全角。注意:第 4.2 条规定的 URL、小数点和版本号场景不得转换。”任务描述越精确,AI 实现越靠谱。

这一步我最大的感受是:任务拆得越小,AI 犯错的概率就越低。一个任务负责一个纯函数,AI 的输出就可以被精准验收。反过来说,如果你塞给它一个“把整个包实现出来”的大任务,AI 很容易在某个角落里自作主张,等你在集成测试时才发现,排查成本就高了。

3.3 第三步:用 AI Agent 按任务逐个实现

拆好任务之后,就轮到 AI Agent 上场了。我用的工具是命令行的 AI 编程 Agent(比如 Claude Code、Codex 这一类),启动后直接把规格文档路径和当前任务描述丢给它,让它自己读仓库、写代码、跑测试。

这一步有个操作习惯值得分享:给 Agent 的任务,我会把“完成标准”写得很具体,比如“实现后运行npm test,确保test/space.test.js下所有用例通过”。AI Agent 是目标导向的,你给它一个可验证的目标,它会主动去跑测试、看报错、修代码,直到达标为止。如果你只说“实现这个功能”,它写完就停了,代码对不对全靠你人肉检查。

不过话说回来,AI Agent 干活的时候,人不能完全撒手。我基本上每个任务完成后都会快速瞄一眼 diff,看有没有“跑偏”的迹象。整体上 5 个任务里,有 3 个是一次通过的,剩下的 2 个在做完评审时发现了问题,具体放在第四步说。

3.4 第四步:人工审查,别把 AI 当监工不当人

AI 实现完之后,审查环节是省不掉的。我这次审查发现了两个典型问题,都是 AI 在边界情况下“自作聪明”导致的。

第一个问题出在空格插入功能上。规格要求“中英文之间插入空格”,但 AI 把3 月这种中文字和数字之间的空格也处理了。这个功能本身没问题,但它把v2.0.1这种版本号里的空格也处理了——它先按 URL/版本号规则跳过了点号,却忘了跳过整个版本号 token。结果v2.0.1被输出成了v 2.0.1,从语义上完全错了。

第二个问题比较隐蔽。AI 实现引号配对时,把所有"都当成中文语境下的引号处理,结果把 JSON 字符串里的引号也转换成了中文引号“”。虽然我的规格里写了“中文语境”,但没定义“什么是中文语境”,AI 就默认了“包含中文的句子里的所有引号都处理”。这个 bug 在纯文本场景下问题不大,但一旦用户传入带 JSON 的文本,转换结果就是灾难性的。

这两个问题的共同点是什么?都出在规格没写清楚的地方。审查环节的价值,就是把这些“规格空白区域”暴露出来,然后你去补规格、改代码。审查一次,规格完善一次,AI 后续的实现就更接近“一次做对”。

3.5 第五步:测试验证,让断言替你说“不行”

SDD 的第五步是测试验证。我的做法是,规格里的每一条功能需求和每一条边界情况,至少对应一个测试用例。测试框架用的是 Node.js 内置的node:test,这个在 Node 18+ 里直接可用,不用额外装依赖。

测试用例我举两个例子:

import { test } from 'node:test'; import assert from 'node:assert/strict'; import { format } from '../src/index.js'; test('中英文之间插入半角空格', () => { assert.equal(format('Hello世界'), 'Hello 世界'); }); test('版本号中的点号不转换', () => { assert.equal(format('当前版本v2.0.1已发布'), '当前版本 v2.0.1 已发布'); });

第二个用例其实就是我在审查中发现的那个 bug 的回归测试。先把 bug 修掉,再把断言固化为测试用例,这样以后 AI 或者任何人改了代码,只要跑一遍测试,问题就会立刻暴露。

3.6 第六步:构建、版本管理、发布

测试全部通过之后,最后一步是构建和发布。虽然这个包是纯 JavaScript 写的,不需要编译,但为了保险起见,我还是加了prepublishOnly脚本,让发布前自动跑一遍 lint 和 test,防止“脑子一热发了个坏包”的事故。

版本管理用的是 npm 自带的 semver 流程:npm version patch提交一个新版本号,然后再npm publish发布。这里有一个小坑,后面避坑实录里会详细说——发布之前一定要确认package.json里的files字段只打包该打包的文件,不然node_modules或者测试文件被一起发布到 npm 上,既浪费空间又显得特别不专业。

4. 核心实现细节与关键代码解析

4.1 中英文之间插入空格:两个正则搞定

排版包的核心功能里,最简单的就是中英文之间插入空格。核心实现其实就两个正则替换:

const CJK_RE = /[\u4E00-\u9FFF\u3400-\u4DBF\uF900-\uFAFF\u3040-\u30FF\uAC00-\uD7AF]/; export function insertSpacing(text) { return text .replace(new RegExp(`(${CJK_RE.source})([A-Za-z0-9])`, 'g'), '$1 $2') .replace(new RegExp(`([A-Za-z0-9])(${CJK_RE.source})`, 'g'), '$1 $2'); }

第一行CJK_RE覆盖了 CJK 统一表意文字、扩展 A 区、兼容表意文字、日文假名和韩文音节。做中文排版的时候,这个字符集合比我一开始想象的重要得多——如果不把日文假名和韩文包含进去,用户处理多语言文本时就会出现“中文和英文之间有空格,日文和英文之间没空格”这种不统一的情况。

两个 replace 分别处理“中文在前英文在后”和“英文在前中文在后”两种方向。这里要特别注意:正则里的字符组千万不能写成[A-Za-z]就把数字漏了,数字和中文之间的空格也是排版规范的一部分,所以字符组里要带上0-9

4.2 标点标准化:转换表加上下文判断

标点标准化比加空格要麻烦一点,因为它不是简单的字符替换,得结合上下文判断。核心逻辑分两层:

第一层是半角转全角的映射表:

const HALF_TO_FULL = { ',': ',', '.': '。', '?': '?', '!': '!', ':': ':', ';': ';', '(': '(', ')': ')', '[': '【', ']': '】' };

第二层是判断“当前半角符号是否处于中文语境”。我的简化策略是:如果符号前面有 CJK 字符,就认为是中文语境,执行转换;如果前面是拉丁字母或数字,则不转换,保持原样。

这个策略看起来简单,实战中效果不错,但有两个例外必须在转换之前先处理。一个是小数点,3.14里的.前面是数字3,按规则不转换,这里天然安全;但3.14 版本。这种句子结尾的.前面是4,也不会被转换,这就不对了。所以规格里专门加了边界规则:当.前面是数字、后面是空格或句子结束符时,按句号处理。这个补丁逻辑看起来有点“脏”,但真实世界的文本就是这样,规格驱动开发的意义恰恰在于把这些脏逻辑提前想清楚。

4.3 直引号配对转换为弯引号

引号配对是我这个小项目里实现上最绕的一个功能。ASCII 直引号"在英文文本里是中立引号,但在中文排版里需要转换成成对的弯引号

实现思路是状态机:遍历字符串,用一个布尔变量记录“当前是否在左引号状态”。遇到"时,如果当前是左引号状态则输出,否则输出,然后翻转状态。

但这里有个现实问题:用户有时候只写了一个引号,比如 “他说” 后面忘了闭合引号,那状态机就会“错位”,后面所有引号都反了。我的处理是:当文本里的引号数量为奇数时,最后一个引号保持原样,不做转换。这不算完美,但至少避免了“越改越错”的尴尬。想深入处理的话,下一步可以用 NLP 模型判断引号方向,但作为排版工具的第一版,这种工程折中是合理的。

4.4 HTML 输出模式:排版规则与标记结构的平衡

第二版我加了 HTML 输出模式,这里其实藏着一个排版工具最常见的设计难点:处理 HTML 时,你不能把标签当普通文本处理。

我的方案是分两遍走:第一遍先把<[^>]+>这种标签通过正则提取出来,替换成占位符\x00加上序号;第二遍对剩余文本执行所有的排版规则;最后再把标签按序号放回去。

export function formatHtml(html) { const tags = []; const placeheld = html.replace(/<[^>]+>/g, (tag) => { tags.push(tag); return `\x00${tags.length - 1}\x00`; }); const formatted = format(placeheld, { output: 'text' }); return formatted.replace(/\x00(\d+)\x00/g, (_, i) => tags[Number(i)]); }

这个占位符方案在绝大多数场景下够用,但有一个已知局限:如果 HTML 属性值里包含中文文本,比如title="你好世界",属性里的内容也会被排版处理。严格来说应该用真正的 HTML 解析器按 DOM 节点处理,但作为文本级排版工具,用占位符方案换取轻量依赖,我认为是划算的。这个取舍也在规格文档里明确写了,避免以后有人拿它当完整 HTML 处理器用。

5. npm 发布全程与避坑实录

5.1 发布前检查清单:别让细节坑了自己

代码写完、测试通过之后,发布 npm 包前我过了一遍检查清单,每一条都是血泪教训换来的。

第一,确认package.json里的files字段。这个字段决定哪些文件会进入发布的包。我的配置是:

{ "files": ["dist", "README.md", "LICENSE"] }

不加这个字段,npm 会把所有文件都打包进去,包括测试文件、源码目录、甚至node_modules里不该出现的东西。这个不是洁癖问题,是专业性问题——别人npm install你的时候,下载的是你的整个项目,而不是最小可用的产物。

第二,确认mainmoduleexports三个字段指向正确的入口文件。很多新手发布完包发现别人import报错,基本都是这三个字段没配对。我用的是exports字段做双入口:require走 CommonJS,import走 ESM。

第三,prepublishOnly脚本必须挂上。这个脚本会在npm publish之前自动执行,我把它配成了先跑测试再跑单元测试:

{ "scripts": { "test": "node --test test/", "lint": "eslint src/", "prepublishOnly": "npm run lint && npm test" } }

这样一来,就算哪天脑子一热直接npm publish,也不会把没测试过的代码发出去。

5.2 完整发布流程:从登录到版本号

发布流程本身不复杂,但新手容易在“登录”这个环节卡住。npm login会让你输入用户名、密码和邮箱,注意邮箱必须和 npm 账号注册时的邮箱一致,否则登录会失败。

登录之后,先跑一遍npm publish --dry-run,这个命令会模拟发布,展示即将上传的文件清单。我每次发布前都会看一遍这个清单,确认里面没有“不该出现的东西”。这个习惯帮我避免过至少两次“误传 node_modules”的事故。

正式发布前,还要确认版本号。如果是一次 bug 修复,用npm version patch把版本号从0.1.0升到0.1.1;如果是新功能,用npm version minor升到0.2.0;破坏性 API 变更才用npm version major。这个 semver 规范必须严格遵守,因为 npm 生态的依赖解析就是建立在版本语义之上的,乱升版本号迟早坑到别人,也坑到自己。

发布完成后,建议立刻npm install cjk-compose装到你自己的一个测试项目里,验证一下发布出去的包真的能用。这一步很多老手都跳过,但新包第一次发布,很容易在files配置上出问题,导致包本身是空的或者入口文件缺失,只有真正“从 registry 拉下来用一次”才能发现。

5.3 高频报错一栏表:这些坑我都替你踩过了

发布和安装 npm 包的过程中,有几个报错是我这次实打实遇到的,也是新手群里出现频率最高的,整理成一张表,方便直接查:

报错现象原因解决办法
npm : 无法加载文件 npm.ps1,因为在此系统上禁止运行脚本Windows PowerShell 默认执行策略限制以管理员身份运行 PowerShell,执行Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser,或者改用 CMD 运行 npm
npm ERR! code CERT_HAS_EXPIRED使用了旧的镜像源,证书已过期检查.npmrc里的 registry 配置,换成官方源https://registry.npmjs.org/或更新到新镜像地址,然后npm cache clean --force
npm WARN deprecated node-domexception@1.0.0依赖树里有老旧的间接依赖npm ls node-domexception定位来源,更新对应的顶层依赖;不要慌,deprecated 不等于不能用
npm WARN using --force recommended protections disabled有人执行了npm install --force别用--force硬装,优先解决依赖冲突。--force会绕过完整性校验,指不定装进来什么
无法将“npm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称Node.js 没装好或 PATH 没配置重新安装 Node.js LTS 版本,安装时勾选“Add to PATH”;装完后重启终端再试

这里面我想重点说一下最普遍的 PowerShell 那个错误。很多 Windows 用户第一次跑npm -v就碰到这个,第一反应是“npm 坏了”,其实不是,这是 PowerShell 的执行策略拦截了.ps1脚本。解决办法有两个:一是用Set-ExecutionPolicy放开当前用户的脚本执行权限,这也是我推荐的方案,不会降低系统安全性,因为RemoteSigned只允许本机脚本和受信任发布者的签名脚本运行;二是干脆不用 PowerShell,用 CMD 或 Git Bash 跑 npm。我个人的习惯是,Windows 开发机上直接用终端(Windows Terminal + PowerShell),把执行策略改好,一劳永逸。

5.4 发布后的收尾:文档、示例和持续迭代

包发布上去只是第一步,后面的收尾工作同样重要。第一个是 README,我必须得说,README 写得好的包和写得烂的包,使用体验天差地别。一份合格的 README 至少要包含:这个包解决什么问题、安装命令、两行代码的快速上手示例、完整的 API 说明、以及常见问题的处理。我这次还加了一个“这个包不做什么”的章节,明确告诉用户禁则处理和分词的边界,免得有人装完之后骂骂咧咧。

第二个是示例项目。我在仓库里放了一个examples/目录,里面是一个可以直接跑的 demo,包含了几段典型的混合文本和对应的处理结果。别小看这个动作,很多用户选包的标准就是“有没有一眼能看懂的示例”。我自己选依赖库的时候就特别反感那种 README 写得云里雾里、全靠翻源码猜用法的包。

第三个是版本迭代节奏。0.1.0发出去之后,我给自己定了两条规矩:每次改动都先改规格文档,再改代码;每次新版本发布前必须跑完整测试套件。这不是流程洁癖,而是 SDD 的核心理念在发布后的延续——规格驱动开发不是一次性动作,它是整个项目生命周期的默认工作方式。

写在最后:一点真实体会

这次做完 cjk-compose 这个包,我最大的收获不是“会发布 npm 包”了,而是彻底想通了一件事:AI 协作开发的瓶颈从来不在 AI 的代码生成能力,而在人能不能把需求讲清楚。

以前我写代码,脑子里有个大概的想法就开始敲,边敲边想,写出来什么样算什么样。但用 SDD 做这个包的时候,我第一次在动手写代码之前,把每个功能的输入、输出、边界、例外、验收标准全部过了一遍。这个过程的体验非常奇妙——当你把需求描述得足够精确的时候,你会发现 AI 写代码的速度快到离谱,因为剩下的真的只是“翻译”工作。

当然,SDD 也不是万能灵药。它更适合那些需求边界清晰、有明确验收标准的工具型项目。如果你做的是一个探索性的、需求每天都在变的项目,前面先花大量时间写规格,可能反而拖慢节奏。这时候我建议你用轻量规格,只写核心约束和边界,别的交给 AI 自由发挥,边探索边补规格。

最后再分享一个小技巧:把规格文档的版本号写进 README。这样一来,使用者看到的说明和 AI 实现所依据的规格永远能对得上。我在 cjk-compose 的 README 里加了一行“本版本实现基于 SPEC.md v0.2.0”,查问题的时候特别省事——你先看版本号,再看对应版本的规格,最后对着代码找差异,基本上一找一个准。

这大概就是我对“AI 协作开发新范式”最朴素的理解:AI 负责跑得快,人负责看得远。规格,就是那条把远和快连起来的线。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 21:03:09

从陶瓷工业百强看京尚“市场与品质双轮驱动”的实战逻辑

前段时间陶瓷行业圈子里最热闹的一件事&#xff0c;就是新一届全国陶瓷工业百强名单出炉。京尚这个品牌不仅稳稳上榜&#xff0c;还成了榜单里被反复提及的“双轮驱动”典型——市场和品质两头都抓得硬。我做这行十几年&#xff0c;见过太多企业要么拼命冲销量把品质丢了&#…

作者头像 李华
网站建设 2026/9/8 21:01:01

Agent执行边界安全实践:从SandBox配置到软边界防护

1. 一个报错把我带到的话题&#xff1a;Agent 执行边界到底是什么 有段时间我运行一个自动分析项目时&#xff0c;日志里反复出现一段看起来很像代码写错了的报错&#xff1a;disabled no sandbox&#xff0c;接着就是 agent execution terminated due to error. 。起初我很不…

作者头像 李华