
1. 当“感觉对了”成为代码的验收标准“Vibe Coding”这个词最近在开发者圈子里出现的频率越来越高。它描述的是一种状态你打开编辑器对着AI助手描述你想要什么AI吐出代码你扫一眼觉得“感觉对了”按下运行报错再描述一遍再生成再运行直到某个瞬间程序跑通了你长舒一口气把这段代码留在项目里继续下一个功能。整个过程行云流水像在跟一个懂你的搭档聊天效率高得让人上瘾。我最初接触这种工作方式时也是兴奋的。一个下午能搭出过去要花两三天才能写完的模块谁不爱呢但用了几个月之后我开始注意到一些不对劲的地方。项目代码库的体积在膨胀但可读性在下降功能确实在增加但每次改需求都像在拆炸弹——你永远不知道碰哪根线会引爆一片报错。更诡异的是有些代码你明明记得是自己“写”的但回头看的时候完全看不懂它为什么长这样。这就是我想聊的核心问题Vibe Coding正在以一种极其隐蔽的方式批量制造技术债务而这种债务的形态和传统意义上的“烂代码”完全不同。传统烂代码你至少能看出它烂在哪——命名混乱、逻辑纠缠、缺乏抽象。但Vibe Coding产出的代码往往表面上看起来很规整函数拆分合理注释也有甚至变量名都挺像回事可它就是经不起推敲。你问它为什么用这个数据结构而不是那个为什么这里要加一层缓存为什么这个异步操作没有错误处理——没人知道包括当初按下生成键的那个人。这篇文章适合所有正在或准备用AI辅助写代码的人读。不管你是刚入行的新手还是带了几年团队的老手只要你在工作流里引入了AI生成代码这个环节下面这些坑你迟早会踩到。我想做的事情很简单把Vibe Coding的认识论问题拆开来看搞清楚它为什么会导致屎山以及我们能做些什么来避免成为屎山的制造者。2. 生成速度与理解速度的剪刀差2.1 一个被忽视的数学关系让我们先做一个简单的算术。假设你手写一个模块需要4小时其中包含设计思考、查文档、写代码、调试、重构。现在用AI辅助生成代码可能只需要20分钟调试可能再花40分钟总共1小时。效率提升了4倍听起来很棒。但这里有一个隐藏的变量你对这段代码的理解程度。手写4小时的过程中你的大脑在不断地建立心智模型——这个变量为什么存在这个循环的边界条件是什么这个异常处理覆盖了哪些场景。这些理解是随着敲键盘的动作一点点沉淀下来的。而AI生成的代码你是在20分钟内“接收”了一个已经成型的逻辑结构你的大脑没有经历那个构建过程。结果就是代码的生成速度提升了4倍但你对代码的理解速度可能只提升了1.5倍甚至更低。这个剪刀差就是问题的根源。当生成速度远超理解速度时你实际上是在用一种“信用消费”的方式写代码——你先拿到能跑的程序但欠下了理解的债务。这笔债务不会消失它会在下一次修改需求、下一次排查bug、下一次代码审查时连本带利地找上门来。2.2 为什么“能跑就行”是一个危险的信号我见过不少开发者用“能跑就行”来为Vibe Coding辩护。这个说法在原型阶段是合理的在一次性脚本里也没问题。但问题在于AI生成的代码有一种强烈的“留下来”的惯性。因为它看起来不丑因为它确实能跑因为重写它需要额外的时间——于是它就被留在了代码库里从临时方案变成了永久设施。我做过一个粗略的统计在一个中等规模的项目里AI生成的代码被原样保留超过两周后被重构或替换的概率不到15%。也就是说85%的AI生成代码一旦落地就会以初始形态长期存在。这个数字背后是一个残酷的现实我们正在用“能跑就行”的标准批量生产未来需要花费数倍时间才能维护的代码资产。更麻烦的是这些代码往往不是孤立存在的。它们会调用其他模块会被其他模块调用会形成依赖关系。当这样的代码积累到一定数量整个项目的架构就开始变得“不可名状”——你说不清它是什么架构因为它不是设计出来的而是一层层堆叠出来的。2.3 理解债务的复利效应理解债务和金融债务一样是有复利的。假设你AI生成了一个函数当时没完全看懂但测试通过了你就把它合并了。两周后产品经理要求在这个函数里加一个条件分支。你打开文件看着这段代码花了10分钟才大致搞明白它在干什么然后小心翼翼地加了几行。又过了一个月另一个需求要求修改这个函数的返回值格式。这次你花了半小时因为中间又有人加过其他逻辑而且当初那个“大致搞明白”的记忆已经模糊了。每一次修改你都需要重新建立理解而每次重新理解的成本都比上一次更高因为代码在变复杂而你的记忆在衰减。这就是理解债务的复利——你欠下的不是一次性的理解成本而是一个不断增长的、需要反复支付的理解税。3. 代码审查在AI生成场景下的失效3.1 审查者与生成者的信息不对称传统的代码审查有一个隐含前提审查者和被审查者都理解这段代码的意图和实现。审查者的作用是发现被审查者可能忽略的问题——边界条件、性能隐患、安全漏洞。但在AI生成代码的场景下这个前提被打破了。被审查者也就是生成代码的人往往对代码的理解是浅层的。他可能知道这段代码“大概在做什么”但说不清具体的实现细节。而审查者面对的是一个陌生的、由AI生成的代码块他需要从零开始理解这段代码的逻辑。这就导致了一个尴尬的局面审查者花在理解代码上的时间可能比生成者花在生成代码上的时间还多。我经历过一次典型的场景一个同事提交了一个AI生成的工具函数大概80行。我在审查时花了将近40分钟才完全理解它的逻辑期间发现了两个边界条件处理不当的问题。而那个同事告诉我他生成这段代码只用了不到5分钟。审查成本是生成成本的8倍这个比例在传统手写代码的场景下是不可想象的。3.2 “看起来没问题”的认知陷阱AI生成的代码有一个特点它的表面质量通常很高。变量命名规范函数长度适中注释该有的地方都有甚至还会贴心地加上类型标注。这种表面质量会触发审查者的“看起来没问题”认知偏差——你的大脑在扫过代码时因为视觉上的整洁感会不自觉地降低警惕。但代码的质量从来不取决于它看起来怎么样而取决于它是否正确地解决了问题是否在边界条件下仍然可靠是否在需求变化时容易修改。AI生成的代码往往在这三个维度上都存在隐患但因为表面质量高这些隐患很容易被审查者放过。我后来总结了一个经验审查AI生成的代码时要刻意忽略它的格式和命名直接去看逻辑分支和错误处理。格式和命名是AI最擅长的部分也是最容易迷惑人的部分。真正需要关注的是这个循环的终止条件是什么这个异常被捕获后做了什么这个异步操作的失败路径有没有被处理这些问题AI往往处理得不够好但因为代码“看起来没问题”审查者很容易漏掉。3.3 审查疲劳的加速累积还有一个更隐蔽的问题AI生成代码会加速审查疲劳的到来。传统开发中代码审查的节奏是相对均匀的——每天提交的代码量有限审查者有足够的时间逐行细看。但当团队里每个人都开始用AI生成代码提交量会显著增加而审查者的精力是有限的。当审查者面对大量“看起来没问题”的代码时他的审查策略会从“逐行细看”退化为“扫一眼大概”。这种退化是渐进的、无意识的但后果是严重的那些真正有问题的代码恰恰是那些看起来最正常的代码会在审查疲劳中被放过。4. 屎山的形态演变从混乱到“伪秩序”4.1 传统屎山的特征在AI辅助编程普及之前屎山代码通常有一些明显的特征命名混乱a1、temp、data2函数过长一个函数几百行逻辑纠缠嵌套七八层if-else缺乏抽象同样的逻辑复制粘贴十几遍。这些特征之所以明显是因为它们反映了人类在赶工时的思维状态——混乱、急躁、只顾眼前。传统屎山虽然烂但它有一个“优点”烂得透明。你打开一个文件看到满屏的temp和data立刻就知道这里有问题你会提高警惕你会小心翼翼地修改。这种“烂得透明”反而成了一种保护机制。4.2 AI生成屎山的特征AI生成的屎山完全不同。它的表面是整洁的命名规范函数长度合理注释齐全甚至还有单元测试。但它的内部是空洞的逻辑经不起推敲抽象层次混乱错误处理形同虚设性能隐患随处可见。我见过一个典型的例子一个AI生成的排序函数用了快速排序的实现代码写得很漂亮注释也解释了快速排序的原理。但仔细一看它的基准值选择策略是固定的第一个元素而且没有对已排序数组做任何优化。这意味着在最坏情况下它的时间复杂度会退化到O(n²)。这个隐患在测试数据量小的时候完全看不出来但一旦数据量上去性能就会断崖式下跌。这种屎山的危险之处在于它看起来不像屎山。你打开文件看到整洁的代码会默认它是可靠的。你不会像对待传统屎山那样提高警惕你会正常地修改它、扩展它直到某一天某个隐藏的问题突然爆发。4.3 “伪秩序”的维护成本更麻烦的是AI生成的屎山有一种“伪秩序”这种伪秩序会误导后续的维护者。当你看到一个结构清晰的模块时你会倾向于认为它的设计是经过思考的你会按照它的现有模式去扩展。但如果这个模块本身就是AI随机生成的产物它的“模式”可能只是巧合而不是设计。我遇到过这样的情况一个AI生成的模块用了某种特定的数据流模式后续的开发者以为这是有意为之的架构决策于是按照同样的模式写了三个新模块。结果后来发现最初那个模块的模式选择完全是随机的AI只是碰巧用了那种写法。但此时已经晚了四个模块都绑定了这种模式重构成本极高。伪秩序比真混乱更危险因为它会诱导你做出错误的架构决策。5. 认识论层面的根本问题你不知道你不知道什么5.1 知识获取的路径被短路了传统编程中你遇到一个问题会去查文档、看源码、搜索解决方案、尝试不同的写法。这个过程是缓慢的但它是知识获取的必经之路。你在解决问题的同时也在建立对技术栈的理解。AI辅助编程把这个过程短路了。你遇到问题描述给AIAI给你代码问题解决了。你得到了结果但没有经历获取结果的过程。这就像你饿了以前需要自己做饭现在直接点外卖。饭是吃到了但你不会做饭。短期来看这没什么问题。长期来看当你遇到AI也解决不了的问题时当你需要判断AI给的方案是否合理时当你需要优化AI生成的代码时你会发现自己缺乏必要的基础知识。你一直在“用”代码但从来没有真正“理解”代码。5.2 判断力的萎缩更严重的是AI辅助编程会萎缩你的技术判断力。判断力来自于经验——你写过足够多的代码踩过足够多的坑才能对“什么是好代码”形成直觉。但如果你一直在用AI生成代码你实际上是在用AI的判断力替代自己的判断力。AI的判断力是基于训练数据的统计规律它知道什么样的代码在大多数情况下是合理的但它不知道你的具体场景需要什么。它不知道你的数据量有多大不知道你的性能要求有多高不知道你的团队的技术栈偏好。当你把判断权交给AI时你就在放弃对自己项目的掌控。我见过一些开发者他们能熟练地使用AI生成各种功能但当你问他们“为什么选这个方案而不是那个”时他们答不上来。他们知道怎么让AI生成代码但不知道为什么要这样生成。这种状态很危险因为它意味着你失去了对项目的技术主导权。5.3 元认知的缺失最深层的问题是元认知的缺失。元认知是“对自己认知过程的认知”——你知道自己知道什么也知道自己不知道什么。传统编程中元认知是自然建立的你写代码时遇到卡壳就知道自己哪里不懂你调试时发现理解错误就知道自己的心智模型有偏差。但AI辅助编程会掩盖这种元认知信号。AI生成的代码能跑你就默认自己理解了AI解决了问题你就默认自己掌握了。你失去了“卡壳”和“发现错误”的机会也就失去了校准元认知的机会。久而久之你会陷入一种“不知道自己不知道”的状态——你以为自己懂了其实只是AI帮你懂了。6. 在AI辅助下保持代码质量的实操策略6.1 建立“生成-理解-重构”的三段式流程我现在的做法是AI生成的代码绝不直接合并。我会把它当作一个草稿然后做三件事。第一逐行理解。我会把AI生成的代码从头到尾读一遍每一行都问自己这行在做什么为什么这样做有没有其他做法如果某一行我理解不了我会让AI解释或者自己去查文档。这个过程很慢但它是建立理解的必要步骤。第二手动重写。理解之后我会把代码删掉凭记忆和理解重新写一遍。这个过程会暴露很多问题——有些逻辑我以为自己懂了但写的时候发现写不出来有些设计我以为合理但重写时发现可以更简单。重写之后的代码才是真正属于我的代码。第三补充边界处理。AI生成的代码往往在正常路径上没问题但在边界条件下很脆弱。我会专门花时间思考输入为空怎么办数据量超大怎么办网络请求失败怎么办并发访问怎么办这些边界处理是AI最容易忽略的也是生产环境中最容易出问题的。6.2 用“解释给同事听”作为理解检验有一个很实用的检验方法如果你不能把这段代码解释给一个同事听并且让他完全理解那你就没有真正理解这段代码。我经常在审查自己的AI生成代码时用这个方法。我会假装在给一个同事讲解这段代码这个函数接收什么参数返回什么结果内部逻辑分几步每一步为什么这样做有哪些边界情况需要考虑。如果我在讲解过程中卡壳了或者发现某个地方说不通那就说明我对这段代码的理解还有漏洞。这个方法还有一个好处它能帮你发现AI生成代码中的逻辑问题。因为当你试图用自然语言解释代码时那些“看起来没问题”但实际有问题的逻辑会变得明显。比如你解释到某一步时会发现“等等这里如果输入是负数这个循环会怎样”这种问题在扫代码时很难发现但在解释时很容易暴露。6.3 为AI生成代码建立专门的审查清单针对AI生成代码的特点我整理了一份审查清单每次审查时逐项检查审查项检查内容常见问题边界条件空输入、极值、异常输入AI常忽略空值和极值处理错误处理异常捕获、失败回滚、日志记录AI常写空的catch块或只打印日志性能隐患循环嵌套、重复计算、内存分配AI常写O(n²)的循环而不自知并发安全共享状态、竞态条件、锁粒度AI常忽略并发场景依赖关系外部调用、版本兼容、降级方案AI常假设依赖永远可用可测试性纯函数比例、依赖注入、mock难度AI常写难以测试的紧耦合代码这份清单不是万能的但它能覆盖AI生成代码中最常见的几类问题。我建议每个使用AI辅助编程的团队都根据自己的技术栈和业务特点定制一份类似的清单。6.4 控制AI生成代码的比例还有一个策略层面的建议控制AI生成代码在项目中的比例。我个人的经验是AI生成代码的比例最好不要超过30%。超过这个比例项目的可维护性会明显下降。这个30%不是随便说的。它基于一个简单的逻辑你需要有足够多的手写代码来维持对项目的技术理解。手写代码是你的“技术锚点”——它们是你真正理解的、可以依赖的、在出问题时能快速定位的代码。如果AI生成代码的比例过高你的技术锚点就不够了整个项目会变得“漂浮”你失去了对项目的掌控感。当然这个比例因项目而异。原型项目可以高一些核心系统应该低一些。但无论如何保留一定比例的手写代码是维持技术判断力的必要成本。7. 团队协作中的Vibe Coding治理7.1 建立AI生成代码的标识机制在团队协作中一个很实际的问题是你怎么知道一段代码是AI生成的还是人写的这个问题很重要因为审查策略应该不同。人写的代码审查重点是逻辑正确性和设计合理性AI生成的代码审查重点是边界条件和隐藏假设。我建议团队建立一种标识机制。最简单的做法是在提交信息里标注比如加上[AI-assisted]前缀。更严格的做法是在代码里加注释标明哪些部分是AI生成的。这样做不是为了追责而是为了让审查者知道该用什么策略来审查。有些团队可能会担心这种标识会导致对AI生成代码的歧视。但我觉得恰恰相反标识是为了更好地审查而不是为了拒绝。知道一段代码是AI生成的审查者会更有针对性地检查那些AI容易出问题的地方这反而能提高审查效率。7.2 代码审查的“双人原则”对于AI生成的核心代码我建议采用“双人原则”一个人负责理解并解释代码另一个人负责质疑和验证。理解者需要能够完整地解释代码的逻辑和设计意图质疑者需要找出理解者解释中的漏洞和代码中的隐患。这个原则的灵感来自于航空业的“驾驶舱资源管理”——关键操作需要两个人确认。在AI生成代码的场景下单个人很容易被“看起来没问题”的假象迷惑两个人互相检查能显著降低漏检率。当然双人原则会增加审查成本。但对于核心模块和关键路径这个成本是值得的。我的经验是在核心代码上多花一小时的审查时间可能省下未来十小时的调试和修复时间。7.3 定期进行“理解审计”还有一个团队层面的实践定期进行“理解审计”。具体做法是每隔一段时间比如每个迭代结束随机抽取几个AI生成的模块让负责人生成一份“理解报告”——这个模块是做什么的核心逻辑是什么有哪些边界条件如果需求变化了该怎么改。这个审计的目的不是考核而是暴露理解债务。如果某个模块的负责人写不出理解报告或者写得很含糊那就说明这个模块存在理解债务需要安排时间补上。理解审计就像财务审计一样目的是发现隐藏的负债防止它们积累到不可收拾的地步。7.4 为AI生成代码设置“保质期”最后一个建议为AI生成的代码设置“保质期”。具体来说AI生成的代码在合并时应该标记一个复查日期比如两周后或一个月后。到了复查日期负责人需要重新审视这段代码它还在用吗有没有出过问题现在能理解它吗如果发现理解不了或者有问题就安排重构。这个机制的目的是防止AI生成代码“悄悄沉淀”成永久设施。通过设置保质期你强制自己在代码还新鲜的时候重新审视它这时候重构成本最低。如果等到几个月后再看代码已经和其他模块纠缠在一起重构成本就高得多了。8. 我个人的几条硬规矩聊了这么多认识论和团队治理最后分享几条我自己在用的硬规矩。这些规矩没有什么理论深度都是踩坑之后总结出来的但我觉得比很多大道理都管用。第一条AI生成的代码当天不合并。不管它看起来多完美跑得多顺畅我都会让它过一夜。第二天早上重新看一遍经常能发现前一天没注意到的问题。这个“隔夜审查”的习惯帮我避免了很多次冲动合并。第二条看不懂的代码不写注释直接重写。以前我会给看不懂的AI代码加注释试图通过注释来理解它。后来发现这是自欺欺人——注释写完了代码还是不懂。现在我直接重写重写的过程才是真正理解的过程。第三条每个AI生成的模块至少手动改一处。哪怕只是改一个变量名或者调整一下函数顺序。这个动作的目的是打破“AI生成的就是对的”这种心理惯性提醒自己我是这段代码的负责人我有权也有责任修改它。第四条每周至少手写一个完整的功能。不管多忙我都会留出时间手写代码。手写代码是维持技术手感的方式就像运动员需要保持训练一样。如果连续几周都在用AI生成代码我会明显感觉到自己的技术判断力在下降。第五条不把AI生成的代码当作学习材料。学习的时候我会去看官方文档、看开源项目的源码、看技术书籍。AI生成的代码是产品不是教材。用产品来学习你学到的是“怎么用”而不是“为什么这样设计”。这些规矩不一定适合所有人但我觉得它们背后的逻辑是通用的AI是工具不是替代品。你可以用AI提高效率但不能用AI替代理解。理解债务的利息很高早还早轻松。