← 全部文章
应用搭建 IT / CIO 已发布 · · 作者 ObjectStack Team

Vibe Coding 技术债:为什么 AI 生成的应用后来难改

AI 生成代码能让原型很快上线,但长期系统的问题在半年后出现:没人完整读过那一万多行实现,也没人能解释当初的业务取舍。企业应用需要生成可审查的定义,而不是难维护的黑箱代码。

Vibe Coding 技术债:为什么 AI 生成的应用后来难改
  • Vibe Coding
  • 技术债
  • 代码生成
  • 元数据
  • AI 治理
  • 趋势观点

先给结论:AI 生成代码的瓶颈不是写得快不快,而是半年后没人读得懂、也没人可问——让 AI 生成元数据而不是代码,这种还不掉的债才不会累积。

故事从第七个月开始。

明享是一家连锁零售公司,门店几百家。去年,它的财务团队(五十多人)受够了等 IT 排期,用 AI”一句话”搭了套报销系统。表单、审批、对接总账,两天就跑起来了,全员叫好。接下来大半年,它一直好好的。

第七个月,税务规则变了:某类发票的抵扣比例调整,报销逻辑得跟着改。一件小事。

然后团队发现,没人敢动它。当初那”一句话”背后,是 AI 生成的一万两千多行代码,没有一个人完整读过。抵扣逻辑散在哪几个文件?改了会不会连带影响审批和月末对账?没人说得清。更尴尬的是——连写出这套代码的 AI 也帮不上忙:它是无状态的,那次生成时脑子里的判断、权衡、为什么这么写,一点没留下。你只能把一万两千行重新喂给一个新会话,让它”猜”一遍当初的自己。

这件小事最后排了三周。而真正的代价不止三周:上线前的评审里,有人发现 AI 顺手改动了一处和抵扣无关的对账逻辑——差一点就让一批报销算错金额流进总账。这次侥幸被拦住了,但它说明了一件事:这套系统已经没人能保证”改 A 不会动到 B”。

这就是 AI 代码技术债落到一个普通团队身上的样子。

这是一种特殊的债:欠了,但找不到债主

技术债不是新词。但 AI 生成的代码,欠的是一种以前没有的债。

人写的代码也会烂、也会没文档。但至少作者还在——你能把写它的人拉来问一句”这里当初为什么这么处理”。代码再差,背后总有一个能解释它的人脑。

AI 生成的代码把这个最后的兜底也抽走了。它的”作者”是一个无状态的模型,生成完那一刻就不存在了。它没有把可追溯的设计判断留下来,于是你手上是一坨能跑、但谁都无法解释、也无人可问的实现。明享那一万两千行,就是这种债——它不欠在代码质量上,欠在”再也没人真正理解它”上。

把它叫作**理解债(comprehension debt)**更准确:系统能跑,但组织没有真正理解它。速度是真的,债也是真的——只是债不在交付那天结账,而是在第七个月、第一条业务规则改变时找上门。

可代码生成不是在飞速变好吗?

这里得认真接一个反驳,否则不公道:模型一直在变强,能读的代码越来越长,还有 AI 代码评审、“自愈”流水线——会不会再过一年,这些债就被更强的工具自动还掉了?

这个期待有它的道理,但它赌错了瓶颈在哪。

代码生成进步解决的是”写得更快”。而明享的问题从来不是写得不够快——恰恰相反,是写得太快了:两天一套系统,改动源源不断地涌出来。瓶颈在”读得懂、担得起”这一侧,而它不随生成能力线性改善。更强的模型生成更多代码、更快,可能也会更快地累积没人读过的实现。AI 评审能帮着扫一遍,但”这段业务逻辑应该是什么”这种判断,它给不了确定答案,因为对错只存在于业务语境里,不在代码里。

换句话说:把希望寄托在”模型再强一点”,是在用加速踏板治刹车失灵。

复利:每改一次,就更看不懂一点

为什么是第七个月,而不是第一个月?因为这种债是复利的。

第一次改,AI 在没读懂旧代码的情况下”在旁边再加一段”;第二次改,它面对的是”旧代码 + 上次没读懂的新代码”,于是再加一段。每一层都叠在没人理解的上一层之上,理解成本指数上涨。所以风险曲线不是缓缓上升的直线,是一条前期平静、中段陡起的指数曲线——平静得让你以为没事,直到某次再普通不过的改动点燃它。

改动系统的难度随时间变化:生成代码指数级上升,生成元数据保持平稳

有个简单的自查,能让你提前看见自己在曲线的哪一段。下面五条,中三条,你已经在欠 AI 技术债:

  1. 系统里有某段代码,团队没人能解释它”为什么这么写”。
  2. 要改一处,第一反应是”会不会碰坏别的地方”,而不是直接改。
  3. 安全 / 告警数量每个月都在涨,且大多来自新增代码。
  4. 每次要改,都得把整块代码重新喂给 AI 让它”重新读一遍”。
  5. PR 越来越大,大到没人真的逐行审,只能看”测试过了吗”。

