用SDD+AI Agent开发Markdown排版npm包:从规格到发布
2026/9/8 14:56:37 网站建设 项目流程

1. 从"人写代码"到"人写规格":这个排版包为什么用 SDD 来做

1.1 先交代一下背景:这是个什么排版包

如果你平时用 Markdown 写文档、写公众号、写技术博客,大概率遇到过这种场景:从 AI 对话里复制一段代码或表格过来,格式全乱;团队多人协作一份 Markdown 文档,表格列宽参差不齐、代码块语言标错、列表层级混乱。我做的这个 npm 包,就是专门干这个事的——输入一段 Markdown 文本,自动把表格对齐、代码块规范、标题层级理顺、列表缩进统一,输出一份"强迫症友好"的排版结果。

最初我很自然地想:这种纯逻辑型工具,直接甩给 AI Agent 让它写不就行了?但试了几次发现,AI 写出来的代码"能用"和"可交付"之间隔着一道很宽的沟。它经常把表格解析逻辑写得很理想化,遇到嵌套列表、行内代码、特殊转义字符就崩;正则更是重灾区,写的时候觉得覆盖了所有 case,实际一跑全露馅。于是我开始尝试用 SDD(Spec-Driven Development,规格驱动开发)来重新组织整个开发流程,让 AI 从"写代码的人"变成"按规格实现的人",而我把精力集中在定义规格、审查实现和补边界条件上。

1.2 为什么我觉得"直接让 AI 写代码"不够用

很多人用 AI 编程的方式是:把需求往对话框里一扔,说"帮我写一个 Markdown 格式化工具",然后等它输出一坨代码,复制进项目里,跑一下发现有问题,再复制报错回去让它改。这个循环看起来高效,实际上你根本不知道自己拿到了什么。AI 会默认做大量假设,比如表格分隔符必须是|开头结尾、列表一定是从-开始的,这些假设在真实语料里根本不成立。

更麻烦的是,你没有给 AI 一个"完成的定义"。需求越模糊,AI 的自由度越大,输出越不可控。等它写出一个 500 行的模块,你很难逐行判断哪些逻辑是对的、哪些是它自己编的。这时候出了问题,你连 bug 是出在需求理解、逻辑设计还是实现细节都分不清。我最终转向 SDD,核心原因就一个:我需要把"做什么"和"怎么做"彻底分开,先让 AI 帮我把"做什么"翻译成结构化规格,评审通过后再让它去实现"怎么做"。

1.3 SDD 帮我锁住了什么

SDD 的思路其实不复杂:一切开发工作从写规格开始。规格不是需求文档那种长篇大论,而是一份可以被机器和人类共同理解的、结构化的行为描述。在这之前,我自己的开发习惯是需求想个大概就开始写代码,写一半发现遗漏,返工成本很高。SDD 强迫我先穷举输入输出的边界,把这些边界写成一条条规格,AI 实现的只是规格的镜像。

在这个排版 npm 包里,SDD 帮我锁住了三件事:第一,输入输出的契约——任何情况下都必须返回合法 Markdown,不抛异常;第二,格式化优先级——是表格对齐优先还是代码块保护优先,冲突时听谁的;第三,不做的事——哪些格式不去动,避免过度格式化破坏原文语义。这三件事一旦写进规格,AI 就不会在实现里自作主张。你可能会觉得,写规格本身也要花时间,值吗?后面我会用完整流程告诉你,值,而且省下来的时间远超你写规格的时间。

2. SDD 六步实践:从一句话需求到一个可交付的包

2.1 第一步和第二步:需求澄清与规格拆解

网上关于 SDD 有很多说法,我实际跑下来觉得最顺手的流程是六步:需求澄清、规格拆解、AI 生成、人工评审、测试验证、复盘沉淀。这两个月我一直按这个节奏走,先把第一步和第二步说透。

