如果你不能外包你的理解,你咋掌控AI写的那一大坨代码

上一篇文章的结尾,我留了一个话题。

我引用了那句话:"你可以外包你的思考,但是你不能外包你的理解。"

有读者在后台问我:道理都懂,可 AI 一天给我生成的代码,比我自己一年写的都多。思考我可以外包给 AI,理解我肯定要自己消化——但是消化也得有时间和精力啊。生成是光速,理解是步行,AI拉的是一大坨,理解缺是要细嚼慢咽,这道题怎么解?

一、先说困境:生成和理解之间的速率差

我们已经有了一个共识了,对吧:AI Coding Agent 已经把"写代码"这个环节的产能拉爆了。

我们现在的日常是这样的:早上给 agent 派一个 Issue,去泡杯咖啡回来,一个几百行的功能已经躺在工作区里了,测试都跑绿了。我们在AI的帮助下梳理好一个需求文档,要是用 /loop-it 或者 /graph 批量跑几个 Issue,一个下午的工作区里能堆出过去一周的变更量。

生成的一大坨代码,诚实的讲,很多情况下我们跑过测试和Code Review就提交了,我们已经不读代码了。

但代码不会因为你没读它,就自动变成"你的"代码。

背后有个很少有人挑明的速率差:

  • 生成是并发的。你可以开十个 agent 同时干活,产能理论上无限。
  • 理解是串行的。理解只能发生在你一个人的脑子里,一行一行过,一夜一夜熬。

以前人写代码,生成速度约等于理解速度——你写一行就懂一行,代码库长在你脑子里。现在倒过来了:代码库膨胀的速度是脑子的十倍、百倍。用不了多久,这个项目对你来说就变成了"考古现场":每一行代码都认识你,你不认识它们。

不理解的代码,具体坑你三件事:

  1. 不敢动。 改之前你不知道哪里有雷,只能小心翼翼绕着走。绕来绕去,代码库就被"谁都不敢碰的祖传区域"占满了。
  2. 答不上。 这是我最切肤的痛。团队协作里,同学指着一段代码问你"这块为什么这么写",你不能说"等我问问 AI"。那一刻你不是工程师,是传话筒。项目里有你名的部分,你得能立刻接住。还有QA同学测试时,测试出问题,需要你快速的解答。
  3. 背不动。 线上出了事故,root cause 藏在三个月前 AI 生成的一段代码里。锅是你的,因为你 review 过、提交过。可你连它为什么存在都不知道,怎么背?

那怎么办?我也试过几招,逐一汇报失败原因:

  • 不读,靠测试兜底。 这是 Uncle Bob 的路子:不读代码,用单元测试、变异测试、覆盖率把约束焊死。这套对"保证质量"有效,但注意——它保证的是代码没有错,不是你懂了这段代码。测试通过只能告诉你程序行为符合预期,不能把意图装进你脑子里。
  • 粗读。 diff 打开,扫一眼,"嗯,看着没啥问题"。这是骗自己。三分钟后你不记得看过什么,五分钟后这段代码在精神上已经易主了。
  • 让 AI 再总结一遍。 这是我一开始最寄予希望的:既然读不过来,让 AI 读,给我写个总结。问题是——读总结和理解代码,根本不是一件事。我增加 /note-it skill尝试做这个。总结是二手转述,会失真;更麻烦的是,总结飘在代码之外,你看到"本模块实现了限流逻辑"这句话,但限流逻辑具体落在哪几行、为什么是滑动窗口不是令牌桶、边界条件怎么处理的,总结里全没有。你等于把"不读代码"换成了"读另一篇更短的代码",理解并没有发生。

绕了一圈你会发现,理解这个东西没法并行,没法压缩,也没法托付给别人。它只能发生在你脑子里。

这周末我也看到了两篇文档:

所以这个困境说穿了就是:AI 能替你写代码,但不能替你长出理解。生成速度可以外包,理解速度不行。

没别的办法,理解的产能提不上去,那就把理解的成本降下来。让 AI 干完活之后,顺手把"备课"也做了,把变更的来龙去脉整理好,摆在你面前,你只需要沿着台阶爬。

这就是我做 /understand 这个 skill 的初衷。

二、我的尝试:/understand,让 AI 指着代码给你讲解

/understand 是我的 goal-workflow 工作流里的一个技能,它干的事很简单:把你刚生成的改动(通常是 AI 写的)变成一个可以交互的审阅网页,帮你在采纳之前吃透这次改动。

我换了个思路:别让 AI 替你读代码,让它指着代码给你讲解。

区别在哪?前者给你一篇总结,飘在半空;后者的每一条解释都钉在具体的代码行上,指着这一段讲这一段。你拿到的不是转述,是带定位的导读,读到哪一段,屏幕上就是哪一段。

