事情要从我想做的那个浏览器插件说起
那段时间我脑子里一直有个想法:做个浏览器插件,在英文网页上点一下,自动把文章正文提出来,丢给 AI 翻译成中文,渲染成 Markdown,再一键复制——目标用户是做公众号的那帮朋友,英文版块直接搬成中文版。
我在对话框里敲了一句"帮我做一个浏览器插件,能提取网页正文、调用 AI 翻译、导出 Markdown",然后 AI 唰唰吐了几千行代码。
说实话,第一天是真的上头。插件居然装到 Chrome 里跑起来了,demo 页面上翻译结果像模像样。我当时觉得"十倍效率提升"真不是吹的。
然后第二周,开始返工。
"提取正文"这个功能在各种网站上花式翻车:导航栏被当成正文、广告混进翻译里、分页文章只抓到第一页。我让 AI 修,修了 A 坏了 B。更崩的是,新开会话之后它完全不记得之前的决策——为什么选这个方案、哪个文件改过、为什么改,全没了。它只能猜,猜错就是幻觉,每一轮返工都在烧我的时间和 token。
真正让我停下来的是一个差点崩盘的晚上:AI 一次"优化"把整个提取逻辑改挂了,我看着满屏报错,脑子里只有一个念头——上一个能跑的版本,我好像没提交。
问题到底出在哪
后来我才想明白,AI 没毛病,是我的用法有问题:我跳过了"想清楚"这一步,直接让它"干出来"。
这就像盖房子不画图纸,工人手快不是什么好事,墙砌得越快,等发现卧室没留门的时候就越绝望。《高效能人士的七个习惯》里讲"以终为始",说任何事物都要经历两次创造:第一次是心智创造,在脑子里把它设计出来;第二次才是物理创造,真刀真枪盖出来。
Vibe Coding 的病根,就是被聊天窗口诱惑着,跳过第一次创造,直接冲进第二次。
Spec-Driven Development(规范驱动开发,简称 SDD)干的事说穿了就一句话:先把脑子里的设计落成文档,再让文档驱动 AI 写代码。 当写代码的成本越来越低,真正稀缺的不是会写代码的 AI,而是一份清晰、可执行、可验证的意图。
文档不用多,按需来,核心就三份:
proposal.md:要做什么、为什么做,边界在哪design.md:怎么实现,技术架构和选型task.md:先干什么后干什么,哪些能并行
拿我的插件真走一遍
先把 MVP 抠到最小
重新开工,我没让 AI 写一行代码,先写 proposal.md,逼自己把需求抠到最小可行单元:
1## 要做什么 2在英文博客页面一键完成: 3提取正文 → 调 AI 翻译成中文 → Markdown 渲染 → 一键复制 4 5## 不做什么 6- 不做收藏夹、历史记录 7- 不做账号系统 8- 不做中英以外的语种 9- 不做整页翻译,只翻正文 10
"不做什么"这栏特别重要,它是用来拦 AI、也拦我自己的。没这栏,AI 会热情地给你加上登录、云同步、深色模式……最后做出来一个谁都不需要的东西。
技术难点要摊开写,不能糊弄
然后是 design.md,把难点一条条摊在桌面上:
1## 技术难点 21. 正文提取:网页结构千奇百怪,先调研 Readability 类方案 32. AI 接入:统一走 OpenAI 兼容格式,deepseek、qwen 只改配置 43. Markdown 渲染:用 npm 的 marked 54. 输出格式要适配微信公众号(标题、引用、代码块样式) 6
比如"AI 模型可配置"这条,写下来之后选型就顺了:不绑死任何一家,全按 OpenAI 的接口格式对接,想换模型只改 baseURL 和 key。这种决策在聊天里随口就定了,没文档的话,三个会话后保证忘得一干二净。
写文档不是写给同事看的,是喂给 AI 的上下文。会话一关上下文就清零,但文件还在。新会话开场不用重新解释项目,一句"先读 proposal.md 和 design.md",它就全想起来了。
真正的后悔药:小步提交
文档解决了"想清楚"的问题,但 AI 写代码照样会幻觉。另一条铁律我是拿血泪换来的:AI 生成的代码,跑通一个可验收的版本,立刻提交。 有版本兜着底,它幻觉它的,我随时能退。
那天晚上之后,我把"改坏了怎么退"练得特别熟。改动出问题,分三种情况,对号入座:
1# 情况 1:改了文件,还没 git add —— 直接丢弃工作区修改 2git restore . 3 4# 情况 2:已经 git add 进了暂存区,但还没 commit 5# 先把改动移出暂存区,再丢弃。别问我为什么知道,试了三次 6git restore --staged . 7git restore . 8 9# 情况 3:已经 commit 了 —— 硬回退到上一个提交 10git reset --hard HEAD^ 11
情况 2 坑了我最久。我原以为 git restore . 是万能的,结果暂存区里那份坏代码纹丝不动,回头 AI 还基于它继续改,错上加错。后来才搞明白:工作区和暂存区是两层,得一层层往外退。
实际跑一遍长这样:
1$ git status 2On branch main 3Changes not staged for commit: 4 modified: src/extractor.js 5 6$ git restore . 7$ git status 8On branch main 9nothing to commit, working tree clean 10
git reset --hard HEAD^会把当前提交之后的改动全扔掉,敲回车前先git status看一眼,确认那些改动你真的不要了。
有了频繁提交的习惯,心态完全不一样了。以前是"AI 你可千万别给我改坏了",现在是"随便改,改坏了一条命令回到能跑的版本"。这大概就是版本控制给 Vibe Coding 上的保险。
再往深想一层:文档治的到底是什么病
用了一段时间我意识到,SDD 治的不是"AI 写代码不行",是上下文丢失。
聊天记录不是持久的,窗口一关、会话一长,早期的决策就被挤出上下文了。而"一键提取文章核心内容"这种话,敲下来只要十秒,真要落成可执行的规范,你得回答一堆问题:什么算核心内容?导航菜单要不要?评论区呢?分页文章怎么办?
这些问题你不回答,AI 就只能猜。你把答案写进文档,它每一轮都读得到,猜的空间就没了。所以写文档这个动作本身,就是在替未来的每一次对话把上下文存档——顺便还能逼自己把事情想明白,属于买一送一。
最后说点实在的
走完这一遍,最值钱的三个体会:
一是万事真的有两次创造,动手前让脑子里那遍先发生,哪怕只花半小时;二是文档不是应付检查的交付物,它是 AI 的上下文存档,写给它看,也顺便治自己的糊涂;三是小步提交是后悔药,没有频繁 commit 兜底,让 AI 改代码跟裸奔没区别。
不过这玩意儿也不是万能的。你要是周末花两小时写个一次性脚本、用完就扔,那真别搞三份文档,那是给自己加戏。问题规模小到脑子装得下、会话不会断,流程就是负担。SDD 真正适合的,是那种要跨好几个会话、有明确技术难点、还打算长期迭代的项目——比如我这个到现在还在改的翻译插件。
对了,如果你也被 AI 的幻觉坑过,或者对 git 那两层区域有不一样的理解,搞懂了记得回来留个言,我也想看看你是怎么从坑里爬出来的。
《被 Vibe Coding 反噬之后,我老老实实地回去写文档了》 是转载文章,点击查看原文。