
半年前我接手了一个AI代码比例高得吓人的项目。功能上线速度是真的快可三个月后团队里没人敢碰那些代码——改一行可能带崩一片查问题像是在考古。这个场景我见过不止一次AI辅助编程让产出暴增技术债也在以同样的速度悄悄堆积。今天这篇分享不打算讲什么宏大理论就想踏踏实实聊聊AI生成代码为什么会变成明天的技术债、怎么提前发现这些债以及我实际在团队里跑过的一套治理流程。说的都是能直接拿去用的做法不是概念。无论你是正在让AI帮你写业务的开发者还是要对代码长期质量负责的技术负责人都可以对照着调整自己的节奏。1. 先从一段“白天提速、晚上救火”的日子说起1.1 一个“两天完成”的模块某小组接了一个内部工具平台的需求把三个数据源合并成统一报表。同事A用两天时间让AI完成了其中一个核心模块代码风格规范注释齐全甚至附了测试。而另一个模块按传统方式排期要一周。当时所有人都觉得AI这条路走对了。两周后需求调整状态机需要增加一个流转分支。维护者B接手时发现状态机的实现散落在三个文件里每个文件是不同轮次的AI对话生成的逻辑相似但行为有细微差异。他改了一处漏了另一处上线后数据直接错乱。那一周连续做了三次热修复每次都在重复同一个故事开头很快修起来很慢。真正让我意识到问题的是新同事C的提问为什么这里要设置两秒重试为什么这个异常被吞掉了没人能完整回答。提交记录里没有设计说明原始提示词也没有被留存。核心问题随之出现这个模块变成了“无主代码”——它存在、能跑但没有人能真正解释它。1.2 为什么“代码能跑”和“代码可维护”是两回事这就像一个人办了张信用卡表面看起来没有欠款其实一直在透支明天的注意力。技术债最典型的路径恰恰是越快得到一段代码就越容易忘记去理解它。AI生成的代码样式往往不难看甚至命名规范、注释完整但它依然会成为债务因为生成时的决策过程没有被记录维护者无法判断它能承受怎样的改动。按业界常见的说法技术债不是“代码写得丑”那么简单而是“当前选择对未来的一种透支”。人写的烂代码一眼就能被识别反而不容易长期存留AI生成的代码看起来太正常了团队会默认它没有问题于是债务就藏进了正常的表象里。其实AI代码完全可以成为正向资产前提是把它当作“可读的草稿”而不是“可上线的成品”让AI搭骨架、写重复逻辑、补文档人负责理解、决策、测试和长期维护。价值会保留债不会积压。2. 表面光鲜的AI生成代码问题藏在四个角落别急着让AI背锅。AI写出来的代码不一定丑很多问题恰恰出在它太“正常”了。我观察过大量生成代码最常见的隐患基本集中在四个角落。2.1 复读机式冗余AI没有仓库全局记忆它基于当前对话的上下文生成代码。于是每接一个新任务它就很可能把已有逻辑重新写一遍。我在那个项目里见过页面三个文件出现几乎一样的格式化函数分别由三次不同对话生成逻辑相近但参数处理略有差异。当时没人觉得有问题可后来格式规则一变就需要同时改三处漏改一处线上数据就错乱。这类问题用肉眼很难察觉因为函数名可能完全不一样但静态扫描会看到很高的相似度。为什么不直接复用因为你在提示词里没有给出已有函数的签名AI只能按自己的理解重新发明。重复代码意味着同一业务规则维护了多份副本任何修改都要同步到所有副本少一处就是一个隐藏bug。2.2 自信的幻觉AI语言模型在生成代码时会有幻觉在不存在的库上构造调用、编造可选参数、或者使用旧版本的接口写法。最典型的场景是消息队列封装——AI“记得”某个方法在库里存在实际上当前版本已经改名了。IDE没报错开发自测也没走到那条路径生产环境在特殊流量下才触发了异常。这种问题的可怕之处在于AI是“自信”地写出这些调用的它不会告诉你自己不确定。于是在静态检查、编译、开发自测全部通过的情况下问题被推迟到运行时才暴露。修复成本往往很高因为你需要先找到那个“看起来存在但实际不存在”的调用点。配合依赖文档、编译期扫描、以及覆盖到真实场景的测试才能兜住这一类幻觉。2.3 目光短浅的上下文耦合AI看不到仓库全貌只能看到你贴在提示词里的局部代码。为了“完成任务”它会绕过现有设计直接访问别的模块。举个例子某个订单状态模块为了标记已处理AI直接在支付通知代码里改了状态字段而不是走状态机接口。当时看起来很省事可后来状态流转增加了新规则这处直改就成了绕过校验的后门。背后的问题是职责混乱。表面上看代码在一个模块里实际上两个模块都在控制同一状态改动任何一处都可能影响另一处。发生线上问题时排查的人根本不知道该看哪个模块。这种债需要靠架构约束来防人在生成之前就要给AI划清楚边界。2.4 平时不响的防御边界AI默认按照快乐路径输出。你不让它考虑失败场景它就不会写异常处理、重试、降级。比如一个导出Excel的功能在文件目录正常时可顺利跑通但只要目录变成只读它就直接抛异常网络抖动时远程调用只做一次没有重试用户界面转圈到超时。这类问题的特点是正常路径上系统很快故障路径上完全裸奔。测试环境很难覆盖到这些场景于是它们全部积压到生产环境。要解决需要在评审时强制追问失败路径也需要在提示词里明确要求AI补充异常分支。2.5 为什么“表面质量”反而会骗过评审最麻烦的地方在于这些代码的表面质量通常很高。AI生成的命名、格式、注释都很统一评审者很容易进入“代码这么干净应该没问题”的状态。人写的糟糕代码反而会唤起警惕AI写的副本和幻觉却会被顺手放行。所以治理AI代码的第一课是把“赏心悦目”和“可靠可用”分开。评审不能只盯着缩进、命名、格式这些AI自己就能做好要盯的是意图、边界、失败路径和测试证据。3. 治债第一步把模糊的“不放心”变成可量化的信号不能等上线后才发现债。我在团队里做的第一件事是建立一套可见的预警清单让AI代码在合入之前就暴露风险。信号编号信号名称检测方法危险级别1相似代码块重复率偏高静态扫描工具对代码块做相似度聚类黄2核心模块分支覆盖率不足覆盖率报告检查条件覆盖情况黄3IO/外部调用附近缺少异常处理规则扫描统计调用点与错误捕获数量黄4魔法数字、硬编码配置散落扫描字面量常量要求抽成配置黄5新引入来源不明的依赖依赖锁定文件和变更diff核对红6跨模块直接改动或访问全局变量静态分析检查引用范围红7同一业务规则出现多个实现代码评审配合语义相似度工具辅助黄8注释描述与实际行为不一致抽查评审对比注释与运行逻辑黄9使用了废弃或可疑API编译警告与IDE废弃标记检查黄10出现明文密钥或凭据正则扫描常见密钥模式红这套清单落地时我做了三件事。第一直接做成MR模板里的checklist每个AI生成片段提交前必须逐项勾选第二把能自动化的检查挂进流水线扫描结果自动标到MR上面第三约定触发条件单次提交命中3个黄灯或1个红灯直接打回。有人问信号这么多会不会太复杂。我的观点是技术债最危险的地方恰恰在于不可见。你只有把模糊的“不放心”变成具体数字才能在合入那一刻拦住它而不是在半年后让某位同事半夜上线救火。另外我还会统计打回率如果一个月内AI相关提交的打回率超过20%说明要求还不明确或者提示词写得太随意。这时候应该停下来调整约束而不是继续快速产出代码。4. 治债第二步四道关卡把AI生成物挡在主干道之外有了预警信号还要有流程。只靠扫描和清单容易被当成额外负担真正起作用的是让AI生成物在合入主分支之前经过四道关卡。4.1 需求关先交方案再交代码大多数团队让AI直接写代码这是流程的第一个缺口。AI不是决策者它只是推断你想要的输出。如果方向本身就错了生成的代码越完整返工成本越高。我现在的习惯是在生成前用一个固定提示词逼它先输出实现方案把涉及模块、调用关系、接口改动、失败路径和风险点列清楚。确认方案没问题再让它写具体代码。这一步看起来多花几分钟实际能砍掉一半因为方向不对而产生的返工。提示词大概长这样请先不要写代码只输出实现方案 1. 涉及的模块和调用关系 2. 需要新增或修改的接口 3. 失败路径和异常处理计划 4. 这个方案可能存在的3个风险点 等我确认后再生成具体实现。4.2 架构关给AI画清楚边界AI看不到仓库全貌所以人必须把边界显式告诉它。我在仓库里放了一个提示词约定文件类似给所有协作者的开发规范但针对AI生成场景做了更强约束禁止访问全局状态、禁止直接改写别的模块内部字段、依赖只能从上层指向下层、新增公共函数必须先说明职责。每次提交AI代码提示词必须引用相关接口签名而不是让AI自己猜。这一步容易被忽略因为很多开发者觉得“把需求描述清楚就够了”。实际上AI为了完成目标会想办法绕过设计直接使用全局单例或访问外部模块内部字段。所以架构约束必须配合评审否则形同虚设。4.3 评审关带着生成背景去审代码AI代码评审最容易被忽略的是意图。只看代码看不出它背后依据了什么假设、做了什么取舍。于是我在提交模板里加了“生成记录”字段原始提示词、AI的完整回答、人工修改了哪些地方。评审者看到的就不只是代码本身而是这段代码为什么长成这样。审通过的标准也从“代码能跑”变成“我们理解并接受这段代码的决策”。这一步的关键是把决策权留在人手里AI只是执行者。如果你发现一段AI代码的生成记录缺失最稳妥的做法是先打回补齐不要替它脑补理由。4.4 运行关没有测试证明的AI代码不允许合入最后一道关卡最难推行也最值钱。无论提示词写得有多好AI代码必须有运行证据才能合入一个能验证它的自动化测试最好再补一两个故障场景的测试比如断网、目录只读、参数非法。我见过团队跳过这一步理由是“功能这么简单不用写测试”。结果两周后那个模块果然出了问题没人能确定自己改崩了什么。把测试当成买保险而不是额外成本这可能是AI时代最值得守住的一条底线。5. 治债第三步让存量债在流水线上自动还四道关卡管住了新的生成物但存量债还在。在接手项目并跑完治理流程之后还需要让债有出清机制。核心思路是把质量门槛变成流水线上的自动门禁而不是依赖某个人的自觉。5.1 把质量门槛写进流水线我给CI流水线加了一套门槛规则示意如下pipeline: - lint: warning 以上不允许合入 - duplication: 相似代码块占比不超过 15% - coverage: 核心模块分支覆盖率不低于 80% - dependency: 新增依赖必须经过人工确认 - secret_scan: 出现明文密钥直接终止这些门槛一开始肯定会挡下很多代码团队也会反弹。所以不要一次拉太高先挑最顽固的一条规则跑两周让团队适应再加下一条。目标不是零债务而是债务不能无意识增长。跑了一段时间后重复率和覆盖率的数字会主动说话比任何人的口头催促都有用。5.2 用AI反治AI债AI留下的问题也可以让AI来帮还但必须小心。我试过两种行之有效的方式。第一种是让AI做“阐释者”把一段没人理解的历史AI代码喂给另一轮对话要求它解释职责、依赖和风险点然后让维护者复核。理解债是技术债里最贵的部分这个方法能大幅降低消化成本。第二种是让AI生成候选重构。把重复代码聚类结果交给AI让它生成收敛到公共函数的候选补丁。但AI会做重命名、调整副作用所以必须做行为等价验证比如录制对比测试或黄金文件确认前后行为完全一致。注意用AI重构AI代码不等于信任第二份AI输出。AI给的东西永远是候选方案不是标准答案人工审阅和测试验证一步都不能少。5.3 存量债分级处理不是所有债都值得立刻还我把存量债按“使用频率”和“风险程度”分成了四档处理策略完全不同。使用频率风险程度处理策略高频高优先重构先补测试再动刀高频低收敛入口统一封装后再替换低频高加监控、加隔离层暂不动结构低频低冻结并留文档标记为技术债不要指望一次清理掉所有债那既不现实也不必要。治理的目标是把未知的债变成已知的债把危险的债变成可控的债。6. 一个季度的数据提速和质量到底能不能兼得这套流程跑了一个季度后我整理了一份真实度量数据以自己管理的一个业务后端小组为样本。先说结论速度没有掉下来质量反而更好了但过程不是一帆风顺。指标治理前治理后周均有效交付版本1115核心模块代码重复率32%14%核心模块分支覆盖率48%76%变更回退率12%6%生产环境故障平均修复时间4.5小时2.2小时新人独立修改核心模块所需时间约3周约10天前两周是最难受的多了方案确认、生成记录、测试补齐团队明显感觉变慢了甚至有人说“不如直接手写”。但从第七周开始返工少了、线上故障少了、累积效率反而超过了之前。所以如果准备推行这套流程一定要做好“先慢后快”的心理准备。我还观察过一个对照组同时期另一个小组不设门槛纯粹追求AI生成速度。半年后他们好几个模块没人敢改最后只能停线重写其中一个模块。这个对比让我认定AI本质上是放大器——如果流程是健康的它会放大效率如果流程本来就失控它只会放大债务。7. 我的最终体会AI是放大器不是背锅侠说了这么多流程最后聊点更个人向的东西。7.1 哪些地方别直接让AI写我给自己划了一条线核心资金计算、权限校验、涉及分布式一致性和不可逆操作的代码不管提示词写得多好都不直接采用AI的第一版输出。可以让AI做代码评审、做逻辑解释但主链路上的关键逻辑必须由人亲手写过并且经过测试。原因很简单这些逻辑一旦出错代价不是重构能挽回的而是线上事故。其他场景则不必因噎废食。脚手架、CRUD、格式转换、常规增删改查让AI写完全没问题只要按前面说的四道关卡走。7.2 把AI当结对程序员而不是外包程序员外包程序员的特征是你给需求他交代码你验收。结对程序员的特征是你们讨论方案、互相挑战、一起对代码负责。如果只把需求丢给AI它就是一个交代码特别快的外包如果你逼它先讲方案、列出风险、解释取舍它就是能让效率翻倍的搭档。一个我每次都在用的小技巧让AI生成了超过20行的代码之后紧接着问它一句“这段代码可能有哪三个潜在的风险点”。它列出的清单通常不是废话AI对自己生成代码中最有风险的分支其实是有感知的。你再把它列出来的风险点写进MR描述里评审效率会明显提升。7.3 无主代码才是最贵的债务再回头看开头的那个模块真正让它变成技术债的不是用了AI而是它成了一堆没人能解释的代码。所以我对团队的硬性要求是AI生成的每一段代码都必须有一个明确的owner。owner要能讲清楚这段代码为什么存在、边界在哪里、怎么测试它。做到这一点这段代码就从“AI产出”变成了“团队资产”。我到现在仍然每天用AI写代码而且写得越来越多。变化只是它负责快我负责懂它负责产出我负责把关。这句话是我实践下来最准确的总结也是我想推荐给所有人的状态。