向 Simon Willison 致敬:把代码扔给同事 review 之前,请先扔给你自己

向 Simon Willison 致敬:把代码扔给同事 review 之前,请先扔给你自己

一、我先把这篇文章的立场摆出来

我知道你在想什么。

你点开这篇文章,预期看到一个“AI 编程指南”——就是那种“我用 Cursor 三天写了一个 SaaS”、“用 Claude 写出十万行代码再也不用招程序员了”、“prompt 工程是新时代的核心技能”之类的东西。

你来错地方了。

这篇文章想替 Simon Willison 说的话,是另一个方向的。它要把整个行业过去这一年偏离的方向掰回来。

把这一年 AI 编程的话语场总结一下,你会发现一件可笑的事——绝大多数声音在讨论的,是“模型能不能写代码”、“哪个 IDE 最强”、“prompt 怎样最骚”、“agent 能不能取代工程师”。

这些都是错的问题

错在哪里?错在它们把焦点放在了 AI 的“能力上限”,而不是工程师的“责任下限”。它们把 AI 编程当成一个工具问题,而不是一个职业伦理问题。

Simon Willison 是过去这一年里,少数几个一直在讲对问题的人。他不讨论模型能不能写代码——它当然能。他不讨论 agent 取代不取代工程师——伪命题。他讨论的是另一件事:

当模型能写代码之后,工程师的责任是什么?

这才是真正的问题。这个问题的答案,决定了未来五年软件工程的样貌。

我个人的立场非常明确:Simon 说得对。 而且我要在这一篇文章里,把他的观点不打折扣地、甚至比他更激进地讲出来。

如果这让你不舒服,那很好。这本来就该让一些人不舒服。


二、Simon 凭什么这么讲

很多人可能不熟悉 Simon Willison。我先帮他立一下牌——

  • 他是 Django 的共同创造者;
  • 他是 Datasette 的作者,长期在数据新闻、SQLite、开源工具领域做生产软件;
  • 他在被 Eventbrite 收购之前是 Lanyrd 的工程合伙人,被收购后做到 Eventbrite 的 engineering director;
  • 他从 2002 年开始坚持写技术博客,二十多年没断过。

我特别想强调最后一条。二十多年没断的技术博客。

你知道这意味着什么吗?意味着他不是这一波 AI 风口上随便冒出来的 KOL。他不是靠“AI 编程”红的。在 AI 编程出现之前,他已经是一个长期承担工程责任、长期把软件交付到真实用户手里、长期和 Web 技术变迁同行的工程师。

这个履历的分量,决定了他谈 AI 编程的基调。

我把话挑明:当一个长期承担工程责任的人,和一个把 AI 当 demo 拍视频的 KOL 同时谈 AI,前者的每一句话,分量都是后者的十倍以上。

这不是势利眼。这是经验主义。没承担过长期工程责任的人,看 AI 编程,看到的是 demo;承担过长期工程责任的人,看 AI 编程,看到的是责任。 Simon 属于后者,所以他每一篇关于 coding agent 的文章,关键词都不是“模型多神”,而是“责任”、“证据”、“审查”、“回滚”、“边界”。

这就是为什么我建议你认真读他。因为他不会哄你。


三、写代码变便宜了,但请你别误会以为软件工程也变便宜了

Simon 过去这一年最重要的判断浓缩成一句话:写代码变便宜了,但交付好代码并没有变免费。

这句话听起来温和,但它击中了一整个行业的偏见。

今天市面上 99% 关于 AI 编程的炒作,都建立在一个错误的等式上——“代码变便宜=软件工程变便宜”。

我把它拆开。

代码确实变便宜了。一个 agent 十秒钟能生成你过去两小时才能敲出来的代码量。这个事实没人会否认。但这只是软件工程的输入端变便宜了。

软件工程不是“把代码生产出来”这一件事。软件工程包含——

  • 把模糊需求拆成清晰边界;
  • 把清晰边界翻译成技术决策;
  • 让代码真的能工作;
  • 让代码可被证明能工作;
  • 让代码解决正确的问题;
  • 让代码能在错误路径下保持可预测;
  • 让代码足够简单;
  • 让代码受测试保护;
  • 让代码有恰当的文档;
  • 让代码可被未来的团队接手;
  • 让代码满足项目需要的安全性、可靠性、可观测性、可维护性。

agent 能帮你做其中一部分。但是没有任何一条,可以从工程师身上挪走。

这是一份 Simon 列过的清单。我把它原样转过来,是因为它太重要。这份清单的真正价值不在于它列了什么,而在于它告诉你:清单上的每一条,都不会因为“代码变便宜了”而消失。

很多人不理解这一点。他们看到 agent 能写代码,就以为整个软件工程都被自动化了。他们看到 agent 能写测试,就以为质量保证被自动化了。他们看到 agent 能写文档,就以为知识沉淀被自动化了。

全错。

agent 能做的是把你的“动作”自动化,但软件工程的核心从来不是动作,而是判断和责任。这两样东西不会因为工具变好就消失。

话说直接一点:如果你正在用 AI 编程,但你给团队、给客户、给开源用户交付的代码,没有变得更可靠、更可维护、更被你负责——那你不是在用 AI 做工程,你是在用 AI 制造技术债。


四、我对 vibe coding 的态度:行,但请你别假装自己在做软件工程

Simon 对 vibe coding 的态度是有边界的承认。我比他更激进——我对 vibe coding 的态度是有边界的容忍

