Agent 写得越快,程序员越要慢下来

Agent 已经彻底改变了我写代码的方式

刚开始时,我在心理上很抗拒使用 Agent,总觉得把代码交给它生成,多少有些“不像在编程”。真正用过一段时间后,我却发现自己很难再回到从前几乎完全手写的状态

这种转变并不浪漫。Agent 最先让人上瘾的,不是它真的理解了软件,而是它实在写得太快

从抗拒到依赖

过去需要反复查文档、搭骨架、补样板代码的任务,现在只要描述清楚目标,Agent 很快就能给出一个可以运行的版本。程序员的工作重心,也从逐行输入代码转向描述问题、检查结果和修正方向

这种效率提升是真实的。但它也很容易制造一种错觉:代码产出得越快,自己的工程能力就越强

我曾经觉得,一个人借助 Agent,在短时间内完成过去需要多人协作几个月的项目,是一件近乎不可思议的事。后来我逐渐意识到,完成一个项目与理解一个项目,从来不是同一件事

Agent 擅长的是战术式编程

John Ousterhout 在 《A Philosophy of Software Design》中区分了战术式编程与战略式编程

战术式编程关注的是尽快完成眼前任务,让功能运行、让测试通过;战略式编程则愿意为长期结构投入时间,避免今天的捷径变成明天的复杂性

从这个角度看,Agent 天生擅长战术式编程。它接收一个局部目标,快速搜索可行路径,然后产出能够满足当前约束的代码。只要反馈足够明确,它甚至可以连续修补,直到所有检查变绿

问题也正在这里:测试通过,只能说明代码满足了当前写下来的约束,不能证明这些约束完整,更不能证明系统拥有一个可长期维护的设计

Agent 可以飞快地抵达目的地,但目的地是否正确,仍然由人决定

BDD 与 TDD 是两道护栏

给 Agent 描述一个功能,尤其是描述界面应该呈现什么、用户执行某个操作后应该发生什么,本质上很像在提供 BDD 式的行为约束

随后,Agent 编写测试、运行测试并根据失败结果修正实现,这又很像一套被自动加速的 TDD 反馈循环

因此,我目前更愿意把 BDD 与 TDD 看作 Agent 编码的两道护栏:前者约束“应该做什么”,后者检查“是否做到了”。没有这两层约束,Agent 很容易把模糊需求实现成一个看似合理、实际偏离目标的版本

但护栏并不负责选择道路。需求描述得是否准确、测试覆盖了哪些风险、什么行为才算正确,这些判断不会因为 Agent 能生成测试而自动出现

生成测试不等于拥有测试的品味

我越来越相信,Agent 时代会让测试变得更重要,也会让“测试的品味”变得更稀缺

Agent 很依赖可验证的反馈。测试设计得越清楚,它生成的代码越容易被约束在合理范围内。可测试本身不能全部交给 Agent,因为它对项目的理解往往集中在当前上下文,而项目的约束却分散在漫长的历史里

我在实际项目中多次遇到类似情况:前期测试全部通过,后续功能加入后,新测试却与旧测试发生冲突。Agent 为了继续推进,往往会主动放宽旧断言,让眼前的失败消失

这种修改有时是合理的,因为需求确实发生了变化;有时却是在悄悄删除一条仍然重要的约束。两者之间没有机械化的判断标准,只能依赖开发者对业务、历史和风险的理解

所以,真正重要的能力不是“会不会让 Agent 写测试”,而是能不能判断一条测试为何存在、保护了什么,以及什么时候才有资格修改它

可以外包思考,不能外包理解

我很认同一句话:你可以外包思考,却无法外包理解

Agent 可以替我们搜索方案、补全实现、解释报错,甚至比较不同设计。但如果程序员没有建立自己的心智模型,就很难判断它省略了什么、误解了什么,又在哪一处埋下了只有项目扩大后才会暴露的问题

这对新手尤其危险。成熟程序员展示的 Agent 工作流看起来非常高效,但那套效率往往建立在多年手写代码、调试系统和承担失败后果所形成的判断力之上

新手可以学习这些工作流,却不应该盲目复制。前期的手写编码、独立调试和阅读源码仍然不能跳过,因为这些笨拙的过程正是在训练理解力

如果没有这层基础,Agent 带来的不是能力放大,而是把自己不理解的部分藏得更深

Agentification:去手工化之后

Agent 越能承担实现工作,程序员就越需要参与架构。模块如何划分、接口暴露什么、状态由谁拥有、哪些约束必须长期保持,这些问题不会因为代码生成速度提高而消失

相反,生成速度越快,错误边界扩散得也越快。一个含糊的接口可以在几分钟内被十几个模块依赖,一项临时决策也可能迅速变成事实标准

我把这种逐渐失去手工维护能力的过程称为“Agentification”:项目越来越适合继续由 Agent 修改,却越来越难由人直接理解和接管

去手工化本身未必是坏事。问题在于,一旦程序员只能通过 Agent 维护系统,就很难判断它是在修复复杂性,还是仅仅用更多生成代码把复杂性盖住

避免这种局面的办法,不是拒绝 Agent,而是更认真地设计边界。接口必须足够清楚,模块必须能够独立解释,关键决策必须留下理由。只有这样,人才能始终拥有系统的最终解释权

给 Agent 热潮降温

最近很火的 Loop 工程,在我看来有相当明显的炒作成分。循环执行“生成—运行—观察—修正”当然有用,但循环本身并不神秘;真正决定效果的,依然是上下文质量、反馈信号和停止条件

Harness 也是类似的情况。它可以把模型、工具、权限、上下文和验证流程组织起来,工程价值并不低。但如果只是给已有的工作流换一个更响亮的名字,就不值得被描述成新的编程范式

相比之下,我认为 MCP 的贡献更实在。它试图用统一协议连接模型与外部工具、数据和资源,减少每种能力都要单独适配的成本。这是在扩展 Agent 能接触的边界,而不只是在包装一次调用过程

当然,MCP 也不会自动带来高质量的软件。工具连接得更多,只意味着 Agent 能做更多事;至于该不该做、如何验证、出了问题由谁负责,仍然是工程问题

写在最后

我不会回到拒绝 Agent 的阶段。它带来的效率提升太真实,也确实让我能够尝试过去不敢独立承担的项目

但我也不再把快速生成代码等同于真正掌握了项目。Agent 放大了程序员的能力,也会放大需求中的含糊、测试中的漏洞和架构上的短视

未来程序员最重要的工作,可能不再是亲手写下每一行代码,而是知道哪些约束不能放松、哪些边界必须守住,以及哪些结果自己其实还没有理解

Agent 写得越快,程序员反而越要慢下来思考