跳到主要内容
Router One

LLM 缓存用量与账单核对:先看懂 usage

缓存计数描述已报告的 token 用量,单凭一个计数不能确定命中率、节省幅度或实付金额。先确认请求协议和完整 usage 对象,区分普通输入、已记录的写入与读取,再对照这次请求的成本记录。本页提供核对方法,不是答案缓存的搭建教程。

第一步:确认 usage 属于哪种格式

不同响应格式里的“输入”可能采用不同口径。请读取同一次已完成请求的字段,不要把原始响应、控制台汇总与整月合计混在一起,误当作互不重叠的 token 分项。

来源需要核对的字段计数口径
OpenAI 风格 Chat Completionsprompt_tokens;prompt_tokens_details.cached_tokens嵌套的 cached 计数已经包含在 prompt_tokens 中,不要再加到输入合计上。
OpenAI 风格 Responsesinput_tokens;input_tokens_details.cached_tokens;可选的 input_tokens_details.cache_write_tokens两个嵌套计数都已包含在 input_tokens 中。普通输入等于全部输入减去已报告的读取和写入分项。核对时保留完整 usage 对象;仅缺少写入字段,不能证明写入用量为零。
原生 Anthropic Messagesinput_tokens;cache_creation_input_tokens;cache_read_input_tokens三者分别是普通输入、新写入输入和读取输入;将三个独立分项相加才是单次请求的全部输入。
归一化日志或 SDK 汇总inputTokens;cacheCreationInputTokens;cacheReadInputTokens;cachedTokens先确认汇总字段的定义。cachedTokens 与 cacheReadInputTokens 可能表示同一个计数,不能当成两笔新增用量。

示例一:嵌套计数已经包含在合计里

以下是假设的 OpenAI 风格 usage,仅用于演算,不是真实请求或账单。本例明确假设写入用量为零。10,000 个输入 token 中,嵌套分项为 6,000,在这一假设下普通输入剩余 4,000;加上 500 个输出,全部用量为 10,500。如果再把 6,000 加到 prompt_tokens 上,就会错误地得到 16,000 个输入 token。

illustrative-usage.json
{
  "prompt_tokens": 10000,
  "prompt_tokens_details": {
    "cached_tokens": 6000
  },
  "completion_tokens": 500,
  "total_tokens": 10500
}

示例二:Responses 已包含两个嵌套分项

以下是假设的 Responses usage,仅用于演算,不是真实请求或账单。10,000 个全部输入已经包含已报告的 6,000 个读取和 2,500 个写入。普通输入为 10,000 − 6,000 − 2,500 = 1,500 tokens。三个互不重叠的分项相加为 10,000,加上 500 个输出,全部用量仍为 10,500;两个嵌套分项都不应再次追加到 input_tokens 上。

illustrative-usage.json
{
  "input_tokens": 10000,
  "input_tokens_details": {
    "cached_tokens": 6000,
    "cache_write_tokens": 2500
  },
  "output_tokens": 500,
  "total_tokens": 10500
}

示例三:独立分项只累加一次

以下是假设的原生 Anthropic usage,仅用于演算,不是真实请求或账单。全部输入为 2,000 + 3,000 + 5,000 = 10,000 tokens;加上 500 个输出,合计为 10,500。这里的 input_tokens 仅指普通输入部分,与示例一中已经包含分项的输入合计不同。

illustrative-usage.json
{
  "input_tokens": 2000,
  "cache_creation_input_tokens": 3000,
  "cache_read_input_tokens": 5000,
  "output_tokens": 500
}

归一化统计为什么不能再叠加分项

统计层可能已经把三个输入分项合成全部输入,同时保留分项计数供查询。这时再用全部输入加上写入、读取,会重复计算部分 token。反过来,如果某字段只表示普通输入,重建全部输入时仍需加上独立分项。仅凭驼峰字段名或控制台中的“输入”标签,无法判断它是哪一种口径。

  • 原始协议字段与派生合计分开记录。
  • cachedTokens 与 cacheReadInputTokens 可能是别名;没有证据表明两者代表不同用量时,不要相加。
  • 输出单独核对。分项用来解释合计,不是需要继续追加到合计上的额外用量。

