自己统计 token 用量:别等厂商账单出来才知道花了多少
数据截至 2026-07,价格与限额以各官网为准。
账单是事后的、聚合的、按厂商自己的口径出的;而你需要的是实时的、能拆到人和功能的、按你自己业务口径出的数。这两者永远不会是同一份数据,所以只要你的 AI 调用量到了”会心疼”的程度,就必须在自己这一侧独立记一份 token 账,而不是等月底看厂商发来的数字。
有个很常见的误解:既然厂商控制台有用量页面,自己再记一遍不是重复劳动吗?如果你只有一个人、一个项目、一个模型,那确实是重复劳动。但只要出现”两个业务线共用一把 key""想知道是哪个功能在烧钱""想在超支之前先收到告警”这三种需求里的任何一种,厂商面板就答不上来了——它按账号和模型聚合,不按你的功能模块聚合;它通常有延迟,而不是调用完立刻可见;它更不会知道你内部想怎么分摊。
厂商账单晚在哪、粗在哪
先把问题说具体,才知道自建统计要补哪一块。
第一是延迟。 大多数平台的用量统计不是实时的,从调用发生到面板上出现数字通常有一段延迟。这段时间里如果有个死循环把 key 打爆,你是看不见的。等看见的时候钱已经花完了。
第二是粒度。 官方能给你的最细粒度一般到”哪把 key、哪个模型、哪一天”。它给不了”是搜索功能还是摘要功能""是哪个客户触发的""是重试打的还是首次调用打的”。而这些恰恰是你做优化时唯一有用的维度——知道总共花了多少没用,知道哪一块占了七成才有用。
第三是口径。 输入 token、输出 token、缓存写入、缓存读取,这几类的计价倍率各不相同,聚合成一个金额之后就还原不回去了。你想验证”上了缓存到底省没省钱”,光看总金额是验证不出来的,必须自己留分项明细。
第四是订阅制的额度制。 现在不少工具已经不是纯 API 计费,而是订阅包一个额度、超出再另算。GitHub Copilot 就是典型:2026-06-01 起全部 Copilot 计划转为按用量计费,用 GitHub AI Credits 替代了原来的 premium requests 计数,1 credit 等于 1 美分,实际消耗按 token(输入、输出、缓存)用各模型的 API 费率折算。这意味着”我这个月还剩多少可用”这件事,你不去主动看是不会有人告诉你的。
最小可用的自建统计:把 usage 字段落下来
好消息是,主流 API 的响应体里都会带一个用量字段(多数叫 usage),里面有输入 token 数、输出 token 数,支持缓存的还会分出缓存写入和缓存读取。你要做的第一件事非常朴素:每次调用完,把这个字段连同你的业务标签一起写到一个地方去。
不用上什么可观测性平台,起步阶段一个 JSONL 文件就够了:
import json, time, os, uuid
LOG = os.getenv("TOKEN_LOG", "token_usage.jsonl")
def log_usage(*, provider, model, usage, feature, user_id=None, latency_ms=None):
"""把一次调用的用量落盘。usage 直接传 SDK 返回的原始对象转成的 dict。"""
record = {
"id": str(uuid.uuid4()),
"ts": int(time.time()),
"provider": provider, # 哪家厂商
"model": model, # 具体模型 ID
"feature": feature, # ★业务标签:这次调用服务于哪个功能
"user_id": user_id, # 可选:分摊到人/租户
"latency_ms": latency_ms,
"usage": usage, # 原样保留分项,别自己先加总
}
with open(LOG, "a", encoding="utf-8") as f:
f.write(json.dumps(record, ensure_ascii=False) + "\n")
有三个细节值得强调:
usage原样保留,不要在写入时就加总成一个数。 一旦加总,缓存命中率、输入输出比这些信息就永远丢了。存储很便宜,信息丢了补不回来。feature这个业务标签是整套统计的价值所在。 没有它,你自建的这份数据和厂商面板没有区别,白记。命名建议用稳定的短标识(如summary、search-rerank),别用会随文案变的中文描述。- 别在这一步就换算成钱。 单价会调整、会有限时价、会有折扣,把单价写死在采集环节,将来改价你就得回头刷历史数据。正确做法是采集只存 token,算钱放在查询/报表环节,单价做成一张可维护的配置表。
流式调用要留个心眼:不同实现里 usage 的返回位置可能不同,有的在最后一个 chunk 里带回来,有的需要显式开启才返回。接每一家的时候,先跑一次最小调用把返回结构打印出来看一眼,别默认它和别家一样。
往上一层:在网关侧统一采集
上面那种方式的问题是要改每一处调用点。如果你的项目里有十几处散落的调用,或者团队里好几个人各写各的,更省事的做法是在调用出口做一层统一封装——所有对模型的请求都走同一个内部函数或同一个网关服务,采集逻辑只写一遍。
这层封装的好处不止是省事:
- 换厂商、加 fallback 的时候只改一处,统计口径自动保持一致;
- 可以顺手做限流和熔断,比如”某个 feature 当日 token 超过阈值就拒绝”,这是厂商面板给不了的能力;
- 能把重试单独打标——重试消耗的 token 是真金白银,但很多人的统计里它被算进了”正常调用”,导致优化时找错方向;
- 多租户场景下可以在这里就把用量归到租户身上,不用事后按日志猜。
如果你已经在用多家 API 的统一封装或聚合网关,那基本上已经有了这层,接下来只是把采集挂上去。这块可以对照 多家 API 怎么统一封装 和 API 成本怎么监控 两篇一起看。
订阅制工具怎么统计:以 Copilot 为例
API 调用你能拿到 usage,但 IDE 插件、订阅制的编码助手你拿不到——那是厂商客户端内部的调用。这类只能靠官方的计费/用量面板,你能做的是定期去看、并把关键数字抄进自己的表里做趋势。
Copilot 这边有几个具体的点值得盯:
- 各计划包含的额度按第三方公开资料的口径,Pro 是 10 美元/月含 15 美元 credits,Pro+ 是 39 美元/月含 70,Max 是 100 美元/月含 200;Business 约 1,900 credits/用户/月,Enterprise 约 3,900。这几个数字来自第三方汇总,具体以 GitHub 官方计费页为准。付费档的基础额度大致等于其价格,另有一份浮动额度,实际总额可能更高;Business 和 Enterprise 走组织池化余额。
- 有一个时间点必须记进日历:既有 Business / Enterprise 客户在按量计费的头三个月(2026-06-01 至 2026-09-01)享受更高的促销额度,Business 是 3,000 credits/用户、Enterprise 是 7,000;促销结束后回落到标准的 1,900 / 3,900。 也就是说,团队现在用着不心疼,可能只是因为额度还在促销价上。稳妥做法是在 9 月之前去 Copilot 的计费面板看”预测用量”那个数——那个数才是促销结束后你要面对的账单。
- 额度耗尽之后没有自动降级到便宜模型的机制。不允许超额就是直接阻断到下一个计费周期,不会悄悄给你换个便宜模型继续跑。管理员用美元预算控制超额,按每 credit 一美分扣减(10 美元预算就是 1,000 credits),预算可以设在用户、成本中心、企业支出上限、组织四个层级上。要特别注意把某个用户的预算设成 0 会立即阻断该用户,这不是”警告”而是”断供”。
- 未用完的额度不结转,每个自然月 1 号重置。所以”这个月省着点用攒到下个月”这个思路是不成立的。
还有一类人容易被忽略:年付的 Pro / Pro+ 用户在计划到期前仍然走原来的 premium request 制(月付用户已在 2026-06-01 自动迁移)。仅对这部分年付用户,2026-06-01 起模型倍率上调,例如 Copilot code review 的模型倍率是 13,也就是每次 PR 或 IDE 里的代码评审要扣 13 个 premium request。另外一个特别容易漏的计量口径:code review 自 2026-06-01 起同时还会消耗 GitHub Actions 分钟数——你在盯 credits 的时候,Actions 那边的账是分开走的,别只盯一处。
这类订阅制工具的统计做法就很朴素了:固定一个频率(比如每周一)去看面板,把”已用/剩余/预测”三个数抄进一张表,看的是斜率而不是绝对值。斜率突然变陡,往往对应团队里某个人换了模型或者开了某个自动化流程。相关的额度管理可以参考 Copilot 团队预算怎么定 和 Copilot 额度用完了怎么办。
自己算的和官方对不上,先查这几处
这是自建统计一定会遇到的场景,别一上来就怀疑厂商算错了,绝大多数时候是自己这边的口径问题。按顺序排查:
- 时区和账期。 厂商多按 UTC 或其账单时区切天,你的日志按本地时区切天,跨零点那几个小时的调用就会串到相邻的日子里。对账时先把两边统一到同一时区再比。
- 失败请求。 请求发出去但报错的那些,有的场景已经产生了输入 token 消耗。你的采集如果只在成功分支里记,天然就会少。
- 重试。 很多 SDK 内置自动重试,你在业务代码里只看到一次调用,实际打出去可能是三次。采集点如果在 SDK 外层,就统计不到内层重试。
- 缓存分项。 缓存写入、缓存命中读取、普通输入,这三类的计价方式不同,如果你把它们混成一个”输入 token”再乘同一个单价,算出来的钱必然对不上。
- 不走 token 的计量。 前面提到的 Actions 分钟数就是一例。有些能力的计费单位压根不是 token,你的 token 账再准也覆盖不到。
对账的目标不是”分毫不差”,而是误差稳定在一个可解释的范围内。如果你自己算的数长期比官方低 3% 左右且波动不大,那说明有个固定的漏采点,找出来就行;如果误差忽大忽小,那才是真有问题。
诚实说局限
自建统计不是万能的,有几件事它做不到,得提前认清:
- 它算不准钱,只能算准量。 单价会变、会有限时价、会有阶梯和折扣,你的报表里那个金额永远只是估算。要精确金额还得以官方计费页为准。
- 它管不到客户端内部的调用。 IDE 插件、桌面应用、厂商托管的 agent,这些消耗你采集不到,只能靠官方面板。
- 它有自身成本。 每次调用多一次落盘,高并发下要考虑异步写入和批量落库,别让统计本身成为延迟来源。
- 额度类产品的政策变动很快。 上面那些额度和倍率都带明确的时间点,过了时间点就未必成立,具体请以各厂商官方计费页的当前说明为准。
另外补一句准入前提:本文提到的部分厂商官方并未把中国大陆列为受支持地区,注册、控制台与 API 端点都在境外。以各厂商官方公布的受支持地区为准;本文不提供也不背书任何第三方中转渠道。
小结
厂商账单回答的是”你一共花了多少”,而你真正要回答的是”这笔钱花在哪、值不值、下个月会变成多少”,后三个问题账单答不了。最小可行的做法是把每次调用的 usage 分项连同一个业务标签落盘,采集只存 token、算钱放到报表环节。调用点多了就往上抽一层统一网关,顺手把重试、限流和多租户归属一起解决。订阅制工具拿不到 usage,就固定频率去看官方计费面板抄”已用/剩余/预测”三个数看斜率,尤其留意 2026-09-01 这类促销到期的时间点。对账时误差稳定可解释就算合格,不必追求分毫不差。