跳转到主要内容

轨迹成本是调度输入,而非事后报告

一条成本曲线,而非一个成本总额,让编排器在每一步权衡深度与开销。本文主张,这种权衡应当属于调度器内部。

Candlestick chart showing a downward trend in the stock market analysis.

总额的问题

大多数 agent 平台报告成本的方式,就像财务团队报告云支出一样:一个总额,归属于某次运行,在运行结束后才交付。这个总额对记账有用,对控制无用。等到这个数字出现时,产生它的每一个决策都已经做完了。

考虑一个检索密集型的研究任务。agent 解析查询,扇出到搜索工具,拉取若干文档,并在产出第一个候选答案之前就把大部分预算花在了上下文组装上。到第三步时,轨迹已经消耗了大部分配额。到第三十步,当 agent 本应检查其答案是否真的有依据时,已经没有剩余可花了。这次运行不会大声失败。它返回一个自信却未经核验的答案,而成本报告显示的是一次舒适、在预算内的运行。

这就是把成本当作报告而非信号的核​​心失败。一次运行的成本不是后台累积的标量;它是一条有形状的曲线,而形状会告诉你 agent 即将无力承担什么。

为什么按运行设上限解决不了问题

显而易见的修复是设上限:当支出越过阈值时停止运行。上限是一种钝器,原因有二。

第一,它们触发得太晚。上限是对总额的限制,而不是对下一个动作的约束。一个已经把配额花在检索上的 agent,会在验证阶段撞到上限,而这恰恰是你最不希望被截断的步骤。上限把预算问题变成了正确性问题。

第二,它们会留下未使用的预算。一次在上限之下完成的运行,没有任何机制把剩余部分花在能帮上忙的地方——多一轮验证、第二个检索角度,或重读一段含糊的指令。上限既过严又过松,因为它管错了量。

真正重要的量是每单位预期步骤增益的边际成本:下一个候选动作要花多少,以及预期能改善轨迹多少。这个信号只在执行期间存在,这意味着它必须由运行时产生,而不是事后重建。

让成本成为一等调度变量

前提是每一步都带有价格。不是运行结束时的估算,而是在编排器考虑该步骤的那一刻就附上的可计算成本。在实践中,这意味着给每一步至少打上四个属性:

A scenic view of a bustling town square in Luxembourg city, showcasing classic European architecture.

  • model —— 该步骤将调用哪一类模型,因为路由和生成的成本可能相差几个数量级;
  • token class —— 输入、输出、缓存输入和推理 token 不可互换,不应加总成一个数字;
  • tool latency —— 墙钟时间,因为慢工具即使 token 便宜,也会消耗运行的时间预算;
  • tool price —— 外部调用本身的成本,这在 token 核算中往往不可见。

有了这些标签,编排器就能在提交之前为下一个候选动作定价。一步不再是不透明的函数调用;它是一个带有预测成本和预测收益的明细项。

# Sketch: pricing a candidate action before dispatch
def price(action, context):
    return {
        "model_cost": model_rates[action.model] * estimate_tokens(action, context),
        "tool_cost": tool_rates.get(action.tool, 0),
        "latency": tool_latency[action.tool] if action.tool else 0,
    }

def should_run(action, budget, context):
    cost = price(action, context)
    gain = expected_gain(action, context)  # from the same policy that ranks actions
    return cost["model_cost"] + cost["tool_cost"] <= budget.remaining_for(action.kind)

重要的是最后一行:预算不是单一池子。它按步骤类型划分,而划分是一项策略决策,不是执行顺序的涌现属性。

按任务类别的支出策略

对所有任务类别采用单一预算策略,必然导致某些类别被服务不当。两种模式覆盖了大部分情况。

探索密集型任务——开放式研究、发现、广度优先搜索——需要递减预算。早期步骤便宜且数量多;编排器应自由地花在检索和候选生成上,然后逐步收窄。收窄正是为后续真正负责选择和综合的步骤保留预算。

