2026-08-19-points-usage-stats-design.md 6.8 KB

积分消耗与 Token 用量统计系统设计

日期:2026-08-19 状态:待审阅

背景与目标

需要基于 mp_user_points_details 明细表建立一套使用量统计系统,支持按日期、用户、模型、中转站四个维度查看数据,供平台管理员(superadmin)查看全部用户、组织管理员(admin)查看本公司(cpid)用户的统计数据。

核心诉求:

  • 定时任务预聚合,前端查询走统计表,保证查询性能稳定。
  • token 消耗为核心统计指标,积分消耗作为附带指标。
  • 初始化"模型名 → 中转站"映射表,便于后续人工维护。
  • 提供前端可用的查询 API,支持日期、用户、模型、中转站筛选。

相关背景修复

审查中发现并修复了视频积分明细 token 恒为 0 的 bug:

  • 根因:AIVideoGenerationService::markVideoTaskSuccess() 更新数据库后未同步内存中 $task->result_json,导致随后扣费解析 token 时读到旧空值。
  • 已修复 markVideoTaskSuccess 同步内存属性,并新增 points:backfill-video-tokens 命令回填历史数据(已执行完毕)。
  • 同时补齐了 analyzeErrorMessage(错误友好翻译)与 geminiGenerateText(潜在未接线路径)两处缺失的 token 记录。

数据库设计

1. 模型→中转站映射表 mp_model_relay_map

用途:维护模型名与中转站的对应关系,统计任务按模型名关联出中转站。

字段 类型 说明
id bigint unsigned PK AI
model varchar(255) NOT NULL UNIQUE 模型名
relay_name varchar(100) NOT NULL 中转站名称
remark varchar(255) NULL 备注
created_at / updated_at timestamp

migration 中初始化以下映射(智能分析所得,后续可人工增改):

模型 中转站
deepseek-chat / deepseek-reasoner / deepseek-v4-flash / deepseek-v4-pro DeepSeek 官方
deepseek-v3-2-251201 火山方舟
doubao-seed-2-0-mini/lite/pro-260215 火山方舟
doubao-seedream-4-5-251128 / doubao-seedream-5-0-260128 / doubao-seedream-5-0-lite-260128 火山方舟
doubao-seedance-1-5-pro-251215 / doubao-seedance-2-0-260128 / doubao-seedance-2-0-fast-260128 火山方舟
doubao-seedance-2.0 百度
zhizhen-20 / zhizhen-20-fast / zhizhen-20-mini 智帧
gpt-5.4 / gpt-5.6-terra / gpt-5.6-sol / gpt-5.6-luna / gpt-image-2 / GptImage2 GPT 中转站
gemini-3-pro-preview / gemini-3-flash-preview / gemini-3.1-pro-preview / gemini-3.1-flash-image-preview-t / gemini-3.6-flash Gemini 中转站
NanoBanana2 / NanoBananaPro NanoBanana

未命中映射的模型在统计中归为 unknown

2. 统计表 mp_points_daily_stats

用途:按 (stat_date, uid, model, relay) 维度预聚合的日粒度统计。

字段 类型 说明
id bigint unsigned PK AI
stat_date date NOT NULL 统计日期(按明细 created_at 归属)
uid bigint unsigned NOT NULL 用户 ID
cpid bigint NOT NULL DEFAULT 0 用户所属组织(组织管理员过滤用)
model varchar(255) NOT NULL 模型名
relay varchar(100) NOT NULL DEFAULT 'unknown' 中转站名称
call_count int unsigned NOT NULL DEFAULT 0 调用次数
tokens_consumed bigint NOT NULL DEFAULT 0 token 消耗合计(核心指标)
points_consumed decimal(13,1) NOT NULL DEFAULT 0 积分消耗合计(附带指标)
created_at / updated_at timestamp

索引:

  • 唯一键 uk_date_uid_model_relay (stat_date, uid, model, relay)
  • 索引 idx_stat_date_cpid (stat_date, cpid)
  • 索引 idx_relay (relay)
  • 索引 idx_model (model)

定时任务

命令 stats:points-daily

参数:

  • --date=YYYY-MM-DD:只统计指定日期(默认昨天)
  • --from=YYYY-MM-DD --to=YYYY-MM-DD:批量补跑日期区间

统计口径:

  • 数据源:mp_user_points_details,按 created_at 归属到日期。
  • 只统计 type IN (chat, image, video),排除 system/company(发放/回收,无模型、无 token)。
  • 不过滤 test_mode,测试用户记录全部纳入(按用户确认)。
  • 模型:优先取 charge_info->model,为空回退 api_type,再为空归 unknown
  • 中转站:按模型名 LEFT JOIN mp_model_relay_map 关联,未命中归 unknown
  • 指标:call_count = COUNT(*)tokens_consumed = SUM(tokens_consumed)points_consumed = SUM(points_consumed)

写入方式:按日期在事务内先删除该日旧数据再批量插入(幂等,可重复执行)。

调度:Kernel::schedule 中每天 00:10 执行 stats:points-dailywithoutOverlapping() 防止并发。

API 设计

1. 查询统计 GET /api/points/stats

权限:

  • superadmin:查询全部用户数据。
  • admin:自动限定 cpid 为当前登录用户所属组织。
  • 其他角色:返回无权限错误。

请求参数:

参数 必填 说明
start_date / end_date 日期范围,默认近 30 天
uid 用户 ID,支持逗号分隔多个
model 模型名
relay 中转站名称
group_by 聚合维度,date/uid/model/relay 任意组合(如 date,model),默认四维全部分组
page / page_size 分页,默认 15,最大 100

响应(沿用现有 ApiResponse 风格):

{
  "code": 0,
  "data": {
    "list": [
      {
        "stat_date": "2026-08-18",
        "uid": 142858,
        "nickname": "用户昵称",
        "model": "zhizhen-20",
        "relay": "智帧",
        "call_count": 10,
        "tokens_consumed": 1309900,
        "points_consumed": 840.0
      }
    ],
    "meta": {
      "current_page": 1,
      "last_page": 10,
      "per_page": 15,
      "total": 145
    },
    "summary": {
      "call_count": 1000,
      "tokens_consumed": 100000000,
      "points_consumed": 80000.0
    }
  }
}

2. 筛选项来源 GET /api/points/stats/filters

返回当前权限范围内的可选值,供前端下拉框使用:

  • 用户列表(id + 昵称/账号)
  • 模型列表
  • 中转站列表
  • 可统计日期范围(最早/最晚 stat_date)

目录与文件规划

  • database/migrations/xxxx_create_mp_model_relay_map_table.php
  • database/migrations/xxxx_create_mp_points_daily_stats_table.php
  • app/Console/Commands/PointsDailyStatsCommand.php
  • app/Services/PointsStatsService.php
  • app/Http/Controllers/Points/PointsStatsController.php
  • app/Transformer/Points/PointsStatsTransformer.php(如有需要)
  • routes/api.php 新增路由

测试计划

  • 定时任务:手动执行 --date 统计结果与明细表 SQL 对账一致。
  • 权限:superadmin 可见全部、admin 仅本组织、其他角色拒绝。
  • 筛选:日期、用户、模型、中转站、group_by 组合。
  • 幂等:重复执行同一日期统计不产生脏数据。