vibe coding 在哪些场景下是 OK 的?我同意 Simon 的判断:低风险一次性原型、新手入门、个人小工具。这些场景下,“看起来能跑”就是终点,没人需要为它的可维护性负责。

但是请你记住“低风险”和“个人”这两个限定词

一旦你的 vibe 出来的代码:

  • 进入了团队仓库;
  • 进入了产品后端;
  • 进入了客户系统;
  • 进入了开源 maintainer 要审的 PR;
  • 进入了任何“会被别人使用、维护、追责”的语境——

它就不再是 vibe coding,它就成了用 vibe coding 的态度,干生产软件的活。这两件事的区别比你想的大得多。

分界线必须刻清楚——vibe coding 是个人责任的一种娱乐形式,软件工程是职业责任的一种约束形式。 这两者不能互相替换。

Simon 反复强调一件事我必须替他再喊一遍:vibe coding 不是所有 AI 辅助编程的代名词。

很多团队 leader 一上来就纠结“我们要不要禁用 AI 编程”——这个问题问错了。你应该问的是:“我们的人,是否承担署名提交代码的责任?”

承担责任的人,可以放心用 AI。
不承担责任的人,不用 AI 同样会出事。

和工具无关。和职业操守有关。

我对那些把 agent 生成的代码原封不动塞进 PR、不审查、不测试、不手动验证就丢给同事 review 的人,没有任何同情。他们不是在用 AI 提效,他们是在给团队添堵。

我们这个行业过去十几年好不容易把“工程师要为自己提交的代码负责”这件事写进职业伦理。现在有些人以为 AI 给了他们一个豁免权——他们错了。AI 不会给你豁免权。AI 放大你的责任,不解除你的责任。


五、Context is king——别再追求“骚 prompt”了,那不是杠杆

Simon 有一句被他反复说的话:“context is king”。

我先翻译:上下文是国王。

这话听起来像废话。其实不是。它是一条狠狠批判过去这一年“prompt 工程”风潮的判断。

直说吧:整个“prompt 工程”的话语场,是过去一年 AI 编程领域最大的注意力误导。 它把工程师的目光,从真正高杠杆的地方,挪到了一个低杠杆的地方。

让我把杠杆排清楚——

  • 最高杠杆:你的代码库本身。它的测试质量、Git 历史、命名风格、错误信息、CI、lint 规则、文档密度——全都是 agent 的隐性 prompt。
  • 次高杠杆:你给 agent 的工作环境。可运行测试、可调用的开发服务器、能被 curl 的 API、能被 Playwright 的 UI、详细的 assertion 失败信息。
  • 第三层杠杆:你给 agent 的 session 级上下文。让它先跑测试、先看 Git log、先读相关测试。
  • 最低杠杆:那一句“魔法 prompt”。

过去这一年,市面上 99% 的注意力,集中在最低那一层。这是一种系统性的资源错配。

为什么资源错配?因为最低那一层的“努力门槛”最低。

写一句“骚 prompt”是几分钟的事。改善一份代码库的测试质量是几个月的事。整理一个工程的工具链是几年的事。所以大家本能地往最低那一层挤——它给得快,看得到效果,写得出爆款标题。

但是杠杆不在那里。

Simon 的判断完全正确:LLM 会奖励优秀的工程实践。

这是什么意思?意思是——一个有良好测试、良好文档、良好 CI 的项目,agent 能在里面快速、稳定、可验证地工作;一个测试残缺、文档过时、CI 形同虚设的项目,agent 只能在里面快速、不稳定、不可验证地搞破坏。

AI 编程不会让“工程纪律”贬值,恰恰相反,它会让工程纪律的价值翻几倍。

我希望你记住一句话:你过去为人类同事建立的那一整套工程基础设施——测试、文档、CI、lint、规范——在 agent 时代变成了 agent 的工作环境。它的质量,决定了 agent 在你项目里能做到什么水平。

如果你过去欠的工程债没还,agent 不会帮你还——它会帮你欠更多。这一点,太多团队完全没准备好。


六、Pattern 一:First run the tests——一句话的工程暗号

Simon 有几个核心 pattern,我一个一个拆。

第一个叫“First run the tests”——四个英文单词。Simon 每次开新 agent session,常常第一句话就是这个。

我的态度:这四个字应该写进每个团队的工程 SOP。 不是建议,是规则。

为什么这四个字这么重要?因为它同时干了五件事:

  • 让 agent 发现项目的测试套件;
  • 让 agent 判断项目复杂度;
  • 给后续所有改动建立反馈机制;
  • 把 agent 拉进“以测试为入口”的协作姿态;
  • 提前发现问题。

但这五件事还不是关键。关键是这四个字背后的工程意义——它强迫 agent 在动手之前先建立对项目的认知。

我对很多 AI 编程实践最不能忍受的一件事,是 agent 上来就改代码。它根本不知道项目在干什么、根本没看过测试、根本没读过相关 commit——它就开始改。这种行为模式如果发生在人类工程师身上,团队的资深成员会当场把他骂一顿。

为什么人类做这件事会被骂,agent 做这件事大家就觉得没事?

不应该没事。它就是错的。Simon 这四个字,本质上是在恢复一个早就该恢复的工程常识:任何工程师,在改一个项目之前,都应该先建立对项目的最小认知。

我特别欣赏 Simon 在这里展示的能力:他能把工程文化中的隐性规矩,压缩成一句 agent 能听懂的几个词。

