博客

如何按功能、团队和客户追踪 LLM API 用量与成本

服务商的账单告诉你花了多少,但没告诉你谁花的。两本账加五个归属维度,让每次请求都能追溯到某个功能、某个团队和某个客户。

如何按功能、团队和客户追踪 LLM API 用量与成本

你的服务商发来一张账单。你大致能认出总额,然后有人问出真正重要的问题:哪个功能、哪个团队、哪个客户?如果没人答得上来,问题不在账单。LLM API 成本归属失败的原因更简单:你应用发起的那些调用,从来没有带着足够的上下文被记录下来,好把总额拆成若干部分。

当两件事同时成立时,归属才开始起作用。服务商一侧和你自己一侧各有一本账,而两本账能通过共享的 request 标识符关联起来。本指南就是搭这套东西:每本账里有什么、每次请求要附带的五个维度、把它们存下来的最小事件表,以及在你记录的内容和你被计费的内容之间撕开缺口的那些陷阱。

为什么账单总额几乎回答不了任何问题

服务商的后台说的是服务商的词汇。组织、项目、API key、模型。这些都是计费对象。而别人问你的问题是产品对象。摘要功能每个活跃用户的成本是不是越来越高了?这个租户的消耗还符合他们的套餐吗?内部工具团队能不能把它的负载迁到更轻的模型上而没人察觉?

AI 用量的可见性就生灭在这道接缝上。盯着总额看多久都补不上这个缺口,基于同一批计费数据搭的任何看板也补不上,因为缺失的上下文只存在于一个瞬间:你的应用内部、请求发出的那一刻。那一刻代码还知道哪个用户在等、哪个功能触发了调用、哪个客户在为它付钱。要么当时就抓下来,要么事后靠猜。

LLM API 成本归属背后的两本账

成本归属需要两本账,因为两侧知道的事情不同。

服务商一侧的账是你的对账来源:实际被计数、被计费的东西。怎么读它取决于服务商。

OpenAI 把组织级的 Usage 和 Costs API 作为其 Administration 端点的一部分发布,文档对凭据说得很明确:应用请求用标准 API key,但 Administration 端点要用 Admin API key(Usage API 参考、Costs API 参考)。用量端点返回按时间分桶的聚合数据,你可以过滤和分组,包括按模型、项目、API key 和用户。

Anthropic 在其 Admin API 中提供 messages usage 报告,其分组维度包括账号、API key、工作区和模型,时间粒度可选按天、小时或分钟分桶。Console 的用量页面也可以按 API key 和模型导出用量数据,这往往是把第一次对账跑起来的最快办法。

如果你通过 String AI 这样的平台消费模型,服务商一侧比你想象的更近:用量记录页面会展示每次调用的详细消耗,平台文档列出了驱动这些消耗的因素,包括所用模型、输入长度、输出长度、是否上传了文件,以及对话历史长度。这份清单很重要,因为它告诉你哪些请求字段值得在你这一侧记录。

应用一侧的账是每次模型调用一行,由你的代码写入:何时发生、由哪个模型服务、进出的 token 数、如何结束、耗时多久,以及只有你的应用才知道的归属标签。服务商没法给功能或客户命名。那套词汇住在这里。

两本账之间的关联键是 request 标识符。服务通常会在每个响应里返回一个 request ID,把它记录下来是标准的运维实践;在你每个应用事件上都写上它,这样你账本里的任何一行都能追溯回服务商对同一次调用的视图。关于对账,需要一点现实感:两本账不会精确吻合,也不该吻合。聚合窗口不同,缓存调用会塌缩,批处理落在与提交时不同的时间桶里。目标是有节奏地解释差异,而不是强行让数字一致。

在调用点附加的五个维度

每次请求都应带上五个归属维度。加上它们都不贵;而事后补加几乎不可能。

  1. 用户 ID。是哪个具体的人在等这个响应。如果你想按用户统计 token 用量,这是唯一诚实的做法;共用一个 API key 恰好藏起了你需要的那个细节。
  2. 租户或账号。这项工作归属于哪个客户,或哪个内部团队。正是这个维度把一张用量账单变成分摊账单,至少也能变成内部展示账单。
  3. 功能。触发这次调用的产品能力:引导助手、每夜摘要、搜索重排,或者你们团队平时怎么叫它。
  4. 路由或模型。在回退和路由都表态之后,实际服务这次请求的是哪个模型。把它与功能标签分开保留;功能和模型是多对多关系,把两者压成一个就失去了把任一问题答好的能力。
  5. 环境。生产、预发,还是某个开发者的实验。未打标签的测试流量,是用量报告长出无法解释的基线的经典途径之一。

