上周的项目周会上技术负责人指着订单服务问这段事务回滚逻辑是谁加的会议室安静了三秒。过了一会儿一个刚入职半年的同事小声说不是我写的是让AI帮我补的它补完我就合并了。我看着他脑子里蹦出三个字完蛋了。这就是Vibe Coding最真实的写照。我们把它当加速器却很少有人意识到它也在悄悄给系统加杠杆——而且是双向杠杆顺风时效率翻倍逆风时债务爆表。这篇内容想聊的不是“AI编程好不好”这种口水问题而是Vibe Coding背后的技术债务和扩展性危机到底藏在哪、怎么发作、如何防范。适合正在用Cursor、Copilot、Claude Code这类工具的开发者也适合团队里开始放开AI写代码的Tech Lead和技术管理者。1. Vibe Coding 热潮背后先搞清楚我们在讨论什么1.1 什么是 Vibe Coding从“写代码”到“描述代码”Vibe Coding这个词最近刷屏很快它的核心不是“用AI协助写几行”而是把主导权交给模型开发者用自然语言描述意图AI生成完整模块开发者做验收和微调。你更像产品经理而不是实现者。举个典型场景。过去加一个“用户积分过期提醒”的功能流程大概是建表、写查询、写定时任务、写通知模板、写日志、部署。现在你只需要在IDE里打开对话框输入“帮我在user_service里加一个积分过期提醒每天凌晨两点扫描发邮件通知”AI会帮你把SQL、调度器、邮件发送全写出来。听着很爽对吧但问题也藏在这里。AI生成的是“看起来合理的实现”而不是“经过项目上下文验证的实现”。它不知道你们的表结构里user_id是bigint还是uuid不知道通知服务用的是Webhook还是消息队列更不知道你们对邮件频率有没有业务限制。1.2 典型工作流代码是怎么被“聊”出来的目前比较典型的Vibe Coding工作流有三种对话式生成在Chat窗口描述需求把生成的代码粘贴到项目里。内联补全式给一个函数注释AI自动补完整段逻辑。多文件Agent直接让AI读项目、改代码、跑测试比如Claude Code或者Cursor的Agent模式。第三种最危险因为它最“省心”也最容易跳过人的思考环节。AI会自己翻文件、自己推断、自己写测试。如果项目本身结构混乱它会基于混乱继续堆混乱而且堆得理直气壮。1.3 “能跑就行”的幻觉是怎么出现的很多人觉得“代码能跑就行”这个想法在Vibe Coding时代被无限放大。因为AI生成的东西看起来太专业了命名规范、注释完整、逻辑链条清晰你很难想象它会在某个角落埋个雷。但请记住一个事实AI模型的训练目标是“生成像人写的代码”不是“生成经过生产环境验证的代码”。它追求的是统计意义上的合理不是逻辑意义上的正确。这中间的距离就是技术债务产生的土壤。2. 技术债务第一层代码能编译不等于系统能扛2.1 语法正确和语义正确之间隔着一条技术债我之前帮朋友排查过一个支付回调的问题。那段AI生成的代码长这样const refund await paymentProvider.refund({ transactionId: payment.transactionId, amount: Number(payment.amount) * 100, });看起来很正常对吗但实际检查后发现这笔业务里amount本来就是以“分”为单位存储的再乘100等于把退款金额放大了100倍。钱多退了客户当然没意见但财务报表直接裂开。这段代码语法完全正确甚至注释都写得像模像样但语义是错的。更麻烦的是这种错误很难靠读代码发现因为它不是一个“崩掉的bug”而是一个“悄悄跑偏的业务逻辑”。2.2 幻觉API、伪造参数我亲自踩过的三个典型坑AI最常见的“幻觉”有三类我每个都踩过第一不存在的API。AI给我生成过fs.readFileSafely()这种不存在的Node.js方法还一本正经地写了错误处理。编译阶段就挂了还好最怕的是它生成一个“存在但参数不对”的调用编译能过运行才炸。第二错误的环境变量名。项目里明明叫REDIS_HOSTAI给我写了个REDIS_URL还自己加了redis://前缀。测试环境没暴露问题上了生产才发现服务起不来。第三版本错配。AI依据训练数据里的旧版本SDK生成代码项目里装的却是新版本两个API签名完全不同。最典型的就是云服务SDK的凭证方式新版本普遍改成动态凭证后AI还在生成旧版accessKey字符串。这类问题的可怕之处在于它们不是“一眼就能看出的bug”而是“看起来完全正常、跑起来才出问题”的隐性错误。开发的时候测试没覆盖到上线两周后数据对不上你根本想不到要去查那段AI生成的代码。2.3 “一次性生成十年修改”的隐性成本有人会说代码能跑就行后续有问题再改嘛。问题就在这里AI生成的代码你懒得读也读不进去因为它不是你写的你没有那种“这段逻辑当时为什么这么写”的肌肉记忆。当业务变化需要修改这段代码时你面对的是一个陌生的、没有上下文关联的黑色盒子。改一行怕影响另一行加一个分支怕破坏原有逻辑最终只能整段重写。而重写又意味着新一轮AI生成新一轮未知Bug。这个循环才是技术债务最本质的形态不是代码烂而是代码没有“主人”没有人真正理解它、为它负责。3. 技术债务第二层架构正在悄悄腐烂3.1 单文件怪兽AI最爱的“一坨化”写法如果你让AI独立完成一个完整功能它大概率会给你一个“单文件怪兽”——把接口、业务逻辑、数据访问全部堆在同一个文件里。原因很简单模型的注意力机制倾向于在上下文范围内生成完整东西而不是跨文件做抽象。我见过一个订单模块AI在一个service文件里写了1800行包含HTTP请求解析、数据库操作、状态机流转、邮件模板拼接、甚至还有一段定时任务。功能倒是都实现了但你想给订单加一个“第三方支付渠道”选项时会发现至少六个函数需要改因为状态判断散落在18个地方。这不是AI笨是它在“快速完成任务”和“维持架构整洁”之间无条件选择了前者。而我们往往没有在提示词里约束这个倾向等于默认接受了一坨化代码。3.2 缺少抽象层业务规则散落成自然语言片段架构腐烂的第二层表现是缺少合理的抽象边界。AI生成代码时更倾向于把业务规则写成if-else里的裸条件而不是提炼成领域模型。举个例子你们的产品规则是“铂金会员可以免运费但生鲜类目除外”。AI可能直接在订单计算函数里写if user.level platinum and category ! fresh: shipping_fee 0这段代码没问题但它没有把“免运费规则”抽象成一个独立策略对象。等到产品说“黄金会员满200也免运费但生鲜还是除外”你就得在一堆生成代码里逐个寻找所有关于shipping_fee的赋值点。这一周改下来你就理解为什么“抽象”不是洁癖而是生存手段。3.3 依赖地狱AI顺手装包团队收拾残局Vibe Coding还有一个容易被忽视的副作用AI倾向于“遇到问题就引入依赖”因为它希望给你一个立刻能跑的答案而不是“建议思考一下现有代码能不能复用”。我见过一个内部工具AI在三天内引入了十几个npm包其中四个是同一个功能的不同实现。项目体积膨胀了40MB启动时间从1.2秒变成4.8秒构建时间翻了不止一倍。更麻烦的是这些包的安全版本我们完全没来得及审计。依赖不是免费的每一个包都是一个需要长期维护、审计、升级的承诺。AI不需要为这些承诺负责但你的团队需要。4. 扩展性危机业务翻倍时系统开始“反抗”4.1 功能叠加时的熵增改一处崩三处技术债务之所以危险是因为它平时沉默只在扩展时爆发。系统规模小的时候单文件怪兽运行得好好的所有逻辑都在一起调试方便。但当你开始叠加第二个、第三个功能时事情就变了。我复盘过一个典型的“AI重构翻车”案例。团队要让原来的“订单只支持在线支付”扩展为“支持货到付款”。因为老代码里支付状态判断散落在多个文件AI在尝试修改时把用户取消订单的逻辑也一起改了。结果货到付款功能没上线线上退款流程先挂了。这就是扩展性危机的核心代码结构决定了修改的局部性。如果一段功能逻辑集中在一个可替换的模块里扩展是安全的如果它散落在各处每一次扩展都是一次拆弹。4.2 团队协作熵增代码所有权模糊之后AI生成的代码还有一个微妙的影响它模糊了代码所有权。以前写代码每个人都有一片自己熟悉的领地别人改你的模块你会敏感地跳出来问“为什么动我代码”。现在呢一行注释“AI generated”甩过来没人愿意认领。结果是多人协作时大家都在AI生成的代码上叠罗汉。A让AI生成一个工具函数B没发现已经有了又让AI生成一个功能相似但命名不同的函数。半年后代码库里躺着一堆“双胞胎”函数各自都有细微的行为差异没人知道该用哪个、该删哪个。合并冲突更头疼。因为AI生成代码的偏好高度一致两个人同时让AI扩展同一个模块生成的代码结构几乎一模一样但细节各有不同冲突起来比手写代码更隐蔽——表面上相同实际上谁也不敢保证能直接替换。4.3 交接黑洞新同学接手的不是系统是盲盒团队流动性是正常的但Vibe Coding会把新人接手成本推到离谱的高度。以前新人来至少能看代码注释、看git提交记录理解作者思路。现在呢提交信息是“feat: add coupon module”代码全是AI生成的注释写得比代码还华丽但没有一条能解释“为什么这里要判断两次用户状态”。更尴尬的是当你去问原作者他只能弱弱回一句“我也不知道AI生成的跑起来没问题”。于是新人只能自己把代码当考古现场一层层挖一点点猜。这个成本不是一次性的它会在每一次交接、每一次重构、每一次扩展时反复出现。5. 测试缺失与安全边界Vibe Coding 绕不开的双重陷阱5.1 “先上线再补测试”的真实代价Vibe Coding的爽感很大程度来自“快速看到结果”而测试是这个流程中最容易被牺牲的一环。让AI写测试可以但AI写的测试往往是为AI写的代码服务的它会天然避开那些不合理的路径因为它在生成测试时就已经知道实现答案了。我自己做过实验让AI写一个订单折扣模块再让AI写对应测试。测试覆盖率显示95%看起来完美。但我在测试里加了一个“折扣后的金额出现小数”的边界系统直接报错因为实现里压根没有处理金额精度问题。测试覆盖率高但不代表测到了关键风险。扩展性要求我们有安全感而安全感只能来自测试兜底。没有测试的代码每一次改动都是心理折磨越到后面越不敢动。5.2 输入校验和权限控制被“顺手优化”掉AI生成代码时有一个非常危险的倾向为了“简洁”它会省略防御性代码。我见过AI生成的接口长这样def update_profile(user_id, data): query fUPDATE users SET nickname {data[nickname]} WHERE id {user_id} db.execute(query)一段看起来极其自然的代码实际上存在SQL注入风险、缺少输入长度校验、缺少权限检查。如果这是手写代码你大概率会多看一眼但AI生成的时候它看起来太干净了你反而会放松警惕。权限控制尤其危险。AI在生成管理员接口时经常把鉴权逻辑“优化”成只在注释里提到代码里直接跳到业务逻辑。这是它在训练数据里学到的“高效写法”但在真实项目里就是安全漏洞。5.3 供应链接手风险依赖里藏了什么没人知道我在前面提过依赖膨胀这里的供应链风险更隐蔽。AI可能根据训练数据引用一个曾经流行、但现在已经被弃用或存在漏洞的库。更常见的是它推荐的库名带着拼写错误比如把lodash写成loadsh这种“仿冒包”一旦安装就会引入未知代码。很多团队用Vibe Coding时连npm audit都不跑更别说做软件成分分析。等到出了安全事件回头一看谁也说不清这个依赖是从哪进来的。6. 怎么把 Vibe Coding 用对我的实操取舍方案6.1 给 AI 划定“信任区间”哪些能生成哪些绝不Vibe Coding不是不能用而是得用对地方。我的建议是画一条清晰的边界把工作分成三档信任级别适合交给AI的任务原因高信任一次性脚本、原型Demo、测试骨架、文档注释、配置解析错了影响可控重写成本低中信任CRUD接口、工具函数、简单页面组件逻辑简单Code Review能兜住零信任支付/退款、权限认证、密钥管理、数据迁移、核心领域状态机出错代价极高必须人肉手写这段边界请写进团队文档里不要只在脑子里过一遍。我见过太多事故都是“本来想先让AI生成一个雏形结果上线时忘了把AI生成的部分替换掉”。6.2 用“编码公约”给 AI 立规矩约束文件怎么写如果你用Cursor或Claude Code这类工具强烈建议在项目根目录放一个AGENTS.md或CLAUDE.md相当于给AI一个团队规范。这比每次重复口头要求有效得多。我自己的约束文件大概长这样# AI 编码公约v1.0 ## 必须 - 新增代码必须放在 src/modules/业务域 目录下禁止擅自新建顶层目录 - 所有网络接口必须经过统一 validation 中间件 - 公共函数必须写清楚输入、输出、边界条件和调用示例 - 异常必须通过统一 logger 记录结构化日志禁止用 console.log - 提交前必须运行 pnpm lint 和 pnpm test:cov ## 禁止 - 禁止生成超过 300 行的函数 - 禁止在 Controller 里写业务逻辑只允许做参数透传 - 禁止绕过 TypeScript strict 模式 - 禁止使用 any - 禁止修改数据库迁移文件任何表结构变更必须等待人工评审 - 禁止为眼前需求引入新依赖除非已有依赖无法满足 ## 流程 - 涉及核心领域逻辑的改动必须先生成 ADR交给技术评审 - 所有生成代码默认视为“外部贡献”必须走合并请求评审流程这个文件看起来不起眼实际效果非常大。因为AI在生成代码时会把这些约束当作上下文的一部分输出质量会明显向规范靠拢。至少我实测下来单文件怪兽和裸SQL出现频率大幅下降。6.3 强制 Code Review把 AI 当外包员工来管Vibe Coding最大的问题不是AI水平不够而是缺少人类把关。所以我的铁律是AI生成的代码必须走Code Review流程而且评审人不能是生成代码的同一个人。为什么因为生成代码的人自己也没有上下文他只能做“表面审查”。评审人必须换一个视角带着“这个代码怎么塞进现有架构”的问题去看。评审时重点查四件事边界条件有没有处理、错误路径有没有兜底、有没有绕过已有抽象、有没有引入非必要依赖。不需要每行都读但这四个问题能挡住大部分技术债务。7. 扩展性安全的护航清单每周10分钟守住底线7.1 架构巡检盯紧最危险的“增长信号”技术债务是慢慢积累的但通常有迹可循。我每周会花10分钟跑一遍简单的体检重点看三个信号单文件行数、重复代码率、模块间耦合度。可以用现成工具辅助# 检查单文件行数排出前20个 find src -name *.ts | xargs wc -l | sort -nr | head -20 # 检查重复代码 npx jscpd --min-tokens50 --min-lines3 src # 检查循环依赖 npx madge --circular src这个巡检不需要多深入目的是发现“异常增长”。如果某个文件突然从300行涨到800行或者重复率在一个月内翻倍多半是AI在无约束状态下写了不少快代码。这时候介入成本远低于半年后的重构。7.2 回归测试基线没有兜底别谈扩展扩展性危机本质上是对“改错”的恐惧。要消除恐惧就得有回归测试基线。我的建议是核心链路必须覆盖三个层次接口冒烟测试、关键业务规则单元测试、数据一致性校验。接口冒烟测试保证“加了新功能老接口还能通”业务规则单元测试保证“折扣规则改了历史订单不受影响”数据一致性校验保证“状态机流转不会出现中间状态卡死”。如果时间紧张至少把支付、订单、用户这三个核心域做成测试基线。这是扩展的底气没有底气AI帮你扩展出来的功能越多系统越容易碎。7.3 关键路径上的“手写禁飞区”在AI协作的最高压区我建议设置“手写禁飞区”。这些区域的代码不允许由AI生成必须由有经验的工程师手写并经过评审。典型禁飞区包括资金计算、税费折扣、身份认证、数据迁移脚本、对外API签名、加密密钥管理。这些地方一旦出错不是代码质量问题是业务事故。我的做法是在这些目录里放一个OWNERS.md明确列出哪些路径禁止AI直接修改必须由指定负责人手写改动。这本来就该是一个工程制度Vibe Coding只是让它变得更必要了。7.4 用 ADR 对抗组织性遗忘凡是涉及架构决策的改动无论是不是AI生成都应该沉淀成一份轻量级ADRArchitecture Decision Record。我用的模板很简单# ADR-012订单模块引入策略模式处理多支付渠道 ## 状态已接受 ## 背景新增货到付款原有 if-else 分支难以维护 ## 决策定义 PaymentStrategy 接口各渠道独立实现 ## 后果新增渠道成本降低需要额外维护策略注册表ADR的价值不是装样子而是让你在三个月后能回答“当时为什么这么设计”。Vibe Coding最大的隐患之一就是“我们改了但没人记得为什么改”。ADR就是对抗这种遗忘的工具。8. 工具选型与成本账Vibe Coding 不是免费的8.1 主流工具怎么选Cursor、Copilot、Claude Code 怎么搭不同工具的侧重点不一样选型要根据团队场景来工具形态适合场景主要风险GitHub CopilotIDE内联补全手写代码时的加速容易无脑接受建议CursorAI优先IDE多文件重构、对话式修改容易生成超范围改动Claude Code终端Agent自动读项目、跑测试、迭代任务自主性太强需要盯紧WindsurfIDE Agent偏前端开发生态还在快速变化我的建议是同一个项目里固定用一到两个工具不要今天Cursor明天Claude Code。因为不同工具的上下文理解方式不同频繁切换会导致AI对项目结构的认知一次次重建反而更容易出错。8.2 技术债务利息怎么算一次真实报价我经常和团队说AI省下的时间迟早要在还债时连本带利付回去。算一笔粗账一个订单扩展需求传统手写大概2天。用Vibe Coding当天就出功能看起来省了1.5天。但因为AI生成的代码没有抽象、没有测试上线后一周内出现边界问题排查加修复花了3天。最后那个功能的总成本是4.5天比手写还多出2.5天。这就是技术债务的利息。它不是不还只是晚点还而且利息按复利算。8.3 小团队和大公司的不同打法小团队用Vibe Coding更多是“省人力”但省下来的部分必须用来补测试和文档否则就是在透支未来。我建议小团队把AI用在“一次性任务”上核心业务保持手写不要追求把所有代码都AI化。大公司则相反真正的风险不是效率而是失控。一个几十人的团队如果每个工程师都在自己的分支上让AI自由发挥合并时就是灾难现场。所以大公司更需要的是约束治理把AI编码公约、Code Review门槛、安全扫描都制度化。Vibe Coding本身没有原罪它只是把代码生成的规模效应放大了。问题的关键从来不是“用不用AI”而是“你的工程纪律跟不跟得上AI的速度”。工具可以换模型可以升级但守住质量底线的永远是人。按照我这几个月的实操体会最靠谱的状态是把AI当成一个聪明但缺乏项目归属感的实习生它负责快速产出候选方案你负责判断、约束、验收。越是核心的地方越要亲自手写、亲自评审。敬畏技术债务就是敬畏系统本身。