向Simon Willison致敬:把代码扔给同事review之前,请先扔给你自己
风格参考:DHH —— 观点鲜明、立场强硬、宣言式、爱戳行业痛处。立场:拥护。
一、我先把这篇文章的立场摆出来
我知道你在想什么。
你点开这篇文章,预期看到一个“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放大你的责任,不解除你的责任。
五、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按一种特定的节奏工作——
- 先列场景清单;
- 选一个场景写失败测试;
- 跑测试,确认失败;
- 写最小实现让它通过;
- 确认通过;
- 重构(可选);
- 下一个场景。
这个流程的每一步都在限制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 bisect、git reflog、git 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”标准非常清楚——
- 代码能工作,而且你有信心它能工作。 不是“测试好像过了”,是“我亲眼看过它跑过,我知道它的边界”。
- 改动足够小、可review。 一个PR一个意图。
- 附带额外上下文。 上层目标、相关issue、设计取舍。
- agent写的PR描述也要审。 让别人读你自己都没读过的文字,是新一代的不专业。
我要把这套标准变成一条 manifesto——所有AI生成或AI辅助的PR,必须附带三类证据:自动化测试结果、手动测试说明、作者对关键实现的解释。
不附带,不收。
这不是建议,是规则。一个团队对自己代码质量的态度,决定了它在AI时代的下限。
十三、Anti-pattern 二:测试装饰化
Simon对“不写测试”的态度过去这一两年是越来越硬。但他同样警告——测试装饰化也是一个严重问题。
我要在这里把这条反模式打到底。
测试装饰化比不写测试还危险。
我重复一下:测试装饰化比不写测试还危险。
为什么?因为没测试至少诚实地告诉所有人“这个项目没保护”。而装饰性测试会给团队制造假的安全感——CI亮着绿灯,所有人觉得很安心,但其实任何回归都会顺利通过。
这种装饰性测试有几个识别特征——
- 测试用例多但覆盖路径浅;
- assert大量用
assert result is not None、assert 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_tenant、test_rejects_negative_amount_for_refund、test_user_cannot_delete_other_admins_account——它本身就是行为契约。
我对所有还在写“测试装饰”的团队最强烈的建议是——把全部“装饰性测试”删掉。
不是说“以后慢慢改”,是现在就删。删完之后真实的覆盖率会低很多——但那才是你真实的工程状态。基于真实状态做改进,比基于虚假状态做“维护”,要好十倍。
十四、Anti-pattern 三:把自动测试当作 manual testing 的替代品
第三个反模式我前面已经铺垫过:自动测试不能替代 manual testing。
Simon特别强调,他自己在发布前喜欢亲眼看到功能运行。这一点听起来很传统,但在agent时代更重要。原因前面讲过——agent写测试的时候非常容易“覆盖自己实现路径”,但漏掉真实用户路径。
我要在这里把manual testing的位置再拔一拔——manual testing不是“测试金字塔的最上层”,它是测试金字塔之外的另一根支柱。
测试金字塔的所有层——单元、集成、端到端——都属于自动化测试家族。它们的共同假设是“我已经知道要验证什么”。
manual testing属于另一个家族。它的假设是“我还不知道有什么问题”。
两个家族解决的是不同的问题,覆盖的是不同的风险。任何认为“金字塔越完整就不需要manual testing”的人,都在自欺欺人。
Simon的推荐其实是“多层验证”——
- 单元测试——证明局部逻辑;
- 集成测试——证明跨模块路径;
- manual testing——证明真实行为;
- 浏览器自动化(Playwright/Rodney)——证明UI;
- Showboat文档——证明过程;
- 截图/录屏——证明结果。
我要把这条说得更彻底——任何涉及用户可见行为的PR,必须附带至少一个真实交互证据。
不是测试结果,是真实交互——一段curl输出、一张截图、一段Playwright trace文件。
我建议你把这条规则刻进团队的review checklist,并且强制执行。不附真实交互证据的PR直接退回。
这不是仪式,这是工程责任。一个对自己提交的代码连“真实跑过一次”都没做的人,没有资格让别人review他的代码。
十五、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时代一个非常特别的工程能力——它能把“模糊需求”转成“可执行规格”。
我把这种能力拆成几种典型用法——
- TDD:把单个功能转成失败测试。 适合做新功能。
- Conformance-driven:把多个现实实现转成测试套件。 适合做替代实现、做兼容层、做协议适配。
- Manual-derived testing:把用户行为转成命令和截图。 适合做面向终端用户的产品。
- 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工程师的需求。它会减少对senior工程师“亲自敲键盘”的需求,但会大幅增加对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”——它们在做的是“用AI制造垃圾”。
十九、我对中文团队再说几句
Simon写文章是面向英文世界的工程文化。他默认很多东西在那边不需要解释——比如code review的严肃性、PR的标准粒度、开源maintainer的责任感。在中文团队里有几件事需要被更明确地讲——
第一,KPI和OKR体系不能只考核“产出代码量”。
很多公司今年开始用“agent生成代码量”作为效率指标。这是非常危险的。 一旦“产出代码量”变成考核维度,工程师就会有动力把agent的输出原样丢出去——因为这能涨KPI。
正确的考核维度应该是“被证明可工作并可维护的功能数量”,而不是“代码行数”。 哪个公司还在用代码行数考核工程师,请尽快取消。这种考核会在AI时代制造系统性的代码质量灾难。
第二,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在中文语境里多补的话。它们的共同主题是——把工程纪律从“个人习惯”上升到“组织能力”。 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走,一步一步来。
先跑测试。
就这五个字。
把它做实。其他的会自然长出来。