OpenAI API 的账单之所以难懂,不是因为单价藏着掖着,而是因为一次请求往往同时触发多个计费维度:普通输入、缓存命中、输出、推理 Token、图片、长上下文倍率、批处理折扣。只看“每百万 Token 多少钱”,很容易低估真实成本。

本文按“计费单位—三笔主账—附加规则—估算公式—降本顺序”拆开讲。所有单价、折扣和门槛以 模型价格 与 OpenAI 官方文档为准,本文不写死数字。

说明:OpenAI、GPT、ChatGPT 是其权利人的商标,本文仅作技术说明。价格随模型和账期变化,做预算前请以站内模型价格为准。

一、先统一单位:Token 不是字数

Token 是模型处理文本的最小单位。一个汉字、一个英文单词、一个标点,可能对应一个或多个 Token;图片、工具定义、结构化 schema 也会被折算成 Token。做预算时不要用“字数 × 单价”估算,直接用接口返回的 usage 字段。

一次请求的输入通常包括:

  1. system prompt 和开发者指令;
  2. 历史对话消息;
  3. 工具(function)定义与参数 schema;
  4. 检索出来的文档、网页正文、代码片段;
  5. 图片、音频等非文本输入折算的 Token。

输出则包括模型生成的正文。对推理模型来说,内部推理 Token 也按输出计费,即使界面上看不到完整思考过程。

计费项 是否计入账单 说明
普通输入 Token 是 系统提示、历史消息、工具定义都算
缓存命中输入 是,按缓存价 只有稳定前缀才容易命中
输出 Token 是 通常单价高于输入
推理 Token 是,按输出价 推理模型常见,可能不展示全文
图片输入 是 按图像尺寸和细节档折算 Token
失败请求 视情况 多数 400 类不计,已生成部分可能计费

二、输入、输出、缓存:三笔主账

输入账看的是“每次请求都带上了什么”。很多团队的成本不是输在问题上,而是输在每次都把整份文档、整套工具定义、全部历史消息重新传一遍。输入单价再低,乘上请求量也会变成主要成本。

输出账看的是“模型写了多少”。输出单价通常高于输入,长报告、长代码、冗长解释都会放大成本。把 max_tokens 设成一个合理上限,要求模型输出结构化结果,比事后压缩更有效。

缓存账看的是“哪些内容被重复使用”。OpenAI 的提示缓存按前缀匹配:只有请求开头一段完全一致,后续内容才可能命中。把固定不变的 system prompt、工具定义、知识库说明放在最前面,把变化的用户问题放在最后,命中率才会稳定。缓存有最短前缀长度和存活时间,不是永久存储,也不是开了就一定命中。

一个常见的误判是:把缓存当成“第二次请求免费”。实际是缓存命中部分按较低的缓存读取价计费,未命中部分仍按普通输入价计费。账单上要分别看 cached_tokens 和普通输入 Token。

三、附加规则:长上下文、批处理、推理模型

除了三笔主账,还有几类规则会改变最终金额。

规则 触发条件 对账单的影响
长上下文倍率 单次输入超过模型设定门槛 整个请求按更高倍率计费,不是只对超出部分加价
批处理 使用 Batch 接口、接受异步返回 通常有单独折扣,适合离线任务
推理强度 调高 reasoning effort 推理 Token 增加,输出费用上升
图片细节档 使用高细节图片输入 图像折算 Token 增加
重试 429、5xx 后重新发送 每次重试都是新请求,可能重复计费

以站内 GPT-5.5 的资料为例,单次输入超过 272K Token 时,整个请求会触发输入、输出的倍率计费。这类门槛要写进预算模型,而不是等账单出来才发现。

四、一次请求的成本怎么估

把单价记作变量,公式如下:

单次请求成本 =
    未缓存输入 Token × 输入单价
  + 缓存命中 Token × 缓存读取单价
  + 输出 Token(含推理 Token)× 输出单价
  + 图片/工具等附加 Token × 对应单价

最终金额 = 单次请求成本 × 长上下文倍率 × 批处理折扣

做月度预算时,用最近一周的真实日志统计四类 Token 的占比,再乘单价。不要用“平均一次多少钱”倒推,因为长请求和短请求的分布差异很大,平均值会掩盖异常。

五、用量日志要记哪些字段

OpenAI 兼容接口的响应里通常带有 usage 对象。把下面几个字段写进日志,对账时能省很多时间:

import json
from openai import OpenAI

client = OpenAI(
    api_key="sk-你的密钥",
    base_url="https://api.zhongshangqihang.com/v1",
)

resp = client.chat.completions.create(
    model="gpt-5.5",
    messages=[{"role": "user", "content": "用三句话总结这份合同的风险。"}],
    max_tokens=800,
)

u = resp.usage
prompt_details = getattr(u, "prompt_tokens_details", None)
completion_details = getattr(u, "completion_tokens_details", None)

record = {
    "request_id": resp.id,
    "model": resp.model,
    "prompt_tokens": u.prompt_tokens,
    "cached_tokens": getattr(prompt_details, "cached_tokens", 0) or 0,
    "completion_tokens": u.completion_tokens,
    "reasoning_tokens": getattr(completion_details, "reasoning_tokens", 0) or 0,
    "total_tokens": u.total_tokens,
}
print(json.dumps(record, ensure_ascii=False))

如果网关或 SDK 版本不返回某个明细字段,用 getattr 兜底,不要让日志代码把主流程打断。

六、降本顺序:先做不花钱的

按投入产出排序,建议依次执行:

  1. 先量化:按业务线统计输入、输出、缓存和重试的 Token 占比,找出最大项。
  2. 压输入:用检索、摘要、分段处理替代整份文档直塞,避免触发长上下文倍率。
  3. 稳前缀:把 system prompt、工具定义、固定知识库放在最前面,减少缓存失效。
  4. 限输出:设置 max_tokens,要求 JSON 或固定字段,减少无效长回答。
  5. 做路由:简单分类、抽取、改写走轻量模型,复杂推理再上旗舰模型。
  6. 用批处理:离线任务走 Batch,接受更高的完成时延换取折扣。
  7. 设预算:按项目、按 Key 设额度上限和告警,异常调用能及时止损。
  8. 查重试:429 和 5xx 用指数退避,设置最大重试次数,避免重复计费。

七、常见问题

为什么输出比输入贵?

生成每个 Token 都需要模型逐步计算,算力成本高于读取已有上下文,所以输出单价通常更高。长回答、长代码、推理过程都会放大这部分费用。

缓存是自动生效的吗?

多数 OpenAI 兼容接口会自动尝试前缀缓存,但命中取决于前缀是否完全一致、是否达到最短长度、缓存是否还在存活期内。稳定前缀是提高命中率的前提。

推理模型的思考过程收费吗?

收费。推理 Token 通常按输出 Token 计价,即使客户端看不到完整思考内容。调高推理强度会同时增加延迟和费用。

同样的请求,两次扣费为什么不一样?

输入长度、输出长度、缓存命中、模型快照、重试次数都可能不同。用请求 ID 和 usage 日志对齐,才能定位差异。

网关价格和 OpenAI 官方价格一样吗?

不一定。网关可能包含汇率、支付通道和服务成本,也可能有活动折扣。具体以站内模型价格为准,不要拿旧截图做预算。

下一步

先注册中商起航 AI 网关,用一把测试 Key 跑通最小请求,把 usage 日志接上,再按业务线拆分预算。模型、上下文和价格以模型价格为准。

相关阅读: