登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  人工智能

OpenAI API 怎样读取模型返回的使用量字段

来源:17golang原创

时间:2026-10-26 22:23:52 234浏览 收藏

OpenAI API 返回的使用量不在模型文本里,而是在响应对象的 usage 字段中。当前最容易混淆的是两套命名:Responses API 读取 input_tokens、output_tokens 和 total_tokens;Chat Completions 读取 prompt_tokens、completion_tokens 和 total_tokens。先判断接口类型,再读取对应对象,就不会把统计逻辑写进 choices 或输出文本解析器。

官方文档:https://developers.openai.com/api/reference/resources/responses/methods/create

Chat Completions 文档:https://developers.openai.com/api/reference/resources/chat/subresources/completions/methods/create

要点速览
  • Responses API 的使用量入口是 response.usage,Chat Completions 的入口是 completion.usage。
  • cached_tokens 和 reasoning_tokens 是总量中的明细,不要再加回 input_tokens 或 output_tokens。
  • 流式 Chat Completions 只有开启 include_usage 后才会出现最终统计块;中断时要允许 usage 缺失。

先分清两种响应对象的字段名

如果请求走 Responses API,SDK 返回的是 response 对象,统计字段位于 response.usage。如果旧代码仍使用 Chat Completions,则对象通常叫 completion,字段名也随之改为 prompt_tokens 和 completion_tokens。两者的 total_tokens 都表示本次请求的总 token 数,但不能把两套字段混写。

接口输入总量输出总量常见明细
Responses APIinput_tokensoutput_tokensinput_tokens_details.cached_tokens、output_tokens_details.reasoning_tokens
Chat Completionsprompt_tokenscompletion_tokensprompt_tokens_details.cached_tokens、completion_tokens_details.reasoning_tokens

Responses API 的官方接口地址是:https://api.openai.com/v1/responses。下面的代码只读取 SDK 已返回的对象,不把示例中的数字当成固定结果。

import os
from openai import OpenAI

client = OpenAI()

response = client.responses.create(
    # 用环境变量切换模型,避免把模型名写死在统计逻辑里。
    model=os.getenv("OPENAI_MODEL", "gpt-5"),
    input="用一句话说明什么是幂等请求。",
)

usage = response.usage
if usage is None:
    # usage 可能为空,调用方要把它当作“未知”而不是 0。
    raise RuntimeError("响应没有返回 usage,不能生成 token 统计")

input_detail = usage.input_tokens_details
output_detail = usage.output_tokens_details
stats = {
    "input_tokens": usage.input_tokens,
    "output_tokens": usage.output_tokens,
    "total_tokens": usage.total_tokens,
    # 这些是总量中的拆分项,不要再次累加到总量。
    "cached_tokens": getattr(input_detail, "cached_tokens", None),
    "reasoning_tokens": getattr(output_detail, "reasoning_tokens", None),
}
print(stats)
Responses API 中 response、usage、输入输出 token 和缓存推理明细的静态结构说明图
图1:结构说明图,展示 Responses API 响应对象与 usage 明细之间的静态关系,不是运行截图。

把总量和明细映射成自己的统计记录

接入日志或成本统计时,建议先统一成应用自己的字段,再交给后续存储。最重要的判断是:缓存 token 已包含在输入总量中,推理 token 已包含在输出总量中;它们适合做拆分分析,不是额外消耗。字段不存在时保留 None,这样能区分“接口没有提供”与“确实为零”。

def read_chat_usage(completion):
    # Chat Completions 使用 prompt/completion 命名,不要套用 Responses 字段。
    usage = completion.usage
    if usage is None:
        return None

    prompt_detail = getattr(usage, "prompt_tokens_details", None)
    completion_detail = getattr(usage, "completion_tokens_details", None)
    return {
        "input_tokens": usage.prompt_tokens,
        "output_tokens": usage.completion_tokens,
        "total_tokens": usage.total_tokens,
        "cached_tokens": getattr(prompt_detail, "cached_tokens", None),
        "reasoning_tokens": getattr(completion_detail, "reasoning_tokens", None),
    }

completion = client.chat.completions.create(
    # 兼容仍使用 Chat Completions 的项目。
    model=os.getenv("OPENAI_MODEL", "gpt-5"),
    messages=[{"role": "user", "content": "解释一次 API 重试的风险。"}],
)
print(read_chat_usage(completion))

这层映射还可以顺手记录模型名、请求 ID 和时间,但不要把 total_tokens 通过输入加输出再次计算后覆盖原值。官方返回的总量应作为本次请求的主统计字段。

流式响应要等最后一个 usage 块

非流式响应通常在整个响应对象中直接读取 usage。Chat Completions 流式请求则不同:需要设置 stream_options={"include_usage": True},中间块的 usage 通常为空,额外的最后一块才携带整次请求的统计。网络中断或主动取消时可能收不到最后一块,因此业务记录必须接受未知值。

stream = client.chat.completions.create(
    # include_usage 会在结束前追加一个携带整次统计的块。
    model=os.getenv("OPENAI_MODEL", "gpt-5"),
    messages=[{"role": "user", "content": "用三点说明如何记录 API 用量。"}],
    stream=True,
    stream_options={"include_usage": True},
)

final_usage = None
for chunk in stream:
    # 文本增量和 usage 是两条独立信息,先保存最后一个非空统计块。
    if chunk.usage is not None:
        final_usage = chunk.usage

if final_usage is None:
    # 中断时不要伪造 0;保留“未收到统计”的状态供重试或补记。
    print("usage unavailable")
else:
    print({
        "prompt_tokens": final_usage.prompt_tokens,
        "completion_tokens": final_usage.completion_tokens,
        "total_tokens": final_usage.total_tokens,
    })

如果统计对计费或配额很重要,可以同时记录请求是否完整结束,并把缺少最终 usage 的记录标记为待补偿状态。不要只因为流中已经收到文本,就认为本次 token 统计也完整。

Chat Completions 流式响应中增量块、最终 usage 块和中断边界的静态关系说明图
图2:边界说明图,展示流式增量、最终 usage 统计与中断状态的关系,不是执行时序截图。

上线前用四个判断避免统计失真

  • 入口判断:Responses 读 response.usage,Chat Completions 读 completion.usage。
  • 空值判断:usage 为空时记录未知,不要自动写成 0。
  • 明细判断:缓存和推理字段是总量拆分,不能重复加入总量。
  • 流式判断:只在收到最终 usage 块后提交完整统计;中断记录应保留缺失原因。

官方 token 统计说明还指出,报告的输出 token 不只等于用户可见文本,某些模型的格式、工具调用或其他内部结构也可能计入输出量。因此不要用字符串长度或可见词数反推 API 返回值。

常见问题

为什么 response.usage 是 None?

usage 是可选结果,流式响应尚未结束、请求被中断,或当前响应形态没有返回统计时都可能为空。把它记录为未知比填 0 更可靠。

cached_tokens 要不要加到 input_tokens 上?

不要。cached_tokens 是 input_tokens 的明细,应该用于分析缓存命中,而不是作为额外输入再次相加。

为什么输出文字不多,output_tokens 却更大?

API 统计的是生成的总输出 token,可能包含不可见的结构、工具调用或推理相关 token,不能只按最终展示文本估算。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>