导语:当 AI 编程代理从“补全几行代码”升级为能够读取仓库、执行命令、安装软件包、修改配置并连续运行数日的自主开发者,软件团队获得了明显的效率提升,也迎来了一个更棘手的问题:代理完成的代码究竟由谁负责审查?那些藏在锁文件、构建脚本、环境变量和工具配置中的依赖变化,又该由谁发现?🤖
自主运行越久,审查难度越高
传统代码审查通常围绕一个明确需求展开,改动范围、提交者意图和影响边界相对清楚。但 AI 编程代理连续工作数日后,可能同时修改业务代码、测试用例、数据库迁移、CI/CD 工作流和依赖清单。即使每一处修改单独看都合理,组合起来也可能改变系统的权限边界、数据流向或部署方式。
真正的风险不一定来自明显的错误代码,而可能来自“看起来能够正常运行”的实现。例如,代理为了让测试通过而扩大文件访问权限,为解决兼容问题而降级安全组件,或者引入功能相似但维护状态不明的软件包。代码可以通过测试,并不等于设计合理、安全可控。
AI 可以生成修改并给出解释,但不能承担组织意义上的审批责任。最终合并、发布和风险接受仍应由具备权限的人类负责人完成。
代码审查责任不能交给一句“AI 生成”
团队首先需要明确责任链。需求负责人确认功能是否符合预期,代码所有者检查架构和可维护性,安全人员关注权限、输入处理与供应链风险,发布负责人决定是否进入生产环境。代理应被视为高效率的代码贡献者,而不是审查人、批准人或事故责任主体。
如果一个代理既编写代码,又调用另一个模型完成审查,再自动合并,那么流程表面上存在“生成与复核”,实际上仍可能共享相同上下文、相似偏差和错误假设。更稳妥的做法是保留独立的人类审查,并通过分支保护、强制审批和代码所有者规则阻止代理自行完成闭环。
NIST 安全软件开发框架强调,应把安全实践纳入软件开发生命周期,而不是等到发布前集中补救。对于代理生成的改动,这意味着审查对象不能只限于源代码差异,还应覆盖需求、设计、测试结果、依赖来源和发布配置。
“隐藏依赖”究竟藏在哪里
隐藏依赖不只是 package.json、requirements.txt 等清单中的直接依赖,还包括锁文件里的传递依赖、容器基础镜像、下载脚本、GitHub Actions、编译插件、远程模块、MCP 工具以及运行时外部服务。代理为了完成任务,可能修改这些位置,却未在总结中充分说明。
另一个容易被忽视的区域是仓库指令文件。代理会读取 README、问题描述、错误日志和专用规则文件,其中的内容可能影响后续行为。OWASP 的 AI 安全编码指南指出,仓库内容、外部页面和工具响应都可能跨越信任边界,因此不能默认代理读到的全部信息都是可信指令。⚠️
依赖变更还可能绕过普通审查者的注意力。一项直接依赖升级,可能同时带来多个间接依赖变化。GitHub 依赖审查文档说明,针对清单和锁文件的审查可以展示新增、删除及更新的依赖,并提示已知漏洞。这类机器检查应成为合并门禁,而不是可选提示。
建立可执行的代理开发控制线
- 限制单次任务边界:将数日任务拆成可独立验收的小阶段,每阶段生成提交、测试记录和变更说明,避免最后出现难以理解的超大差异。
- 采用最小权限:代理默认只获得仓库和测试环境的必要权限,不直接持有生产凭据,也不允许自行关闭安全检查或修改分支保护规则。
- 强制列出依赖变化:每次提交都应说明新增依赖、版本调整、传递依赖、许可证、下载来源及引入理由,并审查锁文件。
- 设置高风险路径:认证授权、支付、密钥管理、数据库迁移、基础设施配置和 CI/CD 文件必须由指定代码所有者审批。
- 组合验证手段:除单元测试外,加入静态扫描、密钥检测、依赖漏洞检查、许可证检查、集成测试和必要的模糊测试。NIST 软件验证指南也建议综合使用威胁建模、自动化测试、静态扫描和第三方组件检查。
- 保留完整审计记录:记录代理使用的模型、工具、权限、指令、命令、网络访问、提交和人工审批结果,便于复盘错误来源。
审查者可以重点追问什么
- 这项改动是否超出了原始需求,新增了哪些未经明确要求的行为?
- 有没有新建网络连接、后台任务、遥测、缓存或数据持久化路径?
- 依赖名称、版本、发布者和来源是否可信,是否存在名称相近的软件包?
- 测试失败后,代理修改的是实现,还是降低了测试、安全规则与权限限制?
- 删除代理生成的说明文字后,人类是否仍能理解并维护这套实现?
总结
AI 编程代理连续自主开发数日,风险并不只在于“写错代码”,更在于改动规模扩大、责任边界模糊和依赖关系悄然变化。解决办法不是禁止代理长时间工作,而是让任务可分段、权限可限制、依赖可追踪、审查可追责、发布可阻断。🚦只有把 AI 的执行效率纳入成熟的软件工程治理,团队才能真正获得生产力,而不是把审查成本和供应链风险推迟到上线之后。