3.2 计费分摊与用量核算


3.2 计费分摊与用量核算

本节摘要:总账说不出责任,也指不出优化方向。本节把第 3.1 节的账本行沿三个维度摊清:团队(谁的责任)、功能(哪条产品线)、用户(单位经济与异常识别)。分摊键来自第 2.2 节随 span 传播的标签;本节附纯标准库分摊脚本,处理两个现实难题——公共成本(embedding、共享网关)按调用量占比二次分摊,未打标的行单列"未知"绝不摊薄。然后讲对账:内部账与供应商账单的差异容忍度建议 ±5% 以内(社区经验值),差异来源可枚举。最后给出用量核算周报模板——环比、TopN、单位经济指标(每活跃用户成本、每成功会话成本),让成本从"财务的事"变成"每个功能负责人的仪表"。

学习目标

  • 建立团队/功能/用户三维分摊模型,说清每个维度各自服务什么决策
  • 运行分摊脚本:多维聚合、占比、公共成本二次分摊、未打标行处理
  • 会与供应商账单对账,能枚举差异来源并设定容忍度
  • 产出一份含量化指标的用量核算周报模板

一、为什么必须分摊

只有总账的世界里,成本对话是这样的:"这个月 4 万美元,涨了 30%。"——然后所有人一起看天花板。分摊之后,对话变成:"客服机器人涨了 8000 美元,因为新版本把检索文档从 3 篇提到 8 篇,输入 token 翻倍;营销文案功能环比持平。"前者是情绪,后者是行动。三个维度各管一件事:

维度 回答 服务什么决策
团队 team 谁的责任 预算归属、优化 KPI、内部结算(showback/chargeback)
功能 feature 哪条产品线 定价与毛利、下线/收缩决策、灰度放量的成本依据
用户 user 单位经济 每活跃用户成本、套餐限额、异常消费者识别(刷量/失控会话)

分摊的前提是账本行打满标签。打标发生在第 2.2 节的传播链路上:请求入口知道 user,路由层知道 feature 与 team,随 trace_id 写进每行账本。未打标率是分摊体系的第一健康指标,目标趋近于 0(社区实践)。

二、分摊脚本

# allocate.py —— 计费分摊:三维聚合 + 公共成本二次分摊(纯标准库) from collections import defaultdict # 账本行:一次 LLM 调用的费用(美元,示意数据;真实来源为第 3.1 节 TokenLedger) rows = [ {"team": "客服", "feature": "机器人回复", "user": "u-42", "cost": 0.0120, "calls": 3}, {"team": "客服", "feature": "工单摘要", "user": "u-42", "cost": 0.0040, "calls": 1}, {"team": "客服", "feature": "机器人回复", "user": "u-77", "cost": 0.0080, "calls": 2}, {"team": "增长", "feature": "营销文案", "user": "u-99", "cost": 0.0310, "calls": 6}, {"team": None, "feature": "共享embedding", "user": None, "cost": 0.0050, "calls": 40}, {"team": None, "feature": None, "user": None, "cost": 0.0015, "calls": 5}, ] def group(rows: list[dict], key: str) -> dict[str, dict]: out: dict[str, dict] = defaultdict(lambda: {"cost": 0.0, "calls": 0}) for r in rows: k = r[key] if r[key] else "(未知)" out[k]["cost"] += r["cost"] out[k]["calls"] += r["calls"] return out def report(title: str, rows: list[dict], key: str) -> None: g = group(rows, key) total = sum(v["cost"] for v in g.values()) print(f"== 按{title} ==") for k, v in sorted(g.items(), key=lambda x: -x[1]["cost"]): print(f" {k:<12s} {v['cost']:.4f} 美元 占比 {v['cost'] / total:5.1%} 调用 {v['calls']} 次") print() if __name__ == "__main__": report("团队", rows, "team") report("功能", rows, "feature") report("用户", rows, "user") ​

输出(示意):

== 按团队 == 客服 0.0240 美元 占比 39.0% 调用 6 次 增长 0.0310 美元 占比 50.4% 调用 6 次 (未知) 0.0065 美元 占比 10.6% 调用 45 次 ​

