本节摘要:总账说不出责任,也指不出优化方向。本节把第 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%~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"。
账已摊清、人人可见,但"看得见"还不等于"管得住"。第 3.3 节给钱装上闸门:预算层级、三线告警与会话级熔断——让最坏情况下的损失是一个设计值,而不是一个意外。