跳转到主要内容

Agent 运行的单位经济学:多步骤系统的成本核算

Token 定价掩盖了 agent 开销的真实去向。按角色和工具调用进行埋点统计的「每个成功任务成本」,才是团队可以据以行动的指标。

机器人机械部件的详细特写,在影棚灯光下被强调。

大多数 agent 仪表盘上缺失的那个数字

问一个工程团队 agent 任务要花多少钱,得到的答案通常是 token 数量乘以公开单价。这个数字很容易算出来,却几乎从不描述业务真正关心的事情。一个完成的任务可能涉及:planner 拆解请求、executor 调用工具、verifier 检查结果,以及验证失败时运行的修复循环。其中每一步都是一次独立的模型调用,往往针对不同的模型,有时针对同一个 prompt 但上下文略有变化。token 计量器把这一切汇总成一行条目,抹掉了结构。

没有这种结构,采用决策就变成了猜测。团队无法判断提高重试上限带来的完成率提升是否足以抵消额外开销,因为额外开销没有与基线分开。团队也无法判断某一类子任务是否该交给更便宜的模型,因为没有按子任务划分的质量或成本信号。真正重要的单位是每个成功任务的成本,与每个被放弃任务的成本并列计算,而要做到这一点,唯一的办法是对运行本身进行埋点。

一个任务包含多次调用

多步骤 agent 是一个控制流在运行时才决定的程序。planner 可能输出五步,也可能输出十五步。executor 可能只调用一次搜索工具,也可能循环到预算耗尽。verifier 可能第一次就通过,也可能触发两次修复。token 核算看到的是这些调用的总和;它看不到是哪个角色产生的、属于哪个任务,也看不到任务最终是否完成。因此总开销上升是模糊的:可能是流量增加,可能是重试变多,也可能是某次 prompt 改动让每次调用的上下文都膨胀了。

重试和失败的工具调用被计费却不可见

失败的工作和成功的工作计费完全相同。一次工具调用在模型已经生成长参数载荷之后超时,既消耗了 token,又什么也没产出。一次 verifier 拒绝触发完整重新规划,会让 planner 成本翻倍。在按 token 的报告里,这些表现为普通用量。在按任务的账本里,它们表现为一个独立的类别,而这正是让它们可被修复的前提。

缓存与上下文复用会改变实际单价

prompt 缓存和上下文复用会以很大的倍数改变一次调用的实际成本,而这些倍数取决于顺序、前缀稳定性以及各角色之间共享了多少上下文。一个保持稳定 system prompt 并追加任务特定上下文的系统,每次调用的花费可能显著低于每次重建 prompt 的系统,即使可见的 token 数相近。任何忽略缓存行为的成本模型都会把这两种设计相互错误定价。实际后果是:prompt 架构是一个成本决策,而不只是质量决策。

Detailed view of a dark electronic audio interface with knobs and buttons.

为每次调用打上任务标识和角色标签

基础是一个贯穿整个运行的关联标识符。每次模型调用、每次工具调用、每次沙箱启动都打上任务 id 和角色标签,例如 planner、executor、verifier 或 repair。这就是把普通的分布式追踪应用到 agent 循环上,而它正是成本报告与成本模型之间的区别。

# 伪代码:每次模型调用一条记录,之后按 task_id 关联
record = {
    "task_id": task_id,
    "role": "executor",
    "model": model_name,
    "input_tokens": prompt_tokens,
    "cached_tokens": cached_prefix_tokens,
    "output_tokens": completion_tokens,
    "attempt": attempt_index,
    "latency_ms": elapsed_ms,
    "outcome": "ok" | "tool_error" | "verifier_reject",
}

outcome 字段让团队之后能把「做这项工作的成本」与「做两遍的成本」分开。cached_tokens 字段让模型对实际单价保持诚实。

分别计算每个已完成任务的成本和每个被放弃任务的成本

对所有任务取平均,会把两个经济特性不同的人群混在一起。已完成的任务是资产;被放弃的任务是纯损失,而且通常两者中更贵,因为放弃与循环相关。把它们合在一起报告,会在放弃率高时美化系统,因为失败的运行拉低了均值,却没有贡献任何价值。

拆分账本:

  • 每个已完成任务的成本 —— 达到已验证终态的任务的总开销,除以这些任务的数量。
  • 每个被放弃任务的成本 —— 触及预算、超时或不可恢复错误的任务的总开销,除以这些任务的数量。
  • 放弃率 —— 两个人群之间的比率,作为与质量并列的一等指标来跟踪。

