
在大模型平台LLM MaaS / Enterprise AI Gateway的商业化运营中计费与账单系统是承载平台现金流与多租户隔离的核心基石。大模型调用计费与传统 SaaS 的按月订阅或微服务按请求次数计费完全不同它具有极高的复杂性计量粒度极度碎片化按 Prompt Token、Completion Token、缓存命中 TokenPrompt Cache Hit、视觉多模态输入Resolution / Pixels等多个细分维度综合定价时效性与准确性的尖锐矛盾租户额度监控与欠费熔断必须在秒级完成一旦租户账户欠费却未能在秒级切断 API 密钥大模型高并发调用会在数分钟内产生数万元的坏账财务核算与大客户月结发票则要求绝对的准确性、幂等性、审计链可追溯性与阶梯折扣平账容不得任何流计算由于节点重启、乱序事件产生的微小偏差。单轨制的架构设计在这一场景下必然走向死胡同。单纯依赖 T1 离线批处理无法实现欠费实时拦截单纯依赖流计算如 Flink在大规模长连接、网络分区、反压与节点漂移场景下累加状态难逃微小误差累积且难以应对跨周期的阶梯折扣重算。解决该矛盾的工业级方案是构建“增量流计算预扣 离线全量对账修正”的双轨制账单架构。双轨制整体架构拓扑系统在数据链路设计上彻底解耦实时控制流与最终财务结算流------------------------------------------- | 网关集群 (LLM API Gateway) | ------------------------------------------- | 异步发射 Token 审计日志 | v --------------------------- | Kafka 计量日志 Topic | --------------------------- / \ / \ (实时轨: 秒级预算与欠费拦截) (离线轨: 绝对一致性与审计) / \ v v -------------------- -------------------- | 实时流处理计算引擎 | | 归档落盘对象存储 | | (Flink / Go-Worker)| | (Parquet / Iceberg)| -------------------- -------------------- | | 秒级扣减租户 Redis 额度 T1 离线批处理重算 | | v v ----------------------- -------------------- | 实时风控 (透支停机) | | 生产财务月结明细表 | ----------------------- -------------------- ^ | | 双轨平账对账 | -----------------------1. 实时轨Speed Layer增量流计算与额度预扣网关在每次流式传输完成后生成包含tenant_id、request_id、model、prompt_tokens、completion_tokens、cache_read_tokens的标准化计量事件。实时流计算引擎消费该消息按租户为 Key 进行窗口内滑动聚合计算出纳分级Nano-cents1元 $10^9$ 纳分彻底规避浮点数误差的预扣金额原子扣减租户在 Redis 集群中的可用信用池。一旦余额跌破安全阈值立即通过分布式发布订阅机制广播网关阻断该租户的后续鉴权请求。2. 离线轨Batch Layer全量审计与最终一致性结账原始计量事件双写或分流持久化至对象存储S3/OSS转化为列式存储Parquet。每日凌晨由批处理作业Spark / StarRocks执行 T1 结算任务。离线任务拥有完整的上下文信息可以精确处理复杂的跨月阶梯折扣规则例如月度消费突破 10 万元后后续 Token 享受 7 折跨周期异常请求冲正如模型网关由于后端 GPU 亚健康中途断连而发起的 SLA 补偿返还严格的幂等去重校验消除分布式网络中可能存在的少量重复计量消息。3. 平账机制Reconciliation Engine离线任务在清算完成后生成标准的不可篡改账单快照并与实时轨在过去 24 小时记录的账本流水进行差异比对。若存在微小偏离例如因网络抖动实时轨多扣或少扣了极少量额度对账引擎会生成一条类型为RECONCILIATION_ADJUSTMENT的单向对冲流水平滑更新租户的可用余额实现双轨闭环。核心对账与双轨平账引擎实现计费系统的核心技术挑战在于跨时钟周期的浮点精度控制与高并发幂等对冲。以下是基于 Go 1.27.1 实现的生产级双轨账单对账核心模块package billing import ( context database/sql errors fmt time ) // 货币单位采用纳分1 CNY 1,000,000,000 Nano-cents杜绝 float64 精度泄漏 type NanoCents int64 // BillItem 代表离线核算出的单项租户精准账单 type BillItem struct { TenantID string Date time.Time ModelID string PromptTokens int64 CompTokens int64 ExactCost NanoCents TierDiscount NanoCents // 阶梯优惠减免 FinalPayable NanoCents } // ReconciliationEngine 双轨对账平账处理器 type ReconciliationEngine struct { db *sql.DB redisClient RedisCreditClient } type RedisCreditClient interface { GetTenantRealtimeUsage(ctx context.Context, tenantID string, date string) (NanoCents, error) ApplyAdjustment(ctx context.Context, tenantID string, delta NanoCents, reason string) error } // ReconcileDailyBilling 执行日终平账闭环 func (re *ReconciliationEngine) ReconcileDailyBilling(ctx context.Context, dateStr string) error { // 1. 从离线分析数仓中提取核算完备的精准账单 items, err : re.fetchBatchAuditedBills(ctx, dateStr) if err ! nil { return fmt.Errorf(failed to fetch audited bills: %w, err) } for _, item : range items { // 2. 查询实时轨在 Redis 中记录的累计扣减流水 realtimeCost, err : re.redisClient.GetTenantRealtimeUsage(ctx, item.TenantID, dateStr) if err ! nil { // 单个租户异常记录日志并报警不阻断整体清算流程 fmt.Printf(Error fetching realtime usage for tenant %s: %v\n, item.TenantID, err) continue } // 3. 计算差异 Delta 离线精准应付 - 实时轨已扣 delta : item.FinalPayable - realtimeCost // 4. 若存在偏离发起平账事务 if delta ! 0 { if err : re.applyReconciliationAdjustment(ctx, item, delta, realtimeCost); err ! nil { return fmt.Errorf(reconciliation failed for tenant %s: %w, item.TenantID, err) } } // 5. 固化不可篡改日结账单入库 if err : re.persistFinalBill(ctx, item, delta); err ! nil { return fmt.Errorf(failed to persist final bill: %w, err) } } return nil } func (re *ReconciliationEngine) applyReconciliationAdjustment(ctx context.Context, item BillItem, delta NanoCents, realtimeCost NanoCents) error { tx, err : re.db.BeginTx(ctx, sql.TxOptions{Isolation: sql.LevelSerializable}) if err ! nil { return err } defer tx.Rollback() // 插入对账调整审计流水 query : INSERT INTO billing_adjustment_ledger ( tenant_id, bill_date, model_id, offline_exact_cost, realtime_deducted_cost, delta_nano, status, created_at ) VALUES (?, ?, ?, ?, ?, ?, APPLIED, NOW()) _, err tx.ExecContext(ctx, query, item.TenantID, item.Date, item.ModelID, item.FinalPayable, realtimeCost, delta) if err ! nil { return err } // 同步调整 Redis 中的实时可用信用额度补偿或追缴 reason : fmt.Sprintf(Daily reconciliation delta for %s, item.Date.Format(2006-01-02)) if err : re.redisClient.ApplyAdjustment(ctx, item.TenantID, delta, reason); err ! nil { return fmt.Errorf(redis adjustment rollback trigger: %w, err) } return tx.Commit() } func (re *ReconciliationEngine) fetchBatchAuditedBills(ctx context.Context, dateStr string) ([]BillItem, error) { // 查询经由离线任务严格去重与阶梯定价后的精准结果集 query : SELECT tenant_id, bill_date, model_id, sum(prompt_tokens), sum(completion_tokens), sum(final_payable) FROM dw_offline_tenant_token_daily WHERE bill_date ? GROUP BY tenant_id, bill_date, model_id rows, err : re.db.QueryContext(ctx, query, dateStr) if err ! nil { return nil, err } defer rows.Close() var result []BillItem for rows.Next() { var item BillItem var pTokens, cTokens, payable int64 if err : rows.Scan(item.TenantID, item.Date, item.ModelID, pTokens, cTokens, payable); err ! nil { return nil, err } item.PromptTokens pTokens item.CompTokens cTokens item.FinalPayable NanoCents(payable) result append(result, item) } return result, nil } func (re *ReconciliationEngine) persistFinalBill(ctx context.Context, item BillItem, adjustment Delta) error { // 归档财务正式账单 return nil } type Delta NanoCents离线数仓高吞吐计费模型 SQL 实现在底层离线数仓ClickHouse / StarRocks中T1 离线任务通过以下经过性能优化的聚合 SQL在数分钟内完成数亿级 Token 日志的幂等清洗与多级阶梯清算-- 离线按租户、模型计算精确消费与去重明细 INSERT INTO dw_offline_tenant_token_daily SELECT tenant_id, toDate(event_time) AS bill_date, model_id, count(DISTINCT request_id) AS total_requests, sum(prompt_tokens) AS total_prompt_tokens, sum(completion_tokens) AS total_completion_tokens, -- 按不同模型精准定价计算原始费用单位纳分 sum( prompt_tokens * price_per_prompt_nano completion_tokens * price_per_comp_nano ) AS raw_payable, -- 结合月度累计用量计算动态阶梯抵扣 multiIf( sum(prompt_tokens completion_tokens) 1000000000, sum(prompt_tokens * price_per_prompt_nano completion_tokens * price_per_comp_nano) * 0.20, sum(prompt_tokens completion_tokens) 100000000, sum(prompt_tokens * price_per_prompt_nano completion_tokens * price_per_comp_nano) * 0.10, 0 ) AS tier_discount, -- 最终应付金额 raw_payable - tier_discount AS final_payable FROM ods_llm_token_events_distributed WHERE event_time 2026-10-10 00:00:00 AND event_time 2026-10-11 00:00:00 GROUP BY tenant_id, bill_date, model_id;避坑指南与生产权衡绝对禁止在货币计算中使用 Float/Double计算机二进制浮点数在长链路累加下会出现经典的0.1 0.2 0.30000000000000004灾难。在单次请求计费只有几厘钱的大模型场景中高频累加会导致日终累计出现无法平账的错账。必须全链路采用整型“纳分”或标准 BigInt/Decimal进行原子计算。实时轨允许“微过冲”防范“死锁假死”实时额度扣减为了追求高性能在 Redis 中使用 Lua 脚本做分布式原子减法即可无需引入沉重的分布式两阶段提交2PC。即使在余额刚好归零的瞬时并发请求导致账户透支了几分钱相比于引入分布式事务锁带来的 50ms 网关延迟损耗允许微小透支并在离线平账时追回是经过工业验证的最高性价比选择。计量日志与计费流水的唯一幂等键设计每笔计量记录必须以request_id作为唯一键。离线任务执行前必须强制基于request_id做去重处理防止因网络重试导致同一笔长推理请求被重复扣款。