获取 API 密钥

大模型 API 的 token 与计费:估算、读取、预算与算例

用大模型 API 就像用水电:不看表,月底账单会吓你一跳;看懂表,每一度都能心里有数。这里的“表”就是 token 计数。本文先讲 token 是什么、中英文怎么粗估,再教你读响应里的 usage 字段、给程序装上预算闸门,最后用三个写明假设的算例,把输入 $0.25、输出 $1.00(每百万 token)的价格落到具体场景里。

更新于

要点

  • 计费公式:输入 token 乘 $0.25,加输出 token 乘 $1.00,再除以一百万。
  • 估算只用于事前预判,真正的用量以响应里的 usage 为准,流式响应在最后一个块里带 usage。
  • 对话类应用的成本大头是反复发送的历史,裁剪历史最划算。
  • 预算控制三板斧:限制 max_tokens、限制历史长度、程序里累计花费并设日上限。

token 是什么,以及怎么算钱

token 是模型处理文本的最小计量单位,既不是字也不是词,而是介于两者之间的“碎片”。你可以把它想成水表上的刻度:用得越多,刻度走得越快。计费分两块:

项目单价(每百万 token)包含什么
输入$0.25messages 里所有内容:system、历史、本次提问
输出$1.00模型生成的回复

注意输出单价是输入的四倍,所以让模型“少说废话”比让你“少发点上下文”往往更省钱,不过对话场景里输入会因历史累积而膨胀,两头都要管。付费方式是预付费余额,不是订阅,余额不会过期;新账户有 $0.50 试用额度,7 天内有效。

多说一句容易混淆的地方:输出 token 是模型实际生成的数量,不是你设置的 max_tokens。max_tokens 只是上限,模型两百字就答完了,只按两百字对应的 token 收费。但在做预算预判时,要按上限来算最坏情况,这样才不会被偶发的长输出打个措手不及。

事前估算:中文、英文各怎么粗估

没发请求前,只能估。下面都是近似值,不同内容会有浮动:

文本粗估规则例子(假设)
中文每字约 1 到 1.5 token3000 字约 3000 到 4500 token
英文每 4 个字符约 1 token,或每词约 1.3 token1000 个单词约 1300 token
中英混排、代码按偏高的值估JSON 和符号多的内容更耗

估算的正确用法是做“量级判断”:这篇文章大概是一万还是十万 token,是否会撑破 100,000 的上下文,一次调用大概几分钱。要精确,就读 usage。一个好习惯是每个业务场景抽样跑几十次,统计 usage 的平均值,用它代替经验值。

举个把估算和实测结合起来的例子。假设你要处理一批 2000 字左右的中文客户反馈,按每字 1.3 token 粗估,单条约 2600 token,加上你的指令 200 token,输入约 2800。先挑 30 条跑一遍,读 usage 取平均,假如实测平均是 2500,那就把你的系数修正为约 1.15。之后整批的预算就按修正后的系数算,误差会小很多。这个实测数字只是演示方法的假设,你的数据会有自己的数值。

读取 usage:真正的“电表读数”

每次成功的响应都带 usage,含 prompt_tokens、completion_tokens、total_tokens 三项。流式响应不需要额外参数,最后会自动追加一个带 usage 的数据块。下面的代码同时演示两种读法,并把读数换算成美元:

import os
from openai import OpenAI

client = OpenAI(base_url="https://api.apidamoxing.com/v1", api_key=os.environ["API_KEY"])
PRICE_IN, PRICE_OUT = 0.25, 1.00     # 美元 / 百万 token

def cost(u):
    return (u.prompt_tokens * PRICE_IN + u.completion_tokens * PRICE_OUT) / 1_000_000

# 非流式:usage 在响应对象上
r = client.chat.completions.create(
    model="uncensored", max_tokens=200,
    messages=[{"role": "user", "content": "用三句话解释什么是通货膨胀。"}],
)
print(r.usage.prompt_tokens, r.usage.completion_tokens, f"${cost(r.usage):.6f}")

# 流式:最后一个数据块带 usage,其余块的 usage 为空
usage_last = None
stream = client.chat.completions.create(
    model="uncensored", max_tokens=200, stream=True,
    messages=[{"role": "user", "content": "再用三句话解释什么是通货紧缩。"}],
)
for chunk in stream:
    if chunk.usage:
        usage_last = chunk.usage
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
print()
if usage_last:
    print(usage_last.prompt_tokens, usage_last.completion_tokens, f"${cost(usage_last):.6f}")

流式时要留意:只有最后一个块有 usage,前面的块里它是空的,所以用 if chunk.usage 判断即可。把每次的读数记到日志或数据库里,月底对账、查异常、算单用户成本,全靠这份记录。

还有一个习惯值得养成:给每个业务功能打上标签,记账时一起记录。比如“摘要”“客服”“翻译”各记各的,月底一对账,就能看出到底哪个功能最花钱,是该优化 Prompt、裁剪历史,还是降低 max_tokens。没有标签,只有一个总数,想优化都无从下手。