第一步需求澄清,不是简单地写一句"做一个 Markdown 排版工具",而是要让 AI Agent 帮你追问出一份完整的需求上下文。我当时给 Agent 的原始输入是:"我要做一个 Node.js 的 Markdown 排版 npm 包,重点关注表格和代码块的规范化。"它反问我一串问题:输入是完整文档还是片段?要不要保留原始换行?表格内容里有代码怎么办?代码块内的 Markdown 要不要处理?这些问题一部分有价值,一部分问不到点子上,但没关系——我来回答和补充,回答的过程就是需求澄清。

第二步规格拆解,是把澄清后的需求转成可验证的行为规格。请注意,这里的行为规格不是"实现方案",而是"行为描述"。比如我会写规格:GIVEN 一个含有 3 列表格 WHEN 其中一列内容超过 20 字符 THEN 表格列宽按最长单元格对齐。这就是一条可测试的规格。AI 可以据此写实现,我也可以据此写测试用例。在这个排版项目里,我拆出了 40 多条规格,覆盖表格、代码块、列表、引用、行内样式等场景。

2.2 第三步到第五步:AI 生成、人工评审、测试验证

规格拆完之后,第三步是把规格喂给 AI Agent 去生成实现。注意这里有个技巧:不要一次性把 40 多条规格全丢进去让它一次性写完,那样大概率会在 2000 行代码里埋一堆雷。我按模块分批给,比如先给表格相关的 15 条规格,等这一批实现通过测试,再给代码块相关的规格。每批规格控制在 10~20 条,AI 的输出质量会明显更稳。

第四步人工评审是最容易被忽略但实际上最重要的环节。我不看每一行代码,但我会仔细看这几个地方:AI 有没有为了通过测试而"硬编码"答案;异常分支是不是真的按规格处理的;正则表达式有没有灾难性回溯风险。说实话,AI 写的正则经常会让你怀疑人生,肉眼很难看出问题,所以我会特意问 Agent:"这个正则在极端长输入下会不会卡死?"它一般会自己意识到问题并改成更稳妥的写法。

第五步测试验证,我在整个项目里推行"规格转测试":每条规格对应一个或多个测试用例,测试名直接引用规格编号,保证可追溯。用 Vitest 跑起来很快。表格对齐、代码块保护、嵌套列表这些核心场景,都做到了 100% 通过。还要补一类规格里没写但现实里有大概率出现的输入,比如空字符串、纯数字文本、包含 HTML 标签的 Markdown,这些边界测试交给 AI 生成,我来补充。

2.3 第六步:复盘沉淀成新规格

第六步复盘沉淀,我一开始没太当回事,直到有次发布后收到 issue 才意识到这个环节的分量。当时用户反馈:表格单元格里有个|转义字符\|,我的包直接把整行拆错了。这就是一条新规格的来源——表格单元格内的转义管道符不应被视为分隔符。我把这个 bug 的复现输入、期望输出、实际输出完整记录成一条新规格,再让 AI 去修。

复盘沉淀的本质,是把"项目运行中暴露的问题"转成"下一次迭代的规格输入",这样每次发版不只是修了一个 bug,而是让规格体系更完整。这个排版包从 v0.1 到 v0.7 一共沉淀了 70 多条规格,其中接近三分之一是在复盘阶段补进去的。如果一上来就想把规格写完整再开工,你大概率会陷入过度设计;反而是先写核心规格、快速交付、再通过复盘补规格的节奏更现实。

3. 实操记录:我在 AI Agent 的辅助下如何定义 API 和边界

3.1 让 Agent 先出"接口草案"而不是直接写函数

在 SDD 流程里,API 设计这件事我也交给了 AI Agent,但方式比较讲究:我先不让它写实现,而是让它给出接口草案。接到指令后,Agent 会给出类似这样的设计:

export interface FormatOptions { alignTables?: boolean; normalizeCodeBlocks?: boolean; normalizeListIndent?: boolean; preserveEmptyLines?: boolean; } export function formatMarkdown(input: string, options?: FormatOptions): string;

