2025 AI 编程年度总结
第一次接触到 AI 在编程中的应用, 是早期的 GitHub Copilot. 那时的 Copilot 功能很简单, 只是一个编码补全工具, 有点类似如今 Cursor 的 Tab 功能, 但远没有那么智能和强大, 不会自动预测和跳转, 只能简单地补全当前光标所在位置的代码片段, 而且代码质量也十分糟糕, 基本上只能用来偷懒, 减轻一些样板代码的工作量. 如今看来十分原始和粗糙, 但与当时基于 LSP 的补全相比, 已经算是相当强大了, 让人眼前一亮. 只不过当时完全无法想象, 三年后的今天, 传统的编码方式已经可以被称为"古法编程"了.
再后来, Aider, Zed, Cline, Roo Code 等工具如雨后春笋般冒了出来. Zed 是由原 Atom 编辑器的核心开发团队用 Rust 写的一款高性能编辑器, 我当时实在是受够了笨重的 JetBrains 全家桶, 想找一款轻量级的编辑器, 误打误撞开始使用 Zed. 它不久后推出了 AI 编程功能, 成了我使用的第一个 AI 编辑器. Aider 则类似如今的 Claude Code, 是运行在 terminal 的 coding agent. 在当时所有人都基于 VSCode 构建 coding agent 的年代, 这是一种很特别的方式, 尤其是当时号称 Aider 的大部分代码都是由 Aider 自己编写的. Cline 和 Roo Code 则是 VSCode 的扩展, 算是当时的主流方式.
这些工具在当时或许受限于模型本身的能力, 效果都很一般. 且不说上下文的限制导致对代码库理解的局限, 交付的代码很多都有语法错误, 甚至无法通过 lint 检查. 而且当时都是直接使用各家模型的 API 按量付费, 成本十分高昂. 花了大价钱写出来的代码却无法使用, 那时确实很难真正大规模投入生产使用.
Cursor 是那个混沌年代的扛把子. 相比于从零打造新编辑器或基于扩展的方式, 直接 fork VSCode 在此基础上开发, 或许是构建 AI 编辑器的最优解. 最吸引我的一点是, Cursor 能够处理它生成的代码的错误, 如果代码有语法错误或编译警告, 它会自动进行修复, 最终交付的代码起码是能跑起来的. 这完全释放了编辑器本身的能力. 同时 Sonnet 3.6(第二个 3.5 版本)的能力也上了一个台阶, 这让 AI 编程开始真正可以交付了, 虽然仍需逐行 review. 就这样, Cursor 毫不费力地从我口袋里掏走了 20 美金.
2025 年早些时候, Sonnet 3.7 发布了. 这个编程能力更强大的模型, 与它一起发布的还有 Claude Code, 那个真正改变了游戏规则的工具. Claude Code 与前面提到的 Aider 类似, 也是运行在 terminal 的 coding agent, 但拥有更好的交互界面, 更强大的 agent 能力, 同时搭配当时最先进的编程模型, 给所有开发者带来了足够的冲击.
此后半年时间里, 是整个开发者社区关于 AI 编程分歧最大的阶段. HN 上几乎每天都有人在讨论 Claude Code:有人吹嘘 Claude Code 有多牛, 有人驳斥这些吹嘘;有人分享自己成功使用 Claude Code 的姿势, 有人批评 Claude Code 交付的代码狗屁不通. 当时给人的感觉就像 <星际穿越> 中墨菲的外公说的那样, 他小的时候, 每天都有新的发明, 新的玩意儿, 新的想法, 每天都像在过圣诞, 让人激情澎湃.
时间来到 2025 年末, 随着 Claude Code 2.0 和 Opus 4.5 的发布, 关于 AI 编程是否真正有用的分歧已经越来越小了. 或许还有人在反对, 但声音已经逐渐听不到了. antirez 在这一年里也在分享他对 AI 编程的看法和体验, 他的看法也在不断地改变, 或许像他这种高手的肯定, 就是对 AI 编程最大的认可. 人们的讨论焦点逐渐从 "AI 编程是否有用" 转向 "如何正确高效地使用 AI 编程". 就像人们对 agent 的理解不断演进, 从 prompt engineering 到 context engineering 一样, AI 编程工具也演进出了 skill, subagent 等新概念, 以及搭配 mcp, lsp 一起使用等方式.
Claude Code 之后, 各家大模型厂商也推出了自己的产品:Gemini CLI, Codex CLI 等等, 还有完全开源, 可以自由切换模型提供商的 OpenCode. OpenCode 是一个不错的选择, 完全开源, 可以自由切换模型供应商, 不用担心被绑定在某一家的产品上. 如今, 各家模型的编程能力大差不差, 各个编程工具之间也没有显著的差距. 相比选择模型和工具, 如何编排工作流, 或许才是如今 "赛博编程" 时代需要考虑的核心问题.
无论是"古法编程"还是"赛博编程", 对于开发者来说, 责任是不变的. 引用 Simon Willison 的话: Your job is to deliver code you have proven to work. 和人一样, LLM 也会犯错, 这无法避免. 可靠的工作流, 可以将犯错的成本降到最低.
自然首先想到的是测试. 测试是保证交付的程序符合预期最直接的方式. 随着 AI 编程的效率越来越高, 自动化测试自然也变得越来越重要. 如何构建高效且可靠的测试, 是十分关键的. 现在 AI 的编程水平已经很不错了, 如果说还有什么可以通过 prompt 优化的空间, 我认为是让 AI 更多地编写纯函数. 相较于有副作用的函数, 纯函数简单, 可靠, 便于测试, 通过单元测试就能保证它的有效性. TDD 是 AI 编程工作流中一种有效的范式, 通过测试先将问题收敛, 能够降低 AI 犯错的概率, 也能让 AI 自己发现错误, 提高自动化的效率.
跟传统开发一样, code review 也是保证交付质量的关键环节. 狭义的 Vibe Coding, 指的是完全不检查 AI 交付的代码, 一股脑地全盘接受. 也许在小型项目一开始不会马上出问题, 但当代码库达到一定规模后, 必然会变得难以维护. 再先进的模型也会犯错, 即便每次只是一点偏差, 但在偏差的基础上不断产生新的偏差, 最终就会导向完全错误的方向.
code review 是必不可少的环节. 使用 agent 来进行 code review 是有效的, 市面上也有很多这类工具, 比如 Greptile, CharlieLabs, 将它们加入工作流中, 在创建 pr 时自动进行 review, 可以一定程度上加速开发, 减轻工作量. 但最终, 整个 review 工作的终点仍然必须是人类, 如果你都不知道代码写的是什么, 怎么能保证最终交付的代码是正确工作的呢?任何没有经过 review 的代码都不是资产, 最终都会变成负债. 考虑到 AI 的生产效率, 负债变得不可维护的速度可能会超过任何人的想象.
人是容易且趋向于偷懒的. 在 AI 如此高效地生产代码的情况下, 人想要追赶 AI 的效率, 就会不由自主地偷懒. 如果实在无法克制自己在这个过程中偷懒, 那么我认为, 以下几个方面是无论如何都不能偷懒的:
- 测试. 审查测试比审查代码更加重要, 如果能手动编写测试就更好了. 测试是程序行为符合预期最直接, 最快速的保证. 虽然 AI 为了让代码通过测试而直接修改原有测试这种离谱情况已经不再经常发生, 但我们仍然很难保证 AI 在编写测试时已经完全理解程序的行为和我们的预期, 编写的测试能够覆盖足够的场景, 所以仍需仔细审查测试.
- 数据结构. 测试是保证程序的行为符合预期, 而数据结构则反映了程序对问题或领域 (domain) 的定义, 反映了程序本身是什么. 在传统编程过程中, 如果在编写函数时发现无论怎么写都感觉很别扭, 那大概率是数据结构一开始就设计错了. 搞清楚定义, 行为自然就出现了. 同样地, 审查数据结构能够检验 AI 是否正确地理解和定义了问题, 能够更早期地发现问题并调整.
- 封装和组合. 清晰且正确的模块化, 能够将问题收敛, 将不确定性收缩在可控的范围内. 对 AI 来说, 将每次任务的范围和边界尽可能缩小, 能够大大降低犯错的概率.
除了测试和 code review, 要长期维护一个 AI 持续交付的项目, 还有一个关键点:及时重构. 这或许是一种全新的范式.
这与传统的开发工作流不同. 传统开发中或许更遵循开闭原则, 人类的生产力和精力是有限的, 这样能够保证程序在持续交付中的稳定. 即便只是一次简单的重构, 要考虑的因素和花费的精力对人类来说依旧巨大, 并且没有直接的收益.
由于 AI 的编程方式和技巧都是从人类的代码中学来的, 它遵循着人类的开发方式. 比如 AI 在编写代码前的规划, 经常会给出十分滑稽的时间表, 每个改动的工作量对应的时间通常按天计算. 它没有意识到, 人类需要花费数天完成的工作, 它十分钟就完成了. 对于人类而言巨大的重构工作量, 对 AI 来说一眨眼就能完成.
重构对于 AI 来说不是可选的, 而是必须要做的. AI 刻板地遵循开闭原则, 如果不在合适的时候重构, 代码瞬间就会变得难以维护. 最直接的例子就是 React 中各种状态的维护, 稍不注意, AI 就会在一个组件中加上数十个状态, 而不是重新思考组件间的关系和数据流向, 最终代码一个不留神就腐烂了.
"古法编程" 的年代正在远去, 我已经不记得上一次编写一个完整的复杂的函数是什么时候了. AI 恐怖的生产力实在让人无法拒绝, 就像用过现代 IDE 之后, 无法再回到传统编辑器一样. 但 AI 并没有让我变得更轻松, 相反, 我花费的精力比以往多得多, AI 实在太快了, 我反而变成了拖慢它的因素. 想要跟上 AI 的速度, 开发者也要学会同时在多个上下文, 甚至多个项目之中不断来回切换. 虽然很吃力, 但人类仍然是当前开发环节中必不可少的因素.
也许有一天, AI 会变得足够智能和强大, 完全能够抛弃人类这个包袱, 完全释放它的生产力. 在一年前这或许还是遥不可及的空想, 但今天看来, 一切都发生得比所有人预想的都要快.
有的人抱怨 AI 剥夺了编程最原始的乐趣, 有的人则欣喜可以抽身于代码的细节而更多地思考更加宏观的设计. 但无论如何, 趋势已经无法改变, 我们能做的或许就是在人类与 AI 开发的协作环节中, 让自己变得更加高效.