一个系统可以在每个已完成任务成本改善的同时整体变差,如果它放弃了更多困难任务。只有这一对数字,加上

模型调用不是全部账单。工具调用有自己的价格:外部 API 调用、沙箱或容器时间、向量存储查询、用于产物的对象存储,以及解析和校验工具输出所消耗的算力。对于工具密集型 agent,这些往往比模型开销更大,而它们几乎总是缺席于 agent 仪表盘。把它们归到同一个任务 id 和角色标签上,这样一次查询就能回答一个任务端到端究竟花了多少。

Detailed view of an industrial conveyor belt system used in manufacturing and production settings.

一个有用的纪律是:维护一个成本 schema,维度小而固定——任务 id、角色、资源类别、结果——并拒绝添加无法可靠填充的维度。有缺口的成本模型比粗糙的模型更糟,因为它会招致虚假的精确。

把子任务路由到已测量质量差异的地方

一旦成本按角色归因,路由就成为一个经验问题,而不是品味问题。模式是把范围窄、定义明确的子任务交给更小的模型,把更大的模型留给规划、模糊综合和验证。约束是质量差异必须在真实任务分布上测量,而不能从基准分数推断。路由变更是一个假设:同一任务集、同一 verifier,比较变更前后的完成率和每个已完成任务成本。

诚实的权衡也在这里。激进的路由降低每次调用的成本,同时增加修复循环的数量,因为更弱的模型产生更多 verifier 拒绝。净效果可能朝任一方向,而且只有当修复成本被归因到导致它的路由决策时才可见。跳过测量的团队往往根据轶事在两个配置之间来回摇摆。

把预算耗尽当作路由信号

按任务的预算作为控制信号比作为硬性停止更有用。当一个任务耗尽预算时,这个事件携带信息:该任务类比假设的更难,planner 过度拆解,或者 executor 在一个永远不会返回可用结果的工具上循环。在耗尽时刻连同角色分解一起记录耗尽事件,就把一次失败变成了路由输入。有些系统的应对是把该类任务升级到更强的模型;另一些则收紧 planner 的步数上限。两者都合理;没有账本,两者都无法被发现。

把成本回归与质量回归并列报告

质量和成本一起变动,分开审查必然导致一方以另一方为代价被优化。一次 prompt 改动把完成率提高几个点,同时让修复成本变成三倍,这是一个权衡,不是胜利,应该这样呈现。审查产物是每次发布一张小表:完成率、放弃率、每个已完成任务成本、每个被放弃任务成本,以及任何变化的角色级分解。任一列的回归要么阻止发布,要么以书面理由明确接受。

这改变了什么

转变在于:从核算消耗转向核算结果。token 开销仍然是有用的输入,但它是原料,不是价值单位。一旦成本按任务、按角色、按结果归因,团队真正需要回答的问题就变得可处理了:哪些任务类值得自动化,哪里更小的模型已经够用,哪些失败模式代价高昂,以及一次质量改进是否收回了成本。这些才是决定一个 agent 部署能否在预算面前存活的問題。

分享XLinkedIn永久链接6 分钟阅读

相关阅读

这能回答的问题

Why is cost per token not enough for agent systems?

A single task spans many model calls across planner, executor and verifier roles, plus retries and failed tool calls that are billed but invisible in aggregate token counts. Per-token reporting cannot separate the cost of doing the work from the cost of doing it twice, so it cannot support routing or adoption decisions.

How do you attribute cost to a task in a multi-step agent?

Attach a correlation identifier and a role label to every model call, tool invocation and sandbox start, then join the records by task id. Record outcome and cached-token counts on each record so repair loops and context reuse can be priced separately from baseline work.

Why report cost per abandoned task separately?

Abandoned runs are pure loss and usually more expensive per task than completed ones, because abandonment correlates with loops. Blending the two populations produces an average that flatters the system whenever abandonment is high. Tracking both, plus the abandonment rate, prevents cost per completed task from improving while overall economics worsen.

Is routing subtasks to smaller models always cheaper?

No. Smaller models reduce cost per call but tend to raise verifier rejections and repair loops. The net effect depends on the task distribution and can go either way, so the quality delta must be measured on real tasks rather than assumed from benchmarks.