这个草案最大的价值不是它设计得多完美,而是它给了我们一个可以讨论的具体对象。比如我看了之后会追问:preserveEmptyLines默认值应该是true还是false?AAgent 会根据 Markdown 渲染行为和用户预期给出建议,我再结合项目定位拍板。这种"先有草案,再作决策"的方式,比我让 AI 直接闷头写几百行代码要高效得多,因为接口层面的修改成本远低于实现层面的重构。

3.2 边界条件清单的生成与人工补漏

AI Agent 在生成边界条件清单这方面的能力很强,但不能全信它。我给它的指令是:"根据规格列出所有可能的边界情况,用表格输出,包含输入样例、期望行为、风险等级。"它一口气给了 30 多条,比如输入为空、输入只有空格、输入包含 BOM 头、输入含有 CRLF 换行、表格单元格含中文全角字符、代码块语言标识不存在等等。

不过它有盲区。它没提到"输入是超大文件(1MB 以上)时的性能"和"格式化后与原文档的 diff 不能大到难以 review"这两个点,是我在实际使用中遇到后手动补进规格的。所以我的经验是:把 AI Agent 当作一个非常勤奋的实习生,它能在 10 分钟内给你列出一个像模像样的清单,但你要花 10 分钟检查,再花 5 分钟补充它没见过、只有真实用户才碰得到的场景。这正好也是 SDD 人机协作的微妙之处——AI 负责广度和速度,人负责经验和判断。

3.3 一份规格样例(节选)

下面是我在这个项目里实际使用的一份规格文档节选,你可以直接参考这个格式,它同时可以被 AI 理解和转成测试用例。

# 规格 S-03:表格格式化 ## S-03-01 - GIVEN 一个包含有效 Markdown 表格的文档 - WHEN 该表格存在列宽不一致的列 - THEN 格式化后表格所有列按对应列中最长单元格对齐 ## S-03-02 - GIVEN 一个表格单元格中包含转义管道符 `\|` - WHEN 执行表格拆分逻辑 - THEN 转义管道符不应被识别为列分隔符 ## S-03-03 - GIVEN 一个表格位于代码块内部 - WHEN 执行表格格式化 - THEN 代码块内的表格保持不变,不进行任何格式化操作 ## S-03-04 - GIVEN 一个没有表头分隔行的类表格文本 - WHEN 尝试识别为表格 - THEN 判定为非表格,保持原样输出

我把这些规格用 Markdown 文件存放在仓库的specs/目录下,每条规格有唯一编号。AI 生成代码时我明确要求它标注每条规格对应的实现函数名,这样 review 和测试的时候能双向追溯。如果你也想用 SDD,我强烈建议你从这种 GIVEN-WHEN-THEN 格式开始,它简单、无歧义,而且大多数 AI Agent 都见过这种格式,理解成本非常低。

4. npm 包发布链路与那些绕不过去的坑

4.1 发布前的准备:package.json、版本号与 npm 账号

开发完成之后,真正的考验才开始——发布一个 npm 包涉及的工程细节,远比你想象的繁琐。先说 package.json 里几个容易被忽略的字段。mainmoduletypes三个字段分别指向 CommonJS 入口、ESM 入口和 TypeScript 类型声明,如果你的包同时支持两种模块规范,这三个字段缺一不可。我当时在exports字段上栽了个跟头,写错了子路径映射,导致用户import { formatMarkdown } from 'markdown-autofmt'直接报ERR_PACKAGE_PATH_NOT_EXPORTED

版本号也是门学问。npm 的 semver 规则大家都听说过,但实际操作中很多人懒得遵守:修了个 bug 结果发了 minor 版本,或者加了新功能还发 patch。我在这个项目里给自己定了死规矩:有新功能且不破坏现有 API,发 minor;只修 bug 或优化内部逻辑,发 patch;API 有破坏性变更,发 major。AI Agent 可以帮你生成CHANGELOG.md,但版本号必须你自己做决策,因为它直接关系到下游用户的依赖解析逻辑。

