LLM Token 计费与用量管控系统:大模型后端的成本治理,从黑箱消费到精细管控
一、大模型调用的成本失控:看不见的账单增长
大模型 API 的计费方式是按 Token 用量收费,输入和输出分别计价。这种计费模式导致了一个独特的成本管理难题:单次调用成本极低(如 GPT-4o 约 $0.005/次),但高频调用下成本累积惊人。一个日调用量 100 万次的 AI 服务,月成本可达 $15,000—$50,000。
更危险的是"成本失控"——某个业务方突然增加调用频率,或者某个 Prompt 模板意外消耗大量 Token(如输出过长、重复调用),成本可能在几天内翻倍。传统的事后对账方式无法及时发现这种异常,等到月度账单出来时损失已经造成。
Token 计费与用量管控系统的核心思路是:在 API 调用链路中嵌入实时计费和限流机制,将每次调用的 Token 用量精确记录到租户/项目维度,支持实时成本监控、预算告警和自动限流。
二、Token 计费系统的架构设计与多租户模型
Token 计费系统的核心是一个"用量采集 → 实时计费 → 预算管控"的三层架构。用量采集层在 API 调用的入口和出口分别记录 Token 数;实时计费层根据模型和计价规则计算费用;预算管控层根据租户的预算和用量趋势执行限流或告警。
flowchart TB A[LLM API 调用] --> B[Token 用量采集中间件] B --> C[API 调用执行] C --> D[响应 Token 计数] D --> E[用量记录写入] E --> F[实时计费引擎] F --> G[租户账单更新] G --> H{预算检查} H -->|未超限| I[正常返回] H -->|接近阈值| J[告警通知] H -->|已超限| K[限流/降级] subgraph 用量采集 B D L[输入 Token 计数] M[输出 Token 计数] N[模型类型记录] O[调用延迟记录] end subgraph 计费规则 P[模型单价表] Q[租户折扣策略] R[阶梯计价规则] end P --> F Q --> F R --> F subgraph 预算管控 H J K S[日预算/月预算] T[速率限制] U[降级策略] end上图展示了 Token 计费系统的完整数据流。关键设计点在于"用量采集中间件"——它在 API 调用链路中透明插入,不影响业务逻辑,但能精确记录每次调用的 Token 用量。
三、生产级实现:Token 计费与用量管控引擎
以下是完整的 Token 计费系统实现,包含用量采集、实时计费和预算管控。
// TokenBillingSystem.java — Token 计费与用量管控引擎 import java.time.*; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; // ==================== 用量采集 ==================== record TokenUsage( String tenantId, String projectId, String modelId, int inputTokens, int outputTokens, long latencyMs, Instant timestamp ) {} // Token 用量采集中间件 // 设计意图:在 API 调用链路中透明插入,精确记录 Token 用量 class TokenUsageMiddleware { private final BlockingQueue<TokenUsage> usageQueue = new LinkedBlockingQueue<>(10000); private final UsageWriter usageWriter; public TokenUsageMiddleware(UsageWriter usageWriter) { this.usageWriter = usageWriter; // 异步消费队列,批量写入存储 startConsumer(); } // 记录单次调用的 Token 用量 // 设计意图:非阻塞写入队列,不影响 API 调用延迟 public void record(TokenUsage usage) { if (!usageQueue.offer(usage)) { // 队列满,丢弃并告警(不阻塞 API 调用) System.err.println("用量队列已满,丢弃记录: " + usage); } } private void startConsumer() { Thread consumer = new Thread(() -> { List<TokenUsage> batch = new ArrayList<>(100); while (true) { try { batch.add(usageQueue.take()); usageQueue.drainTo(batch, 99); // 批量取出 usageWriter.writeBatch(batch); batch.clear(); } catch (InterruptedException e) { break; } } }); consumer.setDaemon(true); consumer.start(); } } // ==================== 实时计费引擎 ==================== // 模型计价规则 record ModelPricing( String modelId, double inputPricePer1K, // 每千 Token 输入价格 double outputPricePer1K // 每千 Token 输出价格 ) {} class BillingEngine { private final Map<String, ModelPricing> pricingTable = new ConcurrentHashMap<>(); private final Map<String, TenantBudget> tenantBudgets = new ConcurrentHashMap<>(); // 初始化模型计价 public BillingEngine() { pricingTable.put("gpt-4o", new ModelPricing("gpt-4o", 0.0025, 0.01)); pricingTable.put("gpt-4o-mini", new ModelPricing("gpt-4o-mini", 0.00015, 0.0006)); pricingTable.put("claude-3-haiku", new ModelPricing("claude-3-haiku", 0.00025, 0.00125)); } // 计算单次调用费用 public double calculateCost(TokenUsage usage) { ModelPricing pricing = pricingTable.get(usage.modelId()); if (pricing == null) return 0; double inputCost = (usage.inputTokens() / 1000.0) * pricing.inputPricePer1K(); double outputCost = (usage.outputTokens() / 1000.0) * pricing.outputPricePer1K(); return inputCost + outputCost; } // 检查预算并执行管控 // 设计意图:在 API 调用前检查预算,超限则拒绝或降级 public BudgetCheckResult checkBudget(String tenantId, String modelId) { TenantBudget budget = tenantBudgets.get(tenantId); if (budget == null) return BudgetCheckResult.allowed(); double currentSpend = budget.currentMonthSpend(); double monthlyLimit = budget.monthlyLimit(); // 硬限制:月预算已用完 if (currentSpend >= monthlyLimit) { return BudgetCheckResult.denied("月预算已用完: " + currentSpend + "/" + monthlyLimit); } // 软限制:月预算使用超过 80% if (currentSpend >= monthlyLimit * 0.8) { // 降级:限制只能使用低成本模型 ModelPricing pricing = pricingTable.get(modelId); if (pricing != null && pricing.inputPricePer1K() > 0.001) { return BudgetCheckResult.degraded( "预算使用超过 80%,请使用低成本模型", "gpt-4o-mini" ); } } // 速率限制:检查每分钟调用次数 if (budget.currentMinuteCalls() >= budget.maxCallsPerMinute()) { return BudgetCheckResult.rateLimited("超过每分钟调用限制"); } return BudgetCheckResult.allowed(); } } // ==================== 预算管控 ==================== class TenantBudget { private final String tenantId; private final double monthlyLimit; private final int maxCallsPerMinute; private final AtomicReference<Double> currentMonthSpend = new AtomicReference<>(0.0); private final AtomicInteger currentMinuteCalls = new AtomicInteger(0); public TenantBudget(String tenantId, double monthlyLimit, int maxCallsPerMinute) { this.tenantId = tenantId; this.monthlyLimit = monthlyLimit; this.maxCallsPerMinute = maxCallsPerMinute; } public double currentMonthSpend() { return currentMonthSpend.get(); } public double monthlyLimit() { return monthlyLimit; } public int currentMinuteCalls() { return currentMinuteCalls.get(); } public int maxCallsPerMinute() { return maxCallsPerMinute; } public void addSpend(double amount) { currentMonthSpend.updateAndGet(v -> v + amount); } public void incrementCalls() { currentMinuteCalls.incrementAndGet(); } // 每分钟重置调用计数 public void resetMinuteCalls() { currentMinuteCalls.set(0); } } record BudgetCheckResult(boolean allowed, boolean degraded, String message, String fallbackModel) { static BudgetCheckResult allowed() { return new BudgetCheckResult(true, false, "", ""); } static BudgetCheckResult denied(String msg) { return new BudgetCheckResult(false, false, msg, ""); } static BudgetCheckResult degraded(String msg, String fallback) { return new BudgetCheckResult(true, true, msg, fallback); } static BudgetCheckResult rateLimited(String msg) { return new BudgetCheckResult(false, false, msg, ""); } } interface UsageWriter { void writeBatch(List<TokenUsage> batch); }四、边界分析与架构权衡
Token 计费系统的 Trade-offs:
Token 计数的精度。不同模型的 Tokenizer 不同,同一文本在不同模型中的 Token 数可能差异 10%—20%。计费系统应使用模型返回的实际 Token 数,而非本地估算。对于流式输出,需要在流结束后统计总 Token 数,无法在调用前精确预估费用。
计费延迟。异步批量写入用量数据会引入秒级延迟,预算检查基于的是"几秒前"的用量数据。在高频调用场景下,可能出现实际用量已超限但预算检查仍通过的情况。建议对高价值租户(月预算 > $1000)使用同步计费,确保实时性。
降级策略的用户体验。预算超限后的降级(切换到低成本模型)会导致输出质量下降,用户可能不理解为什么"AI 变笨了"。建议在降级时明确提示用户,并提供"追加预算"的快捷入口。
适用边界:该系统最适合多租户的 AI 平台(如 AI SaaS、内部 AI 中台)。对于单租户的 AI 应用,简单的月度预算告警即可,无需完整的计费系统。
五、总结
Token 计费与用量管控系统是大模型后端成本治理的基础设施。落地建议:第一步,在 API 调用链路中嵌入用量采集中间件,精确记录每次调用的 Token 数和模型类型;第二步,建立模型计价表和实时计费引擎,支持按租户/项目维度的成本归因;第三步,实现预算管控策略,包括硬限制(拒绝调用)、软限制(降级模型)和速率限制;第四步,建立成本看板,展示每日/每月的成本趋势和 Top 消费来源。核心原则是"成本可见、可控、可归因"——每次调用的成本都应可追溯,超支前有预警,超支后有降级。