三十五万行 Rust,一个 S3 兼容的对象存储。这不是某个团队三年规划的结果,而是一次实验的产物——作者让 AI 把它从头写了出来。代码体量摆在那里,确实唬人,可如果你读完复盘只记住"35 万行"这个数字,那基本等于白读。真正该抄走的是另一件东西:他给自己搭了一套证据闭环,让 AI 交付的每一行代码都必须过堂,过不了就退回去。
三十五万行里,最不值钱的就是那个数字
写出来不难,难的是你敢不敢信
让模型生成代码,今天已经不是瓶颈。一个 S3 兼容的对象存储要处理的东西听着专业,拆开看也都是有标准答案的活儿:SigV4 签名校验、分页语义、range GET、条件写入、multipart 分片合并、错误码到底该返回 NoSuchKey 还是 403。这些规范写得很细,模型也读过无数遍实现,照猫画虎能画出个八九不离十。
麻烦藏在别处。存储系统有个恶劣的性质:它出错的时候往往不响。丢一个字节不报错,并发下的一次竞态只在特定时序出现,断电后重启发现某个分片的元数据没落盘。这些东西你盯着 diff 看一整天也看不出来,跑几个 happy path 用例同样跑不出来。它们只在真实的压力、真实的失败、真实的边界条件下冒头。
Agent 说"已完成"的时候,它其实什么都没说
这是我见过的团队最容易踩的坑。Agent 跑完一轮,回一句"功能已实现,测试通过",人就默认收工了。可它嘴里的"测试通过",指的是它自己刚写的那几个测试——而那几个测试恰恰是它照着同一份错误理解写出来的。自己出题、自己答卷、自己判分,这套流程在形式上是闭环,在信息上是空的。
你需要一个不受它控制的裁判。这个裁判要么来自外部,要么来自比它更硬的物理事实,反正不能来自它自己。
于是问题从"怎么写"挪到了"怎么证"
整篇复盘的价值就在这个转向。当生成成本趋近于零,工程的重心会自动迁移到验证侧。谁能在验证侧搭出更便宜、更快、更可信的证据生产流水线,谁就能真正把 Agent 用起来;搭不出来的,就只能停留在玩具项目里。下面三层,就是这条流水线的骨架。
先找裁判,再谈生成
别自己造标准答案
S3 这个协议的好处是它太老了、太普及了,以至于测试 oracle 是现成的。Ceph 社区维护的 s3-tests、MinIO 的兼容性套件、各家云厂商公开的行为文档和错误码表——这些都不是为你写的,但它们天然就是一份标准答案。拿过来直接打自己的实现,红的就是红,绿的就是绿,没有解释空间。
这一点比听起来重要。很多人做 AI 辅助开发时会本能地自己写测试,因为"需求是我们自己的"。可一旦你面对的是有公开规范的东西,自己造 oracle 就是在给自己留后门——你写的测试会不自觉地绕开你代码里那些你自己也没搞明白的地方。
拿一个真的 S3 当参照物
更狠的一招是差分测试。同一批请求,一份打到你的实现上,一份打到 MinIO 或者云上的真实 S3 上,比对响应状态、header、body 字节、错误信息结构。差异不一定是 bug,但每一处差异都必须有人给出解释,说不清楚的就是隐患。
差分测试在 AI 场景下有个额外好处:它是可自动化的、结果二值化的。不需要人来判断"这个实现算不算对",只需要判断"它和参照物一不一样"。这让整条流水线可以在无人值守的情况下反复跑,而 Agent 最擅长的就是在这样的反馈里迭代。
再补上人想不出来的边角
规范和差分测试覆盖的是"已知的已知"。剩下那部分要靠属性测试和模糊测试:同一个 key 并发写会怎样,分片传到一半连接断了残留怎么清理,签名时间戳踩在过期边界上算不算合法,长轮询的 list 操作在 10 万个对象下会不会漏页。这些场景穷举不完,但可以用生成器随机撒网,让不变量去兜底——比如"任何时刻读到的对象内容,必须是某次完整写入的内容",这种断言不需要你预设 bug 长什么样。
trace:让失败可以原样重放
记录它看到了什么,而不是它说了什么
Agent 的结论不值钱,过程才值钱。一轮会话里真正需要留档的是:喂给它的上下文、它调用的每个工具和返回值、它做出的每个 diff、以及这些 diff 之后触发的测试输出。这些东西加起来,构成一条可回放的trace。
回放能力决定了调试成本。没有 trace,你面对一次失败只能重跑一遍,祈祷它复现;有 trace,你可以精确地停在出问题的那一步,看它当时手里握着什么信息、做出了什么判断。对 AI 这种非确定性执行者来说,这个差别是天壤之别。
上下文一断,人就只能靠猜
我见过不少团队把 Agent 放在 CI 里跑,只留最后那句"通过/失败"和一个退出码。这等于主动放弃了最贵的资产。失败信号本身信息量极低,它会告诉你"这里不对",但不会告诉你"为什么会走到这里"。
存储这类系统尤其如此。一次测试失败背后可能是签名逻辑错了,可能是并发控制错了,也可能是测试环境自己的配置漂移。这三者的修复方式完全不同,而区分它们只能靠过程证据。
让不同轮次之间可以比较
trace 还有第二个用途:横向比对。同一类任务跑了五轮,把五条 trace 摊在一起看,你会很快发现哪一类错误在反复出现——是模型读不懂某段既有代码,还是它对某个 API 的语义有系统性误解。这种模式识别靠单个案例是做不出来的。
顺带一提,这也让"回退"变成一个可推理的决策。当新一版 Agent 表现变差,你能算出是哪些环节退化了,而不是凭感觉把版本号往回拨一格。
人类判断不是兜底,是配额
不是每个改动都值得你看一眼
这一条最容易被误读成"最后还是得人来审"。恰恰相反,人类判断在这套体系里是一种被严格分配的稀缺资源,不是无限的兜底网。三十五万行代码,逐行审阅在物理上就不可能,硬要审也只能审出疲劳。
可行的做法是分层。签名与鉴权、持久化路径、并发数据结构、崩溃恢复逻辑——这些错了就是灾难性的,改动必须有人看。路由解析、参数校验、日志格式这类改动,交给证据链自动兜住就够了。
你的注意力才是真正跑不快的那一环
把人的注意力当预算来管,很多设计选择会立刻变得清晰。如果一次人工介入要花二十分钟,那一周能承受多少次介入?答案通常是十几次,不是几百次。所以整个流水线的设计目标应该是:尽最大可能把需要人判断的问题压缩、聚合、排序,让每一次介入都打在最高价值的地方。
这也是为什么前面两层必须先建起来。oracle 和 trace 越强,人需要亲自看的东西就越少、越准。
提前定好停机条件
最后一个动作是把判断规则写下来,而不是留在某个人脑子里。"触碰鉴权相关的代码必须人工确认""性能分布出现恶化必须停下来查""任何涉及数据删除语义的改动不允许 Agent 单独决定"——这些线画在事前,才能真正约束运行时。画在事后,它就只是一句感慨。
搬走这套方法,先回答一个问题
你的 oracle 是什么
照搬这套东西之前,先诚实地回答:在你自己的项目里,什么东西能充当不受 Agent 控制的裁判?如果是一个成熟的开放协议,恭喜,你几乎可以照抄。如果是一套只有你们自己才懂的业务规则,那你要做的第一件事是把它变成可执行的断言,而不是先急着接 Agent。
顺序反了的人,最后都会停在"AI 写的代码不敢上生产"这一步,然后得出一个错误结论:模型还不够强。其实不够强的是验证设施。
规模感会骗人,证据不会
三十五万行这个数字之所以抓眼球,是因为我们习惯用它衡量工作量。但在 AI 时代,代码行数更像是一个成本项而不是成就项——它意味着更多的维护面、更多的潜在缺陷、更重的审查负担。真正决定成败的是另一个比例:有多少行代码是被证据支撑着的。
差的项目里,这个比例可能不到一成。好的项目里,每一行进入主干之前都留下了自己为什么可信的痕迹。
从最小闭环开始
不必一上来就搭全套。先找一个有明确外部标准的模块,接上现成的测试套件,让 Agent 在红绿反馈里跑起来,同时把每次会话的 trace 存下来。等这套东西跑顺了,再往里面加人类判断的分层规则。
顺序搞对了,剩下的就是时间问题。顺序搞反了,你会花很久在一个看起来很像样、但没人敢碰的代码库上。

