如何统计每个用户token消耗,输入输出分开统计数据库设计

在日常开发大模型API中转或计费系统时,经常需要回答“每个用户到底消耗了多少Token”。
统计每个用户Token消耗,不能只记一个总量,否则无法分析输入输出占比。
正规做法是在数据库里用两个独立字段分别记录输入Token和输出Token,再按用户聚合。
下面这套数据库设计方案,适合零基础直接照做。

先确定统计口径和字段

在写SQL之前,先想清楚:每次API调用,模型会返回 prompt_tokens(输入部分)和 completion_tokens(输出部分),这两个值必须原样落库。
因此最少需要一张调用流水表,记录用户ID、请求ID、模型名称、时间、输入Token、输出Token。
如果还要按项目或者应用维度拆分,再增加对应字段即可。

建表SQL示例:

CREATE TABLE user_token_usage (
  id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  user_id VARCHAR(64) NOT NULL COMMENT '用户ID',
  request_id VARCHAR(64) NOT NULL COMMENT '请求唯一ID',
  model_name VARCHAR(64) NOT NULL DEFAULT '' COMMENT '模型名称',
  prompt_tokens INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '输入token数量',
  completion_tokens INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '输出token数量',
  total_tokens INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '总量,可冗余',
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '请求时间',
  KEY idx_user_created (user_id, created_at),
  KEY idx_request (request_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户token消耗明细';

total_tokens 可以不存,也可以作为冗余字段由应用层计算写入,方便后续直接按总量查询。

写入和统计查询怎么落地

写入时机安排在API响应返回以后。
伪代码逻辑如下:

usage = response.get('usage')
if usage:
    insert(
        user_id=user.id,
        request_id=response.get('id'),
        model_name=usage.get('model', ''),
        prompt_tokens=usage.get('prompt_tokens', 0),
        completion_tokens=usage.get('completion_tokens', 0),
        total_tokens=usage.get('total_tokens', 0)
    )

统计某段时间内每个用户的输入输出消耗:

SELECT
  user_id,
  SUM(prompt_tokens) AS total_input,
  SUM(completion_tokens) AS total_output,
  SUM(total_tokens) AS total_usage
FROM user_token_usage
WHERE created_at >= '2025-01-01 00:00:00'
  AND created_at < '2025-02-01 00:00:00'
GROUP BY user_id
ORDER BY total_usage DESC;

如果想按天查看每个用户的使用趋势,可以改成这样:

SELECT
  DATE(created_at) AS day,
  user_id,
  SUM(prompt_tokens) AS total_input,
  SUM(completion_tokens) AS total_output
FROM user_token_usage
GROUP BY day, user_id
ORDER BY day DESC;

避坑提醒

第一,不要把输入输出Token塞进同一个字段再加类型标记,否则查询时要用 CASE WHEN,索引和汇总都很别扭。

第二,务必在请求日志中记录 request_id,并给 user_id + request_id 建立唯一索引,这样能防止同一请求被重复统计。

第三,Token数量必须依赖上游API返回的 usage 字段,不要自己按字符数估算,因为不同模型的tokenizer不一样,估算结果没有参考价值。

第四,如果流水表数据量增长很快,建议按月分表或者定期归档,否则全表聚合会越来越慢。

验证最终效果

正确落地后,查询结果应满足:每一行的 total_input + total_output 等于该请求的 total_usage,按用户分组后也能看到独立的输入输出数值。
建议先用一条真实API调用插入测试数据,再执行上面的 SELECT 语句验证,确认数值与API返回的usage一致后再接入线上统计。

分享到:
上一篇
Ollama高并发请求下GPU调度队列堆积
下一篇
LiteLLM数据库持久化,用量、密钥
1
系统公告

机房迁移升级通知

尊敬的用户: IP 段 103.23.148.x、156.224.29.x 原香港一区线路波动、攻击频繁,平台定于 7 月 5 日凌晨分批迁移至香港 GIA 机房,硬件升级 AMD 铂金机型。 迁移均在凌晨操作,最大程度降低业务影响,迁移期间服务器临时关机; 升级后配置不降低、费用不涨价,数据默认同步迁移; 迁移后 IP 全部更换,请及时修改域名解析、防火墙白名单; 建议提前备份重要数据,有问题可联系在线客服。 感谢理解与支持! 泽御云科技 2026.06.30
服务中心
客服
在线客服
24小时为您服务
咨询
联系我们
联系我们,为您的业务提供专属服务。
24/7 技术支持
如果您遇到寻求进一步的帮助,请过工单与我们进行联系。
24/7 即时支持
泽御云
售前客服
泽御云
泽御云
售后客服
泽御云
技术支持
评价
您对当前页面的整体感受是否满意?
😞
非常不满意
😕
不满意
😐
一般
🙂
满意
😊
非常满意