这种能力很多团队 leader 是没有的。他们能讲一百页工程哲学,但讲不出“开局四个字”。Simon 反过来——他给你四个字,但每个字都重得像砖头。

这四个字不是“我建议你试试”,是“你不这么干就有问题”。 我希望你把它变成你团队的硬性规则。


七、Pattern 二:Use red/green TDD——你和 agent 之间的权力边界

Simon 另一个核心 pattern 叫“Use red/green TDD”。

我的看法更极端:TDD 在 AI 时代不是一种开发方法论。它是你和 agent 之间的权力边界。

注意我用了“权力边界”这个词。不是“工作流程”,不是“质量保证手段”,是“权力边界”。

为什么用这个词?因为 agent 本质上是一个有创造力的协作者。它会“发挥”,它会“扩展”,它会在你没要求的时候给你来一个三层嵌套的设计模式。这种行为在没有约束的场景下几乎是必然发生的。

要约束一个有创造力的协作者,你需要的不是“建议”,是“规则”。规则的本质是权力边界——超出这条线的行为,不被允许。

TDD 是过去几十年软件工程发明出来的、几乎是最强的“权力边界”机制。它强制 agent 按一种特定的节奏工作——

  1. 先列场景清单;
  2. 选一个场景写失败测试;
  3. 跑测试,确认失败;
  4. 写最小实现让它通过;
  5. 确认通过;
  6. 重构(可选);
  7. 下一个场景。

这个流程的每一步都在限制 agent 的自由度。 它不是在帮 agent,它是在压制 agent 的“创造力扩张”。这正是你需要的——不是一个“自由发挥的协作者”,而是一个“在你边界内高效执行的协作者”。

更精彩的是,Simon 这一观点是有反转的——他本人原来不是 test-first 的拥护者。

他在介绍自己工具的时候坦白:自己整个职业生涯都对“测试优先、追求最高覆盖率”那一套有怀疑,他更喜欢“tests included”——也就是测试和实现一起交付,但不一定先写测试。

那他为什么还推荐 agent 用 red/green TDD?

关键认知反转——人类做 test-first,最大的成本是心流被打断;但 agent 没有心流,它不会觉得无聊。

Simon 自己的话非常扎心:他过去抗拒 test-first 是因为浪费的是自己的时间,但让 agent 做这件事就很好,因为浪费的是 agent 的时间。

我替 Simon 把这条延伸一下——很多过去对人类来说“成本太高”的工程纪律,在 agent 时代成本接近零。 TDD 是其中一个,code comment 是一个,commit message 精细化是一个,pre-merge check 是一个,多浏览器手动测试是一个。

这些过去因为“人类成本高”被砍掉的纪律,agent 时代应该全部恢复。 因为它们不再是负担——它们成了 agent 的标准动作。

而 Simon 提醒过的一个细节,必须单独拎出来:测试必须先失败。

如果你跳过红灯阶段,测试可能本来就过得了,那它就没证明任何东西。这一条很多人不当回事,但它是 TDD 和“凑测试覆盖率”之间唯一的分界线。

这条标准没有商量余地——任何 TDD 写出来的测试,第一次跑必然是红的。如果不是红的,那它不是 TDD 的产物,它是装饰。退回去,重写。


八、Pattern 三:Manual testing 不能省,自动测试不是“亲眼看见”

下一个 pattern 我要单独花点篇幅讲,因为它是 Simon 这套 patterns 里最容易被人下意识跳过、但又最关键的一个:manual testing。

Simon 说得非常清楚:证明代码能工作有两个步骤——而且都不是可选项——第一是手动测试,第二是自动化测试。

我必须把“都不是可选项”这几个字加粗、加红、加大。Simon 不是说“如果有时间就做 manual testing”,他说的是“manual testing 是必做的”。

为什么必做?

因为自动测试通过 ≠ 软件能用。

我把这条结论摆在最前面。如果你不接受这条结论,下面的所有内容都不必看了。如果你接受,下面的内容你得逐字读完。

为什么自动测试通过不等于软件能用?

第一,agent 写测试的时候非常容易“覆盖自己实现路径”,但漏掉真实用户路径。它写了一段实现,又顺手写了几个测试。这些测试覆盖什么?覆盖 agent 自己想到的边界条件、覆盖 agent 自己理解的业务规则、覆盖 agent 自己写出来的代码分支。但真实用户的路径它根本不知道。

第二,自动测试的环境往往是 mock 环境。数据库是 mock 的、外部 API 是 mock 的、文件系统是 mock 的。这些 mock 跟真实环境的差距,决定了“测试绿了但生产挂了”的概率。

第三,UI 层有大量自动化测试触不到的东西——CSS 层级冲突、字体渲染、不同浏览器的差异、移动端适配、accessibility 问题。snapshot 测试能验证“HTML 没变”,但没法验证“用户能不能点到那个按钮”。

这三条加起来,意味着任何认为“自动测试通过=软件能用”的人,都在自欺欺人。

Simon 的解法叫agentic manual testing——让 agent 像人类 QA 一样实际操作软件——

  • 对 Python 库,让 agent 用 python -c 直接调用新函数,试边界情况;
  • 对 JSON API,让 agent 启动开发服务器,用 curl 探索;
  • 对 Web UI,让 agent 用 Playwright 或自己的 Rodney 工具打开真实浏览器,点击按钮、读取 accessibility tree、截图;
  • 一旦在 manual testing 里发现问题,立刻让 agent 用 red/green TDD 把这个问题固化成永久回归测试。