这笔债的账单,最后谁来付

复利曲线最后会变成一张具体的账单,由四个人分着付:

  • 业务付的是速度:明享那个”小改动”排了三周。当每次改都怕碰坏别处,迭代速度会肉眼可见地塌下来——你以为 AI 让你更快了,半年后反而更慢。
  • 风控付的是事故:那次差点流进总账的错算被拦住了,但下一次未必。告警、例外和安全 review 越积越多,迟早会有一个没被拦住。
  • 团队付的是人:没人愿意长期维护一坨自己读不懂、改了就抖的系统。最了解它的人一走,这套系统就彻底变成黑箱——而 AI 代码本来就没有”最了解它的人”。
  • 公司付的是重写:理解债攒到某个点,“改”已经比”重写”更贵、更险,于是项目被推倒重来。第一版省下的那点时间,连本带利还了回去。

这四笔,没有一笔出现在”两天搭好一套系统”的那份惊喜里。它们都记在第七个月之后的账上。

先说清楚:换成元数据,不是没有代价

到这里得诚实停一下,否则又成了卖灵药。

让 AI 生成定义而不是代码,有取舍。声明式的元数据,覆盖的是企业应用里反复出现的结构——对象、字段、关系、视图、权限、流程、审批。它换来的可控性,代价是你放弃了一部分”想怎么写就怎么写”的自由度。如果你要做的是一个全新的实时协作引擎、一套独特的图形算法,那确实需要真正的代码,元数据帮不了你,硬套反而坏事——ObjectStack 解决的是企业里一遍遍重建的业务系统,不是下一个 Figma。

还有一层诚实:选元数据运行时,等于把一部分实现托付给了这个运行时,你押的是它的质量和长期可用性。这是个真实的依赖——只不过,相比”押在一万两千行没人读的代码”上,押在一个被反复审计、版本化、可迁移的运行时上,是好得多的赌注。

把生成的东西换掉:不是实现,是定义

回到明享那套报销系统。同样的需求,如果当初 AI 生成的不是一万两千行实现,而是这样一份定义:

export const ExpenseReport = ObjectSchema.create({
  name: 'fin_expense_report',
  label: '报销单',
  fields: {
    amount: Field.currency({ label: '金额', min: 0 }),
    invoice_type: Field.select({ label: '发票类型', options: ['普票', '专票'] }),
    deductible_rate: Field.percent({ label: '抵扣比例' }),
  },
});

这几十行不是”还要去实现的接口”,它本身就是系统。运行时(ObjectOS)读取它,自动派生数据表、API、界面,以及 agent 可调用的受治理工具;权限、审批流同样是挂在它上面的声明,而不是手写的判断。

那么第七个月那次税务规则变更,长什么样?不再是一场考古,而是一行能看懂的改动:

- deductible_rate: Field.percent({ label: '抵扣比例' }),
+ deductible_rate: Field.percent({ label: '抵扣比例', defaultValue: 70 }),
+ // 专票按新规抵扣 70%,规则下沉到定义,审批与对账自动跟随

这是一个能在五分钟内评审、能一键回滚的 diff,而不是一个没人敢点”合并”的四百行 PR;也不会出现”顺手改坏对账”那种事,因为对账逻辑不在这份定义里、它根本碰不到。差别不在哪种更”高级”,而在半年后,谁还看得懂、改得动、出了错查得到

复利机制为什么被掐断了

换成定义之后,那条曲线为什么能压平?三点,都直指明享那个故事:

  1. 没有”没人读过的实现”。 实现属于被反复审计、所有应用共用的同一套运行时,不是每个应用各生成一份。你的应用里只剩定义,而定义是给人读的。
  2. 没有”无人可问”。 定义是声明式的,它把意图写在脸上——deductible_rate 是什么、归谁管、改它影响哪些流程,一目了然,不需要去问那个早已消失的生成会话。
  3. 漏洞面收窄。 许多常见风险来自手写的认证、查询拼接和输入处理。这些由统一运行时承担后,应用层能引入的漏洞类别会少很多。

结语

问题不在于 AI 写代码这件事本身,而在于太多团队把”快速生成原型”的工具,直接当成了”建设长期系统”的方式。原型可以是一堆没人读的代码,用三年的系统不该是。

下次要用 AI 搭一套真要长期用的业务系统,先别问”它生成得多快”,问明享第七个月才被迫面对的那个问题:半年后规则一变,我还敢不敢改它、查不查得到。 让 AI 生成定义而不是代码,是更可靠地让这个答案变成”敢”的路径。

npm i -g @objectstack/cli && os start

定义一个对象,改一次字段,看看那次改动在 git diff 里有多干净——那就是一笔不会复利的债。