When Code Is Cheap
我有一个朋友讲过,如果大模型能力的边界超过你日常工作的基线,你就会进入一个生产力井喷的状态(并开始发表一系列暴论)。
去年底的时候,我还能共情 Linux 内核开发老哥:

而当今年初 Codex App 发布并日渐完善,GPT 5.5 到现在 5.6 的模型逐渐能够相对可靠地交付我需要它交付的内容之后,我不得不承认,GPT 5.6 Sol Max 的能力边界已经达到我日常工作的基线。所以,我也要发表 Code Is Cheap 的暴论了。
开宗明义,只有当模型能力覆盖你的日常工作需求的时候,你才或许能跟现在的我共情。
反面例子比如,目前 AI 写作还远远达不到我的要求,我试过 AI Gen 文章,但是最后这篇文章还是得我手写才对味。调整 AI Gen 的文章比我自己手写都心累。Codex App 和 GPT 5.5 模型出来之前,模型产生的结果往往充斥着我无法忍受的部分,且无法通过进一步 Prompt 改善。这种情况在下面的案例里还会出现。
现在开始介绍我通过使用 Coding Agent 大幅降低软件开发成本,提升生产力的案例。出于分享方便起见,我主要讨论我在开源社群相关的工作,但是其实日常 ScopeDB 内核、平台和运维也已经全面经过了 AI 的加持。
“我不看代码”
近期 HashiCorp 创始人 Hashimoto 分享了使用 Fable 编程取得巨大成功的经历,由此产生了下面这段经典对话:

与此同时,自去年甚至前年以来,时不时会有开发者强调,自己已经很久不看代码了。
那么,我还看代码吗?我的回答是,有一部分代码我主动或被动的不看了。
首先,源代码不会消失,理由如下:

有人说不看代码了,看测试就好。那我问你,测试不是代码吗?
有人说不看代码了,写 Spec 就好。那我问你,代码不是业务逻辑的 Executable Spec 吗?
如上所述,要表达某种特定的业务逻辑,到头来还是写某种类似代码的东西。
那么,什么情况下我主动的不看代码呢?
答案是以前写过充分的测试,软件 Scope 明确的代码,做重构的时候,可以不细看甚至不看。
这个月初感受到 ChatGPT 订阅 Reset 带来的 Token 盈余的魅力之后,我开始指挥 Codex 在后台处理一些我长期想做,但是优先级不高又还挺花时间的事情。
比如我在《涓滴开源:Cronexpr 的故事》里提到的 Cronexpr 项目,里面有个语法解析器的依赖。我一直知道 Crontab 表达式的语法很简单,其实不太必要有这个依赖,但是手动写 Parser 保证正确性还是太累太枯燥了。这正是 Parser Combinator/Generator 库存在的原因。
但我确实不喜欢多余的依赖,而且 Cronexpr 的测试覆盖非常完整。于是我在本月初用两条 Prompt 向 Sol Max 许愿完成了这个重构:
[我] 现在我们基于 winnow 实现了一个 Parser,但是我发现 cronexpr 的 parsing 需求好像挺简单的,你看看完全保持原语义的情况下,把 winnow 换成手写 parser 或者基于 chumsky 的 parser,评估一下优劣看看值不值得做。[Codex] 结论:不建议把 winnow 换成 chumsky;如果要迁移,直接写手写 parser。 手写迁移从长期维护看是合理的,但目前属于中低优先级重构,不是迫切优化:如果目标只是少一个依赖,暂时不值得承担语义回归风险;如果目标还包括减少 parser 代码复杂度和未来 winnow 升级摩擦,那就值得做。
…[我] 推个 PR 换成手写 parser 吧,然后用 snapshot tests 对齐 Ok/Err 的结果,不要改变现有测试的结果,除非你有充分的理由,要跟我说清楚。具体的语义,以合理的 cronexpr 的设计为准,如果跟现有实现不同,逐一说明供我审查。但是我理解现在的所有 snapshots 应该都是跟目前一样的结果才对。[Codex] 已完成并推送 PR:fast/cronexpr#33。当前可合并、全部 5 项 CI 通过,未执行合并。
…

