第一次把 Agent 接到真实仓库时,我犯过一个很土的错:只盯着“它能不能做完”,没盯着“它最多能跑多久、最多能走几步”。结果某次工具调用卡在外部接口,它一边重试一边换策略,token 和墙钟时间一起烧,最后我手动杀掉,现场还一堆半成品文件。
从那以后,我把超时和步数预算当成和权限同级的安全项。不是为了虐待 Agent,而是承认:自动化一旦没有硬上限,失败模式会从“报错”变成“悄悄耗尽”。
为什么“看起来快结束”不可靠
Agent 的轨迹很会制造希望:每一步都有日志,每一步都像在进步。可进步不等于收敛。常见假象包括:
同一类错误换着措辞重试
在几个文件间来回改,测试始终红
搜索范围越扩越大,上下文越来越脏
等待外部资源时既不失败也不成功
没有预算时,你只能靠盯盘。盯得了一次,盯不了每次。预算的意义是:到点必须停,停了才能进入人类决策,而不是无限接近成功。

图:没有预算时的假象:盲重试、来回改、搜索膨胀、干等(原创示意图)
我设的两类上限
1. 时间上限(墙钟超时)
针对整次任务,也针对单次工具调用。
任务级: 例如本地小改最长 15 分钟,调研类最长 30 分钟。超时后保存状态、退出,而不是“再试一轮”。
工具级: 网络请求、安装、测试套件,各自有更短超时。避免一个慢调用拖死整次运行。
时间上限要按环境调:CI 机器和笔记本不同,外网和内网不同。我的原则是宁短勿长——短了可以人工续跑;长了账单和脏现场先来。
2. 步数 / 工具调用预算
把“一步”定义清楚:一次模型回复、或一次工具调用、或两者合计。我个人常用的是:
简单定位 bug:最多 N 次工具调用
跨模块重构:放宽,但仍有上限,且写操作预算更紧
纯只读调研:步数可稍宽,但时间仍卡死
步数预算能挡住“逻辑上不收敛但一直在动”的情况。光有时间不够:机器很快时,一分钟也能空转上百步。

图:两类上限与三层预算:时间、步数、只读/写入/高风险(原创示意图)
预算要分层,不要一刀切
我现在会把预算拆成三层:
只读预算: 搜索、读文件、跑只读检查——相对宽
写操作预算: 改文件、格式化、本地提交——明显更紧
高风险预算: 推远程、改基础设施、装依赖、删数据——极紧,甚至默认 0,必须人类抬栏
这样 Agent 可以在只读阶段多探索,但不容易在写阶段把仓库拧成麻花。以前我用单一总预算,它会把步数花在反复写入上;分层之后,写入花超会提前停,留下更多只读线索给人类。
超时后做什么,比超时本身更重要
超时不是成功,也不是简单失败。我要求运行时至少做三件事:
冻结现场: 记录最后目标、已改文件列表、最后错误签名
尽量可恢复: 能 git 恢复就恢复到安全点;不能恢复就明确标“脏”
给人类一句可读摘要: 别只甩原始日志;说明卡在哪一类问题上
没有这三步,超时等于制造烂摊子。有了这三步,超时是一次可交接的暂停。
和重试策略的关系
预算不是禁止重试,而是给重试封顶。我的经验是:
瞬时网络错误:短重试 + 退避,计入工具级超时
同一错误签名重复出现:不要吞预算盲重试,直接换路或停
写失败:默认不自动重试,先报告
“再试一次”很便宜的错觉,在 Agent 场景里特别危险,因为它会乘以模型调用和后续推导。预算表上的数字,就是用来对抗这种错觉的。