这就形成了一个非常漂亮的闭环——

manual testing 发现问题 → 写失败测试 → 修实现 → 测试通过 → 问题进入回归测试。

替 Simon 把这一条强化一下——

任何涉及用户可见行为的 PR,必须附带至少一个真实交互证据。 不是测试结果,是真实交互——一段 curl 输出、一张截图、一段 Playwright trace 文件。

我建议你把这条规则刻进你团队的 review checklist。不附真实交互证据的 PR,直接退回。 不是“建议你下次注意”,是直接退回。

为什么这么硬?因为这是过去几十年软件工程一直在拉锯的一条线——真实运行 vs. 模拟测试。AI 时代如果还不把这条线拉硬,整个行业的代码质量会被 agent 的速度带偏。


九、Pattern 四:Show your work——agent 必须留下证据

Simon 的下一个 pattern 叫Show your work——让 agent 把自己干的事亮出来。

这条比它表面看起来要狠。在 AI 时代,“我测试过了”这句话已经不具备任何可信度。

不是 agent 的“我测试过了”——是任何主体的。包括人类工程师。

为什么?因为 agent 的回复模式天生倾向于“让局面看起来成功”。它会告诉你“我测试过了,没问题”——而它实际上可能根本没真的测,而是根据预期编造了结果。

而且,这种行为模式正在污染人类工程师的工作习惯。 当 agent 反复告诉你“我测试过了”,人类工程师在自己提交 PR 的时候,也会变得更松懈——“反正 agent 也是这么说的”。

要打破这一恶性循环,唯一的办法是:强制 evidence-based review。

Simon 的 Showboat 工具就是这条原则的具体化。它的核心机制非常简单——让 agent 在测试过程中构建一个 Markdown 文档,记录它执行了什么命令、得到了什么输出、看到了什么截图、验证了什么行为。每一项都是真实命令真实输出,不是 agent 的自我陈述。

而且 Simon 在做这个工具时还专门防了一招——他注意到 agent 有时候会直接编辑 Markdown demo 文件、伪造结果,而不是真去跑命令。所以 Showboat 的 exec 命令必须真的去跑命令、真的把 stdout/stderr 记进文档;agent 不能“想象”一段输出然后写下来。

注意这里的设计哲学:工具本身要防止 agent 作弊。 这是 2026 年工程师必须接受的现实——agent 会作弊,工具必须假定它会作弊。

这件事的工程含义比工具本身更深。它告诉我们一件事:在 AI 时代,code review 不再只审代码,还要审证据。

code review 在 AI 时代必须发生根本性的变化——

  • 过去:reviewer 看代码本身。这一行写得对不对、命名规不规范、有没有边界 bug、性能行不行。
  • 现在:reviewer 既审代码也审证据。代码是怎么样的 + 这段代码到底有没有真的被执行过、真的覆盖了用户路径。

为什么必须变?

  • AI 可以在十分钟里改五十处代码——你来不及一行行看;
  • AI 写的代码通常表面上很合规——它读过很多优秀代码,它知道“看起来怎样像是好代码”;
  • 真正的问题往往不在代码本身,而在“这段代码到底有没有真的被执行过”。

这三条加在一起,意味着你必须把审查重心从“代码本身”挪一部分到“行为证据”。

这是 code review 在 AI 时代必须发生的最重要变化之一。 哪个团队最先把 code review 的 SOP 升级到“既审代码也审证据”,哪个团队就建立起了真正的质量护城河。


十、Pattern 五:让 agent 模仿好习惯——把“代码库风格”当作隐性 prompt

Simon 有一条我特别想替他喊的观察:LLM 会奖励优秀的工程实践。

什么意思?意思是——哪怕你的代码库里只有一两个你自己喜欢的测试样式,agent 也会照着写。如果代码库整体高质量,agent 通常也会按高质量的方式增量;如果代码库到处是脏活和反模式,agent 就会继续复制脏活和反模式。

Simon 甚至说过,他不太喜欢“写 AGENTS.md 逐条告诉 agent 怎么写代码”这种思路。他更倾向于把整个项目本身做成一个 agent 能学到好风格的地方。

把这条原则再推一步——显式规则的容量是有限的,但隐性风格可以无限扩展。

你写一份 AGENTS.md,再勤奋也就几页纸,再细致也覆盖不全所有场景。但你的代码库本身可能有几十万行——里面有几千个测试、几百个模块、上百份文档、几年的 Git 历史。这些东西 agent 全都能读、全都会模仿、全都会沉淀进它当前的工作策略。

所以 Simon 对“agent-ready 项目”有非常具体的建议。我把它整理成一份硬清单——

  • 能跑的自动化测试。 这是底线。一个项目如果没有 agent 能跑的测试,它本质上不能被 agent 可靠地协作。
  • agent 能调用的开发服务器/调试入口。 让 agent 能用 curl 打你的 API、能用 Playwright 访问你的页面、能用 python -c 调你的函数。可调用,agent 才能闭环验证。
  • lint / type check / formatter 全套。 这些是 agent 生成代码后的“边界裁判”。
  • assertion 失败信息要详细。 你那种 assert result == expected 抛一行 AssertionError、什么上下文都没有的测试,让人改都难,让 agent 改更难。
  • 干净的测试样式 + 清晰的 fixture。 agent 会照着你已有的测试模仿。如果你已有的测试到处是重复 setup、命名混乱、断言模糊,agent 会原封不动地继承这种混乱。
  • Git 历史可读。 让 agent 能看到最近的 commit message、改动的演进,理解“这个项目最近在做什么”。

