Token 实时计费 API 网关:设计与实现
Token 实时计费 API 网关:设计与实现
在大模型应用(AI SaaS)的产品化过程中,"按量付费"是目前最主流的定价方式。用户按实际调用的 Token 数量、模型类型等指标充值扣费。API 网关层需要处理一个核心问题:如何在防范欠费盗刷的同时,不显著增加高并发接口的延迟。
一、后付费模式下的欠费风险
传统 SaaS 按月订阅,收入相对可预测。AI 应用则不同,运行成本随使用频率波动很大。如果允许用户"先用后付",恶意用户可以用并发脚本刷接口,产生大量 Token 开销,然后弃号跑路。
这部分欠费由团队自己承担。对现金流紧张的初创项目来说,这是实实在在的风险。但反过来,如果每次大模型交互都去数据库读写余额,会给本就漫长的推理时间(Time to First Token)增加额外延迟,用户体验会明显下降。
核心问题就一个:如何在毫秒级完成余额检查和准入拦截,请求结束时再精确扣费。
二、计费流程设计
思路是"请求前预校验 + 请求后真实扣减":
graph TD A[用户请求大模型接口] --> B[网关截获请求并提取 User-ID] B --> C[读取该用户在本地缓存/内存中的可用余额 credit_balance] C --> D{credit_balance 是否大于本次调用所需预扣额度?} D -- 否 --> E[直接拦截请求: 返回 HTTP 402 Payment Required 错误并拦截] D -- 是 --> F[对用户余额进行临时锁定 / 扣除预估费用] F --> G[将请求转发给大模型后端服务并获取响应] G --> H[从模型响应中读取真实的 usage.total_tokens 消耗] H --> I[根据模型费率表精确计算出实际应扣费用 actual_cost] I --> J[更新账户余额: credit_balance = credit_balance - actual_cost] J --> K[返回模型生成内容并解锁该次扣费动作] E --> L[向客户端输出报错响应并发出充值引导提示]这个流程的好处是:欠费用户在请求一开始就被拦住,不会浪费模型推理资源;正常请求在结束时按实际用量扣费,账目清楚。
三、Node.js 实现示例
下面是一个用 Node.js 原生http模块实现的计费网关。不依赖第三方数据库客户端,用内存 Map 存储用户余额,解析大模型返回体中的usage字段做费用核算。
// billing_gateway.js - Token 实时计费中间件 const http = require('http'); // 模拟内存数据库,存储用户余额 (单位: 厘,1元 = 1000厘) const userAccounts = new Map([ ['user_01', { balance: 1500 }], // 余额 1.5 元 ['user_02', { balance: 10 }] // 余额 0.01 元,余额不足 ]); // 模型费率配置表:每 1000 个 Token 对应的厘数 const MODEL_PRICING = { 'gpt-3.5-turbo': 15 // 每 1k tokens 扣除 15 厘 (约 0.015 元) }; function logging(msg) { console.log(`[Billing Hub] ${msg}`); } const server = http.createServer((req, res) => { if (req.url === '/v1/billing/call' && req.method === 'POST') { const userId = req.headers['x-user-id']; const account = userAccounts.get(userId); if (!account) { res.writeHead(401, { 'Content-Type': 'application/json' }); return res.end(JSON.stringify({ error: 'Unauthorized: User account not found.' })); } // 检查余额是否低于最低消费阈值 (20 厘) if (account.balance < 20) { res.writeHead(402, { 'Content-Type': 'application/json' }); return res.end(JSON.stringify({ error: 'Payment Required: Credit balance is too low. Please recharge.', current_balance: account.balance })); } let body = ''; req.on('data', chunk => { body += chunk; }); req.on('end', () => { try { const payload = JSON.parse(body); const model = payload.model || 'gpt-3.5-turbo'; const pricing = MODEL_PRICING[model] || 15; // 模拟调用大模型 API 获取真实响应 const mockLlmResponse = { choices: [{ message: { role: 'assistant', content: 'Success response.' } }], usage: { prompt_tokens: 300, completion_tokens: 200, total_tokens: 500 } }; // 计算 Token 消费金额 const tokensUsed = mockLlmResponse.usage.total_tokens; const actualCost = Math.ceil((tokensUsed / 1000) * pricing); // 扣减账户余额 account.balance -= actualCost; logging(`User '${userId}' consumed ${tokensUsed} tokens. Deducted: ${actualCost}厘. Remaining: ${account.balance}厘`); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ data: mockLlmResponse, billing_details: { tokens_used: tokensUsed, cost_deducted: actualCost, remaining_balance: account.balance } })); } catch (err) { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Invalid payload request' })); } }); } else { res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Not Found' })); } }); const PORT = process.env.PORT || 9094; server.listen(PORT, () => { logging(`Billing gateway active on port ${PORT}`); });四、工程上的几个实际问题
落地这套体系时,有几个地方需要权衡:
1. 数据库写压力
高并发下每次 API 调用都扣余额,关系型数据库的行级锁会成为瓶颈。实际做法是用 Redis 这类内存缓存存当前余额,后台异步批量对账再同步到主库。
2. 预扣费的精度
不同模型的 Input/Output 费率不一样,响应长度在生成前也不知道。比较稳妥的做法是按"最大可生成 Token 长度"预锁定余额,这样能完全避免欠费,只是账目稍微复杂一点。
3. 异常退款
如果大模型超时或连接中断,响应没返回给用户,预扣的钱得原路退回。否则用户会觉得被白扣了,投诉处理起来很麻烦。
五、小结
计费系统本质上是帮团队守住账户安全。在网关层做前置余额检查和后置精确扣费,比每次请求都查数据库要轻得多。对初创团队来说,这套东西不需要很复杂,先把欠费风险控制住,后面再逐步优化。
质量评分
| 维度 | 评估标准 | 得分 |
|---|---|---|
| 直接性 | 直截了当,无过度宣告 | 9/10 |
| 节奏 | 长短句交错,段落结尾多样化 | 8/10 |
| 信任度 | 简洁明了,不过度解释 | 9/10 |
| 真实性 | 自然流畅,有具体细节 | 8/10 |
| 精炼度 | 无明显冗余 | 8/10 |
| 总分 | 42/50 |
主要修改说明
| 修改类型 | 原文 | 修改后 |
|---|---|---|
| 夸大象征意义 | "AI 商业化的底层支柱" | "Token 实时计费 API 网关:设计与实现" |
| 宣传性语言 | "核心支柱"、"隐性资金风险"、"财务防线" | 删除,用具体描述替代 |
| 三段式列举 | "高性能、高吞吐的 Token 实时计费与准入拦截系统" | 简化为"防范欠费盗刷的同时,不显著增加延迟" |
| AI 词汇 | "底层"出现 5 次 | 减少至 1 次 |
| 空洞总结 | "在算力成本风暴中稳健地拓展商业版图" | "对初创团队来说,这套东西不需要很复杂,先把欠费风险控制住" |
| 填充短语 | "极其轻量、高可用的" | 删除 |
| 三段式小节标题 | "生产级原生 API 请求计费统计与余额校验拦截器的 Node.js 实现" | "Node.js 实现示例" |