loading

Loading

探索与发现

首页 Agent 工程

Agent 步数预算与提前终止的工程账

分类:Agent 工程
字数: (2651)
阅读: (1)
0
摘要:按线性估算的步数预算会低估多轮 Agent 成本一到两个数量级。拆开硬上限、软预算和提前终止信号,说清楚哪一层对应哪类失败模式。

为什么线性预算总是低估成本

很多团队给 Agent 定预算的方式是:一次调用大约多少钱,乘上预计的工具调用轮数,加一点缓冲。这个算法的问题在于,多轮循环里每一次工具调用都会把结果塞进上下文,后续请求要带着全部历史一起发送。成本不是 N×C,而是接近 N 的平方级增长。一篇关于多轮工具调用成本的文章里给过一个具体对比:一段 9,000 token 上下文的单次调用约 $0.03,同样内容跑十步、每步追加工具结果后,总上下文抬到约 472,000 token,成本变成单次基准的 43 倍。这个倍数不是噪声,它说明按步数做线性预算从第一天就是错的。

所以步数预算的真正职责不是“省点钱”,而是防止一部分永远结束不了的循环。预算太紧,任务做不完;预算太松,失败模式退化成失控重试。两种情况都落在工程上不完全一样的区间。

硬上限和软提示解决两个区间

Anthropic 的 Messages API 里,max_tokens 是硬约束,限制一次请求的输出总量,包括思考和正文;达到上限会返回 stop_reason: "max_tokens",答案被截断。但要注意,工具调用循环中的每个请求都有自己的 max_tokens,它只约束单次响应,不管整个任务。十个请求、每次 4,000,加起来可以生成到 40,000 输出 token,输入另算。

task_budget 是另一条线,放在 output_config 里,用 total 字段告诉模型整个循环大概能用多少 token,涵盖思考、工具调用、工具结果和输出。文档里写得明确:这是软性提示,不是硬性上限,模型可能在一次操作中超过预算,输出仍然只被 max_tokens 摁住。可接受的最小值是 20,000 token,更低会直接返回 400。预算小到不合理时,模型会缩小任务范围或提前停止,表现得像是拒绝了任务。

这种设计对常驻 Agent 是合理的:硬上限保证一张账单不会被单次调用打穿,软预算让模型在接近尾声时改变行为。把它当硬上限用就会理解错。

提前终止的三个可信信号

判断该不该停,工程上比“跑满 N 步”更细的信号大概是这几类。第一是工具响应里的明确终止状态。有团队把 SUCCESS/FAILED 写进工具响应,替换掉模糊的错误码以后,每任务工具调用次数从 14 次降到 2 次。模型停止重试不是靠步数逼停的,而是因为结果终于告诉它事情结束了。第二是重复调用同一工具的模式,也就是断路器。Claude Code 的迭代循环问题在公开的 GitHub Issue 里有记录(#6004、#2283、#2391 等),它的工程价值不在于“免疫循环”,而在于把循环拉回来的速度更快。第三是产出量的边际递减:随着轮次推进输出越来越少、信息增量趋近零,就可以终止。

这三个信号分别对应“做完了”“卡住了”“在磨洋工”。只靠一个步数计数器,三种状态无法区分。

不同 Agent 的默认步数并不通用

常见的开源实现给的默认值可以作一个参照:ToolCallAgent 一般 30 步,SWEAgent 大概 20 步,PlanningFlow 走配置。有经验建议是简单任务 5–10 步,中等任务 15–25 步,复杂任务 30–50 步,超过 50 步就拆子任务。这些数字没法定成标准,因为单步的成本取决于工具返回结果的大小。一次返回 8,000 行日志的调用,和一次返回 200 字摘要的调用,标称步数一样,实际 token 量差一个数量级。按步数预算需要先对“步”做分层,至少把工具输出尺寸作为步数权重的一部分。

可缓存前缀的 token 成本也影响步数设置。以 Claude 5 分钟缓存为例,写入是基础输入价的 1.25 倍,读取是 0.1 倍;Claude Opus 5.5 和 Claude Sonnet 5.5 的读取甚至只有 0.05 倍。如果 Agent 循环每次都变更了系统提示的前缀、带上时间戳或运行 ID,缓存就永远命不中,这时候哪怕步数预算一样,成本实际高出一个量级。把易变内容挪到最新用户消息里、保持工具定义稳定,这些是让步数预算有意义的前置条件。

预算感知如何影响模型行为

给模型看到剩余预算,做的选择并不相同。有研究指出,带显式 token 预算的 Agent 会优先高信息量的工具调用,跳过冗余验证。风险在另一个方向:预算写在最开头还是每轮递减。Anthropic 文档里有明确提醒,客户端如果在每个后续请求中递减 task_budget.remaining,变更后的值会打破缓存前缀,成本反而可能增加。正确做法是在首个请求里设置一次。考虑到最小 20,000 的下限和缓存影响,“预算感知”更像一个启动时附加的航向信息,而不是实时倒计时器。

配套还有一个反直觉的观察:上下文压缩并不是压得越狠越省。一项研究发现把上下文压到 99.3% 之后总成本反而升高,因为它迫使 Agent 重新获取已经检索过的内容。比较稳的区间是减少 50%–80%。这直接影响提前终止的判断——预算不够时快速压缩上下文会引入新的反复检索循环。

可跑的终止策略长什么样

一个不依赖框架的实现大致是:每步前检查当前 token 用量与首轮设置的任务预算,超过 90% 就触发收尾模式;同一工具在最近几轮里返回了相同签名两次以上就中止该路径;工具响应带明确的终止状态就直接状态转移;每一轮记录输出的信息增量,连续两轮低于阈值就收工。括号里这些阈值都得按业务类型调,做日志分类的 Agent 和做多文件重构的 Agent 的合理步数没有共享基准。

死循环不会因为开发人员写下了这几个数字就永久消失。比较可行的预期是,让代价高、收益低的那种循环先被截住,然后在观测里能看到“停在哪一步、为什么停”。没有这个前提,调步数上限只是在闭着眼睛改旋钮。

每一步的花费来自哪里

更根本的一点在于开销的构成。每一次调用重新发送的系统提示通常 2,000–5,000 token;中等规模的工具集本身还有序列化成本,公开数据里单独一次调用的工具定义开销能到 55,000–134,000 token。动态加载是把这部分压低的手段,有记录的实现从 134,000 降到 8,700,减少 85%。并行工具调用则通过减少往返次数压低重复支付的输入侧成本。没有这两件事参与,光靠设定更低的步数上限,Aent 能做的事情会以可见的质量下降作为代价。终止策略是环上的急救手段之一,不是替代基本设计的预算削峰。

转载请注明出处: 皮哈皮阿

本文的链接地址: https://blog.phpat.com/agent-engineering/649.html

手机扫码阅读

微信或手机浏览器扫一扫,随时随地随心阅读与分享

您可能对以下文章感兴趣
1 / 1
预览图