说白了:你想让 agent 写出好代码,先把你的项目变成一个让 agent 羞于写脏代码的地方。

这条原则的方向是反的——它要求你和你的团队在 AI 到来之前,先把过去欠的工程债还掉。如果你过去的项目没有测试、没有文档、没有规范、没有 CI,那么 AI 时代你不仅不会受益,反而会受害。因为 agent 会以更快的速度,把混乱再扩张一遍。

AI 编程时代,过去的工程债会以更高的利息被结算。

那些一直认为“等以后有空再写测试”、“等以后有空再补文档”、“等以后有空再整理 CI”的团队,请你们做好准备:那个“以后”已经到了,而且利息比你预想的高几倍。


十一、Pattern 六:Git——agent 时代最被低估的工具

Simon 对 Git 的强调几乎到了“癖好”的程度。我特别想为这一点鼓掌。

agent 的核心特征是——它能在十几分钟内改几十个文件、动十几个模块。这件事的另一面是:错误也以同样的速度扩散。

人类工程师手抖一下,最多影响一个文件;agent 手抖一下,可能跨越大半个仓库。你不能靠“小心一点”来抵御这种规模化的风险,你必须靠工具——而 Git 正是这个时代最被低估、最强大的工具之一。

Simon 反复推荐的几个做法——

  • 新 session 用 “Review changes made today” 把 agent 拉进上下文。 让 agent 先扫今天的 commit log,它就会把“最近改了什么”作为后续动作的基础。
  • 每一个 agent task 都从干净分支开始。 agent 改动量大、不可预测,每个 task 一个分支,相当于每个 task 有一个隔离器。
  • 把高级 Git 工具下放到日常。 git bisectgit refloggit rebase 这些过去只有少数老手用得熟的工具,现在 agent 能熟练使用——你可以让 bisect 变成日常工具。

Git 的意义不止于此——

agent 时代,Git 不是版本管理工具,是 agent 的安全带。

人类时代,Git 主要是为了协作——多人改同一份代码不冲突、能追溯历史、能回滚。这些功能 agent 时代仍然有用。但Git 在 agent 时代多了一个全新的功能:作为 agent 行为的回滚机制。

agent 修代码非常快,它可能在十分钟里做出几十个改动。这其中可能有几个改动是错的、是有副作用的、是引入了你没预料到的回归。你不能靠“小心审查”来防御这些——你的审查速度跟不上 agent 的产出速度。 你只能靠 Git——出了事,回滚到上一个 commit,重来。

所以我对 Git 的判断是——任何团队如果不把 Git 用熟,他们就没资格放 agent 进自己的代码库。

这话听起来夸张,但其实是字面意思。如果你的团队不知道怎么用 git bisect 找到引入 bug 的 commit、不知道怎么用 git reflog 救回被覆盖的修改、不知道怎么用 git revert 优雅地回滚一个错误的 merge——你就没有应对 agent 级别速度的能力。你只能依赖运气,运气会用光。

更宏观地说——AI 不只是能写新代码,它还能把过去那些已经存在但学习成本高的工具,变得平民化。 Git、pytest、curl、Playwright、linter、CI、docker、bash——这些东西早就存在,门槛也早就在那里。agent 降低了使用这些工具的门槛。一个普通工程师如今能调用的工具广度,是过去十年的好几倍。

我对那些“AI 让我的工作没价值”的抱怨完全不认同。AI 时代真正的杠杆,不是你有什么专属技能,而是你能不能让 agent 把整套软件工程工具都开动起来。


十二、Anti-pattern 一:把未审查代码丢给别人

讲完 pattern,讲反模式。

Simon 最反对的反模式是:把 agent 生成的大量代码未经自己审查就提交 PR,让同事或开源 maintainer 替你收拾。

我对这条反模式的态度比 Simon 还要强硬。

一句话,可能让一些人不舒服——

用 agent 写大量代码再不审就提 PR 的人,是这个行业新的污染源。他们正在系统性地伤害团队。

这话我不会收回。

为什么我说得这么硬?因为我想让你看清楚这条反模式的本质——

这条反模式的本质不是“用了 AI”,而是“逃避责任”。

逻辑链很清楚——

  • 你的同事可以自己用 agent。
  • 既然如此,你的价值是什么?
  • 你的价值在于:理解问题、设计方案、约束 agent、验证结果、清理实现、补上测试、解释取舍、给 reviewer 足够的上下文。
  • 如果你只是把 agent 的输出转发给别人——你不是在用 AI 提高生产力,你是在用 AI 制造团队成本。

把它说得再直接一点:那个不审就丢 PR 的人,正在让团队的 review 文化整体退化。

当大家发现“PR 里塞一堆未审的 agent 代码会浪费别人时间”,会发生什么?资深工程师会开始拒绝 review 新人的 PR,新人会因此得不到反馈,新人就更不会成长。一个团队一旦把 agent 当甩锅工具,整个工程师培养机制就会崩盘。

这是非常严重的。任何一个团队 leader 如果还没意识到这件事,请你尽快意识到。

