11 月 2 号挂到 arXiv 上的那篇 APG(arXiv:2611.02349,cs.SE),我到现在也没把它的实现读明白。SVF 我一行没写过,LLVM-IR 上面架图数据库那套东西更不是我日常碰的范围——按我自己一贯的标准,看不懂的代码不该拿来用,哪怕它能跑。但里面有一个数字我还是抄了:38 项原子能力里,35 项在基准修复运行产生的分析请求上,首次尝试就生成成功查询的比例超过 50%,其中 13 项到了 100%。
抄的是这个度量口径,不是它的代码。理由很实际:这套口径我自己用几十行脚本就能复现一遍,复现过的指标才有资格进到自己的判断里;而它背后的图数据库实现我没有能力验证,那就先放着。这个指标真正测的不是“这套工具全不全”,而是一个没读过文档的调用者第一次伸手够不够得着——给 agent 配工具这件事上,最容易被忽略的恰好是这一面。
我手上的 agent 挂了十几个工具,查库、跑测试、读日志都走它,用得顺不顺一直靠翻会话记录凭印象判断。印象不可靠,尤其是被重试过的调用,翻记录的时候看着像是成了。于是我把日志导出来,按工具名分组算了一遍首次调用即成功的比例。
判定口径先说清楚,不然后面对不上:同一次对话里第一次调用某工具,参数通过校验、没有因为必填字段缺失被打回,直接返回了非错误结果,才记为一次首次成功。被重试过的第二次第三次一律不算。报错但拿到了有用信息的调用怎么算,这个我到现在也没想明白,先按最严格的方式算,宁可把成功率估低。
- 把调用日志导成 JSONL,一行一次调用:
{"turn":12,"tool":"search_code","ok":true,"retry":0,"args_ok":true}
{"turn":12,"tool":"run_test","ok":false,"retry":1,"args_ok":false,"err":"missing field: cwd"}
retry 是同一 turn 内对同一工具的重复调用次数,args_ok 记的是参数校验有没有直接挂掉,两个字段得在埋点的时候就分开记,事后补不回来。
- 统计脚本不用装任何东西,标准库够:
import json, collections
first, total = collections.Counter(), collections.Counter()
for line in open("calls.jsonl"):
r = json.loads(line)
if r["retry"]: # 重试过的调用直接跳过
continue
total[r["tool"]] += 1
if r["ok"] and r["args_ok"]:
first[r["tool"]] += 1
for t, n in total.most_common():
print(f"{t:16s} {first[t]:3d}/{n:3d} {first[t]/n:6.1%}")
- 跑一遍:
$ python first_try.py | head -5
search_code 48/ 52 92.3%
run_test 31/ 47 66.0%
read_log 19/ 41 46.3%
edit_file 12/ 38 31.6%
query_db 3/ 4 75.0%
跑完先别急着下结论,这里有几个坑我是一条一条绕过来的。
query_db 那行 75% 看着靠前,分母只有 4,翻日志才发现整段会话里它就被调过四次。分母小于 10 的行我后来单独标出来,不进排序,否则排序会骗自己。百分比在样本这么小的时候没什么意义,这个道理放在那 13 项 100% 上同样成立,我自己那份统计里就踩过一次。
edit_file 的 31.6% 我一开始以为是模型笨,拆开看,38 次里有 21 次是同一类参数错误——它总想一次改多个文件,而我的 schema 只收单个 path。这不是模型的问题,是接口没给对路,改完 schema 之后这一项回到 80% 上下。💡 小技巧:先看失败是不是聚成一类,聚成一类的基本都是 schema 的锅,散着分布的才轮到怀疑模型。
第三个坑比较丢人:retry 字段是我后来才加的,早期那批日志没有这个字段,我干脆没把它们算进去,样本少了一截。所以这份统计严格说只覆盖最近两周,别拿它当长期结论。
划重点:第一,工具顺不顺手别凭印象,按工具名分组统计首次调用成功率,几十行脚本就能跑;第二,分母小的行要单拎出来看,百分比在 n 小于 10 的时候基本没有参考价值;第三,成功率低先查失败有没有聚集成同一类参数错误,那通常是工具描述或 schema 的问题,不该先怪模型。
你可以自己试试:把手头那个 agent 的日志导出来,先只算你最常用的三个工具,看这个数和你印象里差多少,差得越远越值得往下拆。
至于 APG 里那套“把分析能力拆成原子能力供 agent 自选调度”的思路,我暂时不搬到自己这套工具集上——手头的任务还不需要跨图查询,硬搬一个自己看不懂的东西进来,等哪天真的需要了,大概还是要从头读一遍它的证据轨迹怎么留。这条先记在这儿,下次遇到再翻回来。
