AI 正在把软件开发推向一种“只写不读”的状态:生成代码越来越快,但工程师没有同比增加时间去理解、审查和维护这些代码。Phillip Mortimer 提出的关键问题并不是 AI 能否继续提高产量,而是团队能否在产量激增后,仍然控制系统复杂度。
传统拉取请求并不会立刻消失,但把几十个文件的 diff 丢给另一位工程师、期待对方逐行发现所有风险,已经越来越难以扩展。更可行的方向是把意图从实现中分离出来,让机器检查可机械验证的约束,让人把注意力放在架构、边界和取舍上。
PR 的问题不是界面,而是信息密度
过去,代码产出速度本身就是一道天然限流器。开发者写代码需要时间,审查者通常还能跟上。生成式 AI 改变了这个比例:一个开发者可以迅速产生多个实现、测试和重构方案,但审查吞吐量依然受人的注意力限制。
这会带来三个直接问题:
- 实现掩盖意图:审查者看到数百行改动,却不清楚作者真正想改变哪个系统行为。
- 正确性不等于可维护性:代码可能通过测试,却引入新的依赖方向、重复抽象或隐蔽耦合。
- 责任被 diff 稀释:当大量代码由模型生成时,“这段代码为什么存在”比“是谁敲下这些字符”更重要。
因此,PR 不应只是代码容器,还应携带结构化意图。例如:目标是什么、明确不做什么、允许修改哪些边界、如何验证结果、失败后如何恢复。
把意图变成仓库中的一等产物
“解耦意图与实现”不意味着只写一段自然语言需求。自然语言仍然可能含糊,最好把关键约束变成机器可读取的文件,并与代码一起版本化。
一个最小的变更意图可以包含:
{
"goal": "为订单查询接口增加游标分页",
"non_goals": [
"不修改订单写入流程",
"不迁移数据库"
],
"allowed_paths": [
".change-intent.json",
"src/orders/",
"tests/orders/"
],
"max_changed_files": 12,
"acceptance": [
"旧客户端不传游标时行为保持不变",
"分页查询的集成测试通过"
]
}
这份文件不能证明实现正确,但它能显著改善审查入口。架构师可以先判断边界是否合理,自动化工具可以检查变更是否越界,开发者也能在调用代码生成工具时直接复用这些约束。
需要警惕的是,不要把意图文件变成另一份没人维护的文档。它应当短小、可验证,并在 CI 中真正产生约束力。
可复制实践:在 CI 中阻止“越界改动”
下面是一个只依赖 Python 标准库的最小检查器。它读取 .change-intent.json,再检查当前分支相对目标分支修改了哪些文件。
将以下内容保存为 tools/check_change_intent.py:
#!/usr/bin/env python3
import json
import os
import subprocess
import sys
from pathlib import Path
INTENT_FILE = Path(".change-intent.json")
BASE_REF = os.environ.get("BASE_REF", "origin/main")
def changed_files(base_ref: str) -> list[str]:
result = subprocess.run(
["git", "diff", "--name-only", f"{base_ref}...HEAD"],
check=True,
capture_output=True,
text=True,
)
return [line.strip() for line in result.stdout.splitlines() if line.strip()]
def is_allowed(path: str, allowed_paths: list[str]) -> bool:
for allowed in allowed_paths:
if allowed.endswith("/") and path.startswith(allowed):
return True
if path == allowed:
return True
return False
def main() -> int:
if not INTENT_FILE.exists():
print("ERROR: missing .change-intent.json")
return 1
intent = json.loads(INTENT_FILE.read_text(encoding="utf-8"))
allowed_paths = intent.get("allowed_paths", [])
max_files = int(intent.get("max_changed_files", 20))
files = changed_files(BASE_REF)
violations = [path for path in files if not is_allowed(path, allowed_paths)]
print(f"Goal: {intent.get('goal', '(missing)')}")
print(f"Changed files: {len(files)} / allowed maximum: {max_files}")
if len(files) > max_files:
print("ERROR: change is larger than the declared limit")
if violations:
print("ERROR: files outside declared boundaries:")
for path in violations:
print(f" - {path}")
return 1 if violations or len(files) > max_files else 0
if __name__ == "__main__":
sys.exit(main())
本地运行前,确保已经获取目标分支:
git fetch origin main
BASE_REF=origin/main python3 tools/check_change_intent.py
如果使用 GitHub Actions,可以增加 .github/workflows/change-intent.yml:
name: Change intent guard
on:
pull_request:
jobs:
validate-intent:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Validate declared change boundaries
env:
BASE_REF: origin/${{ github.base_ref }}
run: python3 tools/check_change_intent.py
这个示例只是起点。团队还可以逐步增加依赖方向检查、API 兼容性检查、数据库迁移规则、测试覆盖范围和安全扫描。不过,自动化审查应该提供明确证据,而不是再引入一个只给出模糊“风险分数”的黑盒审查者。
自愈不是让 AI 在生产环境随意改代码
自愈架构容易被误解为“故障后让模型自动提交补丁”。更稳妥的定义是:系统能够检测已知失败模式,并执行经过验证、可回滚的恢复动作。
常见的恢复层次包括:
- 进程失败后自动重启,但设置退避和重试上限。
- 实例异常时停止接收流量,由健康实例接管。
- 新版本指标恶化时自动回滚到已知稳定版本。
- 数据损坏或依赖故障时进入降级模式,而不是继续扩大影响。
- 自动生成诊断材料或修复候选项,但高风险变更仍由人批准。
真正的自愈能力依赖可观测性、故障隔离、幂等操作和可靠回滚。没有这些基础,AI 只会更快地生成未经验证的修复,甚至在故障现场制造第二个故障。
给工程团队的落地顺序
采用这套思路时,不必一次重建整个研发流程。可以按风险逐步推进:
- 先要求高风险 PR 声明目标、非目标、允许修改范围和验收条件。
- 把格式、边界、依赖和兼容性检查交给 CI,减少人工审查中的机械劳动。
- 让资深工程师重点审查模块边界、数据所有权、失败模式和长期维护成本。
- 从自动重启、流量摘除和自动回滚等确定性动作开始建设自愈能力。
- 跟踪逃逸缺陷、回滚次数、审查等待时间和变更规模,而不只统计代码产量。
AI 可以释放开发者的创造力,也可以把偶然复杂度放大到团队无法理解的程度。决定结果的不是生成速度,而是组织是否能把意图写清楚、把规则自动化,并让系统在失败时安全地恢复。