成本并非来自模型
token 总量是结果,不是原因。当同一任务的两个 agent 运行在工具调用次数上相差一个数量级时,差异很少来自模型。它来自分解:规划器创建了多少子任务、每个子任务的范围有多窄、以及每个节点被要求重新读取多少上下文。一个把检索任务拆成五个重叠子任务的计划,会为同一份文档付五次钱。一个把它拆成一个范围明确的节点的计划,只付一次。
失败模式会聚集。重试集中在那些从未说明成功条件的子任务上。上下文重读集中在那些被给予过宽工具面、不得不重新推导已知内容的节点上。当规划器无法判断某个子任务是否完成时,就会出现冗余的验证步骤,于是它添加一个重复工作的检查器节点。这些在单次运行总量中都不可见。总量把成本归因于模型,因为账单行写的是模型。真正花钱的是计划。
计划节点记账
机制很直接:给每个计划节点一个稳定标识符,并把每次模型调用和工具调用分配给发起它的节点。节点标识符不是 span 名称。它是规划器自己的工作单元,作为每个出站请求上的字段贯穿整个运行。
plan_node_id: "retrieve_policy_clauses"
parent_node: "assemble_compliance_answer"
model_calls: [...]
tool_calls: [...]
status: "retried"
跨运行聚合后,每个节点都会获得一个分布:成本、延迟、重试率、失败率。分布才是重点。每个节点的平均成本告诉你一个节点通常花费多少。长右尾告诉你哪个节点偶尔会爆炸。这是不同的工程问题。前者是预算问题。后者是分解缺陷。
大多数 agent 可观测性就停在这里。trace 被收集,span 被渲染,成本视图是按运行汇总的总量,并按模型拆分。这种拆分回答了一个没人问的问题:哪个模型花了 token。真正重要的问题是计划的哪一部分产生了这些工作。节点级视图能回答它,而且能跨运行回答,这是区分坏计划和坏日子的唯一方法。
分布揭示了什么

有三种模式反复出现。
一个平均成本低、尾部很重的节点,通常是成功条件定义不足的节点。它大多数时候成功,偶尔会循环。修复方法不是换更便宜的模型。修复方法是给节点更严格的契约:它必须返回什么,以及什么算完成。
一个平均成本高、方差低的节点在做真正的工作。它是收窄工具面或换更便宜模型的候选,因为它的行为足够可预测,可以在不危及运行的情况下优化。
一个重试率高、成本平稳的节点,是一个总是以同样方式失败、并被没有更好选择的规划器重试的节点。在这里增加预算只会让失败更昂贵。重写该节点才能消除它。
这些区分都无法在聚合到运行总量后保留下来。它们需要以节点作为记账单位。
让它成为调度输入
一旦成本被归因到节点,约束就可以附着到节点而不是运行上。按运行设上限是一种钝器:触发时,整条轨迹都会死掉,包括那些表现正常的节点。按节点设上限,可以让失控的子任务被停止、标记为失败并报告回规划器,然后规划器可以围绕它重新规划。运行的其余部分继续。
这改变了规划器的工作。收到节点级成本反馈的规划器,可以基于预期成本而不只是预期正确性来选择分解。高方差的节点会得到更窄的工具面,因为更小的工具面会减少节点可能出错的空间。总是重试的节点会在获得更多预算之前被重写,因为预算不是约束。便宜且可靠的节点可以获得更大自由度,因为它们的成本有界,行为已知。
预算约束成为调度输入。不再是月底
权衡是真实存在的。节点级记账要求规划器发出稳定的节点标识符,这意味着规划器的分解必须可观测且可复现。每次运行都生成自由形式分解的规划器,会产生无法聚合的标识符。这种埋点迫使做出选择:要么分解足够稳定、可以度量,要么不稳定,成本仍然无法归因。想要第二种规划器——完全自由形式、最大程度自适应——的团队,要为此放弃控制回路。这是一个合理的选择。但它不是免费的。
这取代了什么
事后成本仪表盘是一种报告产物。它们告诉你上个月在总体上发生了什么,而且是在钱花完之后。它们对财务有用,对工程无用,因为当数字可见时,运行已经结束,导致它的计划也已经消失。
计划节点记账是一个控制回路。它在规划器实际控制的单元上度量,跨运行聚合,使方差可见,并反馈到下一次分解。区别不在于图表的粒度。而在于度量能否改变下一次运行。
实际形态
最小实现包含四个部分。
- 规划器在分解时发出节点标识符,运行时在每次模型和工具调用上携带它们。
- 收集器跨运行按节点聚合成本、延迟、重试次数和失败状态。
- 策略层读取每个节点的分布,并在节点边界应用上限、模型选择和工具面限制。
- 规划器在选择下一次分解时消费策略层的先验。
困难的部分不是管道。而是接受分解是一种带有成本特征的工程产物,并且度量它是让预算成为设计决策而非会计事件的唯一方法。
封面照片:Jakub Pabis / Pexels。