这个 PR 总共改了上千行代码,测试快照都是新用例,已有的上百个案例全部通过。我出于好奇扫了一眼新的快照,没看到特别不对的东西,差不多也就合并了。因为 ScopeDB 线上依赖 Cronexpr 的所有场景都有测试用例回归,测试没挂我百分百确定没问题。
本来事情也就到此为止,但是前两天出于好奇查看 Cronexpr 反向依赖的时候,看到一个新库拿 Cronexpr 去打性能测试榜,说它的库比 Cronexpr 解析得更快。虽然 Cronexpr 的解析基本不是热路径,所谓的快也就是几十纳秒到几百纳秒的差别。乍一看是数量级的差异,实际上不是热路径,绝对数字上并不会有什么差别。
但是我就想,这种边界是非常清楚的简单库,追平性能应该是比较轻松的,也没什么好设计能设计出差距。于是我就让 AI 把对方的 benchmark 扒过来,对着性能目标优化。
三个 PR 过去,正向路径性能轻松全面超过打榜哥:

逆向路径还有点距离,但是 Cronexpr 报的是具体的错误,也就承担了存储上下文的成本,其他库基本就是报告“出现了一些问题”或者给个游标你自己看。
提示词基本就是,对着 Benchmarks 的结果,想办法优化直到超过其他竞争对手,并保持代码简洁且正确。前两个 PR 我扫了一眼没啥毒电波就合并了,最后一个改 Error Format 改得乱七八糟的,我还是上手下了几步指导棋扶着 AI 做了正确的设计。
这也是 AI 带给我的一大变化。以前我挺不喜欢搞性能测试,一方面是写起来麻烦,另一方面是经常不知道测什么东西,没有实际的负载导向,很多 benchmark 说白了也只是 benchmarketing 而已。如果有实际的线上瓶颈,一般也是测端到端查询/请求性能,不用针对特定模块测试。反正单一模块优化 30% 放到端到端上可能就看不见了。
但是 AI 很能不厌其烦地做这种事情:回归测试也好,文档注释也好,性能测试也好,AI 真的非常有 Hardworking 的特质。所以对于有性能疑虑的软件库,我现在都一概让 AI 直接加上基础的性能测试套件,构建一个总比没有好的基线。
以下就是我现在新的 Rust 项目逐渐收敛的结构,在这之前基本上我是不怎么写 Benchmarks 的,写 Examples 和区分集成测试也很麻烦,但是其实我都知道怎么做,让 AI 办就很轻松。

至于被动不看的例子,近期主要是 Apache DataSketches Rust 的性能优化和 Fuzz 测试问题修复。
比如 apache/datasketches-rust#229 这样 AI 生成的 PR 我已经看不清楚了。除了那种一看就知道肯定不对的,现在这个 PR 整体味道对了,我只能说,反正它通过了所有的正确性测试和快照测试。而且现在我信 Sol 重构的正确性超过信我自己,人在重构的时候经常丢三落四。
不过,这个 PR 一开始就有一些不对的味道,这个我是能侦测出来并重拳出击的。

然后在今天进一步重构 T-Digest 的 apache/datasketches-rust#231 里,我又觉得代码有点难懂了,于是又详细看了一轮,带着 Codex 做了详细地代码重构。
简单总结一下,对于有充分测试回归的项目,可以选择性地不看代码。如果你的软件主要服务终端用户,终端用户感觉不到问题,那就是没有问题。
实际上,没有 Coding Agent 的时候,我看别人的 PR 也不太可能每一行都看。正如我在《Code Review 的方法》里提到的,Review 主要是看看应不应该做,实际实现跟 Reviewer 脑海里应有的实现有多少偏差,有没有显而易见的问题。AI 生成的 PR 和人生成的 PR 最大的不同是,AI 很容易生成一大堆似是而非的东西,掩盖错误的动机和实现。
在过去,我觉得 Coding Agent 没有显著提效的原因,就是这些似是而非的东西错漏太多,而且无法通过多次 Prompt 收敛,最终必须古法修复,总体成本可能高于直接古法实现。现在,AI 生成的东西大部分还行,一旦理解错误,基本实现出来的东西也能一眼看出问题。此前可能一眼看过去 80% 都有问题,现在大概 20% 有问题,这 20% 当中,80% 的问题不是致命问题,或者可以通过继续 Prompt 改进。这样,Agentic Coding 整体的体验就完全不同了。
“随时随地可以重写”
近期还有一个甚嚣尘上的议题,就是现有软件拿 AI 重写。首当其冲的就是 JavaScript 运行时 Bun 从一个 Zig 项目重写成了 Rust 项目。单一 PR 改动超过十万行,成为 Claude Fable 营销下的经典奇观之一。
值得注意的是,除了造奇观造出来的单个 PR 10w+ 改动,其实哪怕从这个 PR 合并之后算起,Bun 的下一个版本仍然花了数个月的时间才正式发布,并且 Bun 一直都以运行不稳定著称,所以哪怕新的版本出现一些问题,也不会马上被归咎成 AI 重写的问题。
我也用 Codex 把一个自己 Rust 青春期写的 License Checker 项目彻底重写了:

