为什么先记账,而不是先换模型
agent 跑长任务出问题时,绝大多数团队的第一反应是换一个更强的模型。但换模型解决不了「不知道它在哪一步走偏」这件事。你需要的是一份能在事后逐条复盘的台账:每一步它做了什么、基于什么判断、花了多少、结果能不能验证。有了这份台账,换不换模型、要不要加控制层,都会变成可以用数据回答的问题,而不是靠感觉。
这份台账不用做得很重。原则只有一条:能落进结构化字段的,就不要留成一段话;无法自动验证的东西,尽量少写进去。
每一步该记什么:六个字段
- 步号与时间:用来对齐预算消耗与外部事件(上游报错、网络超时、被抢占)
- 动作类型:读文件 / 写文件 / 调用哪个工具 / 请求人工确认。类型要收敛成有限枚举,否则没法统计
- 输入摘要:这一步看到了什么——文件名加哈希、检索命中的条数、上游返回的状态码,不要存整段正文
- 判断依据:为什么选这一步。来自控制层就写下候选列表与选择理由;模型自由发挥就如实标注「无显式依据」
- 成本:token 数、耗时、外部调用次数分开记,这三项的增长方式完全不同
- 产出与可验证性:产出了什么(文件路径加哈希、结构化结果),以及这一步的结果有没有自动判据、通过了没有
一个实用判据:如果一份台账里超过一半的步骤,「判断依据」写的是「无显式依据」,说明这个 agent 还没有真正的控制层——它只是在按惯性往下走。
落盘:一份只能追加的事件流就够了
不要一上来就上数据库。用按行追加的 JSONL,一行一条步骤记录,天然支持中途崩溃后续写,也方便按步号切片回放。需要频繁查询的成本与耗时可以另外汇总成一张小表,但事件流本身保持只能追加、不能修改——一旦允许改历史,事故复盘就没有可信依据了。
- 字段固定,缺项写 null 而不是省略键,否则后续统计脚本会长出一堆分支
- 写入必须是原子的:把这一行写完之后再执行下一步,否则崩溃时丢的恰好是最关键的那一步
- 给每个任务一个 run id,把同一任务的所有步骤串起来,跨任务对比全靠它
用台账回答三个问题
台账不是写给人看着舒服的,它要能回答三个具体问题;回答不了,就说明字段还不够。
- 预算花在哪了:按动作类型汇总成本。如果「重做」和「重新读一遍已有产物」占比很高,是控制层的问题,不是模型的问题
- 失败长什么样:把失败步骤按动作类型分组。集中在一类就是设计问题,散在各类才是模型能力问题
- 哪一步能自动验证:把步骤分成「有自动判据」与「只能靠人看」两组,前者的比例决定了你能把这个 agent 放多远
把台账变成回归门禁
台账最大的价值是被固化下来:从失败案例里挑出最有代表性的若干条,连同当时的输入一起存成回归集;以后每次改提示词、换模型、动工具,先把这批重跑一遍。这样就不需要再争论「这次改动会不会变差」——它有一个可复现的答案。
回到开头:换模型提升的是「单步做对的概率」,台账与回归提升的是「你能发现它做错、并定位到哪一步」。后者是你能自己控制的部分,也应该先做。