以实现这个pigo的issue为例:

工作流程三步:

第一步,扫描变更。

1
python3 understand.py scan

以当前分支和主分支的 merge-base 为基线,把这次变更一网打尽:已提交的、已暂存的、未暂存的、连没跟踪的新文件都不放过。解析成结构化的 diff 数据。

事实上你也可以指定多个变更,某一时间段的变更,某个需求的变更等等,提示词由你写,你可以自由的圈定范围

第二步,Agent 通读改动,逐段写注释。

这一步是灵魂。Agent 把每处改动读一遍,然后给关键段落各写一张"卡片",每张卡片两个东西:

  • 相关单位需求——这段代码是为了满足哪条需求而存在的。这个依据不能瞎编:优先从 commit message、需求文档、issue 里找真实出处;实在找不到,就明确标注为"推测意图"。
  • 代码解释——大白话讲这段在干嘛、为什么这么写、有什么坑。比如"这里把 Instant 改绑成 OffsetDateTime,因为 PG 客户端不认 Instant,不改运行期必炸"这种,才是真正有用的注释。

第三步,渲染成一个网页。

1
2
python3 understand.py render
open .understand/report.html

产出是一个单文件 HTML,长这个样子:

  • 左边是变更文件的目录树,按真实项目结构排列,每个文件标着 A/M/D/R 状态和增删行数;
  • 右边是所选文件的语法高亮 diff,增、删、未变更代码一眼可分,行号是文件真实行号;
  • 右侧边栏就是第二步生成的卡片流:一张需求卡片 + 一段大白话解释,点击卡片,右侧 diff 会跳到对应代码行,高亮闪一下。

使用体验有点像:一个刚写完代码的同事,把 diff 推给你,然后陪你逐段过一遍,指认每一处改动背后的需求和理由——只不过这个"同事"三秒钟就能到位,而且随叫随到。

三、几个我特意坚持的设计细节

做这个 skill 的时候,有几个决策我纠结过,最后都坚持了,说说为什么。

一是"推测意图"必须显式标灰,不许伪装成事实。

AI 最讨嫌的地方是它永远语气笃定。如果让它写"这段对应需求 X",它会毫不犹豫地编一个听起来很合理的需求 X 出来。但一个需要是编的,这个注释就从导读变成了误导——你以为你在学代码的真实意图,其实在学 AI 的脑补。

所以 annotations 里专门有一个 inferred 字段:找到真实出处的需求,正常展示;纯属推测的,前端渲染成灰色的"推测意图"标签。诚实比好看重要。

二是解释必须锚定真实行号,点击必须能跳。

前面说了,这个 skill 和"让 AI 写篇总结"的本质区别就是锚定。所以注释的坐标用的是文件真实行号(不是 diff 里的序号),点击卡片必须跳转、必须闪动高亮。解释不许离开代码独立存在——你想看解释,就得看着代码看。

三是注释密度刻意克制,只讲关键段落。

逐行注释听起来很认真,实际是灾难——满屏卡片等于没有卡片。我的规则是每个重要文件 1~5 条,只挑三类地方下笔:新增的核心逻辑、边界和易错点、最能体现需求的段落。专挑讲决策的地方下笔,其余的闭嘴。

四是单文件产物,离线可用。

report.html 是一个单文件,不依赖任何服务。这意味着它可以进 code review 的评论、可以扔进群聊、可以归档到 docs/ 里——三个月后考古这段代码时,当年的讲解还在。

四、它和 /review-it 是一对搭档

在 goal-workflow 里,/understand 的定位是 /review-it 的"理解型搭档",这两个是一套组合拳:

  • /review-it 问的是"这段代码有没有问题"——它挑毛病、验证发现、迭代修复,对代码负责;
  • /understand 回答的是"这段代码为什么存在"——它讲意图、讲需求、讲理由,对你负责。

一个管质量,一个管理解。合起来才是一个完整的 review。Review 这个词本义就是"重新看一遍",既看它对不对,也看它是什么。

一个可行的日常开发顺序是:AI 生成代码 → /review-it 把明显的问题筛掉修掉 → /understand 生成审阅网页 → 我花十几分钟逐段过卡片 → 确认吃透了 → /ship-it 交付。理解这道工序,被明确地放进了流水线,而不是靠"回头再看"这种永远不会发生的口头承诺。或者将 /understand 放在 /ship-it 之后。


/understand 是 goal-workflow 的一部分,开源在 github.com/smallnest/goal-workflow,安装:

1
npx skills add smallnest/goal-workflow --skill understand

在 Claude Code 里输入 /understand,或者直接说"解释一下这批新生成的代码",就能用了。工作流介绍页:https://goal.rpcx.io/index_cn.html

欢迎你反馈使用体验和优化建议。