验证密集型任务——抽取、合规检查,以及任何错误答案代价高昂的场景——需要预留尾部。运行配额中固定的一部分被保留下来,检索或生成步骤不能动用。无论上下文看起来多么诱人,agent 都不能把验证预算花在更多上下文上。

这是一种权衡,应当直说:预留尾部会让运行在探索期间能力更弱。一个预留了验证预算的 agent,有时会找不到那本可以让验证变得不必要的文档。该策略是在押注验证是更有价值的边际支出,而对某些任务类别来说,这个押注是错的。关键在于让这个押注变得明确且按类别区分,而不是偶然发生。

廉价路由,刻意升级

Close-up of stock market trading screen displaying financial growth and charts.

成本感知调度也意味着模型路由。分类、意图检测、路由决策和格式规范化不需要前沿模型调用。它们需要在狭窄分布上正确,较小的模型通常就足够。

机制是置信度门控,而不是固定规则。编排器将廉价模型的输出分布与阈值比较;低于阈值时,该步骤会带着廉价模型的输出作为上下文重新派发给前沿模型。门控本身就是一个调度决策,它应当与预算属于同一个策略对象。

需要防范的失败模式

成本感知调度会引入它自己的失败模式,而且并不微妙。

验证饥饿。 一个最小化边际成本的调度器会发现,验证很贵,而且很少改变答案。若不加约束,它会跳过验证,运行会廉价地返回未经验证的输出——直到其中某个输出以远超验证成本的方式出错。预留尾部的存在,正是为了让这种失败在策略上不可能发生,而不是靠运气。

不可见的重试膨胀。 重试是成本漂移最常见的来源,因为它们通常被实现为控制流而不是步骤。一个失败并被重试三次的工具执行了四步,却只记录了一步。如果重试不是带有自身成本条目的一等步骤,调度器看到的曲线就会与实际运行产生的曲线背离。显式计数重试、为其定价,并让预算策略看到它们。

扇出倍增。 多 agent 系统会倍增曲线。一个派发五个 worker、每个 worker 又派发三个子任务的 supervisor,创造了十五条成本相关的轨迹——它们共享上下文、重复检索,并在某个共享依赖变慢时一起失败。按 worker 设预算不是预算;它是十五个独立预算,加起来等于一个没人选择过的数。在 swarm 层面执行限制,由 supervisor 从共享池中分配,worker 对其竞价。

权衡该放在哪里

论点不是说成本报告不必要。财务需要总额,团队需要理解他们的系统消耗了什么。论点是:报告是一个信号的下游消费者,而这个信号必须在上游、在编排器内部、在每个动作被考虑的那一刻产生。

一旦一次运行有了成本曲线,调度器就能做仪表盘做不到的事:在每一步,按照人类选择的策略,刻意地权衡深度与开销。那是一个调度问题,它属于调度发生的地方。

延伸阅读

封面照片:Miguel Á. Padriñán / Pexels。

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

相关阅读

这能回答的问题

What is the difference between a cost total and a cost curve for an agent run?

A cost total is a single number produced after the run ends, useful for accounting. A cost curve is the per-step cost accumulated during execution, which lets the orchestrator price the next candidate action and decide whether to spend on it. Only the curve can influence scheduling.

Why do per-run cost caps fail?

Caps govern the total rather than the next action. They fire after the damage is done — often truncating verification — and they leave unused budget when a run finishes early. They are simultaneously too strict and too loose because they constrain the wrong quantity.

How should a scheduler handle retries in cost accounting?

Retries must be first-class steps with their own cost entries. If they are implemented as invisible control flow, the curve the scheduler sees diverges from the curve the run actually produces, and budget policy is applied to a fiction.

Why enforce budgets at the swarm level rather than per worker?

Fan-out multiplies the curve. A supervisor dispatching multiple workers creates correlated trajectories that share context and duplicate retrieval. Per-worker budgets sum to a total nobody chose; a shared pool with workers bidding against it keeps the limit meaningful.