另外,发布前一定要在 npm 官网上注册账号,然后在本地执行npm login。这个步骤看起来简单,但很多人卡在 npm 的 443 端口无法访问或者登录超时。这里我建议确保网络环境能够正常访问官方源,不要使用一些来路不明的代理或镜像。登录成功后,npm whoami会输出你的用户名,看到这个就说明身份认证已经就绪。

4.2 PowerShell 执行策略和 PATH:两台机器上真实遇到的环境问题

发布过程中我最想吐槽的是 Windows 环境。第一次在 Windows 机器上执行npm publish,直接弹出红色报错:npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本。这个报错几乎每个 Windows 用户都会遇到,原因很简单:PowerShell 默认执行策略是 Restricted,不允许运行任何 .ps1 脚本,而 npm 在 PowerShell 下是通过 npm.ps1 这个脚本启动的。

解决方案有两种。第一种是临时放开当前会话的执行策略,在 PowerShell 里执行:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

执行完之后,这个用户就可以运行本地创建的 .ps1 脚本和经过签名的远程脚本。RemoteSignedUnrestricted安全得多,我建议你不要图省事直接设成Unrestricted。第二种方案是绕过 PowerShell,直接用 CMD 运行 npm 命令,但如果你日常就是 PowerShell 重度用户,第一种方案治本。

还有个环境变量问题也很典型:npm : 无法将"npm"项识别为 cmdlet、函数、脚本文件或可运行程序的名称。这个报错说明 Node.js 的安装路径没有加到系统 PATH 里。Node.js 官方安装包一般会自动配置,但如果你是用绿色版或者手动解压的二进制包,就必须把 Node.js 的根目录加到 PATH 里。具体操作是:右键"此电脑"→"属性"→"高级系统设置"→"环境变量",在系统变量里的Path中添加 Node.js 的安装路径。配置完成后,新开一个终端窗口,输入node -vnpm -v都能正常输出版本号,就说明环境已经 OK。

4.3 镜像源与证书过期:npm install 报错的经典处理流程

在配置 npm 环境的过程中,很多新手会碰到npm ERR! code CERT_HAS_EXPIRED这类错误。真实场景是:某些私有 npm 镜像服务使用的 HTTPS 证书过期了,而本地 npm 还在继续请求该镜像源。比如你之前配置过某个淘宝镜像源或公司内部源,这个源的证书失效后,所有npm install都会报certificate has expired

排查思路很简单,先看一下当前实际使用的是哪个源:

npm config get registry

如果输出是一个第三方镜像地址,然后你遇到了证书过期的报错,可以更换为 npm 官方源:

npm config set registry https://registry.npmjs.org/

注意,我这里说的是官方源。网络环境正常情况下,官方源速度完全可以接受。如果你因为网络原因确实需要加速,也请从正规渠道选择可用的镜像,并且要定期关注证书状态,证书过期这个问题只能从源头解决。具体到自己没法核实的情况,我的原则是:优先官方源,少折腾。

4.4 npm publish 与版本迭代规范

终于到了执行npm publish这一步。如果你发布的是公共包,执行完会有两个关键输出:一个是+ markdown-autofmt@0.1.0,表示版本号已经上传;另一个是包的 tarball URL,别人可以通过这个地址下载你的包。但有一点要特别注意:npm 默认会尊重.gitignore文件,如果你的.npmignore没有单独配置,发布时会排除掉.gitignore里列出的文件。很多人辛辛苦苦写的 README 没被发布上去,就是因为他们把 README 写进了.gitignore

还有一个细节是发布前要在本地跑一遍npm pack --dry-run,这个命令能列出所有即将被打包的文件,并有文件大小统计。我发布前一定会执行这个命令,确认specs/目录要不要跟着发布。有些开发者觉得规格文档是内部资料,不想暴露,那就在.npmignore里加一行specs/;如果想让用户了解包的格式化规则,那就保留。我选择了保留,因为对开发者工具类的包来说,透明反而是信任的来源。