输出里"(未知)"一行的构成要注意区分:公共成本(共享 embedding,team 为 None 但 feature 已知)与真正漏打标的行(team、feature 全空)都会落到这里。前者按公开规则二次分摊——把公共行按各团队调用量占比拆成多行追加;后者保持"未知"单列。二次分摊的核心逻辑(示意):

# allocate2.py —— 公共成本二次分摊:按调用量占比拆行(示意) def reallocate(rows): out = [dict(r) for r in rows if r["team"]] total_calls = sum(r["calls"] for r in out) for r in rows: if not r["team"] and r["feature"] == "共享embedding": for t in {r2["team"] for r2 in out}: t_calls = sum(r2["calls"] for r2 in out if r2["team"] == t) out.append({**r, "team": t, "cost": r["cost"] * t_calls / total_calls}) return out ​

两条铁律必须写进制度:

  1. 未打标 ≠ 摊薄:标签缺失的行永远单列"(未知)",盯着它的占比下降,而不是把它偷偷摊进各团队——摊薄会让打标纪律崩坏;
  2. 公共成本规则要公开:按调用量还是按 token 分摊、哪些算公共,规则写进一页纸并周知,否则每次出报表都要吵一遍。

三、对账:内部账 vs 供应商账单

每月拿内部账本与供应商账单对一次:

差异来源 典型幅度 处理
失败重试未入账(请求失败但供应商计费) 1%~3%(示意) 失败调用也要记 usage(能取到时)
批量/承诺折扣、赠金 视合同 对账用目录价、报表用实付价,两套并行
缓存计价口径差 1%~2%(示意) 核对三本账口径与账单分项
时区切日 小 统一按供应商账单时区切日对账

容忍度建议:内部账与账单差异在 ±5% 以内可接受,超差先查漏记(尤其是网关剥掉 usage 的调用),再查口径(社区经验值,示意)。对账差异本身值得进周报——它是账本健康度的哨兵。

四、用量核算周报模板

每周固定出一张表(数据全部来自前两节的账本与分摊):

成本周报(示意模板) 1. 总览:本周 9,420 美元,环比 +12%;调用 410 万次,环比 +5% 2. 三本账结构:输入 38% / 输出 47% / 缓存读 12% / 缓存写 3%(结构变化标红) 3. 分摊 Top:功能 Top5(含环比)、团队占比、未打标占比(目标 <1%) 4. 缓存:命中率 62%(上周 71%,主因:v3.1 prompt 前缀改动,已回滚) 5. 单位经济:每活跃用户 0.21 美元(环比 +9%);每成功会话 0.04 美元 6. 异常消费者 Top3:u-99 单会话 7.8 万 token(agent 循环,已熔断) 7. 对账:内部账 vs 账单差异 +1.8%(容忍 ±5% 内) ​

单位经济是这张表里最有杠杆的两个数:每活跃用户成本支撑定价与套餐设计;每成功会话成本(分母用"成功"而非"全部",质量口径见第 4 章)直接衡量"一次价值交付的边际成本"——它是成本与质量两支柱的第一个交汇指标。

💡 推行建议:先做 showback(只展示、不结算)一个季度,让各团队习惯看自己的数;再决定是否 chargeback(真金白银内部结算)。一上来就结算,团队的第一反应往往是"少记标签"而非"少花 token"。

本节要点回顾

  • 三维分摊各管一事:团队管责任、功能管产品决策、用户管单位经济与异常识别;未打标率要趋近 0。
  • 公共成本按公开规则二次分摊;未打标行单列"未知",绝不摊薄。
  • 每月与供应商账单对账,容忍度 ±5% 以内(社区经验值),差异来源可枚举。
  • 周报七件套 + 单位经济两指标(每活跃用户成本、每成功会话成本);先 showback 再 chargeback。

账已摊清、人人可见,但"看得见"还不等于"管得住"。第 3.3 节给钱装上闸门:预算层级、三线告警与会话级熔断——让最坏情况下的损失是一个设计值,而不是一个意外。


作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U