图:超时后三件事:冻结现场、可恢复、可读摘要(原创示意图)
怎么观测:没有计数就不算设了预算
我踩过的另一个坑是:配置里写了 max_steps=20,但日志里看不到当前步数,挂了才发现计数器没接上。
所以上线预算时,我会同时要:
每步日志带
step=i/max任务结束带原因:
completed/timeout/budget_exhausted/aborted_by_user简单仪表:近一周因预算耗尽停下的比例
若耗尽比例奇高,可能是任务切得太大,或工具太容易失败;若几乎从不为预算停下,可能是上限虚高,等于没设。
给产品/业务同学的一句话翻译
如果你不写 Agent 运行时,只需要记住:
任何会自己循环调用模型或工具的东西,都要有“最多跑多久、最多走几步”的硬开关;开关触发后必须能安全停,并且告诉人卡在哪。
这和网页请求超时是同一类工程常识,只是 Agent 的循环更隐蔽,更容易被“它还在思考”安慰过去。
实操上我怎么写进任务说明
给 Agent 的任务提示里,我会显式写:
本任务墙钟上限
工具调用上限
允许的写操作次数
超时后必须输出的摘要字段
写进提示,不只是写进平台配置。原因是:有的 Agent 会自己开子任务;提示里的预算意识,能减少它在子任务里“假装没有上限”。当然,真正强制仍靠运行时;提示只是双保险。
收尾
给 Agent 设超时和步数预算,本质是承认自动化会失败,而且失败可能很贵。我的默认立场是:
时间与步数都要有硬上限
只读、写入、高风险分层
超时必须可交接,不可只杀进程
日志里要看得见计数与停止原因
别让它无限跑。 宁肯多次短跑 + 人类续杯,也不要一次长跑烧出不可解释的现场。预算不是冷漠,是对系统和账单的基本礼貌。
预算数字从哪来:我怎么定初始值
没有神圣数字,只有可调整的起点。我的起点通常是:
个人本机、小修复:15 分钟,工具调用 25 次,写操作 8 次
功能开发会话:30 分钟,工具调用 40 次,写操作 15 次
只读调研:20 分钟,工具调用 40 次,写操作 0
跑一周看耗尽率。若总是在还差一口气时耗尽,说明任务切太大或上限略紧,就微调;若几乎从不触顶,把上限降下来,逼任务更早暴露不收敛。
数字写进配置,也写进周记。靠感觉调,最后会漂回“反正给大一点”。
子 Agent 的预算怎么切
一旦有子 Agent,总预算要切块,而不是每个子 Agent 各自拿一份满额。否则五个子任务等于五倍账单。我的做法是:父任务持有总预算,子任务申请配额;父任务可回收未用完的配额。实现可简可繁,但概念上要有“同一笔钱”。
若平台还不支持配额下发,至少在提示里写死子任务上限,并在父任务日志核对。软约束好过没有。
超时与用户体验
对人可见的产品里,超时要转换成可读状态:“已暂停:达到时间上限,你可以续跑或收窄任务。”不要只显示转圈消失。对内工具也一样:给续跑按钮,等于承认预算是暂停而非死刑。
续跑时应继承冻结现场,而不是从零再探索一遍。否则预算系统只是把一次长烧变成多次长烧。
和成本告警的配合
步数/时间是近端保险丝,账单告警是远端保险丝。我建议两层都有:
近端:单任务立刻停
远端:日/周额度告警,防止很多小任务合谋杀死预算
只有远端时,单任务仍可能失控很久;只有近端时,小任务洪水仍可能把月账单打穿。
失败案例(简化复盘)
一次“帮我把测试弄绿”的任务,没有写操作分层。Agent 在失败断言间反复改实现、改测试、再改实现,步数耗在写入上,最后测试仍红,工作区却已难读。若当时写操作预算为 5,它会更早停在“测试仍红,已尝试的方向如下”,我就能接手做判断。预算不是让它更聪明,是让失败更干净。
收尾补一句
时间和步数都要有硬上限。 上限会冒犯那种“再给我两分钟就能好”的幻觉——恰恰该冒犯。自动化值得拥有的,是可控的短跑,不是浪漫的长跑。


2026-10-14鱼鱼