推理 token 通常按输出计费,但“按输出计费”不等于“在输出字段外再加一次”。 OpenAI 与 Claude 的输出总数字段已经包含思考;Gemini 原生 generateContent 的候选输出和思考是两个独立计数,需要相加。把同一套加法套给三家,会在前两家多算,在 Gemini 上又可能漏算。
本文核对截至 2026 年 9 月 7 日 的官方接口文档,处理普通文本请求的输出 token 统计。你需要先拿到原始响应的 usage 或 usageMetadata,并确认使用的接口。下面的字段规则可以帮助核对输出部分;输入缓存、工具调用和多模态等费用仍需按对应价格分别处理。
先选对这一列:哪个数才是输出计费总量
| 实际接口 | 输出计费总量 | 思考明细 | 对账时的关系 |
|---|---|---|---|
| OpenAI Responses | usage.output_tokens | usage.output_tokens_details.reasoning_tokens | 思考已在总数内,不再相加 |
| OpenAI Chat Completions | usage.completion_tokens | usage.completion_tokens_details.reasoning_tokens | 思考已在总数内,不再相加 |
Gemini 原生 generateContent | usageMetadata.candidatesTokenCount + usageMetadata.thoughtsTokenCount | thoughtsTokenCount | 候选输出与思考分开报告,需要相加 |
| Claude 原生 Messages | usage.output_tokens | usage.output_tokens_details.thinking_tokens,视支持情况返回 | 思考已在总数内,不再相加 |
OpenAI 明确说明生成 token 总数包含推理;Google 的 UsageMetadata 把候选输出与思考分别列出;Claude 当前文档把思考计数定义为输出总数中的明细。OpenAI 输出计数说明、Gemini UsageMetadata、Claude 思考成本说明
这张表按接口分类。通过第三方网关、兼容 OpenAI 的端点或转换后的 SDK 字段调用 Gemini 时,不能只看模型名就执行 Gemini 原生加法。适配器可能已经把思考合并到 completion_tokens;再次相加就会重复。应查该端点和适配器版本的字段说明,并保留转换前的 usage。Gemini Interactions、Live、Vertex 以及工具和多模态响应,也需要各自的使用量与价格口径。
用三条记录,定位多算和漏算

