“vibe coding 一时爽,维护火葬场”。这句话我过去几个月体会得淋漓尽致。用自然语言让模型帮我写功能,十分钟能出一个能跑的版本,那种“人机合一”的流畅感确实容易上瘾。但等代码量堆到几千行、组件之间开始互相牵扯、改一个前端弹窗能把后端接口带崩的时候,我才意识到:vibe coding 总是失控,问题多半不在模型,而是我根本没搞懂工程化到底在解决什么问题。
这个认知是被一个 24.5 万星的开源仓库点醒的。不是模型不行,是我缺了它沉淀下来的那一整套系统设计思维。如果你也在 vibe coding 的爽感和失控之间反复横跳,这篇内容应该能帮你少走几个月弯路。我会从症状聊到病根,再把我实际用下来的六条“反失控”经验完整分享出来,全程可操作。
1. vibe coding 的爽与失控,是同一枚硬币的两面
1.1 从“一句话生成功能”到“三小时修 bug”的真实体验
先说说我自己的真实经历。上个月我想给一个内部工具加一个数据导出功能,对着模型说了一句“加个按钮,点击后把当前表格导出成 Excel”,三十秒不到,代码出来了,点击、下载、打开,文件内容完全正确。那一刻真的觉得:编程已经死了,人人都是产品经理。
这种体验在最初两周特别上瘾。新功能一个接一个加,UI 调得飞快,接口也能自动拼出来。我当时甚至觉得,以后写代码根本不需要再“设计”什么了,想到什么直接让模型生成就好。
但问题在第三周集中爆发。先是导出的 Excel 里日期格式和旧文件对不上,我让模型改,结果它把生成 Excel 的库换掉了,旧文件的样式全部失效。接着是权限校验逻辑,模型“贴心”地加了一层缓存,结果管理员的权限变更要等十分钟才生效。最崩溃的一次,我只是想加一个空状态提示,模型却把整个数据请求的链路重写了,线上直接报 500。
我统计过,那段时间我花在“让模型理解我以前写了什么”上的时间,比它帮我写新功能的时间还多。后来我翻 Git 提交记录,发现项目在两周内新增了 4000 多行代码,但真正被保留下来、没有返工的,只有不到三分之一。
1.2 失控的三层表现:代码、依赖、需求
这不是个例。我观察过团队里其他喜欢 vibe coding 的同事,失控几乎都沿着同一条路径发生。
第一层是代码失控。AI 生成的代码风格不稳定,同一类工具函数可能同时存在三个版本,命名一会儿用 camelCase 一会儿用 snake_case。最麻烦的是它倾向于“一次性生成一大坨”,而不是像有经验的工程师那样小步拆分。你很难从几百行的函数里定位到底是哪一段逻辑出了问题。
第二层是依赖失控。模型会为了一个小功能引入一个很大的库。我之前遇到过为了让一个字符串格式化功能更“优雅”,它偷偷装了一个包,结果这个包和项目原本的 lodash 版本冲突,整个构建直接挂掉。这种依赖层面的问题最难排查,因为错误信息往往出现在完全不相干的模块里。
第三层是需求失控。这是最隐蔽的。当项目里没有清晰的 TODO、没有设计文档、没有验收标准时,vibe coding 很快就会“自作主张”。模型会基于它对“一个导出功能应该长什么样”的概率理解,去填充你没说的细节。而这些细节十有八九不是你真正想要的。于是你和模型之间会陷入“改了又改、越改越乱”的循环。
这三层失控叠加起来,就形成一个观感:vibe coding 只在两种情况下好用——代码量极小的一次性脚本,或者你对整个系统已经有了极其清晰的边界把控。
2. 病根不在模型,到底在哪?
2.1 模型的本质是“概率逼近”,不是“工程承诺”
很多人把失控的锅甩给模型能力,说“要是有了更强的模型,这些问题就自动消失了”。这话我不同意。
从原理上看,Transformer 这类模型做的事情是:基于海量代码学习词汇和结构之间的概率关系,然后在你给出一段 prompt 时,预测最可能的下一段 token。它本质上是一个“概率逼近器”,它在做的不是“保证这个功能在工程上正确”,而是“这段代码在统计意义上最像人类程序员会写的代码”。
这就意味着,模型输出的代码,是在“很多网友公开代码”的平均水平附近浮动。它擅长那些网上有大量样本的、约定俗成的写法,但一旦你的项目有独特的业务规则、特有的历史包袱、微妙的边界条件,模型就开始“凭感觉编”。它不知道你三个月前为了兼容某个旧系统做了什么妥协,它也不知道你现在的生产环境上有哪些暗坑。
所以,模型不是不够聪明,而是它没有一个“像你一样理解项目”的入口。你给它的上下文越少,它越只能靠通用经验来猜。猜中的概率在你项目复杂度上升后,会急剧下降。
2.2 vibe coding 最大的误区:把临时方案当长期架构
我反思自己失控的根源,是一个错误的心态:把“能跑”当成了“做完了”。
Vibe coding 天然鼓励快速产出,这本身没错。原型验证阶段、黑客松项目、个人小工具,快速跑通比设计方案重要得多。但问题是,很多人直接把这个节奏带进了长期项目。前端框架随便选,后端结构不划分,异常处理全部靠模型自动生成,数据库表设计完全交给模型的“感觉”。
结果就是,项目第一次能跑时,看起来一切正常。但从第二次改动开始,你就要为当初省的每一步设计买单。改一个字段,要连带改十个文件,因为当初没有做参数收敛;加一个接口,要复制三段几乎一样的鉴权代码,因为当初没有做中间件抽象;出了一个线上 bug,要沿着五六层嵌套函数一层一层往里钻,因为当初没有做模块边界。
说白了,vibe coding 失控的病根,是你把“临时方案”当成了“最终架构”。模型只是忠实地执行了你的这个错误决策。它不会主动说“这个设计只能支撑三天”。
2.3 “模型”在不同领域从来都不是银弹
还有一个认知偏差值得点一下。“模型”这个词本身有太多含义。机器学习里有 Transformer 模型、扩散模型、世界模型;工程上有电机模型、温控系统的 FOPDT 模型;管理上有最大覆盖模型。这些“模型”都是对现实某种程度的抽象和简化,从来没有任何一个模型是“完整”的。
当你在 vibe coding 时使用“模型”,你用的其实是一个经过压缩的、平均化的“程序员行为模型”。它对你项目的理解,远不如你对它的理解那么完整。所以指望模型自动搞定架构、自动管理依赖、自动判断业务边界,本来就超出了它作为“模型”的物理上限。
想明白这一点,你就不再跟模型较劲了。你要做的,是把自己变成一个能补全模型短板的人:你负责给系统画边界、定规则、控依赖,模型负责在边界内高效生成。换句话说,控制权必须在人手里。
3. 24.5 万星仓库的启示:系统化思维才是解药
3.1 超高星仓库里藏着的不是代码,是“反脆弱”的工程经验
那个点醒我的 24.5 万星仓库,名字我就不具体点了,主题是“系统设计入门”(System Design Primer)。这类仓库能拿到这么多 Star,不是因为里面的代码多炫酷,而是它把软件工程里那些“看不见摸不着但决定项目生死”的东西,整理成了一套可以学习的方法论。
我翻它目录时的第一感受是:它讲的全都是 vibe coding 最不爱讲的“硬知识”——容量估算、一致性哈希、分布式事务、缓存策略、API 设计、数据库选型。这些东西在你写 CRUD 的时候好像都用不上,但你的项目一旦开始承担真实流量、真实业务、真实迭代,每一项都是决定你能不能“睡得着觉”的关键。
我当时就明白了一个道理:高 Star 仓库的本质,是大量从业者用血泪换取的经验凝练。它能获得几十万人的认可,说明这些工程实践不是少数人的教条,而是被反复验证过的“避坑指南”。Vibe coding 爽归爽,但它恰恰绕过了所有这些经验。你把工程上的“边界约束”全丢掉,只让模型自由发挥,那失控就是必然的,而不是偶然的。
3.2 从仓库结构里反推出的“反失控”方法论
我把这个仓库的目录结构反复读了几遍,发现它本质上是一个“多层防御体系”:每一层都在回答一个具体问题,每一层都在压缩后续出错的概率。
第一层是概念层:先把术语和原理讲透。这对应到你做项目,就是要在动代码之前,先想清楚“这个系统到底有几部分、每部分的职责是什么”。第二层是设计层:容量怎么估算、数据怎么存储、服务怎么拆分。这对应着你画架构图、设计数据模型、约定接口契约的过程。第三层是实现层:缓存怎么用、消息队列怎么接、异常怎么处理。这对应到你写具体业务代码时,要遵循的那些规范。第四层是运维层:监控、日志、告警、回滚。这对应到项目上线后的可观测性。
每多一层的约束,系统就更稳一分。反观 vibe coding,它的问题是直接跳过了前三层,从“实现层”开始,而且实现层也没有任何团队约定。你让一个模型去写它不了解业务背景的代码,然后期望它能自动形成架构、自动做好边界、自动防御未来可能出现的风险,这等于你把方向盘、油门、刹车全交给了一个刚拿到驾照的新手。
所以那个 24.5 万星仓库真正教会我的不是某个具体技术,而是一种“分层设防”的思维方式。Vibe coding 可以用,但它必须被装进这套防御体系里,而不是独立存在。
3.3 为什么这么多人需要“把病根说透”
再往深一层想:这类仓库能火到 24.5 万星,本身就说明了一个问题——行业中“会写代码但不理解系统”的人太多了。
以前我们要独立负责一个模块,得从前端写到后端,再写数据库脚本,跑通了还要看看日志。这个过程倒逼你必须理解系统是怎么串起来的。但现在有了 AI 辅助编程,很多基础薄弱的开发者可以直接跳过“理解完整链路”这一步,让模型把代码全部生成出来。
这不是否定 AI 辅助编程的价值,而是说:如果你没有系统思维作为底盘,AI 帮你写的每一行代码,都可能是在给未来埋雷。24.5 万星仓库本质上在做的,就是把这些“病根”掰开揉碎讲清楚。它告诉你:不要等到系统崩了才去补系统设计,不要等到代码改不动了才想去理清架构,更不要以为把一句话需求丢给模型,就真的能拿到一个可以长期维护的系统。
4. 实操落地:六条“反失控”实践
4.1 划定边界:原型可以 vibe,生产必须收敛
我实践下来最有效的一条,是把项目分成两种状态:“原型态”和“生产态”。
原型态的定位是验证想法。这时候随便让模型发挥,代码多乱都无所谓,只要能快速验证“这个功能用户认不认可”“这个交互顺不顺畅”。我自己做原型时甚至不建 Git 仓库,写废了就删掉重来。
但一旦决定要把原型固化成正式功能,就必须切换成“生产态”。这意味着 style 上要有规范,结构上要有分层,数据上要有校验,异常上要有兜底。这个切换动作必须由人来触发,不能由模型自动完成。我现在的做法是:当一次 vibe coding 的产出要进入主分支时,强制自己先做一轮“契约审查”,把模型生成的代码里不符合当前项目约定的地方全部改掉。
这就像写文章,初稿可以意识流,但定稿必须经过修改。Vibe coding 负责给你一个足够好的初稿,你负责把初稿改成能拿得出手的定稿。两者都不该缺席。
4.2 全局上下文:用全局 md 文档给 AI 立规矩
模型之所以“失控”,很多时候不是它不会写,而是它不知道你的规则。我现在的做法是:在项目根目录维护一个AGENTS.md或CLAUDE.md这样的全局说明文档,把项目的技术栈、目录结构、命名规范、常用模式、禁忌事项全部写进去。
举例来说,我在一个 Node.js 项目里写的是:
# 项目约定 - 技术栈:Express 4 + MySQL 8,禁止引入 Mongoose 或 TypeORM。 - 目录结构:路由放在 src/routes,业务逻辑放 src/services,数据库操作放 src/repositories。 - 命名规范:文件名小写中划线,常量 UPPER_SNAKE_CASE,函数名动宾短语。 - 错误处理:所有 service 层错误必须转成 AppError,禁止直接 throw new Error。 - 时间字段:统一使用 UTC 存储,返回给前端之前再转本地时区。 - 鉴权方式:使用项目现有的 jwt 中间件,禁止另起一套 session。每次让模型生成代码之前,我都会在 prompt 里附上这份文档的地址,或者直接把关键部分贴进对话。效果立竿见影,模型输出风格立刻就能对齐项目,返工率至少降了一半。
很多人忽略了这个“给模型喂规则”的过程,总觉得模型应该自己会。但它真的不会。你不说清楚,它就只能靠猜。全局 md 文档就相当于给 vibe coding 立了一份“基本法”,让它在你画的圈里跳舞。
4.3 系统设计思维:先画图再写码,哪怕只画三分钟
我以前的习惯是拿到需求就开写,写完再想架构。现在我会强迫自己先花三分钟画一张粗糙的图,哪怕是手写几个方块都行。这个动作的目的是把“系统的边界”在脑子里显性化。
画图的时候要想清楚几个问题:入口是谁、出口是谁、需要哪些数据、数据存在哪、谁调用谁、谁不能调用谁。这几个点一旦明确,再让模型去生成代码,你就可以把上下文描述得很具体。我之前让模型写代码总是失控,后来发现是因为我自己都没想清楚边界,模型自然只能瞎猜。
举一个实际例子:有一次我要加一个“批量导入用户”的功能。以前我直接说“帮我实现批量导入”,模型会给你写一个全流程:上传、解析、校验、落库、返回结果。听起来很好,但它会把解析逻辑和落库逻辑混在一起,还会自动处理重复数据,这正是我不想要的。现在我画完图之后,prompt 会变成:“只实现 CSV 解析模块,入参是文件路径,返回结构化的行数据数组,不包含去重逻辑,校验逻辑交给上一层 service 处理。”模型立刻就能写出一个边界清晰、好测试、好复用的模块。
这不是说模型变聪明了,而是我作为人的部分变靠谱了。我把复杂度挡在了自己这一侧,模型只需要在一个很小的上下文里完成任务,出错的概率自然就低了。
4.4 代码仓库卫生:Git 管理是最后一道保险
Vibe coding 的另一个隐患是“没有存档点”。你让模型改了一版代码,跑起来看着没问题,但三天后发现少了一个边界处理,而你根本找不到上一版是怎么写的。所以我现在的铁律是:所有项目一律纳入 Git 管理,哪怕只是临时原型。
具体操作上,我推荐做到三点。第一,每次让模型做一次完整的代码变更前,先打一个提交点。这样万一改坏了,一条git checkout .就能回到安全状态。第二,遇到“模型越改越乱”的情况,直接用git log找到能跑的版本。这个命令就是你的后悔药。第三,多用分支。我不会直接在 master 上让模型改东西,而是开一个feature/xxx分支,等确认没问题再合并。
有同事问我说“git 回退会不会把新功能也搞丢”,这里要澄清一下:git revert是产生一个新的提交来抵消旧提交,历史不会丢;git reset才是把 HEAD 指到旧提交,有丢失新提交的风险。你用git revert做回退,其实是最安全的。Git 这块不需要多高深,掌握clone、add、commit、push、log、revert这六个命令,就足够给 vibe coding 上一道保险了。
我个人还会用 GitHub/Gitee 这类代码托管平台的“私有仓库”作为云端备份。本地改乱了大不了从远端重新拉一份。这跟仓库出入库管理的思路一样:入库存的是稳定版,出库的修改随时可以被回滚。代码这种资产,也需要一套“出入库”流程。
4.5 依赖管理:别让 AI 帮你“随便装包”
模型在生成代码时,最不拿手的就是依赖治理。它经常会因为觉得“用某个库更方便”就直接在代码里引入新依赖,但它不知道这个库的维护状态、许可证、体积、和你现有依赖是否冲突。
我之前在 Java 项目里被坑过一次:模型为了解析一个 JSON 字段,引入了某个小众库,结果它传递依赖里包含一个旧版本的日志组件,直接压过了项目里原本的 slf4j 绑定,导致日志神秘丢失。排查了整整两天才定位根源。从此以后我定了一条规矩:模型生成代码时,默认只允许使用项目里已有的依赖;非要引入新包,必须由我手动评估后再加。
如果你是 Java 后端,Maven 仓库管理尤其要小心。建议在settings.xml里把国内镜像配好,比如阿里云仓库,既能加速下载,也方便统一管理仓库源。配置方式大致是这样:
<mirrors> <mirror> <id>aliyun</id> <mirrorOf>central</mirrorOf> <name>Aliyun Central Mirror</name> <url>https://maven.aliyun.com/repository/public</url> </mirror> </mirrors>配置多个镜像时,要注意mirrorOf的匹配规则。如果你把所有仓库都*匹配到同一个镜像,某些私服或者特殊仓库里的内部包可能就拉不到了。我的建议是:中央仓库走国内镜像,私服用自己的地址,用逗号分隔匹配规则。核心原则是,依赖的加载路径必须可控、可追溯、可重复,这一点恰恰是 vibe code 最不关心的。
4.6 测试与回归:唯一能拉住失控列车的手刹
最后一条,也是最难坚持的一条:给关键路径写测试。很多人觉得 vibe coding 就是图快,再写测试不是更慢了吗?但我的实测结论正好相反:没有测试的项目,改一次崩一次,每个功能都要手工回归;有测试的项目,模型改完代码,你只需跑一遍测试就知道有没有破坏旧功能,反而省时间。
我不建议一上来就追求什么 100% 覆盖率,那对 vibe coding 项目来说不现实。我的做法是:挑出项目里最核心、最容易出问题的三条路径,比如登录鉴权、支付流程、数据导入导出,给它们各写一个端到端测试。这三条路径稳了,项目的底就不会漏。
模型生成代码之后,我会先跑一轮已有的测试,如果变红,就让模型去看测试失败的信息,自己修。这个过程非常有价值,因为它就像给模型加了一个“即时反馈器”,让它不会再靠猜去写代码,而是以“让测试通过”为目标。测试就是你和模型之间最客观的验收标准。
5. 常见问题与排查经验
5.1 典型失控症状与对应解法速查
我把自己和团队成员踩过的坑整理成一张表,方便你按图索骥。
| 失控症状 | 病根 | 解决手段 |
|---|---|---|
| 模型改 A 功能导致 B 功能挂掉 | 缺少测试与模块边界 | 给关键路径补端到端测试;拆分模块,明确每个模块的对外接口 |
| 同一个功能出现多套实现 | 缺少全局上下文约束 | 在 AGENTS.md 里写明“统一使用哪个工具函数”,并在 prompt 里强调 |
| 代码能跑但看不懂,改不动 | 函数过长、职责混乱 | 要求模型将函数拆成小函数,每个函数只做一件事,附上注释 |
| 依赖包冲突,构建失败 | 模型擅自引入新库 | 默认禁止新增依赖;新增必须由人工评估 |
| 越改越乱,无法回退 | 没有存档点 | 每次让模型改代码前先 git commit;用 revert 而非 reset |
| 模型自作主张加需求 | Prompt 里需求不明确 | 写出明确的验收标准,列出“不要做什么” |
这张表不是标准答案,但大概率覆盖了你大多数失控场景。核心思路就一句话:出了问题先去查“是不是人这边少了约束”,而不是急着换更强的模型。
5.2 我在实际使用中的几个私藏技巧
第一个技巧:让模型先“说方案”再“写代码”。我以前总是一上来就让模型直接生成完整代码,现在我会先让它给我一个实现方案的简要描述,我来判断这个方案会不会引入新依赖、会不会破坏现有结构。方案不对就继续磨,方案对了再让它落代码。这就像一个简单的可行性审查,能把 80% 的方向性错误消灭在生成之前。
第二个技巧:用“负面清单”来约束模型。很多人给模型的指令全是“要做什么”,但我发现“不要做什么”往往更关键。比如“不要修改 existing 函数”“不要加缓存”“不要做去重”“不要自动处理错误,直接抛给上层”。这些负面约束能极大压缩模型的“自由发挥空间”,失控概率直线下降。
第三个技巧:定期做“代码走查”,每天抽半小时翻一遍模型当天生成的代码。不用真的一行一行读,重点是看目录结构有没有长歪、有没有多出不认识的依赖、有没有复制粘贴的重复代码。半小时的走查,能避免未来八小时的重构。我的经验是,vibe coding 的失控都不是突然发生的,它是每天都在“多一点点”地发生。你只要每天花半小时踩住刹车,车就翻不了。
第四个技巧:遇到反复改不好的问题,别在一个对话里死磕。模型在长对话里会逐渐丢失早期的上下文,尤其是上下文窗口被塞满之后,表现会明显下滑。我现在的做法是,一个功能如果来回改了四五轮还没收敛,就新建一个对话,把需求、相关代码路径、测试结果打包重新喂一遍。很多时候换个“状态”就解决了,旧对话里积累的混乱反而会成为干扰。
5.3 为什么我不再抱怨模型,而是调整自己的工作流
我经常看到有人在社区吐槽“这模型怎么这么蠢,让它改个 bug 越改越多”。如果放在半年前,我也会加入吐槽。但现在我会先问自己一个问题:我有没有把这个 bug 的完整背景、复现步骤、以及与上下文的关系讲清楚?
大多数情况下,答案是没有。我只给了模型一句“修一下这个 bug”,然后期望它像读心术一样理解我项目里错综复杂的依赖和业务逻辑。这不叫 vibe coding,这叫“许愿 coding”。调整工作流之后,我发现自己跟模型之间的配合明显顺畅了。我不再指望模型比我更懂我的项目,而是把它当成一个执行力很强但需要明确指令的伙伴。我负责判断方向、设定边界、验收结果,它负责在边界内高效输出。
这个转变,本质上就是把系统设计思维重新请回来,只不过实现系统设计的方式,从“手写所有代码”变成了“手动设定规则、让模型填充代码”。
6. 个人经验:给同样在失控边缘的你的几点真心话
如果你现在正处于“vibe coding 一时爽,项目维护火葬场”的阶段,我想说:问题不在你用的模型强不强,也不在你天赋够不够,而在于你还没有把工程化的护栏装进你的工作流里。
我现在的状态是:vibe coding 依然在用,而且用得很频繁,但我会用全局文档给它立规矩,用 Git 给它存档,用测试给它兜底,用系统设计给它画边界。模型负责速度,我负责方向。这个组合到目前为止,是我试过的最稳定的方式。
最后分享一个小技巧:下次让模型生成代码之前,你只加上一句话——“请先查看项目根目录的 AGENTS.md 和现有代码风格,严格遵循项目已有约定,不要引入新的依赖,不要修改与本次需求无关的文件。”就这一句话,能让你的 vibe coding 体验发生质的改变。去试试看,然后告诉我效果如何。