
译者按:作者踩的坑相当典型——月度账单爆掉,但不知道烧钱的是谁。我读完觉得最有价值的是他把「计费」这件事从应用层抽到了凭证层,这套思路在国内多供应商(阿里云百炼、百度、腾讯混用)的场景下同样适用,整理出来供国内做 AI 应用的朋友们参考。
上个月的 AI 调用账单:47300 元。我原本的预算:9000 元。凌晨两点收到微信支付的推送通知,整个人清醒了——这个数字怎么可能?
但数字没错。更要命的是,我不知道是哪个用户把预算烧穿的。监控面板只显示了总量,我的日志里有几千次请求,但两者对不上。等我溯源完(一个用户,跑了自动化脚本,大概每分钟 60 次请求跑了整整两天),损失已经发生了。
六周后,AI 账单降到了 14850 元——降幅接近 60%。产品功能没变,用户还在增长。这篇文章讲的就是我做了什么,包括真实的代码、账务数字,以及几个关键的架构决策。核心其实就是一点:为每个用户生成独立的 API Key,并设置硬性花费上限。
我最初踩的坑(以及为什么行不通)
第一反应是自己做计费。PostgreSQL 建一张表:requests(user_id, model, input_tokens, output_tokens, cost_micros, created_at)。每次请求记一行,按 user_id 汇总。搞定。
没搞定。三个地方出了问题:
调用国产大模型的流式接口时,中途取消请求的话,直到整个流结束才知道用了多少 token。我在这上面踩了两次坑——第一次是漏算了取消的情况,第二次是加了重试逻辑但没去重。
「记录每条请求再汇总」是观察层,不是执行层。等凌晨的定时任务跑出来时,那个失控的用户可能已经烧了 3600 元了。要真正执行上限,每次请求前都得同步查一次数据库——这等于把数据库查询放到了 API 调用的热路径上,性能问题随之而来。
我当时不只是用一家模型供应商。有些流程跑阿里云百炼,有些跑百度文心,有些跑 DeepSeek。每家的定价不同、token 计算方式不同(百炼把缓存命中部分单独计价,腾讯把输入输出打包),我的 PostgreSQL 汇总脚本里塞满了供应商特定的定价逻辑和针对不同响应格式的解析代码。每新增一个模型,计量路径就要改一次。
到第二周,我意识到自己在构建一个错误的层。我真正需要的是一个能帮我做计量的网关,让应用代码回归应用逻辑本身。
核心方案:每用户 API Key + 硬性上限
微信支付的分级商户、阿里云(Alibaba Cloud,简称 AC)的 RAM 子账号、GitHub 的细粒度个人访问令牌——现代多租户基础设施都用同一套模式:持有一个主凭证,为每个用户生成子凭证,每个子凭证有自己的权限和限额。成本追踪和访问控制天然在凭证层面定义好,不需要额外去凑。
在 AI 推理场景下,原理相同:
你注册一个网关服务,获得一个主 Key。
用户的应用每创建一个新用户,就动态生成一个子 Key,并设置 70 元(约 10 美元)的花费上限。
该用户的请求带上自己的 Key,网关在转发前先检查上限。
月末拉取每个用户的用量,想怎么计费就怎么计费。
整个流程的代码大概 30 行:
第一步——用户注册时生成 Key
用户注册时,在服务端执行:const userKey = await gateway.keys.create({
user_id: user.id,
name: user.email,
scope: "standard",
max_spend_usd: 10, // 硬上限——这就是关键
});
await db.users.update(user.id, {
ai_gateway_key: userKey.secret,
});
第二步——在官方 SDK 里使用用户的 Key
import OpenAI from "openai";
每次请求时,从数据库取出用户的 Key:const client = new OpenAI({
baseURL: "https://api.gateway.ai/v1",
apiKey: user.ai_gateway_key,
});
const completion = await client.chat.completions.create({
model: "qwen-plus",
messages: [...],
stream: true,
});
这就是全部的客户端改动。SDK 不知道自己在调一个网关——响应格式、错误处理、流式返回都一样,只是 baseURL 变了。百度的 SDK 也是同样用法(设置 BAIDU_BASE_URL 环境变量即可)。
第三步——用户触达上限时,返回 402 并优雅提示
网关会在用户额度耗尽时自动返回 402 Payment Required。在你的前端捕获这个响应,弹出升级提示:
try {
const completion = await client.chat.completions.create(...);
} catch (err) {
if (err.status === 402) {
showUpgradeModal({
message: "您的 AI 调用额度已用完,升级以继续使用",
planLink: "/pricing",
});
return;
}
throw err;
}
第四步——月末拉取用量数据
const usage = await fetch("https://api.gateway.ai/v1/usage?from_ms=...&to_ms=...", {
headers: { Authorization: `Bearer ${process.env.GATEWAY_MASTER_KEY}` },
}).then(r => r.json());
// usage.by_key[].cost_micros — 除以 1000000 得到元
for (const k of usage.by_key) {
await wechatPay.invoiceItems.create({
customer: getWechatCustomerByUser(k.user_id),
amount: Math.ceil(k.cost_micros / 10000), // 这里加了利润率
currency: "cny",
});
}
你想留多少利润是你的事。网关收上游成本加 7% 的服务费。你的账单可以按 token 数、按功能、按包月套餐来设,怎么都行。
六周内的变化(真实数字)
切换之后每周的账单变化如下。这些是真实数据——产品没变,用户还在增长:
周次 账单(元) 活跃用户 备注
0 47300 74 基线(那个 47300 的冲击月)
1 28620 78 用户 A 第 2 天触达 70 元上限
2 24480 85 5 名用户触达上限;3 人升级付费
3 21060 91 新增 80% 上限预警邮件
4 18135 97 调整套餐默认值:免费 35 元,付费 180 元
5 16290 104 清理流失用户——问题用户已移除
6 14850 112 进入稳定状态
从数字里能看出几件事,比单纯的百分比更有价值:
失控用户被立刻控制住了。第 1 周第 2 天,用户 A 触达上限。他的脚本不断重试,不断收到 402。该用户当月总花费:70 元。上个月预估:16200 元。
触达上限本身就是升级信号。第 2 周有 5 名用户正常触达上限——他们是真的在用产品的深度用户。显示升级弹窗后,3 人完成了付费转化。触达上限后的升级转化率高达 60%——这是我之前完全没有办法看到的信号。现在「用户触达上限」已经成了我最好的销售线索。
套餐默认值会产生复合效应。有了每用户花费数据,我重新设计了免费档:从「70 元还算宽松」变成「35 元有限额」。付费档(168 元/月)给了 180 元的用量。转化率上涨了,因为免费档更快触达上限,而付费用户平均贡献收入现在高于 AI 调用成本——第一次实现了可持续的单位经济模型。
这套方案解锁的不只是成本控制
杀手级功能不是那 60% 的账单降幅,而是「每用户成本归属」这件事现在成了产品的基础原语,而这个原语是可以组合出更多价值的:
队列分析( cohort analysis)
按注册时间、套餐、地区、来源渠道给用户分组。看每组用户的「平均成本」「触达上限比例」「产生第一个价值的中位时间」。这类分析能把「凭感觉定价」变成真实的单位经济数据。
异常检测
某用户第 1 周花费是同组中位数的 10 倍?要么是深度用户(好信号——主动联系,推定制套餐),要么是恶意用户(也是好信号——在烧更多钱之前审查并封禁)。
细粒度功能定价
之前按估算定价:「AI 功能每次调用大概 0.35 元」。现在有了真实数据:图片生成 0.28 元,摘要 0.02 元,Agent 循环 1.26 元。定价不再是拍脑袋。
按用户分配模型路由
免费用户路由到 DeepSeek V3(输入 token 每百万 1.9 元)。付费用户路由到阿里云百炼(输入 token 每百万 21 元)。人均成本差 10 倍,但用户感知到的产品质量差距没那么大。
如果重来,我会怎么做得不一样
几个回头看来的决策,列得简短是因为事后分析总是说起来容易:
第一天就给每个用户生成 Key,别等到被账单教育了才做。事后加这套逻辑要处理一次麻烦的数据迁移;但不做的话,只要一个恶意用户就能让你的账单失控。
免费档上限设低一点——从 70 元起,降到 21 元。真正需要的人会付费;不需要的人你给再多额度也不会转化。
80% 上限预警邮件第一天就加上,别等到第 3 周。意外触达上限的用户会流失;提前预警并给出清晰升级路径的用户会转化。
看网关的响应时序数据,不只是花费。延迟数据能暴露花费数据暴露不了的问题(一个用户反复走到慢路径,说明产品里有地方需要优化)。
总结
把按用户计费做成凭证层原生支持的特性,它就不会再是事后补救。给每个用户生成 Key、设上限、插进官方 SDK、月末拉用量——这是全部流程。自己构建这套基础设施是可行的,但会分散精力;用网关方案的话,一个注册账号加一个 baseURL 改一下就够了。
有 200 美元的体验额度可以试用。和 OpenAI、Anthropic、阿里云、腾讯云、Vercel AI、LangChain、LlamaIndex 的 SDK 都兼容。第一个月的账单异常,你不会再遇到第二次。