虽然没有 10w+ diff 那么夸张,但也是完整的工具重写大几千行的变化。图上值得注意的是 155 次提交,对应我跟 AI 超过 100 次的对话。
工具的重写不像库的确定性重构,很多端到端的行为其实不太好测试或者无法穷尽。当然,我趁着 HawkEye v7 重写的机会,把之前因为完全不懂 Rust 测试硬凑的基于 Python 的集成测试也换过来了,相对覆盖面还好一些。
对于 HawkEye 重写的正确性保证,我的办法跟 Hashimoto 是一样的:我读了代码。
这个 PR 是 8 月 10 日创建的,此前七月份我用 AI 许过一次愿,出了一个 Draft PR 作为曳光弹,大致感受了一下 Review 重构后的代码的感觉。然后,我在本地把 v6 和 v7 分别 checkout 出来,同时用 RustRover 打开比照逻辑。但是很快我就发现我不太需要看 v6 的逻辑了,因为我也是从头开始设计 Context 更清楚。
我的 Review 过程是这样的:
- 8.10-8.13 其实还没有开始专注看这个 PR 的内容,先把重写的 Scope 确定下来,第一个重写只包括功能,不包括多端发布的细节,以帮助我集中 Review 的注意力。多端发布很简单,核心功能做完再加一个 PR 就能搞定。
- 8.16 晚开始集中看代码。第一步是看最终界面,也就是从
main.rs每行代码往下看。实际上,最后我把 main.rs 看完了,这个 PR 就彻底做完了。 - 第一部分是 main 的入口,于是包括了命令行界面 Command 的定义,配置的定义,错误类型的定义和错误处理的细节。这部分其实是程序的输入和输出契约,要先确定下来。
- 这部分工作占据了一半以上的 Commits 才基本完成。然后我开始看内部引擎的逻辑,实际上也很简单,分成(1)初始化格式引擎(2)发现并加载所有待处理文件(3)计算格式化后的结果。
- 内部实现的 Review 和 Polish 过程就是反复应用软件工程实践,移动代码,重构,改造模块,确定名词。尤其确定名词是最难的,错误的名词往往指向错误的设计。
8.18 就做完了,而且其实是在白天正常工作的情况下 part-time 提示 Sol Max 完成的。
我发现我同时工作的项目最大并发度大概是四个,也就是本职工作 + 开源工作,以及各自 Primary 工作 AI 在思考的时候,人转向 Secondary 工作。当然,要 Reset 的时候开个十个八个实验性的 Session 出 Draft 那不在话下。
重写其实也挺简单的,因为有一个参考对象,我不用考虑具体的文件格式化算法,因为跟原来一样就行,也不用考虑模板引擎的选型和输入输出方式,因为之前已经选完了。
重构基本完成之后,我让 AI 自己拿开源项目测试工具的效果。AI 选择了大小不一、开启了不同功能的原先就依赖了 HawkEye 的项目若干,用于测试迁移的情形。然后选取了 Apache Flink 和 Rust 等大型项目,确保核心功能在大项目上不会死机。
接下来就是如我所想的一个 PR 完成多端发布的功能,然后测试两天没什么问题就发布了。接着再指挥 AI 到所有依赖 HawkEye 的下游给个更新的 PR 狠狠刷一波贡献🤣
发现下游使用都非常流畅没有什么问题,爽也。
“那你的愿望呢”