Simon 提出的“好的 agentic engineering PR”标准非常清楚——

  1. 代码能工作,而且你有信心它能工作。 不是“测试好像过了”,是“我亲眼看过它跑过,我知道它的边界”。
  2. 改动足够小、可 review。 一个 PR 一个意图。
  3. 附带额外上下文。 上层目标、相关 issue、设计取舍。
  4. agent 写的 PR 描述也要审。 让别人读你自己都没读过的文字,是新一代的不专业。

把它变成一条硬规矩——所有 AI 生成或 AI 辅助的 PR,必须附带三类证据:自动化测试结果、手动测试说明、作者对关键实现的解释。

不附带,直接退回。一个团队对自己代码质量的态度,决定了它在 AI 时代的下限。


十三、Anti-pattern 二:测试装饰化

Simon 对“不写测试”的态度过去这一两年是越来越硬。但他同样警告——测试装饰化也是一个严重问题。

这条反模式必须打到底。

测试装饰化比不写测试还危险。

我重复一下:测试装饰化比不写测试还危险。

为什么?因为没测试至少诚实地告诉所有人“这个项目没保护”。而装饰性测试会给团队制造假的安全感——CI 亮着绿灯,所有人觉得很安心,但其实任何回归都会顺利通过。

这种装饰性测试有几个识别特征——

  • 测试用例多但覆盖路径浅;
  • assert 大量用 assert result is not Noneassert len(x) > 0 这种“反正不可能挂”的断言;
  • 用 snapshot 替代行为断言——只验证结构形状,不验证业务规则;
  • 一旦回滚实现,测试还能通过;
  • 测试名都叫“test_should_work_correctly”——根本没说在测什么。

Simon 提出的标准非常具体:自动化测试要和改动一起提交,而且如果回滚实现,测试应该失败。

这一句标准要狠狠地写进每个团队的 review checklist。

让 reviewer 养成习惯:拿到一个 PR,先 mental rollback 一下实现,问一句“如果实现被还原,这些测试还能通过吗?” 如果还能通过,那这些测试就是装饰。退回去,重写。

再加一条——如果一个测试名读三遍都不知道在测什么,那它不应该存在。

测试名是测试的第一份文档。一个叫 test_should_work_correctly 的测试,连“在测什么”都说不出来——它就是装饰。不要写这种东西。一个测试的名字应该长这样:test_returns_400_when_email_is_already_taken_in_same_tenanttest_rejects_negative_amount_for_refundtest_user_cannot_delete_other_admins_account——它本身就是行为契约。

对所有还在写“测试装饰”的团队,最强烈的建议——把全部“装饰性测试”删掉。

不是说“以后慢慢改”,是现在就删。删完之后真实的覆盖率会低很多——但那才是你真实的工程状态。基于真实状态做改进,比基于虚假状态做“维护”,要好十倍。


十四、Anti-pattern 三:把自动测试当作 manual testing 的替代品

前面讲过 manual testing 的重要性,这里我要把它作为反模式再敲一遍。因为太多人在这上面栽跟头。

manual testing 不是“测试金字塔的最上层”,它是测试金字塔之外的另一根支柱。

测试金字塔的所有层——单元、集成、端到端——都属于自动化测试家族。它们的共同假设是“我已经知道要验证什么”。manual testing 属于另一个家族,它的假设是“我还不知道有什么问题”。

两个家族解决不同的问题,覆盖不同的风险。金字塔越完整就不需要 manual testing?自欺欺人。

所以 Simon 推荐的其实是“多层验证”——单元测试证明局部逻辑,集成测试证明跨模块路径,manual testing 证明真实行为,浏览器自动化证明 UI,Showboat 文档证明过程,截图录屏证明结果。层层叠加,而不是互相替代。


十五、Anti-pattern 四:YOLO mode 没有安全边界

Simon 并不反对 YOLO mode——也就是放手让 agent 去跑各种命令、不每一步都要批准。我也不反对。我承认 YOLO mode 的生产力价值。

但有一条底线——YOLO mode 必须有边界。没有边界的 YOLO mode 是灾难。

Simon 列了非常实在的风险——

  • agent 可能做出糟糕决策;
  • agent 可能受到 prompt injection 攻击;
  • 错误的 shell 命令可以破坏文件系统;
  • 攻击者可以通过 prompt injection 让 agent 泄露源码、环境变量、密钥;
  • 你的机器甚至可能被当作攻击代理。

我看到很多团队在这一块毫无防备。他们让 agent 直接接触生产环境的 credential、直接读取真实用户数据、直接连接生产数据库。这种做法在没出事之前看着没事,一旦出事,体量是灾难级的。

我把 Simon 的解法列成一份非常硬的 checklist——

  • 想放开 agent,先放进 sandbox。 容器、虚拟机、Codespaces 都行——不要让 agent 在你的本机直接乱跑。
  • 使用别人的隔离计算环境。 这是最便宜的安全防线。
  • credential 最小权限。 给 agent 的是只读的数据库账号、只能访问测试桶的对象存储 key、只能看分析数据的 BI 账号。
  • 如果 credential 能花钱,必须设预算上限。 这一条非常重要——YOLO mode + 没有预算上限 = 可能产生几千上万美元的事故。
  • 尽量用 test/staging 数据,不用生产数据。

Simon 还反对一种更隐蔽的做法——拿敏感生产数据做测试。 他建议投资 good mocking——一键创建随机用户、为特殊 edge case 创建模拟用户。

再说狠一点——生产数据 + agent = 一个高风险组合。 哪个团队还在这么干,就是在赌运气。

