一、争议的构成:口径为主,信任为辅

近期技术社区里有一类关于大模型账单的问答:结算出来的 token 消耗看着比预期多,是不是虚标。把这类讨论拆开看,绝大多数落点是计费口径的理解偏差,少数才是对中转层上报数据的信任问题。两类问题的处理方式不同,但都建立在同一个前提上——你手里得有可复现的请求记录。先说清哪些东西一直在计费,这是口径部分:

  • 系统提示词。每次调用都完整发送,不会因为”它是固定的一段”而免计。
  • 多轮对话的完整上下文。对话式应用在每一轮都把之前的消息重新拼进去发送,轮次越多,输入侧增长越快。
  • 工具与函数定义。function schema 属于请求体的一部分,定义了十个工具,这十个的序列化文本都在计费。
  • 检索增强拼进去的文档片段。RAG 的召回质量提升,直接体现为输入 token 上升;召回条数和片段长度既是可调项,也是账单变量。
  • 模型返回的推理部分。少量模型会输出思考类 token,它们计入用量,却在最终答案里看不到,因此最容易被当成多扣。
  • 失败重试与超时重发。请求失败重发一次,上游就处理了一次。

这些加起来,一个”用户只问了一句话”的请求,实际发送的文本可能是那句话的几十倍。这不是虚标,这是这类应用的正常形态。真正的虚标指人为放大上报用量,那是另一回事,需要另一套手段应对。两类问题混在一起谈,得出的结论通常两边都不对。

大模型 token 用量的口径构成与对账方法

二、自查第一步:本地估算与 usage 对齐

动作本身不复杂,容易做错的是前提。

用与目标模型一致的 tokenizer 在本地估算 prompt 的 token 数,再和响应里 usage 的 prompt_tokens、completion_tokens 比对。三个约束要先接受:

  1. 不同模型词表不同。同一个 tokenizer 对同一文本给出的数字本来就有差异,跨模型套用估算结果没有意义。
  2. 偏差要有容忍区间,且区间由实测确定。拼接细节——分隔符、序列化格式、消息模板里的隐藏标记——都会影响结果,凭理论值定阈值只会造成误报。跑一批真实流量样本,把估算值与实际值的分布画出来,再定阈值。
  3. 缓存命中单独归类。prompt caching 的计费与正常请求不同,把命中与未命中的请求混在一起看平均值,结论必然失真。

比对的时机比方法更关键。不是月底看总账,而是在每次改动 prompt 组装逻辑、增删工具定义、调整召回片段长度时各看一次。账单异常很少来自模型侧变化,几乎总来自自己代码里的一次拼接改动。

三、企业接入后应具备的四件事

尤其是通过中转或代理层接入的情况,下面四件事缺任何一件,后续所有对账都停留在猜测。

  1. 完整入参快照落库。记录的是拼接之后的最终 prompt,不是用户原话。用户原话可能只有几十个 token,快照却可能有几千个——只有快照能解释账单。同时把响应的 usage 原样存下,与快照绑在同一行、同一个请求 ID 上。
  2. tokenizer 对齐与偏差容忍区间。明确用哪个 tokenizer 估算、容忍区间是多少、这个区间由哪批样本测出。这三条进配置或文档,不留在某个人的经验里。
  3. 重试与超时的计入策略要可见。重试了几次、每次是否都被上游计入、超时之后请求是否真的没被执行——这些信息必须能在网关层看到,不能只有客户端知道。客户端自行实现的退避重试,是最常见的账对不上的来源。
  4. 对第三方中转的验收要求。内容单独写在下一节。

四、对中转层的验收标准

如果用量数据来自一个中转或代理服务,它就不该是不可质疑的黑箱。验收时要求三件事,且都能在接入文档或合同里核对:

  • 透传上游原始 usage 字段,不由中转层自行重算或换算。中转层重算等于多加了一层口径,而这一层不受你控制。
  • 给出上游请求 ID。出现单条异常用量时,要能用这个 ID 回到上游侧核对。这是区分”自己代码拼多了”和”上报被放大”的唯一路径。
  • 可按天导出。能导出才能做独立统计。只给一个控制台汇总数字,等于把核对工作取消掉了。

三条都满足时,信任问题会退化成纯粹的数据处理问题;缺任何一条,就只能靠”看起来差不多”来决策。顺带一提,怀疑用量被放大时,先做的不是找供应商,而是拿自己的入参快照重算一遍——多数情况到这一步就结束了。

五、洹拓视角:上线前必须能在系统里回答这五个问题

这五个问题不该在复盘时靠口头回答,而要能在系统里查出来。任何一条答不上,说明观测有洞:

问题 答案来源 答不上来说明什么
这次调用一共花了多少 token 落库的 usage 与入参快照 未记录响应侧原始字段
其中上下文占多少 快照的分区统计 prompt 组装没有分区,无法归因
重试贡献了多少 网关层重试计数 重试策略在客户端,服务端不可见
缓存省了多少 命中标记与计费分类 缓存命中没有单独标记
异常请求能否定位到具体会话 请求 ID 与会话 ID 的关联 只有聚合数字,单条不可追溯

落地按顺序来:先做到每条请求有快照和 usage,再补分区统计(系统提示词、历史上下文、工具定义、检索片段各占多少),最后接重试计数与缓存标记。第一件做完就已经能解释大部分账单波动;第二件做完才有资格谈优化——在不知道上下文占比的情况下讨论降本,通常只会得到删掉几轮历史的结论,而那往往损害效果。