AI Agent的Token消费容易失控——重试循环、上下文膨胀、幻觉式重试会导致单次运行烧掉50倍预算;文章详解在API层实现硬性上限拦截而非事后报警的工程方案。
你可能已经连续几周在监控 Agent 的 token 消耗。然后某次运行突然失控——token 数量飙到平时的 50 倍——等你发现的时候,半个月的预算已经没了。
可见性只是第一步。执行才是第二步,而且真正能阻止预算流失的,是执行。
问题所在:看到峰值时损害已经造成
大多数监控方案只是给你一个仪表盘。你的 Agent 运行、消耗 token,到月底你才看到账单。即便是实时仪表盘,响应链条也很慢:监控 → 告警 → 人工 → 决策 → 暂停。这中间的 gap 是在烧真金白银。
你真正需要的是一个护栏,在 Agent 越过你提前设定好的上限的那一刻,就把它停下来。不是"通知团队",而是"在调用发生前直接拒绝"。
这很重要,因为 token 爆炸的真实场景是这样的:
重试循环——Agent 因为误读响应而不断调用同一个工具。每次重试都在烧 token。一次运行可以循环 10 到 50 次才被人注意到。
上下文膨胀——Agent 在上下文窗口中累积了对话历史或调试日志。到第 100 次运行时,输入 token 已经是基准的 3 倍。
幻觉式重试——模型以为某个工具调用失败了,而实际上它成功了。日志看起来干干净净。但费用不会骗人。
在所有这些情况下,Agent 仍然成功了——HTTP 200。但 token 消耗不会。
如何为每个 Agent 设置 token 预算
先建立基准。让你的 Agent 在正常条件下运行 20-50 次,记录每次执行的 token 数量。这是你的参考点——不是月均花费,而是单次运行的典型消耗。
Example: a document-retrieval agent
- Run 1: 3,200 input + 450 output = 3,650 total
- Run 2: 3,100 input + 480 output = 3,580 total
- Run 3: 3,400 input + 520 output = 3,920 total
Average per run: ~3,700 tokens
在基准基础上,设定两个阈值:
单次运行上限。设为典型消耗的 2-3 倍。异常值是存在的——真正复杂的查询可能需要更多 token——但 3 倍通常是一个分水岭,再往上就是真的出问题了。如果基准是 3,700 token,上限就定在 10,000-11,000 左右。
月度预算上限。用月度 LLM 预算除以预期运行次数,再加一个安全边际。预算 100 美元/月,预期 100 次运行——那就是每次运行 1 美元。按较便宜的模型大约每 1K token 0.002 美元来算,大约是每次运行 500 token。把月度上限设在 80 美元左右(20% 的余量),并在所有 Agent 上强制执行。
计算很简单。真正的关键是执行。
实现:kill-switch 模式
一旦你定义好了上限,Agent 需要在每次调用前检查它们,而不是之后。
如果你使用的是 AI Agents Control Tower,这是内置功能。kill switch 是一个可选项功能,在你的组织越过月度预算的那一刻就暂停所有 Agent:
在组织设置中启用 kill switch,并定义你的月度 token/费用限制。
用 SDK 的执行层包装你的 LLM 客户端(LangChain 模型用 wrap_langchain)——在每次推理调用前添加一个轻量级的状态检查(约 3ms,有缓存)。
如果超过了限制,SDK 会抛出 OpsVeritasKilledError 而不是调用模型。Agent 停止。不烧 token,不产生意外账单。
kill switch 是失效开放的——如果状态检查本身失败了(比如网络抖动),调用会正常继续。你防护的是静默失败,而不是你自己的基础设施故障。
from opsveritas import init, wrap_langchain
from langchain.chat_models import ChatOpenAI
init(api_key="your-secret")
# Wrap the model for telemetry (which agent ran, how many tokens)
model = ChatOpenAI(model="gpt-4o-mini")
# Add enforcement: blocks the call if budget is exceeded
model = wrap_langchain(model, agent_name="my_agent")
# model.invoke() now raises OpsVeritasKilledError
# if the org's monthly limit is breached
对于非 LangChain 的设置,使用 Universal Webhook 在每次运行后将你的 Agent 的 token 遥测数据 POST 到 control tower。在 payload 中包含 cost_usd,系统会跨所有 Agent 实时追踪消耗。kill switch 仍然在组织级别触发,但你需要自己决定是否真的调用模型。
单 Agent 上限:第二层防护
组织级的 kill switch 是保险。要更精细地控制,在 Agent 自己的执行循环中加入单 Agent 上限:
def run_agent(query):
baseline_tokens = 3700 # your per-run baseline
ceiling_tokens = 11000 # 3x baseline
response = model.invoke(query)
total_tokens = response.usage.input_tokens + response.usage.output_tokens
if total_tokens > ceiling_tokens:
log.error(f"Agent exceeded token ceiling: {total_tokens} > {ceiling_tokens}")
# retry with a simpler query, alert the user, or flag for review
return {"status": "budget_exceeded", "data": None}
return response
这层防护捕获的是每次执行的异常,而不是按月统计。如果某次运行花了太多钱,你会立即知道,可以重试、优雅降级,或者直接报错。
衡量真正重要的指标
护栏就位后,追踪三个指标:
每次运行的 token 数(p50、p95)——告诉你基准是否在漂移。上升趋势意味着 Agent 在退化。
每次运行的费用——token 数量本身不能反映模型差异;一次 gpt-4o 运行的成本和 gpt-4o-mini 完全不同。
触及上限的运行占比——如果超过 1-2% 的运行超出阈值,要么是上限设置错了,要么是 Agent 真的有问题。
大多数监控工具展示的是总花费。你需要的是每次执行的可见性——那一次失控的独立运行,而不是汇总后的账单。
没有执行的可见性,是东西坏掉之后你才去看的仪表盘。没有可见性的执行,是一个莫名其妙触发的开关。两个你都需要。
用真实数据设定基准。把上限设在正常的 2-3 倍。在调用前执行,而不是调用后。追踪每次运行的指标,而不仅仅是汇总花费。当异常发生时,你会在几毫秒内捕获它,而不是等到月底。
成本治理就是可靠性。静默的 token 循环是一种故障模式,和崩溃一样真实——只是藏得更久而已。