三个算例(假设条件已写明)

算例一:客服问答

假设:每次请求输入 800 token(含 system 与知识片段),输出 200 token;每天 10,000 次。

单次费用:800 × 0.25 ÷ 1,000,000 = $0.0002,输出 200 × 1.00 ÷ 1,000,000 = $0.0002,合计 $0.0004。每天 $4.00,30 天 $120。按这个速度,$0.50 的试用额度可以支撑约 1250 次这样的调用。

算例二:长文章摘要

假设:每篇文章输入 20,000 token,摘要输出 600 token;共 500 篇。

单篇:20,000 × 0.25 ÷ 1,000,000 = $0.005,加上 600 × 1.00 ÷ 1,000,000 = $0.0006,合计 $0.0056。500 篇共 $2.80。可见长输入、短输出的任务很便宜。

算例三:多轮聊天与历史裁剪

假设:system 100 token;每轮用户输入 60 token,回复 150 token;一场对话 20 轮。

方案累计输入 token累计输出 token总费用
每次带全部历史43,1003,000约 $0.0138
只带最近 3 轮14,5403,000约 $0.0066

全历史方案的输入是:20 × (100 + 60) + 210 × (0 + 1 + … + 19) = 3,200 + 39,900 = 43,100。裁剪方案前三轮分别是 160、370、580,第 4 到第 20 轮每轮 790,合计 14,540。费用相差一半左右,而且轮次越多差距越大,因为全历史方案的输入是随轮数平方级增长的。

从这三个例子里可以总结出一个经验公式:成本主要由“请求次数 × 每次的输入输出量”决定,而每次的输入量里,历史和附带资料是最能动手脚的部分。客服场景降低知识片段长度、聊天场景裁剪历史、摘要场景分块并行,都是同一个道理:别让不必要的 token 白白付费。需要强调的是,这三个算例的数字全部来自上面写明的假设,你的实际数据请以 usage 为准。

再看一个反向的推算:如果你的月预算是 $30,想知道聊天产品每月能撑多少场 20 轮的对话。按算例三的“只带最近 3 轮”方案,每场约 $0.0066,$30 ÷ 0.0066 约 4545 场。同样的预算,若用全历史方案,每场 $0.0138,只够约 2174 场。这就是裁剪历史带来的实际差别。

预算控制:给程序装上闸门

估算只是预测,闸门才是保险。下面是一个按美元记账的日预算类:请求前用“最坏情况”预判(输出用满 max_tokens),请求后用真实 usage 记账。

class Budget:
    """按美元计的日预算。超出时拒绝新请求。"""
    def __init__(self, daily_usd):
        self.limit = daily_usd
        self.spent = 0.0

    def check(self, est_prompt_tokens, max_tokens):
        # 最坏情况:输出用满 max_tokens
        worst = (est_prompt_tokens * 0.25 + max_tokens * 1.00) / 1_000_000
        if self.spent + worst > self.limit:
            raise RuntimeError(f"预算不足:已用 ${self.spent:.4f},本次最坏 ${worst:.4f},上限 ${self.limit}")

    def record(self, usage):
        self.spent += (usage.prompt_tokens * 0.25 + usage.completion_tokens * 1.00) / 1_000_000

budget = Budget(daily_usd=5.0)
budget.check(est_prompt_tokens=1200, max_tokens=500)   # 请求前
# ……发请求……
# budget.record(response.usage)                        # 请求后

除了程序内的闸门,还有三个配置层面的手段:

  1. max_tokens 按任务设,别一律拉到上限,默认 2048,最大 16,000;
  2. 对话历史设长度上限,见聊天机器人搭建里的做法;
  3. 在账户里只充值你计划使用的额度,用完再补,预付费模式天然就是一道硬上限。

单价和余额规则以价格页为准,接口细节在参数详解。

最后总结成一张核对表:事前,估算量级、设置 max_tokens、检查历史长度;事中,流式输出时留意最后一个块的 usage;事后,记账并按功能归类、对比预算。三步走完,账就清楚了。

常见问题

输入和输出的 token 都要付费吗?

是的。输入每百万 token $0.25,输出每百万 token $1.00,分别按 usage 里的 prompt_tokens 和 completion_tokens 计算。

我可以提前算出确切费用吗?

只能估个量级。准确数字要看响应里的 usage,建议每个场景抽样统计平均值,用来预测。

余额会过期吗?

充值的预付费余额不会过期。新账户的 $0.50 试用额度有效期是 7 天。

怎样避免对话越聊越贵?

限制带入的历史长度,只保留最近几轮,或把更早的内容压缩成摘要,同时按任务设置合适的 max_tokens。

只需填写表单即可获取密钥

创建账户,复制密钥,修改 Base URL。配置就是这么简单。

获取 API 密钥