复制粘贴传染病:AI 辅助开发如何传播架构反模式
你的代码库中有三种不同方式实现的身份验证逻辑,而且团队中没人在写过其中任何一种。通过 git blame 快速查看,发现这三个文件都出自同一位工程师之手,但去问那位工程师,他们会告诉你他们只是接受了 AI 的建议,而且看起来“没问题”。这种反模式的蔓延并不是因为有人偷懒,而是因为一个对你现有认证模块毫无记忆的 AI 模型,在每次有人打开新文件寻求帮助时,都生成了看起来合理的实现。
这就是“复制粘贴传染病” (copy-paste contagion),它在结构上与你已知如何应对的经典复制粘贴问题完全不同。
为什么这不再是你爷爷辈遇到的那种复制粘贴问题
传统的复制粘贴反模式是具有自我限制 性的。开发者复制代码块,队友在评审中发现它,作者会为自己的选择感到负责。反馈循环——即使很慢——也是存在的。模式在蔓延,但它是以人类的速度蔓延,且有人类作者可以被拉到一边解释其逻辑。
AI 辅助开发同时拆除了该系统中的所有制动装置。
当开发者接受来自 Copilot、Cursor 或 Claude Code 的建议时,提交的代码模式在任何有意义的问责层面上都没有作者。生成它的 AI 模型并不知道你的代码库存在。它优化的是局部正确性——通过其上下文窗口中可见的任何即时测试或类型检查——而不是为了与它看不见的 20 万行现有代码保持一致。接受建议的开发者在按下 Tab 键之前,可能只进行了三秒钟的视觉扫描。
然后他们打开下一个文件,向同一个 AI 寻求帮助。同一个模型生成了同样的模式。他们再次接受。接着他们打开第三个文件。
GitClear 对 2025 年 AI 辅助代码库的分析发现,代码克隆(code clones)比 AI 普及前的基准增长了 4–8 倍,在三年内从所有变更行的 8.3% 跃升至 12.3%。更具说服力的是:自该数据开始追踪以来,2024 年的复制粘贴操作首次超过了重构。重构——这项历史上用于清理重复代码的活动——从 2021 年变更行的 25% 崩塌至 2024 年的 10% 以下。
这些数字描述的不是生产力问题,而是结构性退化问题。
局部与全局的一致性鸿沟
一项 2026 年的分析对比了 AI 编码质量与可维护性标准,发现在“能运行的代码”和“可维护的代码”之间存在 26 分的性能差距。这种差距并非偶然,而是架构层面的。
目前的大语言模型(LLM)是“上下文窗口推理者”。它们能看到你正在编辑的文件,如果你仔细配置了上下文,或许还能看到几个相关文件以及对话历史。但它们看不见的是隐性架构:依赖规则、所有权边界,以及你的团队在这个特定系统中工作多年形成的惯例。模型不知道你的团队曾约定永远不要从 HTTP 处理器直接调用数据库,或者身份验证应始终通过中间件层,又或者 UserService 是用户状态的唯一事实来源。
因此,它会充满自信地生成违反这些惯例的代码。从语法上看,它无懈可击。类型正确,测试通过。然后它被合并了。
在 AI 辅助的代码库中一致出现的特定反模式是可以预见的:
- 并行的身份验证实现:在面对新上下文时,同一个模型会从头开始重新生成认证逻辑,而不是调用你现有的认证服务。
- 从 HTTP 处理器直接访问数据库:当模型看不到你的存储层(repository layer)时,它会直接编写查询语句。
- 重复的错误处理:模型不会使用你团队的集中式错误类型,而是在每个新模块中创建局部适用但全局不一致的错误处理。
- 幻觉 API:模型会调用你拥有的类中并不存在的方法,或者调用在你运行的版本中已被删除的内部库方法。
孤立来看,其中每一项都是微小的违规。但 AI 工具可以在一次会话中生成 20 个文件。过去需要数月积累的问题,现在一下午就会发生。
机器速度下的破窗效应
破窗效应描述了城市环境中一种已被充分证实的动态:可见的混乱信号暗示了混乱是可以接受的,从而诱发更多的混乱。同样的动态也存在于代码库中,只是速度较慢——在历史上慢到足以让代码评审和重构冲刺打断这一循环。
AI 辅助开发压缩了时间跨度。当开发者在三个文件中看到重复的认证逻辑时,自然的反应不是去重构,而是复制现有的模式。如果三个文件都这么写,那肯定就是这么做的。AI 会非常乐意通过生成与现有三个实现一致的第四个实现来确认这一点。
这种复利效应是迅速的。代码变更率(code churn,即两周内被还原或重写的 AI 生成代码百分比)比人工编写的代码高出约 55%。这并非 AI 无能的迹象,而是局部一致性无法转化为系统一致性的信号。代码在需要与系统其他部分集成之前运行良好,但一旦集成,就不灵了。
作者责任真空
当反模式在人类编写的代码库中传播时,你有迹可循。git blame 显示了谁做出了这个选择。你可以就为什么做出这个选择以及是否应该重复该选择进行对话。模式违规是有作者的,而作者是可以被教育的。
当 AI 传播反模式时,git blame 显示的是接受建议的开发者。该开发者可能真的不知道他们违反了架构约束——因为 AI 看不到该约束,在 diff 中也看不出来,而且如果代码审查的速度达到了 AI 辅助团队通常运行的速度,审查者也同样看不出来。
结果就是一个代码库中存在反模式,但没有人决定引入它们。没有 人能解释为什么这个模式是错误的,因为最初根本没有人决定使用它。这使得架构修正比 AI 普及前的基准线要困难得多。你无法对一个从未做出过的决定进行回顾。
这种责任真空还破坏了传统的模式治理机制。架构审查假设架构决策是由人做出的。代码审查假设作者理解他们写了什么。当 AI 生成代码时,这两个假设都会动摇。
适应度函数作为主要防御手段
如果 AI 破坏架构的速度超过了人类在代码审查中捕捉的速度,那么防御手段就必须是自动化的。这就是架构适应度函数(architectural fitness functions)从“锦上添花”变为主要工具的地方。
在《演进式架构》(Building Evolutionary Architectures)一书中被正式定义的架构适应度函数,是验证系统是否仍然遵循特定架构决策的自动化检查。它们不是单元测试——它们测试的是代码结构,而不是行为。一个适应度函数可能会断言 http 包中的任何类都不能直接依赖 persistence 包中的类,或者 AuthService 是唯一有权访问 JWT secrets 的模块,或者任何接触数据库的函数都必须带有特定的装饰器。
ArchUnit (Java)、Dependency Cruiser (JavaScript/TypeScript) 和 NetArchTest (.NET) 等工具允许你将这些约束表达为代码。在 CI 中运行它们。当 AI 生成的文件违反架构边界时,适应度函数会在代码合并前报错。
这将问题从“人类审查员能捕捉到这一点吗”转变为“这一约束是否被编码为机器可检查的规则”。AI 生成的代码量 太大,第一种方法无法应对。只有第二种方法在 AI 的速度下才具有可扩展性。
这里的实践原则是将团队关心的每一个架构规范都视为适应度函数的候选对象。如果你曾在代码审查中说过“我们在代码库中不这样做”,那么这句话就是一个潜在的适应度函数。将规则写进代码中。针对每个 PR 运行它。
AI 辅助时代的代码审查
适应度函数能捕捉结构性违规,但它们不能捕捉一切。代码审查仍然很重要——只是它的导向必须与 AI 工具出现前有所不同。
传统的代码审查问题是“这段代码实现了它应有的功能吗?”对于 AI 生成的代码,答案几乎总是肯定的。代码在局部是正确的。关键的问题是“这段代码符合我们既定的构建方式吗?”
这种重新定位意味着一些实践上的变化:
在架构模式层面进行审查,而非代码行层面。 在审查 AI 辅助的 PR 时,观察新代码是否引入了处理关注点的新方式,而这些关注点在代码库中已有既定模式。新的错误处理方式?新的状态管理模式?调用外部服务的新方法?这些都是信号。
警惕单体式贡献。 AI 工具很少建议重构——它们生成的是新代码。当一个 PR 增加了 500 行并涉及 15 个文件时,与现有模式不一致的风险会随规模增加。对大型 AI 辅助的 PR 应给予成比例的更高关注。
检测上下文窗口产物。 AI 在看不到现有实现时会自行实现。重复的工具函数、并行的验证逻辑以及重新实现的服务类经常是上下文窗口产物: 模型没有看到现有的代码,所以它又写了一遍。了解代码库的审查者应该通过询问“我们不是已经有实现这个功能的代码了吗?”来捕捉这些问题。
留意幻觉式的 API 调用。 AI 编写的 PR 显示出的关键问题是人类编写代码的 1.7 倍(在大规模分析中,每个 PR 有 10.83 个 vs. 6.45 个关键问题)。其中很大一部分是对不存在的 API、方法或接口的调用——这些代码看起来正确,但在运行时会失败。
团队常犯的错误
最常见的错误是将 AI 辅助开发视为交付问题而不是设计问题。团队专注于速度提升——更快地交付更多代码——并以代码行数和交付的功能来衡量成功。架构退化在无声无息中累积,因为最重要的指标(结构一致性)没有被衡量。
当退化变得显而易见时——比如添加一个新功能需要修改 12 个文件以兼顾重复的实现,或者安全审计发现三个独立的身份验证路径且验证不一致时——修复成本已经高得惊人。
第二个错误是认为在不改变流程的情况下,代码审查可以扩展到 AI 的速度。如果 AI 生成了 41% 的新代码(这一数字只会增加),而审查吞吐量没有相应增加,那么合并的代码中经过有意义审查的比例就会下降。适应度函数是审查能力的“力量倍增器”,而不是替代品——但尚未实施这些函数的团队完全依赖人类的注意力来捕捉那些目前到达速度超过人类处理能力的问题。
