Grok API 成本边界先算清
立项会上被问到「这东西一个月多少钱」,回答「大概几百块,不会超过一千」。上线三周,控制台显示四位数。回头翻单价表,发现自己记的价格是对的——漏掉的不是数字,而是维度。
文本按 token 计价,图像按张,视频按秒,语音按分钟,语音合成按字符,工具调用另按次数算。文本 token 通常体现在响应体的用量字段里,其余几条一般要在账单侧单独看。用「请求数 × 单价」估算,注定只算到一部分。
这一节不教省钱技巧,只做两件事:上线前把维度盘完,然后判断先动哪个变量。
一、先把计费维度盘完
按 2026-11-04 官方模型页与定价页,文本之外还有五条独立的计价线:
| 维度 | 计价单位 | 官方页数值示例 | 是否进文本 token 账 |
|---|---|---|---|
| 文本生成 | 每百万 token | grok-4.7 输入 $2.00 / 缓存 $0.50 / 输出 $6.00 |
是 |
| 图像生成 | 每张 | grok-imagine-image-2.0 $0.04 |
否 |
| 视频生成 | 每秒 | grok-imagine-video $0.050 |
否 |
| 语音对话 | 每分钟 | grok-voice-3.0 $0.08,另加 $0.004 文本输入 |
部分 |
| 语音转写 | 每小时 | 非流式 $0.10,流式 $0.20 | 否 |
| 文本转语音 | 每百万字符 | $15.00 | 否 |
文本那一行特意把缓存价也列出来了:后面算例里「五成命中缓存」能砍掉多少成本,靠的就是 $0.50 与 $2.00 的差,只看输入与输出两个数算不出来。
另有一条容易漏的:官方工具页写明,工具调用由token 用量 + 工具调用次数两部分组成,一次请求可能触发多次工具调用。也就是说,同一笔对话在账单上可能拆成「文本 token」与「工具次数」两个来源,把一个函数算准了也未必等于估算准确。
所以立项估算的第一步不是套公式,而是列清单:这个功能会碰到哪几条线,每条线的量级靠什么参数决定。
二、月成本量级与敏感度排序
下面的脚本是纯计算,不联网、不读真实响应。它回答两个问题:月成本在什么量级,以及哪个变量最值得动。
"""月成本量级与敏感度:纯计算,不联网。
单价单位 USD / 每 1M token,核验日期 2026-11-04。
提示达到 20 万 token 的请求,整个请求的所有 token 按高档计价。
本模型把跨阈值请求单独建模:它们的提示量级远高于普通请求。
"""
from dataclasses import dataclass, replace
PRICE = {
"grok-4.7": {"in": 2.00, "cached": 0.50, "out": 6.00,
"in_long": 4.00, "cached_long": 1.00, "out_long": 12.00},
"grok-4.3": {"in": 1.25, "cached": 0.20, "out": 2.50,
"in_long": 2.50, "cached_long": 0.40, "out_long": 5.00},
}
@dataclass(frozen=True)
class Workload:
name: str
daily_requests: int
prompt_tokens: int # 普通请求的提示量
output_tokens: int
long_share: float = 0.0 # 提示达到阈值、整包高档计费的请求占比
long_prompt_tokens: int = 0 # 这部分请求的提示量;0 表示与普通请求相同
cache_share: float = 0.0 # 输入中命中缓存的比例
def month_usd(w: Workload, model: str = "grok-4.7", days: int = 30) -> float:
p = PRICE[model]
req = w.daily_requests * days
long_req = req * w.long_share
short_req = req - long_req
short_prompt = short_req * w.prompt_tokens
long_prompt = long_req * (w.long_prompt_tokens or w.prompt_tokens)
short_cached = short_prompt * w.cache_share
long_cached = long_prompt * w.cache_share
cost = (
(short_prompt - short_cached) * p["in"]
+ short_cached * p["cached"]
+ (long_prompt - long_cached) * p["in_long"]
+ long_cached * p["cached_long"]
+ short_req * w.output_tokens * p["out"]
+ long_req * w.output_tokens * p["out_long"]
)
return round(cost / 1_000_000, 2)
BASE = Workload("基线", daily_requests=5_000, prompt_tokens=3_000,
output_tokens=400, long_share=0.02,
long_prompt_tokens=210_000)
VARIANTS = [
replace(BASE, name="请求量 +50%", daily_requests=7_500),
replace(BASE, name="输入五成命中缓存", cache_share=0.5),
replace(BASE, name="长请求占比降到 1%", long_share=0.01),
replace(BASE, name="输出 +50%", output_tokens=600),
]
if __name__ == "__main__":
base_cost = month_usd(BASE)
print("基线月成本 USD:", base_cost)
print("| 变动 | 月成本 USD | 差额 | 幅度 |")
print("| --- | --- | --- | --- |")
for w in VARIANTS:
cost = month_usd(w)
diff = round(cost - base_cost, 2)
print(f"| {w.name} | {cost:.2f} | {diff:+.2f} | {diff / base_cost:+.1%} |")
long_share 与 long_prompt_tokens 是这一版的关键。只给占比、不给这部分请求的提示量,会算出一个看似合理的假结论:如果 2% 的请求只是「单价翻倍」而 token 量不变,它们对账单的影响自然也只有 2% 左右。但现实中能跨过 20 万 token 阈值的请求,提示本身就在 20 万量级——请求数占 2%,token 占比可以超过一半。
其余参数也都不是官方给你的数字,而是你要显式说出来的假设。假设写在参数里,评审时能被质疑,能被改,这正是脚本存在的意义。
三、参数含义与建模口径
| 参数 | 含义 | 容易漏的地方 |
|---|---|---|
prompt_tokens |
普通请求带进去的全部提示 token | 只算用户问题,漏系统提示与检索片段 |
long_share |
提示达到阈值、整包高档计费的请求占比 | 用平均 token 估算,掩盖长尾 |
long_prompt_tokens |
跨阈值请求的典型提示量 | 省略它,等于假设长请求和短请求一样长 |
cache_share |
输入中命中缓存的比例 | 假定「开了缓存就有五成」 |
output_tokens |
每次生成的 token 数 | 流式只统计了最后一段增量 |
days |
月按 30 天折算 | 与自然月账单不一致,差额留给对账 |
三点需要说清:
- 平均值会骗人。5000 次请求平均 3000 token,听起来很温和;真实分布可能是 4900 次 3000 token 加 100 次 21 万 token。跨阈值的是那 100 次,而平均值里看不出来。所以
long_share与long_prompt_tokens必须分开给,不能从均值反推。 - 缓存命中不是开关。它取决于前缀是否稳定、服务端是否还有该前缀的状态。本模型把
cache_share做成输入参数,是为了让「假设」暴露在代码里,而不是让你相信某个固定数字。 - 估算不是账单。工具调用、图像、语音不在这个函数里。要分段记账,不要用一种估算覆盖全部计费项——这条在第 5 章还会出现,因为它是成本工程里最常被违反的纪律。
四、预期输出与异常分支
运行 __main__,输出应为:
基线月成本 USD: 3769.2
| 变动 | 月成本 USD | 差额 | 幅度 |
| --- | --- | --- | --- |
| 请求量 +50% | 5653.80 | +1884.60 | +50.0% |
| 输入五成命中缓存 | 2493.45 | -1275.75 | -33.8% |
| 长请求占比降到 1% | 2514.60 | -1254.60 | -33.3% |
| 输出 +50% | 3952.80 | +183.60 | +4.9% |
这张表最值钱的地方,是它把「占比」和「成本占比」拆开了。基线里 2% 的长请求贡献了 630M 输入 token,比其余 98% 的短请求合计 441M 还多;按高档单价算,这 2% 的请求吃掉约 67% 的账单。
这也接上了 5.1 的结论:那里算出单次请求跨过阈值会跳到 2.32 倍,看起来只是「一次请求贵了」;放到组合视角,2.32 倍乘上远超比例的 token 量,就变成了账单主力。所以「长请求占比降到 1%」能砍 33.3%,与五成缓存命中砍 33.8% 几乎是同一量级的杠杆;而「输出 +50%」只带来 4.9%。
优化顺序由此反过来了:先看缓存与长尾请求,再看输出长度。请求量 +50% 是线性放大,属于对照组,不是优化手段。
常见失败分支:
| 现象 | 原因 | 处理 |
|---|---|---|
| 估算只有账单三分之一 | 漏了工具调用与媒体维度 | 按维度分账,别用一个函数兜 |
| 上线后成本突然跳一档 | 少量长请求跨过阈值,整包按高价计 | 按分位数建模,别只看平均 token |
| 缓存收益始终不出现 | 前缀每次都在变,缓存未命中 | 先固定前缀顺序(见 5.2) |
| 换了模型但估算没变 | 单价表没跟着模型走 | 把模型名写进账目,按模型取价 |
五、判据卡
| 判断项 | 该这么做 | 不该这么做 |
|---|---|---|
| 立项估算 | 按六个维度分别列,再合计 | 用「请求数 × 单价」一句话带过 |
| 工作量建模 | 给分位数、跨阈值占比与该档提示量 | 只用平均 token,或只给占比不给量级 |
| 优化顺序 | 缓存与长尾请求优先,再看输出长度 | 盯住单请求的 2.32 倍跳变就下结论 |
| 缓存假设 | 写成显式参数并标注来源 | 假定一开就命中五成 |
| 赠送额度与预付 | 到控制台当前页面核对 | 把第三方说法写进预算表 |
这张卡的顺序很关键:先看绝对差额,是因为评审会只关心总数;再看幅度,是为了判断「这个变量值不值得为它改架构」。两个顺序颠倒,就会得出「长请求只占 2%,不用管」这种听起来专业、实际漏掉三分之二账单的结论。
六、来源与核验
- 官方定价页:
https://docs.x.ai/developers/pricing(核验日期 2026-11-04)。文本分档单价与计价单位来自该页。 - 官方模型页:
https://docs.x.ai/developers/models(核验日期 2026-11-04)。上下文窗口、图像/视频/语音价目表,以及「提示达到阈值的请求整包按高档计费」的说明均来自该页。 - 官方工具页:
https://docs.x.ai/developers/tools/overview(核验日期 2026-11-04)。工具调用由 token 用量与调用次数两部分计价的表述来自该页。 - 本文数值为教学算例,按美元展示;
BASE的请求量与提示量是虚构假设,不是任何真实业务的观测值。实际计费以官方页与开发者控制台当前显示为准。是否存在赠送额度、预付要求与充值规则,也以控制台当前页面为准。
七、动手试
- 把
BASE换成你的真实日请求量、平均 token 与长请求提示量,跑一遍,看最大差额落在哪个变量上。它和你原本以为的一样吗? - 给
Workload加image_count与audio_minutes两个字段,把图像与语音折进合计。想一想:这两项该不该参与「按差额排序」?它们和 token 成本的优化手段有什么区别? - 把
long_prompt_tokens改成与prompt_tokens相同(即 3000)重跑,观察「长请求占比」这一行的幅度变化。那个结果为什么不能用来做决策?

TRAE-AI编程


更多建议: