背压:AI 驱动软件工程中缺失的一环
编程智能体(coding agents)的兴起给开发者带来了一种令人沮丧的二分法。一方面是“无人值守”的方法:让 LLM 在代码库中肆意运行,这虽然速度快,但往往会导致大量低质量的 PR 和回归错误。另一方面是“自动补全”的方法:将智能体视为一种高级建议工具,人类必须审查每一行代码。第二种方法虽然安全,但实际上违背了委派的初衷,因为人类仍然是主要的瓶颈。
为了超越这些极端情况,我们需要引入系统工程中的一个概念:背压(backpressure)。在传统系统中,背压是一种机制,下游组件向其上游生产者发出信号,表明其无法接受更多工作,从而迫使生产者减速或纠正其输出。在 AI 编程的语境下,背压意味着构建自动化护栏,在代码达到特定的质量和正确性标准之前,拒绝让智能体继续前进。
自动化背压的演进
从历史上看,软件工程一直在努力将“拒绝”的权力从人类手中移走。我们从手动审查开始,然后增加了编译器、linter、类型系统,最后是 CI/CD 流水线。每一层都增加了一种新形式的背压,确保在人类审查者看到 PR 时,代码已经通过了语法检查、类型安全检查并能通过基础测试。
当生产者是一个编写代码速度比任何人类阅读速度都快的 LLM 时,人类往往成为了默认的背压。这是一种对昂贵的人类认知能力的低效利用。我们的目标是停止让人类成为主要的过滤器,而是构建一个“机器对机器”的反馈循环,让智能体在人类看到结果之前,先针对自动化检查进行迭代。
在实践中实现背压
构建一个有效的背压循环需要从简单的提示词转向结构化的、多阶段的工作流。可以将以下机制集成到智能体的循环中,以确保高质量的输出:
1. 迭代阶段:快速反馈
在核心开发循环中,智能体不应只是写完一个补丁就停止。它应该被要求在每一个迭代中运行一套质量检查:
- Linting 和测试: 标准的测试套件和 linter 应该是第一道防线。必须指示智能体在每次提交补丁后运行这些工具,并且在结果为绿色(通过)之前不继续前进。
- 基准测试(Benchmarking): 对于性能敏感型应用,集成具有结构化输出的基准测试工具可以使智能体立即检测到回归。
- 审查智能体(Review Agents): 使用独立的 LLM 实例作为“审查智能体”可以捕捉到确定性测试无法发现的主观质量问题——例如可读性、过度复杂性或松散的类型定义。
2. 后迭代阶段:真实世界验证
一旦自动化测试通过,智能体应该进入一个模拟真实世界使用的验证阶段:
- 通过工具进行手动测试: 教会智能体运行
docker-compose、使用cURL进行 API 测试,或使用 Playwright 进行基于浏览器的验证,这可以确保代码在实际环境中运行正常,而不仅仅是在模拟测试中。 - 视觉设计审查: 对于前端工作,可以要求智能体对实现结果进行截图,并使用特定的启发式算法(例如针对对齐和间距)将其与设计规范(例如 Figma 文件)进行对比。
3. 规划与监控阶段
背压应该存在于编写第一行代码之前以及 PR 提交之后:
- 规划审查: 在实现之前,智能体应生成一个轻量级的架构计划。必须由一个审查子智能体批准该计划,以防止智能体走上根本性的错误路径。
- PR 监控: 在提交 PR 后,智能体应该对该 PR 进行 24 小时的监控,自动处理 CI 失败、合并冲突或来自其他人类/AI 审查者的评论。
批判性视角与权衡
虽然“背压”方法为实现真正的委派提供了一条路径,但它也并非没有争议。社区讨论突出了几个关键挑战:
- Token 成本: 运行多个审查智能体和迭代测试循环在 API 成本方面可能非常昂贵。正如一位批评者所指出的,当自动化一切从容器启动到集成测试时,“token 消耗得非常快”。
- 确定性 vs. 非确定性: 有些人认为依赖另一个 LLM 进行审查是多余的。相反,他们建议使用 hooks(例如 pre-commit hooks 或 CI gates)来重新引入确定性。通过将检查放在测试框架(harness)中而不是提示词中,你可以确保智能体不会“忘记”运行其测试。
- 过度工程化: 存在一种风险,即构建的系统使得维护验证层的成本比实际编码的成本还要高。批评者认为,对于许多项目,来说简单的规范驱动计划和几次手动迭代比复杂的智能体流水线更有效率。
结论
无论这些护栏是通过复杂的智能体技能还是简单的 git hooks 实现的,软件工程的发展轨迹是清晰的:我们必须将正确性的负担从人类转移到系统。正如原论文作者所言:“任何依赖人类来纠正机器错误的系统,都会受到人类能力的限制,而不仅仅是机器的能力。”