以下只计算输出费用。为便于验算,统一假设输出单价为每百万 token 10 美元;这不是任何模型的现行报价。真实计算应代入请求当时的模型、服务档位和价格。
OpenAI:1,186 已经包含 1,024
OpenAI 推理指南给出的 Responses 示例中,输入为 75,输出为 1,186,其中推理为 1,024,总 token 为 1,261。下面保留与本题有关的字段:官方推理指南
json{ "input_tokens": 75, "output_tokens": 1186, "output_tokens_details": {"reasoning_tokens": 1024}, "total_tokens": 1261 }
正确输出费用是 1186 ÷ 1000000 × 10 = 0.01186 美元。如果成本面板把 1186 + 1024 算成 2,210,就会显示 0.02210 美元,多出的 0.01024 美元恰好对应被重复计入的推理。
1186 - 1024 = 162 可以叫作“非推理输出余量”,但不能直接命名为“用户可见答案 token”。生成统计还可能涉及格式、通道或工具结构;即便推理明细为零,输出总数也不保证等于把屏幕文字重新分词后的结果。OpenAI 对输出计数差异的解释
Chat Completions 的原则相同,只是总数字段换成 completion_tokens。不要为了“统一变量名”,把已包含推理的总数转换成“总数加推理”。
Gemini:只算候选输出,会漏掉思考
这是一条用于说明字段关系的合成 usage,不是实测请求:
json{ "promptTokenCount": 900, "candidatesTokenCount": 600, "thoughtsTokenCount": 1400, "totalTokenCount": 2900 }
普通文本输出的计费总量为 600 + 1400 = 2000,假设费用为 0.02000 美元。只用 candidatesTokenCount 会算成 0.00600 美元,漏掉 0.01400 美元的思考输出。
这里的 totalTokenCount = 900 + 600 + 1400 用于核对整体 token 关系,不能直接乘输出单价,因为它也包括输入。更不能再给 2,900 加上 1,400:总数中已经有思考。Gemini 字段定义
Google 的价格表把思考纳入输出定价;查 Batch 请求时也要看该模型的 Batch 输出栏,不能一律按 Standard 价格给思考计费。输入中的缓存内容另有统计和价格处理,不能因为 promptTokenCount 包含缓存就把缓存量再加一遍。Gemini API 定价
Claude:348 是总数,312 是其中的思考
Claude 当前文档示例列出输入 25、输出 348、思考 312:思考 token 与费用说明
json{ "input_tokens": 25, "output_tokens": 348, "output_tokens_details": {"thinking_tokens": 312} }
应使用 348,假设输出费用为 0.00348 美元。如果计算 348 + 312 = 660,就会得到 0.00660 美元,多算 0.00312 美元。
部分旧 SDK、模型或网关未暴露思考明细。没有 thinking_tokens,不代表没有产生思考费用。 只要接口定义明确、output_tokens 已完整返回,输出总量仍可使用;思考拆分可以记为未知。也不应再写成“Claude 完全不提供思考计数”,因为当前文档已经描述该明细字段。
成本面板怎样保存数据,才能不再重复相加
最容易出问题的设计,是同时展示“输出 token”和“推理 token”,然后在通用汇总函数里把所有数字列相加。建议明确区分以下三种信息:
| 保存的信息 | 含义 | 能否直接参加费用相加 |
|---|---|---|
| 输出计费总量 | 按已确认接口规则得到的完整输出量 | 可以,匹配适用的输出价格 |
| 推理明细 | 输出计费总量中用于思考的部分 | 仅用于分析,不能再加到总量上 |
| 原始 usage 与接口标识 | 原始计数、API 类型、适配器版本等 | 用于追溯,不与归一后的列一起相加 |
在接入层完成一次转换后,后续汇总只用“输出计费总量”。例如 Gemini 原生记录中的 600 与 1,400 先合并为 2,000;归一后的推理明细仍是 1,400,但此时它已经是 2,000 的子项。前端不应再重做原生字段加法。
还要让系统区分“0”与“未知”:
- 完整的总数已知,明细缺失: OpenAI 或 Claude 可以保留输出总量,把推理明细显示为“未提供”,不要假装知道推理为零。
- Gemini 原生加法缺少一个操作数: 没有可靠接口约定证明缺失等于零时,输出计费总量应标为待确认,不能把缺失的思考自动补成零。
- 流中断,没拿到最终 usage: 保留待对账状态,后续用可获得的最终响应、请求日志或账单记录补齐。
- 计数为负数、非整数,或已包含思考的总数小于思考明细: 记录数据异常并回查转换,不要用截断、取绝对值或强行归零掩盖问题。
这些是针对跨接口统计的实现建议,不是供应商承诺的统一账单格式。保存原始记录,才能在 SDK 更新或映射出错后重新计算,而无需猜测当时到底返回了什么。
字段没加错,账单为什么仍然对不上
流式 usage 是累计值时,只取最终总量
Claude 的 message_delta 使用量是累计计数,不能把连续事件相加。假设两个累计输出快照依次为 120、348,最终输出是 348,不是 468。优先使用 SDK 的最终消息对象,或该接口明确规定的最终 usage;不要把一套流事件算法直接复用到所有供应商。Claude 流式响应文档
当前 Claude 文档也指出,思考明细会出现在最终 message_delta。若只读首个事件,可能拿到不完整的拆分;若最后一个事件未收到,就应保留未知状态。Claude 思考成本说明
同一个提示词重试,不一定是同一笔消耗
对账要区分一次业务操作和它触发的多次 API 尝试。超时之后的重试可能产生第二次调用;客户端没显示第一份答案,也不能据此判断第一次未被处理。
建议把业务操作 ID、尝试编号、供应商请求或响应 ID、模型与时间一起保留。对同一请求的重复日志做去重,对不同尝试分别核对。不要按提示词文本去重,否则相同问题的真实多次调用也可能被错误抹掉。
最终答案很短,不代表输出成本应该很低
OpenAI 的输出预算包含隐藏推理,响应可能在可见答案产生前就达到预算,并产生费用。Claude 的隐藏思考同样计入输出;展示的思考摘要长度不能代替实际思考计数,官方说明摘要生成本身不另收费。OpenAI 推理预算、Claude 思考与摘要费用
此外,Claude 后续请求保留的历史思考内容可能进入输入计费,具体取决于模型的上下文保留行为。上一轮作为输出生成、下一轮作为输入处理,是两次请求中的不同计费环节;不能直接判为同一条 usage 的重复加法。Claude 思考文档
输出费用算对了,也不等于整张账单算完了
完整对账还需要普通输入、缓存读取或写入、实际模型、服务档位、生效日期,以及适用的工具、存储或多模态项目。先用本文方法核对输出量,再给各项匹配价格。不要把含输入的 total_tokens 或 totalTokenCount 全部乘以一个输出单价,也不要套固定的“推理模型贵几倍”倍率。
如果下一步是比较不同工作负载适合哪家供应商,可继续阅读三家 API 的成本决策指南;其中历史价格需要再与请求日期的官方价格核对。
发现“多扣费”时,先提交哪几项证据

先选一条差额明确的请求,拿出原始 usage、接口名称、请求或响应 ID、实际模型、请求时间与服务档位,再附上本地公式和适用价格。按这个顺序比较:
- 原始字段与面板总量。 差额正好等于推理明细时,优先检查子项是否被重复相加;Gemini 少了思考量时,检查是否只计候选输出。
- 单次请求与事件汇总。 总量像是多条累计快照之和时,检查流事件;同一请求出现多次时,检查日志重复入库。
- 单次尝试与全部尝试。 面板只记最后一次成功、供应商侧还有其他请求时,逐次核对重试与超时。
- token 数与金额。 数量一致而金额不同,转查模型价格、缓存、档位和独立计费项目。
本地统计 bug 确实可能造成“像是被多扣费”的观感。例如 browser-use 的历史问题曾把 reasoning_tokens 加到 completion_tokens,抬高本地用量与成本显示;该问题已通过修复关闭。这是重复计数的具体案例,不能作为供应商重复扣款的证据。项目问题与修复记录
只有把原始用量、自己的计算结果与实际结算记录对到同一批请求,才有依据判断差额来自哪里。先让每个 token 在正确的位置出现一次,再讨论价格或扣款,排查会快得多。



