Think Deep,Work Lean

让 Agent 动手前先做 3 件只读的事,返工少一半

Posted on By zack

大家好,我是Zack。

先说一个我这周踩了三次的坑。

让 agent 改一个脚本,它改完说”好了”。我一跑,报错。把报错贴回去,它又改,还是报错。来回四轮,最后发现——那个报错在我让它改之前就存在。

四轮里三轮是白跑的。

后来我改了一处:让它动手之前,先做三件只读的事。返工次数直接砍了一半。

原来的做法:上来就改

我以前的提示词长这样:

scripts/post_one.js 跑不通了,帮我修一下

这句话有三个坑。

第一,它不知道改之前是什么状态。改完还是红的,它以为是自己改坏的,就接着改本来没问题的地方。

第二,我贴给它的报错夹着一堆无关的东西——本地没提交的其他改动、上一次跑留下的缓存。

第三,它手里那份文件可能是旧版本。同一轮里我自己改过一次,它还按上一版的行号下手。

三个坑最后都变成同一件事:返工。

现在的做法:动手前先做三件只读的事

我现在的任务开头固定加一段:

动手之前先做下面三件事,把结果贴给我,这个阶段不要改任何文件:
1. 跑一遍基线,记录当前结果
2. 报错先缩到最小复现
3. 重新读一遍你要改的文件当前版本
三件事做完,等我确认再动手。

关键是最后那句”不要改任何文件”。不写这句,它大概率顺手就改了。

第一件:先跑一遍基线

基线就是”改之前,现在是什么状态”。绿的还是红的,红在第几行。

改完再跑一次,跟基线一比,就知道是它改好的还是本来就好的。

我这个运营仓库 scripts/ 下有 59 个 js 文件,全量语法检查跑一遍 1.5 秒,结果 0 报错:

# 基线:59 个文件,1.5 秒出结果
for f in scripts/*.js; do node --check "$f"; done

1.5 秒换后面不用猜,这笔账怎么算都划算。

不同项目跑基线的命令不一样,常用的就这几条,直接抄:

# Node 项目:跑测试;只看改动的加 --onlyChanged
npm test -- --silent
# Python 项目:-q 精简输出,红了直接看失败用例名
pytest -q
# Go 项目
go test ./... 2>&1 | tail -20
# 实在没有测试的,先做语法检查当基线
for f in scripts/*.js; do node --check "$f"; done

跑完让它把结果原样贴出来,别让它总结成”测试通过”。贴出来的原文里有几条用例、挂在哪一行,这些细节总结完就没了。

没有现成测试也没关系,让它先补一个最小的:跑得起来、能过能挂就行,别追求覆盖率。

第二件:报错先缩到最小复现

日志别整段贴。300 行的堆栈,有用的往往只有中间十几行。

缩复现我用一个命令:

# 把没提交的改动先收起来,只留能触发报错的那部分
git stash push -m "tmp: 排除无关改动"
# 再跑一次,看还复现不
git stash pop   # 确认完放回来

还复现,说明跟那些改动无关,范围立刻小一半。

再不行就新建个空目录,只放能触发报错的那个最小输入。

它拿到的复现范围越小,定位越快——这个不用解释,你想想自己 debug 也一样。

第三件:让它重读当前文件

它改错行,多半不是笨,是它手里那份文件过时了。

同一轮里你自己动过一次,前面插了 12 行,它还按旧行号去改,位置就全偏了。

所以我在任务里写死一句:

动手前先重新读一遍目标文件的当前内容,不要凭上一轮的记忆改行号。

补丁打不上、改的位置对不上,先怀疑这个,别怀疑它能力。

前后对比

同一类任务,我这个月跑了大概二十次,体感差别是这样:

对比项 原来的做法 加三件只读的事
动手前步骤 0 步 3 步(都是只读)
动手前多花时间 0 约 1-2 分钟
平均返工轮次 3-4 轮 1-2 轮
归因错误(把旧问题当新问题) 三次里有一次 基本没有
改完不敢确定是不是它改好的 经常 有基线,能确定

多花的 1-2 分钟,换的是少跑两轮。一轮来回按 5 分钟算,净赚。

数字是我自己这二十来次的体感,不是严格统计——样本就我一个人,你那边项目不一样,可能没这么明显。

两条能迁移到自己活儿里的原则

第一条:只读的事让它多做,写的事让它少做。

跑测试、读文件、查日志,这些不会搞坏东西,让它放开跑。真要改文件,一步一 commit,坏了只退一步。

具体就两条命令,提交前必看:

# 看一眼它到底动了几个文件、各改了多少行
git diff --stat
# 按一个小步提交,别攒到最后
git add -p src/xxx.js && git commit -m "fix: 只改报错那一段"

git diff --stat 这行很值:它说改了一个文件,stat 显示动了四个,你就知道该问一句了。

我吃过亏——提交历史里躺着一次 120 files changed, 11669 insertions 的整包提交,出问题只能整包退,退完连好的改动一起没了。

第二:它说”好了”不算,基线说了才算。

验收看的是基线到现在的差值,不是它自己的总结。

顺带说一句,这个原则对人也一样。别人交给你一个”改好了”的东西,先问一句”改之前是什么样”。

还有两个我没解决的问题

这三招在单文件、能跑起来的任务上好使,但有两种情况还是没辙:

一是跑一次要十几分钟以上的任务,基线成本高,我目前是隔几天才跑一次完整基线,中间靠局部冒烟顶着。

二是涉及多个服务联调的,基线本身就不稳定,绿和红会自己跳,这种我还没找到省事的办法。

有更好做法的,欢迎在留言里指个路。

以上就是我这周在用的三件只读的事。

你现在让 agent 改东西之前,会先让它跑一遍基线吗?还是跟我以前一样上来就改?

欢迎留言聊聊你的做法,踩过的坑也可以一起说说。

公众号:Zack说AI