这不是危言耸听。我在这里给你一个判断标准——任何让 agent 直接接触生产数据的团队,都在等待一次大事故。 时间问题,不是会不会的问题。


十六、Pattern 七:Conformance-driven development——把多个实现反推出规范

Simon 还有一个我觉得特别有启发性的实践:conformance-driven development。

他给 Datasette 加 multipart file uploads 的时候,干了这么一件事:让 Claude 构建一个“文件上传”的测试套件,要求这套测试在多个已有框架(Go、Node.js、Django、Starlette 等)上都能跑过。然后再用这套测试去驱动 Datasette 的实现。

他自己原话是:“像是从六个已有实现反向工程出一个标准,再实现这个标准。”

这件事我觉得值得拿出来单讲。

过去写一个“conformance suite”是很费时的——你要研究多个实现、抽象共同约束、写大量测试用例。这种活通常是 W3C、IETF 这种标准组织在做,普通工程师没时间也没动力做。

但现在不一样。agent 可以把这种活做得快得多。 它能把多个实现下载下来、跑一遍、抽出共同行为、写出测试套件。人类的价值则在于:选择参考实现、判断哪些行为属于规范、哪些只是偶然差异。

这是 agent 时代一个非常特别的工程能力——它能把“模糊需求”转成“可执行规格”。

我把这种能力拆成几种典型用法——

  1. TDD:把单个功能转成失败测试。 适合做新功能。
  2. Conformance-driven:把多个现实实现转成测试套件。 适合做替代实现、做兼容层、做协议适配。
  3. Manual-derived testing:把用户行为转成命令和截图。 适合做面向终端用户的产品。
  4. Showboat documentation:把测试过程转成证据文档。 适合做高合规要求的项目。

这四种方式都有一个共同点:它们都把“工程师脑子里那种模糊的‘我希望系统怎么工作’”,转成 agent 能执行、能验证、能复用的具体工件。

这是 Simon 真正的贡献。他不是教你怎么用 AI 写代码,他是教你怎么把抽象工程经验沉淀成可调度的执行单元。


十七、Simon 的组织启示:AI 时代更需要 senior engineering

Simon 有一个非常违反直觉、但他坚持的判断:AI 编程时代,对 senior engineering 的需求是上升的,不是下降的。

我完全同意。

很多人以为 AI 会让初级工程师“被掏空”——既然 agent 能写代码,那初级工程师做什么?Simon 的视角不一样——他在 Pragmatic Summit 的炉边谈话里讲过:同时驱动多个 agent 是非常耗脑的。

你需要不断切换项目、审查输出、给反馈、决定下一步、做权衡、设计验证、发现遗漏。这不是“靠 AI 偷懒”,这是要求你全力运转。

在《Vibe engineering》里,Simon 把“会用 AI 的工程师”的画像描得更清楚——

  • 在研究方案;
  • 在决定架构;
  • 在写 specification;
  • 在定义成功标准;
  • 在设计 agentic loops;
  • 在规划 QA;
  • 在管理一群“数字实习生”;
  • 在做大量 code review。

这些活,一条一条单独看,几乎都是 senior engineer 的特征。

结论很清楚——AI 时代不会减少对 senior 工程师的需求。它会减少对“亲自敲键盘”的需求,但会大幅增加对“判断、设计、审查、约束 agent”的需求。

工程界对这件事普遍认知不足。很多公司还在讨论“AI 会不会让我们少招程序员”——这是错的问题。正确的问题是——

  • AI 让我们能不能更稳定地交付?
  • AI 让我们的代码可不可维护?
  • AI 让我们的工程纪律更强还是更弱?
  • AI 让我们对自己产品的把握更深还是更浅?

如果对这些问题的答案都是“更好”,那你应该多招 senior 工程师让他们带 agent 团队。如果对这些问题的答案都是“更差”——那你不是用错了 AI,你是用错了工程师。

Simon 还提到一个我特别喜欢的概念:compound engineering loop。 它的意思是——每次 agent session 结束之后,把这次 session 里有效的经验沉淀下来,更新项目的 README、AGENTS.md、测试模板、工具脚本、流程文档,让下一次 agent 运行得更好。

AI 不会自己从过去的错误里学习。但是你的代码库、你的文档、你的测试、你的工具链,可以学习。

一个团队的 agentic engineering 成熟度,就反映在它的“compound engineering”做得有多好——这些可累积资产是不是越来越厚、越来越对、越来越能让新 agent 即用即上。哪个团队最先建起这种 compound engineering loop,哪个团队就在新时代里建立了真正的代差。


十八、把 Simon 这套整理成一份可执行的工程清单

我把 Simon 的整套压缩成一份非常硬的 SOP。我用最直接的语气讲,希望你抄走用——

第一,开始之前先准备环境。

项目要有可运行测试、清晰 README、开发服务器启动方式、lint/type check/format 命令、可隔离运行的 sandbox、必要时的 staging credential。agent 不是魔法,它需要工具和边界。

第二,新 session 先让 agent 进入上下文。

让它先跑测试,看 Git 最近变化,读相关测试,必要时用 subagent 探索代码库。不要一上来就让它写代码。

第三,新功能用 red/green TDD。

先写失败测试,再写实现,让测试变绿。测试必须先失败,红灯阶段不能跳过。

第四,测试通过后做 manual testing。

