教程2026-10-26 · 智涌AI

代码库怎么改才适合 Agent:类型、快照测试与确定性模拟

Agent 友好代码库头图:类型、快照测试差异 FILL 5@101 变 5@102

Agent 写代码越来越快,瓶颈挪到了两头:它自己怎么知道写对了,人怎么放心合进去。Jane Street 在 2026 年 5 月 Antithesis 主办的 Bug Bash 大会上有一场主题演讲,讲的就是这件事:Agent 靠反馈活着,代码库要先把反馈做快、做准。这篇按演讲内容整理出四层反馈(类型、快照测试、确定性模拟、形式化方法),快照测试那一层我们在本机用 Python 跑了一遍。

说明:观点和例子来自 Jane Street 在 Bug Bash 2026 的演讲《Now more than ever》(大会官网与 YouTube 录像)。快照测试一节在本机实测:Python 3.13.5、pytest 9.1.1、inline-snapshot 0.36.1,2026-10-26。OCaml 的 ppx_expect、Antithesis 和形式化证明工具都未实测。

Agent 靠反馈活着

演讲的核心判断很简单:Agent 能不能把活干好,主要看它拿到反馈的速度和质量。人写代码时脑子里装着全局约束,Agent 不一定。演讲里举了个例子:Agent 一开始知道构建命令怎么调,跑了二十多万 token 之后,未必还记得。靠上下文记住规则不可靠,要把规则做进代码库,让违反时立刻报错。

这就引出四层反馈,从快到慢、从便宜到贵。

反馈层速度能管住什么上手成本
类型系统写代码当下全局不变量、非法状态低到中,取决于语言
快照测试秒级行为变化,一眼看出差异低
库级确定性模拟毫秒到分钟并发、网络、时钟相关的 bug中到高
形式化方法慢,按需可证明的正确性高

第一层:类型,把约束写死

类型检查在写代码的当下就给反馈,还能强制全局不变量。演讲举的例子是防 XSS:给 HTML 字符串单独一个类型,没转义过的文本根本拼不进去,Agent 忘了规则也写不出漏洞。

另一个例子是「让非法状态无法表示」。他们有一段配置代码原来是一串命令,组合起来可能互相矛盾;改成记录类型的字段之后,矛盾组合在类型层面就不存在。换到 TypeScript 或 Python,可以用判别联合、枚举和 dataclass 做同样的事:与其写注释提醒 Agent 「这两个选项不能同时开」,不如让它们同时开时类型检查直接报错。

第二层:快照测试,让测试便宜到随手写

演讲把测试列了一长串:单元测试、属性测试、模糊测试、Antithesis 的确定性模拟、生产与开发并排对比、历史回放。最推荐的是 expect test:测试只负责把输出打印出来,框架把输出记在测试旁边;行为一变,给你看差异,接受就更新。Jane Street 的 OCaml 版本是开源的 ppx_expect。

按例子写的测试为什么对 Agent 有效?演讲的解释是软件很脆,大部分 bug 用几个具体例子就能抓到;而 expect test 让写例子几乎零成本,Agent 和人都愿意多写。打印出来的文本还能当「示波器」:把内部状态打成人能读的文本,出问题时一眼看出哪一步变了。

本机实测:Python 里用 inline-snapshot

Python 没有 ppx_expect,inline-snapshot 是同一思路的 pytest 插件。我们写了一个 20 行的迷你撮合函数,每一步都把订单簿打成一行文本:

python3 -m venv .v && . .v/bin/activate
pip install pytest "inline-snapshot[black]"
# test_order.py
from inline_snapshot import snapshot
from order import apply

def test_cross():
    out = apply([("ask", 101, 5), ("ask", 102, 5), ("bid", 102, 7)])
    assert out == snapshot()

第一次跑 pytest --inline-snapshot=create,插件把实际输出直接写回 snapshot("""…""") 里,测试文件自己变成了一份可读的预期结果:先挂两笔卖单,买单吃掉 101 的 5 手和 102 的 2 手,剩 102 的 3 手。之后正常 pytest 显示 1 passed。

然后我们故意埋个 bug,把成交价从对手价写成了自己的报价。再跑一遍:

终端:inline-snapshot 报告快照差异,FILL 5@101 变成 FILL 5@102
2026-10-26 本机实测:成交价写错后,inline-snapshot 直接给出差异,-FILL 5@101 / +FILL 5@102。

差异就一行,人和 Agent 都能马上看出是成交价错了。如果这次变化是有意的,跑 --inline-snapshot=fix 接受即可。我们改回原代码后又是 1 passed。

有个细节要注意:默认模式下发现差异会弹出「Do you want to fix these snapshots?」确认,非交互环境(CI、Agent 的工具调用)里没有终端,会直接抛 EOFError。给 Agent 用时显式加 --inline-snapshot=report 只报告,或者 --inline-snapshot=disable 当普通断言失败。

测试便宜到随手就能写,Agent 才会真的去写;输出可读,人才能一眼审完。

第三层:在库这一层做确定性模拟

全系统的确定性模拟能找到很深的 bug,但一轮要几分钟甚至更久,不适合 Agent 每改一行就跑一次。演讲推荐往下做一层:在库里把网络、时钟、外部服务都换成可控的模拟,一次跑完只要毫秒级。演讲的说法是:一项测试从 17 小时降到 7 分钟已经好很多,做到「感觉是即时的」更好。

对普通团队,起步可以很小:把 time.now()、随机数、HTTP 客户端都通过参数注入,测试里换成固定值,同样的输入永远得到同样的输出。

代码审查反而更重要了

演讲认为 Agent 打破了代码审查的社会契约:以前提 PR 的人自己理解过这段代码,现在不一定。Agent 还会钻空子,比如为了通过把测试删了;而大量生成的 diff 会让审查者看到走神。

Agent 也能帮人审:把一个大功能拆成一串小提交,补上说明意图的测试,给 diff 做一份带讲解的导览。人的注意力是最稀缺的资源,这些工作都是为了省它。

第四层:形式化方法,正在变便宜

演讲用 seL4 微内核说明过去形式化验证有多贵:约 8,700 行 C 代码,花了约 25 人年,每行 C 对应约 23 行证明(演讲给出的数字,我们没有另行核对)。他们认为 Agent 会让这件事便宜很多,可选的路径从轻到重有精化类型、差分验证、Coq/Lean 全量证明,以及 Rust 生态的 Verus。按演讲里的说法,Jane Street 大约在演讲前 8 周才决定认真投入这件事。

大多数团队这一层可以先等等,把前三层做扎实就够忙一阵了。

常见坑

完成标准

最后

反馈做好之后,下一步是让 Agent 交出能核对的证据。可以接着看 Agent 完成证据:用截图和录屏验收,把测试结果和录屏一起附进 PR。

关注公众号「智涌AI速递」

每天的 AI 快讯、实用教程和 AI项目实测,也会同步发到微信公众号。在微信里搜索「智涌AI速递」就能关注;不用微信的话,可以用 RSS 订阅本站。