编码 agent:改代码要闭环
会写代码不难,难的是改完自己验证。测试就是编码 agent 的眼睛。
学完这节你能做到
- 设计一条「改动 → 验证 → 修正」的闭环,并让 agent 自己跑完
- 在整文件重写与精确补丁之间做出选择
- 为大仓库设计定位代码的检索策略
写代码不难 —— 模型一直都会。难的是改完自己知道对不对。 一个没有验证闭环的编码 agent,本质上是在猜。
闭环的三段
定位 ──→ 编辑 ──→ 验证
↑ │
└──── 失败回灌 ────┘
三段都做好才有闭环。缺了验证,你得到的是「看起来合理的 diff」; 缺了失败回灌,它第一次没改对就卡住了。
定位:在大仓库里找到该改的地方
工具就那几个:grep、find、read、ls。差别在策略:
| 场景 | 顺序 |
|---|---|
| 有报错信息 | 从堆栈的文件行号直接 read → 往上找调用方 |
| 有功能描述 | grep 关键词(UI 文案、路由、常量名)→ 顺依赖找 |
| 要改一类模式 | grep 出全部命中 → 先数量后明细 → 分批改 |
| 完全陌生 | ls 顶层 + read README + package.json → 建立骨架认知 |
最容易出事的是第三类:grep 出 200 处,全量塞进上下文,一次改完 ——
窗口撑爆、改错了也回不去。正确做法是先要数量和分布,再分批。
「这个功能在哪实现」这种问题,翻十几个文件才能得出一句结论 —— 中间过程主 agent 完全不需要。这是 L2 讲的 sub-agent 的最佳场景。
编辑:整文件重写 vs 精确补丁
整文件重写(write) | 精确补丁(edit) | |
|---|---|---|
| token 成本 | 高:要输出整个文件 | 低:只输出改动片段 |
| 出错方式 | 容易漏掉没读到的部分 | 定位串了会改错地方 |
| 大文件 | 很容易超输出上限 | 无压力 |
| 适合 | 新建文件、小文件、结构性重写 | 绝大多数改动 |
Pi 的 edit 工具在 details.patch 里给出统一格式的 patch(给 SDK 消费方),
details.diff 给 TUI 渲染 —— 又是 content / details 分离的例子。
「把这个字符串替换成那个」在文件里有多处匹配时,改错位置。 所以补丁工具应该:匹配不唯一时报错并列出全部候选,而不是默默改第一处。 这条规则能挡住编码 agent 最常见的一类静默错误。
并行修改还有个坑:同一个文件被两个工具调用同时改。Pi 的答案是
withFileMutationQueue(absolutePath, ...),把读-改-写整个窗口串行化。
自己写编辑类工具时照抄。
验证:agent 的眼睛
按「反馈速度 ÷ 可信度」排,agent 应该优先用快的:
| 手段 | 速度 | 覆盖 |
|---|---|---|
语法/类型检查(tsc --noEmit) | 秒级 | 类型与拼写 |
| lint | 秒级 | 风格与低级错误 |
| 单测(相关文件) | 十秒级 | 逻辑 |
| 全量测试 | 分钟级 | 回归 |
| 构建 | 分钟级 | 集成 |
在 AGENTS.md 里把这个梯子写清楚,收益极高:
## 验证梯子(按顺序)
1. `bun run typecheck` —— 每次改完必跑,10 秒
2. `bun test <改动涉及的文件>` —— 逻辑改动时跑
3. `bun run build` —— 只在改了构建配置或依赖时跑(3 分钟,别乱跑)
真实仓库里经常有一批长期失败的测试。agent 不知道这件事, 会花很多轮去「修」一个和它无关的失败。 在 AGENTS.md 里写明「这些测试本来就挂,别管」,或者让验证命令只跑相关子集。
失败回灌:把报错原样喂回去
这是编码 agent 最有效的一环,也是最容易做砸的:
✅ tsc 的完整报错(文件:行:列 + 消息)—— 原样给
✅ 测试失败的断言消息 + 期望/实际 —— 原样给
⚠️ 完整的 200 行堆栈 —— 截断,保留最上面的应用栈帧
❌ 「构建失败」四个字 —— 等于没说
一个实用技巧:报错超过 N 行时,保留头尾。 头部有具体错误,尾部常有汇总(「3 个测试失败」)。中间的重复堆栈可以省掉。
大改动:分步且随时可停
「把这 40 处调用都改成新 API」不该一轮做完。分步的三个理由: 上下文撑得住、错了容易回滚、人能中途叫停。
推荐节奏:
1. 先改 1 处 → 验证 → 确认方案对
2. 按目录/模块分批,每批改完就验证
3. 每批之后报告进度(改了几处、还剩几处)
4. 遇到不确定的(比如某处语义确实不同)停下来问,而不是自作主张
第 4 条要写进提示词。默认行为是模型倾向于「硬着头皮做完」, 而在重构里,一处自作主张的语义变更可能几个月后才暴露。
交出去之前
编码 agent 的产出必须能被人审。三条硬要求:
- 改动可 diff —— 别在版本控制之外改文件。
- 改动范围可预期 —— 「改这一处」就别顺手格式化整个文件 (在 AGENTS.md 里明确禁止无关格式化)。
- 说清做了什么、没做什么 —— 包括「有 3 处我没改,因为它们的语义确实不同」。
编码 agent 改完代码就报告完成,但用户经常发现根本没编译通过。最该先补哪一环?
这一节的结论
- 定位 → 编辑 → 验证 → 失败回灌,缺一段就不是闭环。
- 大范围搜索先要数量和分布,再取明细;定位类任务适合派子 agent。
- 补丁优于重写;匹配不唯一时必须报错,不能默改第一处。
- 验证梯子按秒级 → 十秒级 → 分钟级排,写进 AGENTS.md。
- 报错原样回灌(长的保留头尾);大改动分步、随时可停、不确定就问。