四步核对一次请求

  • 对齐 request ID、准确模型 ID、时间与状态。客户端或应用发起的每次重试都是新请求,内部供应商 fallback 尝试可能仍属于同一次请求。先核对同一次调用,再汇总整个会话。
  • 在客户端记录完整响应 usage。流式调用在有报告时使用最终用量,早期事件或中断的流可能不完整。给计费支持提供示例时,移除 API Key 与消息正文。
  • 在 Dashboard → Logs 找到对应请求。详情显示输入、输出、费用与状态;已记录的读取计数大于零时才展示该行。精简视图不会显示全部原始响应字段,因此缺少某一行不能证明用量为零。
  • 核对适用的模型价目与输入长度阶梯。实时模型页展示当前单价,不能证明旧请求当时采用的单价。计数或费用仍有差异时,提供 request ID、时间、模型与最小 usage 片段协助核查,不要假设当前目录一定能复现旧账单。

token 算术与实付金额分开核对

先确定互不重叠的输入分项,再分别用用量乘以适用单价,并单独计算输出;不要把一个百分比套用到所有分项。套餐覆盖或其他计费条款适用时,请求的 token 成本演算也不等于最终钱包扣款。

  • 读取计数大于零,不代表必然节省固定金额。不同模型与请求条件下,各分项的单价可能不同,应对照模型详情和请求记录。
  • 模型存在输入长度阶梯时,全部输入包括普通输入以及独立的写入、读取输入。越过门槛后,整次请求采用对应阶梯,包括输出;不是只给超出部分加价。
  • 成本计算器按明确假设估算工作负载,不预测未来缓存行为。价格方法页解释目录单价和阶梯边界;逐请求记录用于核对具体调用。

常见问题

cached_tokens 要加到 prompt_tokens 上吗?

在 OpenAI 风格响应中,prompt_tokens_details 下的 cached_tokens 已包含在 prompt_tokens 里,不需要再加。原生 Anthropic Messages 的结构不同:普通 input_tokens、cache_creation_input_tokens、cache_read_input_tokens 是独立分项。先确认响应格式,再决定如何相加。

Responses 的 cache_write_tokens 应该怎么算?

在 OpenAI 风格 Responses 的 usage 中,input_tokens_details.cached_tokens 与可选的 input_tokens_details.cache_write_tokens 都已包含在 input_tokens 里。普通输入应由全部输入减去两个已报告的分项;有写入记录时不能只减读取,也不能把任一分项再追加到全部输入上。仅缺少写入字段不能证明写入用量为零,应确认完整 usage 的口径后再计算。

缓存计数大于零,就能证明优惠或实付金额吗?

不能。它只说明已报告某类用量,不代表统一价格或节省幅度。还要对照适用的模型价目、请求条件和该次调用的计费记录,不能从单个计数推导固定百分比或未来命中率。

cachedTokens 和 cacheReadInputTokens 能相加吗?

不能直接相加。归一化响应可能用两个名称表示同一个读取计数。应先核对原始 usage 格式和汇总字段定义,同时确认输入合计是否已经包含该计数。

已记录的读取输入也计入长上下文阶梯吗?

阶梯判断使用单次请求的全部输入,包括普通输入以及独立的写入、读取输入。如果手头已经是包含分项的输入合计,不要再次追加分项。只有全部输入严格大于门槛时才进入下一档,选中的阶梯适用于整次请求。

这份指南是否承诺每个模型都支持缓存?

不承诺。本页用于理解已报告的用量并核对账单,不据此保证请求参数支持、共享缓存答案、留存时长、缓存可用性、命中率或固定节省幅度。具体使用的模型应以协议文档和实际响应为准。