控制 LLM 预算:Token 计数、用量统计与没有官方数据时的做法
分清请求前预估、响应 usage 和最终账单,避免缓存与推理 token 重复计费;用预算预占、逐次结算和任务成本指标管住长会话。
更新与核对 · 2026-10-11
AI 功能上线后超预算,常见原因是少算了工具结果、重试和多轮历史。预算控制首先要分清三本账:发送前的估算决定是否放行,响应里的 usage 用于逐次记账,供应商账单用于最终对账。 三者相关,但不能互相替代。
本文面向调用 API 或维护 Agent 网关的开发者。接口按 2026 年 10 月的官方文档核对;价格算例是教学假设,不代表现售模型报价。
Token 为什么不能按字数结账
Token 是分词器处理的单元,可能是一段词、一个汉字,也可能是字符的一部分。不同模型不一定使用同一种分词方法;中文、代码、JSON、图片和音频的规则也不同。“一个汉字等于两个 token”只能粗估,不能作为跨模型计费公式。
本地 tokenizer 能统计目标模型的文本,但完整请求还包括系统提示、消息包装、工具定义和多模态内容。只统计用户输入会漏掉上下文。JSON 也没有固定的“三倍膨胀率”:字段名、数组规模和输出任务共同决定体积,应在自己的样本上测量。
最小校准集分别收集中文问答、代码、结构化抽取和长工具结果,保存完整请求的估算值与实际 usage。按模型、任务比较误差,模型升级后重新校准。
官方用量:先分 API,再分字段
图 1 · 计数帮助预估,usage 帮助记账,最终还要核对账单和工具费用。
OpenAI:Chat Completions 与 Responses
Chat Completions 常见字段是 prompt_tokens / completion_tokens;Responses 使用 input_tokens / output_tokens。缓存和推理明细通常是总量的子集,不要再次加到总数上。支持缓存写入分类的模型还可能返回 cache_write_tokens,应按具体 API 和模型归一化。OpenAI 缓存文档[2]
下面是 Chat Completions 风格的示意响应:
{
"prompt_tokens": 8000,
"completion_tokens": 1500,
"prompt_tokens_details": { "cached_tokens": 6000 },
"completion_tokens_details": { "reasoning_tokens": 300 }
}
300 个推理 token 已含在 1500 中。没有独立缓存写入收费项时,普通输入是 8000 - 6000;有写入明细时还要扣除写入部分,分别计价。
Chat Completions 流式可用 stream_options.include_usage 请求最终用量块;Responses 应处理携带最终响应的终止事件。连接提前断开,客户端可能拿不到最终 usage,此时标记“待核对”,不能写成零。请求前,OpenAI 现在提供 Responses 输入 token 计数能力[1],本地 tokenizer 仍可用于支持范围内的预估。
Anthropic:输入分类口径不同
Claude Messages 的 input_tokens、cache_creation_input_tokens、cache_read_input_tokens 分别描述普通输入、缓存写入、缓存读取。计算本次输入处理量时合计这三个分类;费用乘各自费率,不能照搬 OpenAI 的减法。Claude 缓存文档[5]
messages.count_tokens 可在发送前计数,但官方明确说明它是估算,实际 usage 可能有小幅差异;服务端工具等输入也有支持限制。它适合预检,不能承诺与账单精确一致。Claude token counting[4]
本地模型与网关
Ollama 的 prompt_eval_count / eval_count 等计数描述工作量,自托管成本还包括 GPU 占用、空闲容量和运维。每百万 token 的摊销价随负载变化。
网关适合统一字段、价格表与归因维度,不会让缺失用量自动变精确。保留原始 usage、归一化值、估算标记和价格版本,才能追溯差异。
预算闸门:检查与预占必须原子化
用户还剩 1 元,10 个请求同时查到“余额够”,事后扣费就可能超额。预算闸门需要原子检查并预占:
创建 task_id
估计输入 + 最大输出 + 允许的重试成本
原子预占;不足则排队、缩小任务或拒绝
每个 attempt 独立保存 request_id、usage、费用
结算已知费用,释放未使用的预占
usage 缺失进入待核对队列;恢复未结算任务
新增工具轮次或子任务要追加预占。仅限制输出 token,挡不住无限工具循环。还要限制任务轮数、并发和最长运行时间。
图 2 · 估算误差靠样本校准,并发超额靠原子预占,两者需要不同机制。
没有官方用量时,依次尝试目标模型 tokenizer、分任务经验估算、供应商聚合账单校准。安全余量取决于低估误差的分布,不能假定乘 1.2 一定安全。估算费用和确认费用应在报表上区分。
Agent 为什么越聊越贵
设固定提示与工具定义为 S 个 token,每轮新增历史 h 个 token,每次发送全部历史。第 i 轮输入约为 S + i·h,共 n 轮:
总输入 ≈ n·S + h·n·(n+1)/2
固定增量、重发全部历史、没有裁剪时,总输入量呈平方增长。 这是输入量模型,不是所有 Agent 账单的复杂度定律。工具结果大小、缓存费率和压缩频率都会改变曲线。
图 3 · 缓存降低重复前缀成本,压缩与裁剪限制历史体积,不能画成同一种效果。
例如 S=1000、h=500、n=10,总输入是 37,500,而不是最后一轮的 6,000。一次 20,000 token 的工具结果还可能进入之后多轮历史;分页、按需读取常比精简一句提示更有收益。
Claude Code 的 /cost 和监控指标、Codex 的会话状态与执行事件可辅助观察。订阅额度、上下文余量和 API 美元账单是不同指标;CLI 显示不能直接作为跨产品收费凭证。固定提示的体积随版本和配置改变,没有永远固定的“12K 底价”。
一笔可复算的账
假设普通输入 $2/M、缓存读取 $0.20/M、输出 $10/M,本次普通输入 2,000、缓存读取 6,000、输出 1,500,没有缓存写入或其他工具费用:
费用 = (2000×2 + 6000×0.20 + 1500×10) / 1,000,000
= $0.0202
每天 30 万次、每月 30 天,则月费用 $0.0202 × 9,000,000 = $181,800。真实费率、缓存写入、工具费、失败重试与折扣必须逐项代入。
业务上更有用的是 每个成功任务的总成本:把任务内所有调用、重试、检索和外部工具费用计入。便宜模型若增加轮次、降低成功率,单请求价格下降不一定降低任务成本。
落地检查
- 按接口归一化,保留缓存分类和原始 usage;推理子集不重复累加。
- 每次尝试单独记账,流式中断进入待核对状态。
- 用户、项目与任务预算原子预占,循环和重试设上限。
- 价格表带生效时间、版本、单位和币种,定期与账单核对。
- 按中文、代码、多模态分别校准,升级模型后重测。
- 同看缓存命中、上下文长度、成功率与每成功任务成本。
长输入也影响等待,下一篇拆解 首 token 延迟。
参考资料
正文中的编号可跳转至对应来源。工程报告、官方文档与研究论文分别标注;支撑范围说明该资料能证明什么,以及不能推导什么。
- [1]官方文档OpenAI — Counting tokens
支撑范围: 调用前输入计数的能力与口径;预估不是最终输出与费用账单。
- [2]官方文档OpenAI — Prompt caching
支撑范围: OpenAI 提示缓存条件与 usage 语义;缓存不等于答案缓存或零费用。
- [3]官方文档OpenAI — Chat Completions API
支撑范围: Chat Completions 的 usage 与推理明细等字段;避免把子项重复相加。
- [4]官方文档Claude — Token counting
支撑范围: Claude 输入计数能力及估计边界;实际用量以调用结果核算。
- [5]官方文档Claude — Prompt caching
支撑范围: Claude 缓存读取、写入与生命周期;计费字段不能与其他厂商直接互换。
- [6]官方文档Claude Code — Monitoring usage
支撑范围: Claude Code 用量监测与记录;聚合前确认会话和去重口径。
- [7]官方文档Claude Code — Manage costs
支撑范围: 上下文、模型选择与费用治理建议;定价和可用能力需另行核对。