拓冰建站拓冰建站
首页 / 资讯中心 / 正文

规范驱动开发(SDD)实战:用AI协作开发中文排版npm包

先说背景。最近我在折腾一个给中文长文做排版增强的Node.js库功能不复杂统一中文引号、处理中西文之间的空格、清理行尾空白、给段落做缩进标记最后对外提供命令行和API两种用法。这类型工具放到npm上正常情况下就是闷头写写完发版但我实际写到一半就意识到一个问题排版规则看着简单边界多到离谱。比如“引号后面跟英文标点怎么处理”“破折号两边要不要空格”“代码块里的空格改不改”每个都是细节每个细节都可能改崩前面的逻辑。于是我把开发方式整个切到了SDD也就是Specification-Driven Development规范驱动开发。这个方法论最近在AI编程圈讨论很多核心就一句话先写清楚“要什么、怎么算对”再去写代码。配上AI agent之后整个开发链条变得非常顺——需求拆成规范规范喂给AIAI按规范实现我再按规范验收。这篇文章就把我这次用SDD做排版npm包的完整过程、规范文件怎么写、AI怎么用、npm发布踩过的坑全部分享出来。适合正在用AI写工具类项目、或者想优化AI协作流程的人参考。1. 为什么是SDDAI编程时代的“先写需求再写代码”1.1 SDD到底在解决什么问题先说痛点。最早我用AI写代码的方式很原始丢一段需求描述让AI给我一个完整文件或者补全函数。需求写得细一点代码质量就高一点需求写得模糊AI就开始自由发挥变量名、函数边界、错误处理全看心情一个功能能给出五种不同写法。后来我开始写详细的prompt把输入输出样例、边界条件、异常情况全塞进去效果确实好了不少但随之而来的是新问题prompt越来越长上下文越来越乱改一个需求要连带改好几段描述AI有时候还会自己发挥一些我没要求的“增强”功能把代码库搞得乱七八糟。SDD解决的就是这个问题。它把需求描述变成一个结构化的规范文件也就是一个包含功能定义、输入输出样例、验收标准的文档。AI不再从自然语言里猜需求而是从规范文件里读取明确的“契约”照着契约实现。对人来说验收也变成了“逐条对照规范检查”而不是凭感觉看代码写得顺不顺眼。我在这个排版包里最深的一个体验是手工写代码的时候需求是在脑子里想清楚的代码是实现这个想法的过程但用AI写代码的时候如果需求不在纸面上AI就无从下手更没法帮你处理那些你没写出来的边界情况。规范文件就是那张“纸”。1.2 我理解的SDD三级分类框架SDD在网上已经有挺多实践总结我之前翻资料的时候看到ThoughtWorks的Birgitta Böckeler对SDD分类有过一个框架性的分享网上搜“SDD三级分类”也能看到相关讨论。我实际用下来把规范分成三个层级是最顺手的项目级规范说明这个项目是什么、给谁用、核心目标是什么相当于项目说明书。模块级规范拆解项目由哪些功能模块组成每个模块的输入、输出、处理逻辑是什么。任务级规范具体到某个函数或某个操作包括函数签名、参数约束、返回值格式、异常处理方式。这套分层的价值在于不是所有内容都要写进同一个文件。AI在实现某个小功能时只需要读相关的任务级规范而不是把整份项目说明书重新看一遍。这就避免了上下文过长导致的理解偏差也让规范文件本身更易于维护。我在项目里实际建了三个目录specs/project.md、specs/modules/、specs/tasks/。项目级规范只有不到一页模块级规范按功能拆成4个文件任务级规范则是随着开发进度逐步补进对应模块里。这样写起来不累AI读起来也快。1.3 什么时候不值得用SDD我也得泼一盆冷水。SDD不是万能的小项目用它完全是浪费。如果你只是写一个几十行的脚本或者需求本身就很清晰且不太可能有边界变化直接让AI写反而更快因为写规范的时间可能比写代码还长。SDD真正适合的是两类场景一类是业务规则多、边界情况复杂的项目比如我这个排版包规则条数多且互相影响另一类是维护周期长、后续可能要持续改动的项目规范文件能让人快速重新理解项目也让AI在隔了很久之后还能稳定产出。我这篇博文后面的内容全部建立在“项目复杂度值得用SDD”这个前提上。如果你的项目很小看完思路就行不用照搬结构。2. 这个排版包到底做什么需求拆解与边界划定2.1 项目定位不做编辑器只做文本处理做工具类npm包最怕的就是边界无限扩张。我做这个排版包之前也试图把“识别标题”“自动加粗”“生成目录”这些功能塞进去后来很快发现野心太大只会让AI和人都陷入泥潭。所以我在项目级规范里第一件事就是定义“这个包不做什么”不做富文本编辑器不解析HTML。不做Markdown完整解析只处理纯文本行。不处理图片、链接、脚注等复杂元素。不做语言检测输入文本的语言由调用方说明。这些“非目标”写在规范里最大的作用是约束AI。AI一旦被明确告知“不要做这些”就不会在实现时自作主张去引入dom库或者markdown解析器。这个教训来自我之前一个项目AI“好心”帮我加了个markdown转HTML的功能结果引入了一堆依赖被我全删了。定位成纯文本处理包之后项目就清爽了很多。输入是字符串数组或者带换行的纯文本输出是处理后的文本外加一个可选的格式化报告告诉用户改了哪些位置。所有逻辑都可以在Node.js环境里用纯函数实现不需要任何外部依赖这对npm包的体积和可维护性非常友好。2.2 功能拆解与优先级我在模块级规范里把功能拆成四个模块并且给每个模块标了优先级模块功能说明优先级复杂度标点规范化中文引号、书名号、破折号统一格式P0中空格优化中西文之间加空格清理行尾空格P0低段落处理识别段落边界支持首行缩进标记P1中格式报告输出修改记录辅助用户审查P2低P0是首版必须完成的P1是首版尽量完成P2放到第二版。实际开发时我先把P0两个模块做扎实了再补P1P2最后顺手加上。优先级写进规范最大的好处是AI不会在实现P0的时候突然去处理P2的需求任务的颗粒度和推进顺序都能被控制住。这里有个很关键的细节每个模块的规范里都要写清楚“输入长什么样、输出长什么样、有几个典型的输入输出样例”。举个例子空格优化模块的规范里有这么一条输入中文和English混排时输出中文和 English 混排时这个样例看着简单但它其实同时确定了“中文字符和英文字母之间要加空格”这条规则。AI靠这个样例就能写出正确的正则或者字符判断逻辑我验收的时候也轻松跑一下输入对比输出就知道过没过。3. 六步走从规范到npm发布的完整实操3.1 第一步写产品意图一句话讲清楚项目SDD的起点是一句话产品意图。我在specs/project.md里写的第一段话是本工具是一个纯文本排版增强库主要面向中文内容创作者。输入带基本标点的纯文本输出经过中文排版规范处理后的文本并提供可选的编辑记录。核心目标是让中文长文的排版更规范、更统一。这段话不长但它定义了目标用户、核心功能、可交付物和核心价值。AI agent在工作之前先把这份文件读一遍它对整个项目的理解就有了一个锚点后面所有二级、三级规范都是对这句话的展开。写这段意图的时候我建议反复打磨几个词。比如“排版增强”而不是“排版”因为“排版”可能让人联想到设计、版式、图片而“增强”明确表达出我们只做文本层面的优化。再比如“面向中文内容创作者”直接圈定了语言处理的核心方向AI看到这句话就知道不需要处理日语假名。3.2 第二步拆模块、定义输入输出产品意图确定之后就是拆模块。我在第一节列出的表格就是在这个步骤里写出来的。但模块清单只是骨架每个模块还得配上输入输出定义这一步是规范文件里最接近“接口文档”的部分。以标点规范化模块为例我在specs/modules/punctuation.md里定义了输入包含中英文标点的字符串。输出标点统一后的字符串。处理规则中文语境下使用全角引号“ ”和‘ ’英文语境使用半角引号和书名号统一为《》省略号统一为……共6个字符。定义输入输出的时候有一点很关键要写清楚“什么情况下不做处理”。比如我的规范里特意加了一条如果输入文本中已经包含正确的全角引号且上下文符合中文使用习惯不做重复修改。这条限制看起来多余但它防止了一个实际问题——AI可能会对同一段文本反复规范化导致引号从全角变半角再变全角最后变成不可控的状态。写清楚“不处理”的情况相当于给AI画了一条安全线。3.3 第三步写验收标准越具体越好规范文件和普通需求文档最大的区别就是规范必须写清“怎么算完成”。我在每个模块的规范里都会加一个“验收标准”章节用可以运行测试的方式描述。标点模块的验收标准我写了五条输入他说“今天天气不错。”输出他说“今天天气不错。”全角引号保持不变输入他说: 今天天气不错。输出他说“今天天气不错。”半角引号转为全角输入这本《活着》很好看输出不变书名号正确时不修改输入他顿了顿...接着说输出他顿了顿……接着说省略号规范化输入Its a test输出Its a test英文语境下引号不改为全角验收标准一旦写成这样后面的开发流程就从“写代码”变成了“让代码通过测试”。AI实现的时候我在系统提示词里加了这么一句话“请严格对照验收标准实现每个验收标准都应该有对应的测试用例。”这句话的效果显著AI写完代码后会自动补测试而且不是敷衍式的测试它会对照每一条验收标准一条条写。3.4 第四步组装上下文交给AI agent实现规范文件写好了接下来就是AI agent干活的部分。我在这个项目里试过通用对话式AI也试过能直接操作文件、跑命令的agent工具实际体验下来真正拉开差距的不是模型本身而是你给它的上下文结构。我现在用的工作目录结构是这样的layout-helper/ ├── specs/ │ ├── project.md │ └── modules/ │ ├── punctuation.md │ └── spacing.md ├── src/ ├── test/ └── package.json让AI agent开工时我不会把整个specs目录丢给它而是按任务逐份给。比如这一轮要处理标点模块就只让它读project.md和modules/punctuation.md并且明确告诉它“这是项目规范和标点模块规范请按照规范实现src/punctuation.ts测试文件写在test/punctuation.test.ts测试命令是npm test。”上下文精简之后AI的理解准确率高了很多代码风格也更统一。之前我把所有规范一次性喂进去AI写后面的模块时经常忘了前面的约束来回返工的时间比写规范还长。3.5 第五步逐条验收别信AI的“我觉得没问题”AI agent跑完一轮之后它自己会说“完成”也会跑一遍测试给你看。但这个阶段绝对不能直接信任因为AI构造的测试用例往往会偏向实现本身它知道自己代码的意图测试就很难发现逻辑错误。我的验收流程分三步。第一步我手动跑一遍验收标准里的输入输出样例确认和规范一致。第二步我写一批规范里没有的“变体用例”比如在标准输入前后加上换行、Tab、连续空格看看AI的实现会不会崩。第三步故意制造异常输入比如空字符串、只有标点的字符串、很长的连续英文单词验证程序的健壮性。在这个排版包里我抓到一个特别典型的bug空格优化模块在处理“中文和English混排”时表现正常但换成“中文English中文”这种中英交替多次的情况会在两个英文单词之间也加上空格导致HelloWorld被拆成Hello World。这正是标准验收样例覆盖不到、只有人为构建变体用例才能发现的问题。3.6 第六步跑通发布流程代码验收通过后就是npm包发布环节。这里有一个很多新手会忽略的步骤正式发布之前先运行npm pack看看生成的压缩包里到底有哪些文件。我第一次做这个包的时候满脑子都是功能逻辑一上来就npm publish结果把src目录下的TypeScript源码也发布了还带了一大堆无用的测试文件。后来我学乖了始终用npm pack预览确认包里只有编译后的dist目录、README.md、package.json和LICENSE文件再执行发布。发布相关的命令我用得很简单npm login npm version patch npm publish --access publicnpm version patch会自动把版本号从0.1.0升到0.1.1同时生成一条git tag省得手动改package.json。--access public是发布公共包必须的参数如果你不写npm会默认认为你要发私有包非付费账号会直接报错。4. 规范文件怎么写三个容易翻车的地方4.1 验收标准必须可执行不能写成“希望”写SDD规范最容易犯的错就是把验收标准写成“希望实现中文引号统一”“需要支持省略号替换”这种描述性的话。这种话对AI来说就是需求陈述不是验收标准AI确实会去实现但你没有办法客观判断实现得好不好。我的经验是验收标准的每一个条目都应该满足三个条件有具体的输入文本。有预期的输出文本。能在几秒钟内用测试设备完成验证。写成“输入A输出B”的形式人和AI都能直接理解测试用例也能直接从里面生成。如果某个验收标准需要文字描述才能解释清楚那就说明你对这个功能的期望还不够明确需要继续拆解。4.2 边界用例必须在规范阶段就补进验收清单边界用例这个词听起来很专业实际上就是“正常情况之外的输入”。我在标点模块里加了一个边界用例输入空字符串时输出空字符串不抛异常。这个用例写进验收标准就是逼着AI在实现时考虑空值处理。如果不写AI大概率不会主动加空字符串的判断逻辑因为它的训练数据里这类边界处理常常被省略。一旦线上或者CLI调用时传入空字符串轻则返回undefined重则直接报错。类似的边界输入还包括只包含空格的字符串、只包含标点的字符串、连续1000个字符的超长字符串。每个都尽量在规范阶段写进验收标准因为规范阶段加一行字比开发阶段返工一个函数要便宜得多。4.3 规范粒度要匹配任务不是越细越好我见过有些SDD实践者把规范写成了完整的技术设计文档连变量名、循环结构都规定好了。我的体会是这样做反而适得其反——你既然把所有实现细节都定了那还要AI干什么不如自己写代码。合适的规范粒度是定义清楚“做什么”和“怎么算对”但不规定“怎么做”。比如我在空格优化模块里写的是“中文字符和英文字母之间加空格”而不是“用正则/[a-zA-Z]/判断英文用/[\u4e00-\u9fa5]/判断中文匹配到边界时插入空格”。前者留给AI发挥空间后者把AI变成了一个打字员。AI在实现层面的自由度恰恰是它能给出不同解法、帮你发现新思路的地方。5. npm发布踩坑实录从证书过期到PowerShell拦截5.1 镜像源证书过期cert_has_expired处理发布流程进行到一半我在另一台电脑上想拉取依赖测试一下新包结果碰到一个很恶心的报错npm ERR! code CERT_HAS_EXPIRED npm ERR! errno CERT_HAS_EXPIRED npm ERR! request to https://registry.npm.taobao.org/vuex-along/download/vuex-along-1.2.11.tgz failed, reason: certificate has expired问题的根源是这台机器配置了旧的npm镜像源而那个源服务本身维护不积极证书过期了还在继续用。npm把证书校验当作安全底线不会因为源地址失效就跳过校验。解决办法也很直接换回官方源或者用更新过的镜像npm config set registry https://registry.npmjs.org/如果因为网络原因必须用镜像也要找能正常提供服务的维护中镜像别再用已经停摆的旧地址。这里我多说一句不要在全局环境配置镜像源最好用项目的.npmrc文件配置每个项目独立指定避免互相污染。5.2 PowerShell禁止运行脚本npm.ps1的坑发布之后的某个环节我需要在Windows上跑一个npm脚本命令结果PowerShell直接给我来了个下马威npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1因为在此系统上禁止运行脚本这个报错本质上是PowerShell的ExecutionPolicy执行策略把.ps1脚本给拦了npm本身没问题是Windows的安全策略默认不信任脚本执行。我在实际操作中推荐两种处理方式第一种临时绕过在当前窗口允许本机脚本Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass这个设置只在当前PowerShell窗口生效关掉就失效适合临时救急。第二种遇到这种情况直接用cmd来跑npmcmd不会受到PowerShell执行策略的限制所以很多老手在Windows上干脆一路用cmd操作npm。5.3 发布前检查的三件套除了上面两个坑我每次发版前会固定检查三件事也算是给读者一个现成的清单第一npm pack --dry-run查看即将发布的文件列表确认没有源码目录、测试文件、临时文件混进去。第二npm view 包名 version确认当前线上的版本号避免重复发布或者版本号倒挂。第三README里写上安装方式、基础用法、API说明很多npm包我下载之后不看代码先看READMEREADME写得清楚印象分直接拉满。这三件事整套流程下来也就两分钟但能规避掉发布完之后才发现问题、再发一个hotfix版本的尴尬。6. 一些实操心得AI时代规范写得好比代码敲得快更值钱这个排版包从立项到发版前后花了两天多时间真正的编码工作大多由AI agent完成我主要的时间都花在写规范、改规范、验收和踩坑上。我自己仔细回想了一下如果沿用老办法手工写至少需要一周到十天而且边界用例大概率不会覆盖得这么全。但我也想强调一点SDD不是让AI替你工作的魔法它更像是一个质量管理工具。规范文件写得越清晰AI的输出就越可控规范文件写得到位你就能像检查清单一样去验收AI的工作而不是大海捞针式地读代码。最后分享一个小技巧规范文件里的验收标准我通常会用和测试代码一样的命名风格。比如标点模块有一条验收标准叫“中文半角引号转为全角引号”在测试文件里就会对应一个测试用例test(中文半角引号转为全角引号, ...)。这样不仅AI好理解连你之后维护测试代码的时候都能直接对着规范文件找到每一个功能的测试来源。这个习惯我保持了很久非常管用。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门