# 推理 Token 到底怎么计费？Gemini、OpenAI、Claude 的去重对账方法

> 对照三家原生 API 的 usage 字段，区分输出总数和思考明细，避开重复相加与 Gemini 思考漏算，并处理流式累计、缺失数据和重试造成的账单差额。

- Source: https://www.aifreeapi.com/zh/posts/reasoning-token-billing
- Language: zh
- Published: 2026-09-07
- Updated: 2026-09-12
- Publisher: AI Free API (https://www.aifreeapi.com)

**推理 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 输出计数说明](https://developers.openai.com/api/docs/guides/token-counting#understand-output-token-counts)、[Gemini UsageMetadata](https://ai.google.dev/api/generate-content#UsageMetadata)、[Claude 思考成本说明](https://platform.claude.com/docs/en/build-with-claude/thinking-steering-and-cost#pricing)

这张表按**接口**分类。通过第三方网关、兼容 OpenAI 的端点或转换后的 SDK 字段调用 Gemini 时，不能只看模型名就执行 Gemini 原生加法。适配器可能已经把思考合并到 `completion_tokens`；再次相加就会重复。应查该端点和适配器版本的字段说明，并保留转换前的 usage。Gemini Interactions、Live、Vertex 以及工具和多模态响应，也需要各自的使用量与价格口径。

## 用三条记录，定位多算和漏算

![OpenAI、Gemini 和 Claude 的三张示例用量卡片，对照输出总数与思考明细](https://www.aifreeapi.com/posts/zh/reasoning-token-billing/img/usage-comparison.webp)

以下只计算输出费用。为便于验算，统一**假设**输出单价为每百万 token 10 美元；这不是任何模型的现行报价。真实计算应代入请求当时的模型、服务档位和价格。

### OpenAI：1,186 已经包含 1,024

OpenAI 推理指南给出的 Responses 示例中，输入为 75，输出为 1,186，其中推理为 1,024，总 token 为 1,261。下面保留与本题有关的字段：[官方推理指南](https://developers.openai.com/api/docs/guides/reasoning)

```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 数”，但不能直接命名为“用户可见答案 token”。生成统计还可能涉及格式、通道或工具结构；即便推理明细为零，输出总数也不保证等于把屏幕文字重新分词后的结果。[OpenAI 对输出计数差异的解释](https://developers.openai.com/api/docs/guides/token-counting#understand-output-token-counts)

Chat Completions 的原则相同，只是总数字段换成 `completion_tokens`。不要为了“统一变量名”，把已包含推理的总数转换成“总数加推理”。

### Gemini：只算候选输出，会漏掉思考

这是一条用于说明字段关系的**构造的用量记录**，不是实测请求：

```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 字段定义](https://ai.google.dev/api/generate-content#UsageMetadata)

Google 的价格表把思考纳入输出定价；查 Batch 请求时也要看该模型的 Batch 输出栏，不能一律按 Standard 价格给思考计费。输入中的缓存内容另有统计和价格处理，不能因为 `promptTokenCount` 包含缓存就把缓存量再加一遍。[Gemini API 定价](https://ai.google.dev/gemini-api/docs/pricing)

### Claude：348 是总数，312 是其中的思考

Claude 当前文档示例列出输入 25、输出 348、思考 312：[思考 token 与费用说明](https://platform.claude.com/docs/en/build-with-claude/thinking-steering-and-cost#pricing)

```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 流式响应文档](https://platform.claude.com/docs/en/build-with-claude/streaming)

当前 Claude 文档也指出，思考明细会出现在最终 `message_delta`。若只读首个事件，可能拿到不完整的拆分；若最后一个事件未收到，就应保留未知状态。[Claude 思考成本说明](https://platform.claude.com/docs/en/build-with-claude/thinking-steering-and-cost#pricing)

### 同一个提示词重试，不一定是同一笔消耗

对账要区分一次业务操作和它触发的多次 API 尝试。超时之后的重试可能产生第二次调用；客户端没显示第一份答案，也不能据此判断第一次未被处理。

建议把业务操作 ID、尝试编号、供应商请求或响应 ID、模型与时间一起保留。对同一请求的重复日志做去重，对不同尝试分别核对。不要按提示词文本去重，否则相同问题的真实多次调用也可能被错误抹掉。

### 最终答案很短，不代表输出成本应该很低

OpenAI 的输出预算包含隐藏推理，响应可能在可见答案产生前就达到预算，并产生费用。Claude 的隐藏思考同样计入输出；展示的思考摘要长度不能代替实际思考计数，官方说明摘要生成本身不另收费。[OpenAI 推理预算](https://developers.openai.com/api/docs/guides/reasoning)、[Claude 思考与摘要费用](https://platform.claude.com/docs/en/build-with-claude/thinking-steering-and-cost#pricing)

此外，Claude 后续请求保留的历史思考内容可能进入输入计费，具体取决于模型的上下文保留行为。上一轮作为输出生成、下一轮作为输入处理，是两次请求中的不同计费环节；不能直接判为同一条 usage 的重复加法。[Claude 思考文档](https://platform.claude.com/docs/en/build-with-claude/thinking)

### 输出费用算对了，也不等于整张账单算完了

完整对账还需要普通输入、缓存读取或写入、实际模型、服务档位、生效日期，以及适用的工具、存储或多模态项目。先用本文方法核对输出量，再给各项匹配价格。不要把含输入的 `total_tokens` 或 `totalTokenCount` 全部乘以一个输出单价，也不要套固定的“推理模型贵几倍”倍率。

如果下一步是比较不同工作负载适合哪家供应商，可继续阅读[三家 API 的成本决策指南](/zh/posts/gemini-api-vs-openai-vs-claude-2026-cost-guide)；其中历史价格需要再与请求日期的官方价格核对。

## 发现“多扣费”时，先提交哪几项证据

![从用量字段、累计事件、重试请求到模型价格的账单差额排查流程](https://www.aifreeapi.com/posts/zh/reasoning-token-billing/img/billing-investigation.webp)

先选一条差额明确的请求，拿出原始 usage、接口名称、请求或响应 ID、实际模型、请求时间与服务档位，再附上本地公式和适用价格。按这个顺序比较：

1. **原始字段与面板总量。** 差额正好等于推理明细时，优先检查子项是否被重复相加；Gemini 少了思考量时，检查是否只计候选输出。
2. **单次请求与事件汇总。** 总量像是多条累计快照之和时，检查流事件；同一请求出现多次时，检查日志重复入库。
3. **单次尝试与全部尝试。** 面板只记最后一次成功、供应商侧还有其他请求时，逐次核对重试与超时。
4. **token 数与金额。** 数量一致而金额不同，转查模型价格、缓存、档位和独立计费项目。

本地统计 bug 确实可能造成“像是被多扣费”的观感。例如 browser-use 的历史问题曾把 `reasoning_tokens` 加到 `completion_tokens`，抬高本地用量与成本显示；该问题已通过修复关闭。这是重复计数的具体案例，不能作为供应商重复扣款的证据。[项目问题与修复记录](https://github.com/browser-use/browser-use/issues/4065)

只有把**原始用量、自己的计算结果与实际结算记录**对到同一批请求，才有依据判断差额来自哪里。先让每个 token 在正确的位置出现一次，再讨论价格或扣款，排查会快得多。