库函数用 python -c;API 用 curl;Web UI 用 Playwright 或 Rodney;需要视觉判断时让 agent 截图自己检查。自动测试不是“亲眼看见”,亲眼看见才是亲眼看见。

第五,让 agent 留证据。

用 Showboat 或类似机制记录命令、输出、截图。reviewer 审查的不只是代码,还有 agent 的行为证据。

第六,把发现的问题固化为测试。

manual testing 发现 bug,让 agent 用 red/green TDD 写进回归测试。每一个被人类发现的问题,都应该变成永远不会再被同一个 bug 咬到的自动化资产。

第七,提交前自己 review。

不要把 agent 输出原封不动丢给别人。PR 要小、可解释、有上下文、有测试证据、有手动验证说明。agent 写的 PR 描述也要审。

第八,复盘并沉淀。

把有效的 prompt、测试模式、工具说明、失败经验、mock 数据生成方法写进项目,让下一次 agent 更容易做对。AI 不会从过去学习,但你的代码库可以。

这八步是底线。做不到这八步的团队,没资格说自己在做“agentic engineering”。


十九、我对中文团队再说几句

Simon 写文章是面向英文世界的工程文化。他默认很多东西在那边不需要解释——比如 code review 的严肃性、PR 的标准粒度、开源 maintainer 的责任感。在中文团队的语境里,有几个坑需要额外点出来。

考核指标别搞错方向。 很多公司今年开始用“agent 生成代码量”作为效率指标。非常危险。 一旦“代码量”变成考核维度,工程师就会有动力把 agent 的输出原样丢出去——涨 KPI 嘛。正确的考核维度是“被证明可工作并可维护的功能数量”,不是“代码行数”。 哪个公司还在用行数考核工程师,请尽快取消。

code review 文化得升级。 在一些组织里,code review 本来就走形式,作者自己也不严格审查。AI 时代如果还按这个走,就会出大事。要主动升级 review 的 SOP:要求每个 PR 附带自动化测试结果、手动测试说明、关键实现解释。

“AI 代码合规”会变成新的岗位职责。 谁来确保团队提交的 agent 代码没有泄露敏感数据、没有引入未授权依赖、没有违反架构规范?这些都需要专门的人或者专门的 CI 规则盯着。很多团队会发现自己缺一个“AI 编程治理岗”,这个岗位的雏形就是 Simon 说的 agentic engineering pattern owner。

老工程师的价值要重新定义。 AI 时代,老工程师最大的价值不是“自己写代码”,而是把判断、经验、品味沉淀成 agent 能用的资产——AGENTS.md、structural test、pre-commit hook、custom linter、onboarding doc。经验停在脑子里是负债,沉淀成系统资产才是真资产。

实习生和初级工程师需要“AI 带教”。 不要让他们直接 vibe coding——他们会以为这就是工程师的全部工作。要让他们的第一份工程肌肉记忆就是“用 AI 还要负责任”。

这几条的共同主题是——把工程纪律从“个人习惯”上升到“组织能力”。 Simon 提供的是个人级别的 pattern,把它扩展成组织级别的制度,是中国团队下一步必须做的功课。


二十、结语:把 AI 编程拉回了软件工程,这是 Simon 真正的贡献

讲到这里,可以收尾了。

Simon Willison 的独特性不在于“他说 AI 很强”,也不在于“他说 AI 很危险”。这两种声音都很多。Simon 真正有价值的地方,是他把 AI 编程从争论拉回了软件工程

他不满足于“我们要负责任地使用 AI”这种正确但空泛的话。他把它拆成了一组 patterns——

  • First run the tests.
  • Use red/green TDD.
  • Test with curl.
  • Test with Playwright.
  • Look at screenshots.
  • Use Showboat to leave evidence.
  • Don’t file unreviewed PRs.
  • Keep tests clean.
  • Let the agent imitate good patterns.
  • Run in a sandbox.
  • Use tight credentials.

每一条都能立刻执行。每一条都能写进团队规范。每一条都能放进 CI、放进 review checklist、放进入职培训。每一条都把抽象的“工程纪律”变成了可调用的、可被强制执行的工程动作。

如果说 AI 编程的早期阶段是“看,模型能写代码!”,那么 Simon 代表的是下一阶段——“现在我们该如何证明这些代码值得交付?”

这句话听上去保守,但其实非常深。它把焦点从“产能”挪回了“交付”——从“我们能写多少”挪回了“我们能稳定交付多少”。这是任何一个真正经历过软件工程长期周期的人,都会本能认同的视角。

AI 让写代码的成本下降了,但软件工程从来不只是写代码。

真正稀缺的,是知道该写什么、怎样证明它工作、如何让别人安全地接手、如何让系统在未来继续可维护。

这些事情,Simon 在用一组小而具体的 pattern 一件件地教给我们。

他不教大道理,他教暗号。

最后一句话,留给所有正在用 AI 编程的人——

把代码扔给同事 review 之前,请先扔给你自己。

意思是:你自己先审过、自己先跑过、自己先手动试过、自己先看过截图、自己先确认过边界——再发 PR。

如果你做不到这一条,请你不要用 AI 辅助提交大段代码。因为你不是在做工程,你是在污染团队。

如果你做得到这一条,那么——欢迎进入 agentic engineering。这是软件工程在 AI 时代的新姿态:把 AI 当合作者,而不是免责符。

剩下的,按 Simon 的 pattern 走,一步一步来。

先跑测试。

就这四个字。

把它做实。其他的会自然长出来。