审查难题

对 AI 生成代码的标准建议是”仔细审查”。

这个建议正确但在规模化时毫无用处。

开发者审查 AI 输出时,在精力充沛、熟悉领域且没有时间压力的情况下能发现问题。在其他所有条件下——而这是大多数情况——问题会漏过。

用 AI 审查者来发现 AI 生成的问题更不可靠。你是在要求一个概率系统验证另一个概率系统的输出。失败模式是相关的。

唯一可扩展的模式是确定性 enforcement。在每次提交时检查的规则,不会被疲劳或乐观所覆盖,在违反时使构建失败。

确定性意味着什么

确定性意味着检查每次产生相同的结果,无论谁运行或何时运行。

  • Linter 规则是确定性的。
  • 类型检查是确定性的。
  • 边界导入限制是确定性的。
  • Contract tests 是确定性的。
  • 人工审查者的注意力跨度不是。
  • 大语言模型的评估不是。

这个区别在 AI 生成的 codebase 中更加重要,因为生成的代码量超出了任何团队手动审查的能力。你无法让审查能力与生成速度线性扩展。你可以轻松扩展确定性检查。

护栏体系

对于 AI 生成的 codebase,护栏体系有四个层次:

第一层:类型系统

类型系统是第一道护栏。严格类型能捕获一类任何审查流程——无论人工还是 AI——都无法持续捕获的错误:

  • 空值违规
  • Interface 不匹配
  • 缺失的分支处理
  • 错误的参数类型

如果项目使用 TypeScript,strict: true 是不可商议的。如果使用没有强类型系统的语言,通过工具添加一个,或者选择另一种语言。

第二层:架构规则

架构规则执行边界纪律:

  • 任何页面不得导入另一个页面的内部实现。
  • 领域逻辑不得直接导入基础设施。
  • 任何 module 不得绕过 composition root 来获取依赖。
  • 供应商 SDK 不得出现在其适配器 module 之外。

Semgrep、ArchUnit、dependency-cruiser 或自定义 ESLint 规则等工具可以静态地执行这些规则。关键是它们在 CI 中运行且使构建失败。开发者可以忽略的警告不是护栏。

第三层:Contract Tests

Contract tests 验证 module 满足其 interface,而无需运行完整系统:

  • 认证适配器满足认证 interface。
  • 数据分析适配器满足数据分析 interface。
  • 存储适配器满足存储 interface。

这些运行速度快,测试集成边界,并捕获 AI 生成代码满足类型签名但违反行为 contract 的特定失败模式。

第四层:确定性集成检查

在集成层面,检查验证系统级属性:

  • Composition root 解析所有依赖时不产生运行时错误。
  • 依赖图不包含循环。
  • 所有必需的环境变量均已声明。
  • 配置在构建时有效,而非仅在运行时有效。

Semgrep 用于 AI 生成代码

Semgrep 值得特别提及,因为它擅长将架构规则表达为代码:

  • 基于 AST 结构的模式匹配,而非字符串匹配。
  • 每个项目的自定义规则,而不仅是通用 linting。
  • 足够快,可以在每次提交时运行。
  • 足够表达力,能编码边界违规。

大量使用 AI 生成的团队应该维护一套 Semgrep 规则集来编码他们的架构边界。当 AI 生成的代码违反边界时,构建在合并前失败。无需人工关注。

这不是为了捕获 AI 输出中的缺陷,而是为了使结构违规无论如何产生都不可能被合并。

AI 代码审查实际能捕获什么

AI 代码审查工具适用于:

  • 风格一致性
  • 文档缺失
  • 明显的逻辑错误
  • 建议替代方案

AI 代码审查工具不可靠的方面:

  • 架构边界违规
  • 跨 module 引入的隐蔽耦合
  • 行为 contract 违规
  • 需要全系统推理的安全属性

失败模式不在于 AI 审查偶尔遗漏问题。失败模式在于它不可预测地遗漏问题,而你无法知道它何时遗漏了。这就是为什么它不能取代确定性 enforcement——只能补充它。

经济性分析

确定性护栏运行成本低廉,但初始构建成本较高。

编写架构规则需要几天。维护 Semgrep 配置需要持续关注。设置 contract tests 需要先定义 interface。

但一旦存在,它们在每次提交时以接近零的边际成本运行。它们不会疲劳。它们不会在周五下午跳过检查。它们不会屈从于资历或社交压力。

对于代码量大、生成速度快的 AI 生成 codebase,这种经济特性是决定性的。替代方案——让人工审查能力匹配 AI 生成速度——是不可行的。

与 AI-Native 架构的关联

我在斯坦福 CS146S 对 AI 编程的判断是对的——缺失的主题是架构中写过这个更广泛的模式。确定性护栏是使可替换架构成为现实的 enforcement 机制。

没有护栏,架构边界只是愿望。有了护栏,边界成为结构。“我们尽量保持 module 隔离”与”module 隔离被违反时构建失败”之间的区别,就是能在 AI 速度迭代下存活的架构与在其下崩溃的架构之间的区别。

现代软件开发者不仅需要 AI 工具的熟练度,还需要一套护栏体系,使 AI 生成代码在高速发布时仍然结构安全。

常见问题

对 AI 生成代码执行架构规则的最佳工具是什么?

Semgrep 是自定义架构规则最灵活的选项。它支持基于 AST 结构的模式匹配,在 CI 中运行速度快,并允许团队编码项目特定的边界。对于 JavaScript/TypeScript 项目,dependency-cruiser 和自定义 ESLint 规则也很有效。

AI 代码审查能取代人工代码审查吗?

不能。AI 代码审查在风格和文档方面补充人工审查,但在架构边界 enforcement 和安全属性方面不可靠。确定性检查(类型系统、linter、架构规则、contract tests)是注意力依赖型审查唯一可扩展的替代方案。

如何在不拖慢团队的情况下建立护栏?

从类型系统开始(严格模式,无例外)。为三个最高风险的边界添加架构规则。为外部集成添加 contract tests。每一层只需一天来设置,运行仅需几秒。拖慢团队的是违规行为,而非检查本身。

护栏和 linter 有什么区别?

Linter 提出改进建议。护栏使构建失败。区别在于 enforcement。在 AI 生成的 codebase 中,建议在规模化时会被忽略,因为代码量太大,无法保持一致的手动关注。只有构建失败才能保证合规。