一个超级用户在第三天早上 9 点就耗尽了你的月度 token 预算。熔断机制(kill-switch)准确触发——网关返回 429,模型停止调用,账单停止增长。与此同时,智能体(agent)已经订好了机票,发送了确认邮件,并将支持工单标记为已解决。仪表盘显示“支出已停止”。用户却问:“为什么要为我从未要求的行程扣费?”两者都没错。预算上限阻止了模型思考,但它没能阻止世界的改变。
这是几乎每个智能体预算护栏都会携带的失效模式:上限信号位于 支出 平面,但损害发生在 行动 平面,而这两个平面在连接时并没有共享的事务边界。告诉模型停止并不等同于告诉世界撤销模型刚刚所做的一切。
这种模式在不同团队中如此一致,以至于你在阅读复盘报告(postmortem)之前就能预测结果。检测到失控。熔断机制因触发迅速而受到赞扬。随后,客户支持队列中充满了针对熔断机制在技术上无力阻止的行动的退款请求,因为这些行动发生在最后一次工具调用和上限评估之间的半秒钟内。“我们停止了支出”被视为胜利。而“我们停止了行动”实际上从未在考虑范围内。
两个平面从未在同一个循环中
大多数智能体运行时的成本控制和工具执行路径是独立演化的。成本控制存在于网关:token 计数器、每用户配额、预算封口、流量限制。工具执行存在于智能体运行时:函数调用、HTTP 请求、数据库写入、第三方 API 调用。网关看到模型流量。运行时看到副作用。两者都无法全局审视,也没有人负责回答“如果我们现在停止,接下来的行动是否可恢复”这个问题。
结果是,这种检查顺序在理论上看起来正确,但在实践中却失败了。流程如下:模型调用 → 带有工具调用的响应 → 网关计算 token → 工具执行 → 下一次模型调用 → 网关检查预算 → 熔断。上限在模型调用 之间 触发。它不在 工具调用 之间触发。因此,一个先发出重度推理响应,紧接着是三个快速工具调用的链条,将在预算检查有机会介入之前执行所有三个工具调用。
更糟糕的是,该链条中的工具调用往往是不可逆的。模型进行昂贵的思考,决定该做什么,然后发出廉价的行动——send_email、confirm_booking、post_message、close_ticket。预算信号在这些廉价行动之后到达,因为这些廉价行动恰恰是预算认为不值得暂停检查的。以成本作为控制手段失效了,因为成本从来不是衡量影响力的良好指标。
成本不等于影响力
将 token 视为智能体风险的通用货币是更深层次的错误。一个只有 100 token 的 delete_customer_record 调用可能是一个监管事件。而一段 50,000 token 的推理追踪,如果只是解决问题而不触及任何工具,则不会产生外部后果。因此,按 token 制定预算混淆了两个几乎没有因果关系的东西——模型思考了多少,以及世界将记住模型思考了多少。
一旦你看到了这个差距,架构上的调整就是将预算分成两个独立的账户:token 账户和行动账户。token 账户是网关已经在衡量的。行动账户则是没有人衡量但应该衡量的:一个针对每个动作的“爆炸半径”权重,用于捕获副作用是内部的还是外部的、可逆的还是不可逆的、幂等的还是单次的、软状态的还是硬提交的。
一个在生产环境中行之有效的务实分类法:
免费(Free) :纯模型推理且不含工具调用、沙盒读取、工具自身标记为预览的试运行查询。
廉价(Cheap) :写入智能体拥有的、可以撤销的内部存储,具有已知补偿动作的幂等写入,发送到预发或测试频道。
昂贵(Expensive) :写入记录系统、客户可见的沟通、资金变动、更改外部状态的第三方 API 调用。
单向(One-way) :原则上无法补偿的行动——没有墓碑标记的删除记录、已被阅读的邮件、已向现已关闭的卡收取的款项、现实世界的事件(如打印发货单或派遣快递)。
一旦有了这个账户,预算上限将不再仅仅针对 token 触发。它将针对该会话剩余部分的预期单向行动计数触发。如果用户已经用掉了 80% 的 token 预算,而智能体的下一步计划是 send_external_email,那么无论 token 成本如何,上限都应拒绝该步骤。如果用户处于 99% 的 token 预算,而下一步是沙盒搜索,则上限应允许其通过。
上限必须在正确的位置触发 一旦你接受了成本不等于影响力,接下来的问题是上限评估应该放在哪里。默认的答案是“网关,因为那是 token 计费的地方”。这种默认思维正是熔断机制总是在行动之后触发的原因。
正确的位置是在工具调度边界,而不是模型调度边界。工具调度边界是运行时中,在副作用脱离你控制 之前 ,你拥有其结构化描述的最后一个环节。你已知工具名称、参数、用户、剩余的会话预算,以及到目前为止的会话不可逆性统计。你可以利用网关所不具备的信息来回答“这是否应该触发”。
有三种常见的实现方式,它们各有权衡。最轻量级的版本是运行时中的同步策略检查——在调用 tool.invoke() 之前,运行一个根据工具资格、预算状态和工具自身声明的静态可逆性标签来返回拒绝/允许的保护程序。中间版本是一个位于智能体运行时和实际工具执行之间的工具调用拦截器,它拥有预算状态,并可以在不让调用通过的情况下返回一个补偿动作令牌。最沉重的版本是适配智能体的 saga 模式:每个不可逆的工具调用在执行前都会写入一条补偿动作记录,上限通过触发补偿链而不是允许下一次调用进行来发挥作用。
你不需要全部三种。大多数团队应该首先尝试最轻量级的版本,因为它只改变了智能体循环中的一行代码——if (await policy.allow(toolCall, budget))——而这一行代码抓住了网关所遗漏的失效模式。中间和沉重版本则留给那些真正需要链式不可逆行动和可组合撤销的智能体。
将不可逆性定价为一等公民成本 一旦你拥有了一个可以拒绝执行的操作平面(action plane),你所解锁的严谨性就是将不可逆性与 Token 成本分开定价。Token 成本是供应商账单。不可逆性成本是一份 风险 账单 —— 当事情出错时,它以客户信任度为单位向你计费,且其预算由产品团队而非财务团队设定。
在机制上,这表现为每个工具在注册时声明两项成本:Token 成本(根据典型用法计算)和不可逆性成本(由操作负责人选择的整数或权重)。那么,一个会话的预算包就是一个 向量 —— N 个 Token,M 个不可逆性单位 —— 当 任一 轴超过限制时,熔断机制就会触发。用户可以将全部 Token 预算花在推理上,而完全不触及不可逆性预算。另一个用户可能在第一次调用后不再消耗 Token,但在执行第三个操作时被限制,因为每个 send_message 都消耗了一个不可逆性单位,而预算包上限是三。
不可逆性预算还能让你表达 Token 预算无法表达的东西:爆炸半径的分级(blast-radius graduation)。新用户获得的不可逆性预算包比经过验证的用户小。生产环境中的智能体(agent)比离线批处理智能体获得的预算包小。试用层级的客户获得的预算包允许读取但不允许写入。这一切都无法用 Token 来表达,因为界线两侧的操作在 Token 成本上是无法区分的。
事后分析本该说的话 当切断开关(kill-switch)正确触发但智能体已经执行了操作时,正确的问题不是“为什么上限没有更早触发”。上限触发的时机正是它被设计时的初衷。正确的问题是:“当损失是由操作信号引起的,为什么上限却是一个 Token 信号?”这种重新构思通常会暴露出值得在下一个 Sprint 中发布的三个具体修复方案。
首先,注册表中的每个工具都需要一个可逆性标签(reversibility tag)。默认设置为“单向”,除非有人证明其并非如此 —— 这种保守做法成本很低,并将举证责任推向了最接近操作的人。其次,运行时需要在模型的工具调用输出与工具执行之间进行同步策略检查,并拥有访问会话预算和可逆性标签的权限。第三,预算包需要一个由产品策略设定的不可逆性轴,并且独立于 Token 轴触发。
这一切都不是什么前沿研究。Saga 模式可以追溯到 1987 年。补偿事务(Compensating transactions)在各类云架构指南中都有详尽记录。这种新颖性不在于机制,而在于认识到智能体运行时需要在 操作平面建立事务边界 ,而网关的支出信号并非该边界,也永远不会是。
下次当你看到切断开关图表在上午 9:13 趋于平缓,而退款请求图表在 9:14 飙升时,两者之间的差距就是本文所探讨问题的答案。正确的指标不是上限触发的速度。而是从失控开始到上限触发之间的窗口期内发生了多少不可逆操作 —— 这个窗口几乎总是比支出窗口长,因为支出是一个数字,而操作是事件。
用一句话总结这种严谨性:停止将 Token 视为智能体风险的通用货币,开始将不可逆性视为产品拥有的预算。模型提供商的账单是一项成本。客户支持队列的账单是另一项成本,而后者由决定先触发哪个上限的团队支付。
会员专享
余下内容仅对会员开放。 会员可读完整内容 —— 每一个公开发布的观点背后,那些框架、决策与推理的全貌。
— 完整文章,包含未公开存档的部分 — 可落地的工作框架,附带权衡与决策依据 — 新文章抢先看,先于公开发布 登录以继续阅读→ 随时取消 · 一次订阅,畅读全部