AI 协作开发新范式:我用 SDD 做了个排版 npm 包
上一次我把 SDD(Spec-Driven Development,规范驱动开发)的理论捋顺了:任何项目都要经历两次创造,先在脑子里设计一遍(心智创造),再动手实现(物理创造),对应到工程上就是先写规范、再让 AI 照着规范写代码。当时总结出三份核心文档------proposal.md 管需求、design.md 管架构、task.md 管任务。
理论是通的。但留下一个问题没解决:文档写完之后呢? 把 task.md 往 AI 面前一丢,说"照着做",它就能乖乖交付吗?
这次真刀真枪跑了一个完整项目,才发现理论和实操之间还隔着一门学问------怎么"管"AI。这篇文章记录整个流程:需求怎么做出来、架构怎么定、原型怎么生成、任务怎么拆、规则怎么立。项目本身也不复杂,但过程里的方法论,比代码值钱。
一、这次要做的东西:wx-md
先交代项目。写技术文章的人大多有个共同体验:正文用 Markdown 写,顺手、专注、不折腾。可一到发微信公众号,排版就成了体力活------编辑器不认 Markdown,样式、代码块、标题层级全得手动调。
所以这次的目标是一个 npm 包:wx-md,微信公众号 Markdown 渲染组件。传入 Markdown 字符串,实时渲染成公众号风格的排版,一键复制,粘贴进公众号编辑器后样式原样保留。作为组件发布,别的项目直接安装集成。
做这个项目用 SDD 流程走,还有个背景概念值得记一笔:OPC(One-Person Company,一人公司)。AI coding 时代,一个人加上 AI,就足以自主开发一个 MVP 甚至完整项目------需求、设计、开发、发布,全流程一个人闭环。SDD 正是支撑这件事的协作范式:它是我和 AI 之间的"交流语言",我把意图写成规范,AI 把规范变成代码。
整个流程的文档链是这样的,一条线走到底:
markdown
proposal.md(需求文档)
↓
design.md(技术架构) + design_guide.md(设计指南)
↓
ui-design.html(可交互原型)
↓
task.md(任务拆分)
↓
project_rules.md(项目规则)
↓
AI 逐任务开发
二、需求文档:模糊时让 AI 启发,清楚时让 AI 完善
第一站是需求文档。这里有个前置认知:需求文档对应的是"产品经理"这个角色,产出物是 PRD(产品需求文档)------产品分析、市场分析、竞品分析、调研,再加上产品设计原型。
但产品经理不会凭空工作,我面临一个现实问题:我自己都还没想清楚要什么,怎么写需求?
实践下来是两条路,按需求状态分流:
- 需求模糊时,找 AI 启发。 直接用 AI 编程工具里现成的头脑风暴技能(brainstorming skill),让它从核心功能、用户界面、可配置性这些不同维度分析,给出需求建议。它列的维度不一定全对,但能把我没想到的角落补上。
- 需求已经清楚时,找 AI 完善。 这时别让它自由发挥,而是把我写好的初稿交给它查漏补缺。
这两条路的区别很本质:前者是让 AI 帮我"想",后者是让 AI 帮我"查"。方向反了,效果就没了。
最终的 proposal.md,核心功能定了五块:
- 预览组件------接收 Markdown 字符串,内容变化时实时更新渲染视图;
- 主题切换------内置 5 个主题:简约白(默认)、薄荷绿(清新低饱和)、微信暗黑(深色背景)、科技蓝(专业冷静)、复古橙(文艺暖调),H2~H6 标题前带主题色竖线装饰,切主题时竖线颜色跟着变;
- 代码块样式 ------容器模仿 macOS 窗口,带"关闭、最小化、最大化"三个装饰性彩色圆点,语法高亮默认
github-dark风格; - 响应式设计------手机 / 桌面两种视图切换,默认手机视图;
- 内容复制------一键把渲染结果转成公众号编辑器支持的 HTML 复制到剪贴板。
除了功能,PRD 还规定了 UI 交互(设置区域顶部居中、滚动时悬浮固定、按钮全部图标化)和可配置性(通过参数控制设置区域显隐;把主题切换函数等内部功能导出,让使用方可以不用内置设置栏、自己摆按钮)。
三、架构与原型:AI 的用武之地不止写代码
需求确认后,下一步是技术架构设计。这一步 AI 的参与方式变了------它得先"查资料"。
Tavily:专为大模型与 AI Agent 打造的搜索 API,可输出结构化的网页检索内容,用来给大模型补充实时网络信息、缓解幻觉问题。
这个思路很有意思:做技术选型时,模型自身的知识有截止日期,而且会一本正经地胡说。接一个 Tavily 这样的搜索 API,让它先去查最新的生态现状,再给选型建议,靠谱程度完全不同。AI 辅助架构设计的正确姿势,不是让它凭记忆答题,而是让它带着搜索结果答题。
最终的选型清单,每一项都写了理由:
| 用途 | 选择 | 理由 |
|---|---|---|
| 核心框架 | React 18+ | 社区庞大、组件化开发模式适合做可复用 UI 组件,Hooks 管状态和副作用方便 |
| 构建工具 | Vite | 极速冷启动和 HMR,基于 Rollup 的打包为生产环境输出优化代码 |
| 样式方案 | CSS Modules + PostCSS | 局部作用域避免全局污染,PostCSS 用最新 CSS 特性并自动加前缀 |
| Markdown 解析 | react-markdown + remark-gfm | 安全性高、可定制性强,GFM 插件支持表格、删除线等扩展语法 |
| 代码高亮 | react-syntax-highlighter | 支持多语言和丰富高亮主题,github-dark 满足需求 |
| 样式内联转换 | juice | 成熟的 CSS 转内联样式库,"复制到公众号"功能的核心 |
配套的还有目录结构规范(模块化、高内聚低耦合:components、hooks、styles/themes、utils 各归其位)和编码规范(Prettier 格式化、ESLint + react 插件查质量、组件 PascalCase、函数变量 camelCase、复杂逻辑必须注释)。
技术文档定稿后,就到了AI 辅助原型设计 :基于需求和架构,快速构建一个可交互的视觉原型。现在的原型工具生态比我想的成熟------蓝狐、Figma、Google Stitch 这些产品原型设计工具,全都提供了对应的 MCP(Model Context Protocol,模型上下文协议) 接口,AI 可以直接调用它们生成可交互的原型,界面上能直接看到 MVP 的效果,包含大致功能和交互逻辑。
但这里有个认知必须摆正,不然原型会变成负资产:
- 产品经理的 MVP,只能用于演示"产品经理脑中的产品界面与交互长什么样";
- 设计师,负责审美;
- 程序员,负责性能、稳定、开发流程。
三个角色三种立场,意味着 MVP 天生不是终稿------肯定要基于 MVP 进行二次开发。原型回答的是"做什么",不回答"怎么做对"。把原型当圣旨直接往上垒代码,后面全是坑。
四、真问题来了:AI 扛不动大任务
原型有了,文档齐了,接下来该让 AI 写代码了。这时候整个流程里最重要的认知出现了:
现在,程序员是架构师,AI 是代码开发者。
架构师不给开发者丢一句"把这个系统做了",而是拆任务、定规范、排依赖。管理 AI 的方式,和管理一位人类初级工程师的方式,本质上是同一件事。
那为什么不能直接把宏大的复杂任务丢给 AI,指望它完美交付?两个硬约束摆在那:
- 上下文限制。 AI 有记忆模块,但处理一个长任务的过程中,它可能遗忘早期的关键细节。对策是把细节全部文档化------比如存入 AGENTS.md 这类项目说明文件,让 AI 随时能回查,而不是指望它"记住"。
- 大任务期间细节处理能力下降。 一次性处理的内容越多,AI 对每个细节的关注度就越低。跟人一样:同时干十件事,每件事都是六十分。
所以方法论收敛成两条,一软一硬:通过精细的任务拆分来引导 AI(任务最好细化到结果可以复现),通过明确的项目规则来约束 AI(任务间的依赖与执行顺序写死)。拆分保证它不会消化不良,规则保证它不会自由发挥。
五、方法一:任务拆分,细到结果可复现
任务拆分的最终产物是 task.md。动手前先定了四条拆分原则:
- 渐进式开发------从基础功能到高级特性,每个阶段都有可见成果;
- 模块化设计------按组件和功能模块拆,降低耦合;
- 优先级导向------核心功能优先,增强功能其次;
- 可测试性------每个阶段都能独立测试验证。
整个项目拆成了九个阶段:
| 阶段 | 内容 | 一句话目标 |
|---|---|---|
| 一 | 项目基础架构 | Vite + React 初始化、库模式配置、5 个主题的 CSS Modules、玻璃拟态基础样式 |
| 二 | 核心预览功能 | react-markdown + remark-gfm 渲染引擎、预览容器组件 |
| 三 | 主题系统 | useTheme Hook、Context 状态管理、设置面板 |
| 四 | 代码块增强 | CodeBlock 组件、macOS 三色点、github-dark 高亮 |
| 五 | 响应式与视图 | useViewMode、手机/桌面切换(默认手机)、平板适配 |
| 六 | 复制功能 | useCopyToClipboard、juice 内联样式转换(公众号兼容的关键) |
| 七 | 组件导出与可配置 | Props 接口设计、导出组件和 Hooks、默认配置合并 |
| 八 | 本地开发与测试 | npm link 本地联调、vite build --watch 实时更新 |
| 九 | NPM 包发布 | 库模式打包、ES/CJS 双格式输出、README 和 demo |
每个任务卡片都是统一结构:优先级(🔴 最高 / 🟡 高 / 🟠 中)+ 预期效果 + 具体任务清单 + 验收标准。拿整个项目里优先级和含金量都最高的"任务 6.2 微信公众号样式兼容"举例:
- 优先级:🔴 最高
- 预期效果:复制的内容能够在微信公众号编辑器中正确显示
- 具体任务:集成 juice 库、实现 CSS 到内联样式的转换、获取当前主题的 CSS 字符串、实现 HTML + CSS 合并处理、确保代码高亮样式兼容、在微信编辑器中实测
- 验收标准:复制内容在公众号编辑器中样式正确、所有主题都能正确转换、代码块高亮在微信中正常显示
注意验收标准这一栏------它就是"结果可以复现"的落点。任务拆得再细,没有验收标准,AI 做完自己说"完成了",你没法判断。
还有一步容易漏:拆分本身也要审查与迭代。第一版拆出来的任务,回头审视一遍:够不够具体?够不够清晰?不够就继续拆。拆任务不是一次成型的动作,是个打磨过程。
六、方法二:项目规则,给 AI 立一本员工手册
任务拆好了,还差最后一块:项目规则。
它的意义用一句话说清:AI 编程助手如何保证它像团队成员一样严格遵守项目的规划和任务,而不是自由发挥。规则写在 project_rules.md 里,放在 .trae/rules/ 目录下,AI 每次干活都会读到。核心就四条:
- 任务的执行边界------AI 何时开始、何时停止;
- 代码风格------确保生成代码的统一性和可读性;
- 技术栈遵循------必须用指定的语言和框架,不得引入未经批准的替代方案;
- 沟通方式------规定 AI 遇到问题时如何响应和提问。
技术栈之外,规则里还写了组件开发指南,几条都很实在:单一职责 ------Previewer 只管渲染,SettingsPanel 只管交互控制;布尔类型的 Prop 用 is、has、should 开头(比如 isDarkMode),看名字就知道是个开关;状态管理优先 useState 和 useReducer,跨组件共享的状态走状态提升或 useContext;可复用逻辑(比如剪贴板操作)封装成自定义 Hook 放进 src/hooks/;逻辑(JavaScript)、结构(JSX)、样式(CSS Modules)三层关注点分离。
前四条是"约束做什么",这个项目里更有意思的是专门写给 AI 的任务执行规范,把"怎么管一个初级工程师"落到了可执行的程度:
任务范围控制:严格按照 task.md 定义的范围执行,不得超出指定任务的边界;每次只执行一个明确指定的任务(比如"任务 1.1"),完成后等待确认再进行下一步;禁止基于架构文档自行扩展任务范围------确实需要扩展,先通知确认。
任务指令格式:给我自己也定了话术,避免歧义------
- 明确任务编号:"请执行任务 X.X:任务名称"
- 范围限制:"只完成任务 X.X 中列出的具体任务,不要超出范围"
- 停止指令:"完成后等待我确认再进行下一步"
执行验收:每个任务完成后,对照 task.md 里的验收标准自检;检查所有创建的文件和代码都在任务范围内;总结完成情况,等确认。
异常处理:任务描述不清晰,先询问而不是自行决定;当前任务依赖其他未完成任务,明确指出依赖关系等指示;发现超范围的代码,主动问是否清理。
盯着这份规范看一会儿,会发现它和公司里带新人的手册几乎一模一样:限定职责范围、一次一件事、做完汇报、不懂就问、越界先报备。区别只在于对象是 AI------它不会累、不会闹情绪,但会遗忘、会自作主张、会在你看不见的地方发挥。规则就是冲着这三点去的。
规则文件里还有一些纯工程约束,同样值得抄走:react 和 react-dom 必须声明为 peerDependencies 而不是 dependencies(组件包不该把宿主的 React 打包进去);Vite 配置库模式并在 rollupOptions.external 里排除 React;files 字段设为 ["dist"] 只发布构建产物。
七、技术核心:公众号只认内联样式
流程讲完了,回到这个项目技术上真正难的那一关:为什么从网页复制内容到公众号,样式总是全丢?
因为微信公众号编辑器对外部 HTML 的样式支持有严格限制------class 选择器一律不认,所有样式必须以内联 style 属性的形式写在元素上。而正常网页的样式全靠 CSS 类挂在外部,粘贴过去自然全没了。
design.md 里给了完整方案,核心武器是 juice------一个专门把 CSS 规则转换为 HTML 内联样式的库。整个复制流程六步:
- 用户点击"复制"按钮,触发
handleCopy函数; - 通过
ref拿到预览区域div的innerHTML; - 根据当前选中的主题,动态加载对应主题的 CSS 内容(字符串形式);
- 把 HTML 字符串和主题 CSS 字符串一起交给 juice,由它解析 CSS、把所有匹配的样式规则应用到对应元素的
style属性上------比如 CSS 里的.title { color: blue; }会被转成<h1 class="title" style="color: blue;">...</h1>; - 代码块高亮不用额外处理:
react-syntax-highlighter默认生成的就是带style的<span>标签,天然是内联的,微信直接认; - 用
navigator.clipboard.writeText把处理后的 HTML 复制到剪贴板。
第 5 步算是个幸运的巧合:选 react-syntax-highlighter 的时候是冲着高亮主题丰富去的,后来才发现它的输出格式天然过得了微信这一关。技术选型的理由文档里写得越清楚,这种"意外的兼容"越容易在复盘时被发现。
主题系统则是另一套设计:每个主题覆盖一组 --pd-* 前缀的 CSS 变量,全局背景色、正文色、H1~H6 的字号颜色字重、引用块、列表项、链接、行内代码......全走变量。切主题就是换一整套变量值,标题竖线装饰绑定 --pd-head-bar 变量随主题同步变色(H1 作为最大标题不加竖线),再用 CSS transition 让颜色过渡平滑。五套主题各有主色:简约白 #15181d、薄荷绿 #2fbf8f、微信暗黑 #9aa2af、科技蓝 #1e80ff、复古橙 #d97706。
视觉风格上,设计指南走的是玻璃拟态(Glassmorphism) :半透明背景加 backdrop-filter: blur() 毛玻璃、白色半透明边框、大圆角(主容器 28px)、8px 网格间距系统、手机/平板/桌面三档断点(≤480px / 481-768px / >768px)。缓动统一用 cubic-bezier(0.4, 0, 0.2, 1),还定了对比度 ≥ 4.5:1 的可访问性底线。
设计指南里还铺了一层工程兜底。性能上:动画走 transform 而不是改布局属性,频繁操作做防抖,长列表上虚拟滚动,非关键资源懒加载。测试上分四层:单元测试管组件功能和状态管理,集成测试管组件间交互和数据流,视觉回归测试保 UI 一致性,可访问性测试守无障碍底线。往后再扩展也留了口子------主题创建工具、自定义主题导入、插件机制,同时 API 保持向后兼容。
不过复盘时翻文档,发现一个真实的问题:design.md 里写的主题是"简约白、薄荷绿、微信暗黑、科技蓝、复古橙",而 design_guide.md 里迭代出来的版本却变成了"极简白、樱花粉、森林绿、海洋蓝、日落橙"------两份文档的主题清单对不上了。
这恰好是 SDD 理论的反面教材:规范是唯一真值,文档之间不同步,真值就分裂了。AI 到底照哪份执行?如果 task.md 是从 design.md 生成的,那实现出来就和设计指南冲突。正确做法是发现差异时先修文档、对齐口径,再让受影响的代码重新生成------而不是放任两份规范各说各话。文档是活的,但活得有序。
八、我现在的理解
跑完这一整圈,我对"AI 时代的开发"这件事的理解刷新了不少。
以前觉得 AI 编程的核心是 prompt 写得好不好。现在看,prompt 是点状的努力,SDD 是系统性的工程:需求阶段用头脑风暴技能把模糊想法逼清楚,架构阶段让 AI 带着搜索做选型,原型阶段用 MCP 驱动设计工具出 MVP,开发阶段用任务拆分和项目规则管住 AI 的边界。每一环都有 AI 参与,但每一环的"方向盘"都在我手里。
那句贯穿全程的话值得再写一遍:程序员是架构师,AI 是代码开发者。 架构师的核心产出不再是代码,而是规范和任务;价值不再体现在"我会实现",而体现在"我知道该实现什么、怎么拆解、怎么验收"。这大概也是 OPC 成立的原因------当"实现"的成本被 AI 压到极低,一个人加上一套严谨的文档流程,就真的能顶一支队伍。
当然,这套流程不是没有成本。写 proposal、design、task、rules 四份文档,比直接开聊 prompt 麻烦多了。我的判断是看项目体量:一次性小脚本,Vibe Coding 依然最快;要多文件、要长期维护、要发布给别人用的东西------比如这个要上 NPM 的组件------文档投入就是划算的。麻烦是真的,返工更疼也是真的。
术语速查
- SDD(Spec-Driven Development):规范驱动开发。规范文档是唯一真值,代码是从规范派生的产物;代码跑偏时先修规范,再重新生成受影响的代码。
- OPC(One-Person Company):一人公司。AI coding 时代,一个人借助 AI 完成需求、设计、开发、发布的完整闭环。
- PRD(产品需求文档):产品经理角色的产出,包含产品分析、市场分析、竞品分析与调研。
- MVP(Minimum Viable Product):最小可行产品。在原型阶段只用于演示界面与交互逻辑,正式实现必须基于它二次开发。
- MCP(Model Context Protocol):模型上下文协议,让 AI 调用外部工具(如 Figma、Google Stitch)的标准化接口。
- Tavily:为大模型与 AI Agent 打造的搜索 API,输出结构化检索内容,用于补充实时信息、缓解幻觉。
- GFM(GitHub Flavored Markdown):GitHub 扩展版 Markdown 语法,支持表格、删除线、任务列表等,由 remark-gfm 插件提供支持。
- juice:将 CSS 规则转换为 HTML 内联 style 属性的库,实现"复制到公众号"的核心。
- peerDependencies:npm 的"同侪依赖"声明。组件包把 react 声明在这里,表示"我需要它,但请用宿主项目自己的那份",避免重复打包。
- SemVer(Semantic Versioning) :语义化版本控制,版本号格式为 主版本.次版本.修订号,配合
npm version命令管理。 - npm link:本地包联调命令,在全局创建符号链接,让其他项目可以直接引用未发布的本地包。
- 玻璃拟态(Glassmorphism):半透明背景 + backdrop-filter 模糊 + 细边框 + 大圆角构成的视觉风格。