你的编码 agent 不知道自己弄坏了什么
先说结论: 编码 agent 是个局部优化器。它做出你要求的那处改动,对曾经好用的那上百件事没有任何常驻记忆。这不是 prompt 的问题,也不是模型大小的问题——它是结构性的。唯一可靠的修法,是把你应用的不变量放到 agent 之外,用一套不依赖它就能跑的检查来守。
让 Claude Code 或 Cursor「给结账加个折扣框」,它会照做:读相关文件、改、框就出现了。它不会做的——从构造上就做不到的——是问一句「我是不是刚把三个会话前写的那个访客结账跳转弄坏了?」那个行为不在它的上下文里、不在它的目标里、也不在它看得见的任何地方。agent 不是马虎,它只是瞄准了一个靶子,而昨天那个好用的功能不是那个靶子。
agent 为什么会在结构上制造回归
三件事让 agent 对自己造成的回归视而不见,而且没有一件会随着模型变聪明而好转:
- 局部优化。 目标是「满足这句 prompt」,不是「在不扰动此前每一个不变量的前提下满足这句 prompt」。这是两个不同的函数,而第二个既不是你要求的、也不是它被评分的。
- 对不变量没有长期记忆。 这次会话之前什么是好的,都活在上下文窗口之外。它可以重读代码,但代码告诉它的是应用现在做什么——包括它刚引入的 bug——而不是应用本应做什么。
- 自己给自己判卷。 让同一个 agent 去测这个功能,它写出来的测试,是对着它刚写的代码通过的。测试把当前行为连 bug 一起编码了进去。改动作者给出的那个绿勾,不算证据。
合起来看:做出改动的那个东西,恰恰是你整条链路里最没资格证明「别的没坏」的那个。
更大的模型补不上缺失的契约
一个诱人的反驳是「等模型更强就好了」。不会好,因为缺口不在能力,而在信息。哪怕是完美的推理者,也保护不了一个从没被告知、也看不见的不变量。你可以把更多代码库塞进上下文,但代码库是对现状的描述,不是对什么必须保持为真的规格。那条需求——访客开始结账后购物车还在——在你把它写到机器能检查的地方之前,只存在于你脑子里。
这才是真正的修法,而且很朴素:把不变量外置。 把那些必须存活下来的行为,写成活在你仓库里、不依赖 agent 就能跑的检查——这样「还能用」就由一个既没有看到绿的动机、也不会忘掉上周的东西来裁定。
「外部」到底得是什么意思
不是随便什么检查都算外部。有两条性质要紧:
- 它不跑模型。 如果你的回归闸在运行时调 LLM,那你又把想逃开的那套非确定性、那股「让它过」的压力请了回来。闸应该是朴素、确定性的代码——绿,每次都代表同一件事,而且跑起来不花钱。
- 它归你,而且比会话活得久。 契约不能是一段明天就没了的聊天记录。它得是一份耐久的产物——对我们来说,就是你 git 仓库里一个纯粹的
@playwright/test——下一个 agent、再下一个 agent,都得过它。
这正是先定义行为、再让 AI 把代码拟合上去背后的整个想法:spec 是定点,代码是变量。agent 想重写多少遍实现都行、想多快都行——这本来就是 vibe coding 的魅力所在——恰恰是因为有个它管不着的东西,替你守着「什么必须保持为真」这条线。
说点不那么好听的
Vibe coding 没有消灭对测试的需求。它让测试更吃重了,因为它拿掉了那个原本记得「这段代码是为了什么」的人。当一个人写下结账流程时,是这个人把它的不变量记在脑子里,改动一旦威胁到它就会本能地一激灵。把写代码交给 agent,那份记忆也就随之而去——除非你把它写了下来。
所以,对任何要发布 AI 所写代码的人来说,问题不是「我的 agent 够不够好、会不会弄坏东西」。而是:除了 agent 本身,还有什么,被允许告诉你它坏了? 如果答案是「没有」,那你不是在快,你只是在慢慢地才发现。
常见问题
这不就是「写测试」吗? 是——但带上多数 AI 测试方案会丢掉的两条约束:测试必须不跑模型(确定、免费、没法被糊弄),而且必须归你(一份耐久的文件,不是云端一段录制)。
我 prompt 它别弄坏东西不行吗? 可以,它照样会弄坏,因为它需要保护的那个不变量不在它的上下文里。prompt 改善的是意图,不是信息。
那测试到底谁来写,如果不是 agent? agent 完全可以从一次真实运行里把它写出来——关键是它随后在 CI 里跑时回路里没有任何模型,而且需求是在代码之前声明的,不是从代码里反推出来的。
Hover 在这里是什么位置? Hover 就是为这件事打造的回归测试套件:声明行为,让 agent 把它结晶成一个你拥有的纯粹 spec,在 CI 里零 AI 运行,并把每次失败分诊为漂移还是 bug。它就是那份外部契约,落到了实处。
在你自己的应用上试试 Hover。
把 Hover 的 MCP 加到你已经在用的编码 agent。它探索你的应用,结晶出你自己拥有的纯 Playwright spec。
npm i -g @hover-dev/mcp && claude mcp add hover -- hover-mcp阅读快速开始 →