所以,AI 能力的边界超过我日常工作的基线,我在很多场景下可以释放创造力了。
对我来说,体感就是之前要焚香沐浴集中精力做的开源工作,尤其是重体力的重构和实现劳动,现在基本主要卡点是有没有想清楚要做什么,也就是每天精力相对充沛的情况下能够集中思考的时间,以及《思考,快与慢》中所称的系统一,其默认思考水平的质量。
因此,现在我的生产力最大的制约是身体健康,甚至不是时间。我在身体疲劳的情况下 reasoning effort 显著下降,结果就是无法阅读和引导 AI 的产出,软件产品处于一个 Plausible 而非 Convincing 的状态。因为我大脑罢工了,无法判断将 Plausible 的内容认证或改造成 Convincing 的内容。
积极点说,只要你能想清楚要实现的目标,以及有搞定核心技术决策的能力,基本上实施的工作或者说填充细节的部分,Coding Agent 都能替你完成。但是到底哪些是细节,这是一个随时间变化的标准。
比如去年底的时候,我感觉 AI 写异步代码简直就是个弱智,完全判断不清楚时序关系。到了今年年初,我尝试让 AI 实现 singleflight 的原语,发现它组合现有代码实现功能的方式超出了我指挥它的范围,能够发现我不仔细想想不到的方法。
从这个时候开始,我就意识到 Coding Agent 在某些地方可能能够代替我完成具体工作,而不只是简单辅助了。顺带一提,这个 PR 是 Gemini CLI + Gemini 3 Pro 做出来的,所以当时 Gemini 跟 GPT 5.2 真没太大区别。后面 Gemini 拉了跟我当时吹 Gemini 没·有·关·系😅

这个模式推到极致就是我在 Apache Asyncband 孵化项目里分类实现 Rust 并发编程的同步原语的过程。首先是确定原语要解决的问题和适用场景,然后是确定原语名字、接口名字和语义,这部分是最难的,最后是实现、测试和性能回归,这部分有了 AI 以后基本是纯机械的工作,而且完全可以做到先实现正确性,再优化性能,可以说是 MIT 派的全面胜利。
- Tracking Issue to evaluate async primitives
- Tracking Issue to deliver the channel family incrementally
- 《Async Rust 原语实现与品鉴》
反面例子就是,如果你说不清楚自己要什么,不知道实现路径上的关键点如何决策,即使有 AI 支持,很可能也做不出来。
比如我知道现有编程语言的一系列问题,每个具体的问题也有一些前沿的解决办法,但是没有一个很好的切入点去增量的落地,于是目前我并不能够在短时间能开发出自己满意的一个新的编程语言。同样的事情也适用于一个服务元数据查询的数据库,一种尽在掌握的资源/服务运维部署工具,一个 AI 老婆,诸如此类。
但是像 Asyncband 这样“一个完备的并发编程工具库”是可以实现的,我还发现 Rust 在 Web 编程和测试套件的部分也有缺口,看起来也有具体落地的路径。至于已经落地一部分的 Fastrace 和 Logforth 这样的可观测生态库,由于一两个核心决策还在摇摆,所以算做还处于一种中间态。
Agentic Coding 时代,说清楚愿望的能力,以及构建愿望落地路径的能力,是核心竞争力。

You Aren’t Gonna Need It
长话短说,有些库以前只是因为自己写很麻烦,随便捡个开源库用的,我之前一般就都是能自己写就自己写。但是现在你会发现,很多逻辑 AI 写起来不复杂,直接内联就行了,不必为了省力气引入新的依赖。
这也是 Agentic Coding 时代下,编程语言和开源软件库势必发生的变化。
对编程语言来说,用户能像小白一样写出能运行的代码不再是推广的核心因子,很多语言好写,但不见得好读。Rust 大家嫌弃它难写,学习曲线高,但是 AI 逐渐积累知识库,尤其是 Rust 编译器的 tool call 反馈进入训练之后,写出来的代码还是挺好读的。至于写的累,反正不是你逐行手写,管它呢。AI 又不会累。
对于软件库来说,为了满足用户需要不断接受业务下推的日子总算可以看到头了。用户也不满意自己今天下推了自己的业务逻辑好爽,明天就要被别人下推的业务逻辑影响好不爽,但是之前大家都在公共厕所拉屎,不去公共厕所只有拉裤里,只能忍了。现在有更好的选择,我希望大家不要忍。从这种意义上说,AI 就是你的移动厕所。
P.S. 其实原本这里还有一个 ScopeDB SaaS Platform AIOps 的例子,但是写累了,回头多整点实践想写再写吧。