重要的部分是标签附加在哪里:在调用点、在代码里、作为模型客户端封装层的必填参数。读取日志时才加上的标签属于重构,而从消息文本重构就是猜。有一条规则能让这件事保持诚实:如果一次调用说不清它的用户、租户和功能,那是 bug,不是数据点。

最小事件表,以及三个真正回本的视图

在你考虑看板之前,先做一张原始事件表,每次模型调用一行。能回答大多数问题的最小列集:

ColumnWhat it holds
timestampwhen the call was made
request_idthe provider's identifier, when one is returned
user_idwho was waiting
tenantcustomer or team
featureproduct label
modelwhat actually served it
input_tokens, output_tokensusage as reported for the call
statuscompleted, failed, retried, or cancelled
latency_mshow long it took, recorded uniformly

两条结构性备注。第一,存原始事件,在它们之上再建聚合。在写入时聚合,等于把今天的问题烤进 schema,而问题会变:按功能变成按客户,再变成按功能加模型一起。第二,把状态和耗时与用量放在同一张表里,因为成本问题很少单独到来;它们总是附着在可靠性问题上一起到来。

在原始表之上,三个视图能自己赚回成本:

功能视图按功能对一段时间内的用量和成本分组。按功能追踪用量能抓住最重要的模式——某项能力的增长快于它的用户基数——趁它还只是一条趋势线、而不是一个季度惊吓的时候。

客户视图按租户切分消耗。这是财务和支持团队都想要的视图:一个用来核对用量是否跟随合同,另一个用来在不等工程团队的情况下回答某个账号为什么看起来不对劲。

模型视图显示哪些模型在服务哪些功能,比例如何。多模型成本追踪从这里开始,因为不同模型定价不同,所以组合的变化能解释与用量规模无关的成本变动,反之亦然。

如果一个视图没有人会去看,就先别建。归属基础设施很容易长出没人读的看板;从你已经被问到的三个问题开始。

你的日志与账单之间的四个陷阱

流式用量来得晚。响应以流返回时,token 计数通常要等流结束才最终确定。在第一个字节就写记录的日志器,恰恰会为用户最在意的那批调用记下空的用量。要在流结束时写记录,或在最终 usage 事件到达时更新它。

失败和重试也是用量。失败的调用照样可能消耗 input tokens,而重试逻辑会把你发出的所有东西成倍放大。只记成功调用的账本在服务商的计数面前会显示一个缺口,而这个缺口看起来会像是别人的错。记录每一次尝试及其状态,并标明哪一次最终成功了。

一个功能,多个模型。回退、分级路由、区域变体和多服务商配置,会把一个功能的用量散落到多行模型记录上。如果你先按模型分组,你正在调查的那个功能就消失在碎片里。按功能聚合,把模型保留为一列,而不是主键。

缓存和批处理是有意改变时机的。缓存响应意味着服务商统计到的调用次数少于你代码发出的次数。批处理按服务商的排期计数,而不是你的。两者造成的差异都是正确的。有节奏地对账,解释差异,并把解释保存下来。你一旦通过调整日志来“修正”差异,两本账都变成了虚构。

从归属到计费、配额与承诺

归属数据是任何你想许下承诺的前提:额度、套餐上限、团队配额、面向客户的用量报告。如果你说不出某个客户消耗了什么,你就无法给它设上限、定价或解释,每一次配额谈话都变成用猜测进行的谈判。同一套机器在卖方一侧的用法,也就是先计量再变现,在《2026 年如何将 API 变现》一文里有讲。

顺序很重要:先埋点,再承诺。在能测量用量之前就公布配额的团队,接下来一个月都在谈例外。

当这些承诺是按客户给的,多租户指南讲了让每个租户的数字保持可分离的凭据、配额与归属安排。

接下来做什么

  • 先让调用值得记录。先看《五步快速上手》带你从零走到第一次成功调用,那就是你应用账本里的第一行。
  • 先核实表面。再看《兼容性清单》确认你的核算所读取的响应形状和流事件,这样流水线记下的就真是它以为在记的东西。
  • 用恰当的怀疑读单个响应。 API 响应不是搜索结果,而一次调用只是用来解释更大事情的微弱信号。
  • 规划你的模型组合。 别让每个 AI 模型去做所有事;按任务分配模型,是让模型视图清晰可读而不是噪音一片的习惯。
  • 继续探索。更多指南与开发者文章覆盖集成路径的其余部分。

先追踪,再拆分,从第一次调用就开始。把归属能力事后补装到几个月未打标签的用量上,是这个项目的昂贵版本。