版本迭代方面,我后来接入了np这个工具来规范化发版流程,它会在发布前自动帮你跑测试、更新 CHANGELOG、打 Git tag。但我的建议是:AI 可以帮你写 CHANGELOG、甚至帮你起草 release notes,但"这个版本该不该升 minor"这件事,必须你自己判断。AI 没有上下文知道你是不是破坏了向后兼容性,只有你心里清楚。

5. 用 SDD + AI 协作一个月后的真实体会

5.1 效率提升之外,最大的变化是什么

用 SDD 加上 AI Agent 搭档了一个多月,最大的感受倒不是"干活更快了",而是"返工变少了"。以前写代码是"先写再想",写完了才发现漏了边界,补丁套补丁。现在规格先行,虽然前期多花了两三天写规格,但后面写代码和修 bug 的时间大幅减少,整体算下来项目的交付周期反而缩短了将近一半。

更让我惊喜的是,SDD 从根本上解决了"AI 写的代码没法维护"这个痛点。以前 AI 写出来的代码,过两周我自己都看不懂当时为什么这么写。现在每个函数都能对应到一条规格,行为逻辑清清楚楚。甚至有次同事接手这个小项目,我只需要让他先看specs/目录,他说比读代码快多了,还想把这套流程引入他们团队。

5.2 AI 的边界和"规格评审"的重要性

我也踩过不少坑。最典型的一次是我没有认真做规格评审,让 AI 自己生成规格,自己生成代码,自己生成测试,结果三类内容是一致了,但一致地偏离了真实需求。它把"表格格式化"理解成了"表格转 HTML",所有测试都围绕这个错误目标来写,看起来绿油油一片,实际上完全不是我想要的。

从那以后我规定:规格必须我本人或至少一个不参与实现的人来评审。AI Agent 是全能的,但这个"全能"恰好是它最大的风险——它能把错误目标完美实现,而且讲得头头是道。规格评审就是在项目早期把这些偏差找出来,成本最低,收益最大。你可以把规格评审想象成建筑施工前的图纸会审,图纸上有问题,改起来很快;等楼盖起来了再说图纸不对,那就麻烦了。

5.3 给想尝试 SDD 的人几条建议

如果你准备在自己的项目里尝试 SDD,我给几条实操建议。

第一,不要一开始就在大项目上搞。选一个像我这个排版工具一样的小型、边界清晰的项目当试验田,一个模块、一个工具库、一个脚本都可以,跑完六步流程你就知道这套方法的边界在哪里。

第二,规格文档不是一次性的。我见过很多人写规格只是走个过场,写完就扔,后续代码迭代根本不更新规格。这比不写规格更糟,因为规格和代码不一致时,你会完全失去判断依据。我自己的原则是:代码改了,规格必须跟着改,否则就不算完成。

第三,AI Agent 在规格生成和测试用例生成上的帮助非常实用,但核心决策必须自己拿。用 AI 起草一份有 30 条边界的清单,你人工补了 5 条进去,这比从头写 35 条更省力,质量也更可控。人机协作,不是人做 AI 做的事,而是让 AI 做人做不到或不擅长的规模覆盖,人做 AI 做不了的判断和取舍。

最后再分享一个小技巧:我在项目里开了个AI.md文件,记录每次和 Agent 协作时哪些提示词效果好、哪些规格格式容易让 AI 误解。这个文件变成我自己的"AI 协作配方",下一个项目直接复制调整,不用从零摸索提示词格式。SDD 是一套流程,但真正让你越用越顺手的,是在重复中积累出的方法论。希望这篇实战记录能给你一些启发,也欢迎你带着自己的项目去试一次 SDD,它会改变你对"写代码"这件事的认知。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询