[billing] 真实用量统计与计费分析#36
Merged
Merged
Conversation
- pricing.py:新增 LLM 价格表,覆盖 openai/anthropic/deepscope/dashscope/moonshot 常见模型,支持跨 provider 模型名兜底查找,估算 cost_estimate - buffered_usage_writer.py:重写为真缓冲批量写入(asyncio.Queue + 后台 flush loop,定时/定量批量 INSERT,shutdown 排空防丢数据) - usage_tracker.py:UsageTrackingCallback 增加费用估算与 in-process token 累加;on_llm_end 用 run_coroutine_threadsafe 修复工作线程跨 loop 写入 - token_count.py:从 AI 消息 response_metadata/usage_metadata 提取 token - chat/llm.py:build_llm 自动挂载 UsageTrackingCallback 并启用 stream_usage - models.py/database.py/system.sql:CredentialUsage 新增 cost_estimate 列 影响范围:用量统计写入链路,不改业务接口契约
修复用量统计一直为 0 / 归属错误的多个根因: - orchestrator:移除硬编码 credential_id=None / provider="openai",改用 build_llm(uid) 读取真实 credential/provider/model;新增 _make_usage_callback - dispatcher/agent_run:callbacks 作为显式参数进入 run_config(此前被塞进 agent state 导致 on_llm_end 从不触发) - harness/app.py + lifecycle/manager.py:dispatch/invoke/_invoke_locked 全链路 透传 callbacks 到 run_config - harness/orchestrator.py:route() 接收 uid,路由 LLM 调用也记录用量 - delegate.py:Memory Agent 子调用经 invoke_reentrant 传入 usage callback - agent_sse.py:监听 root on_chain_end 提取 token(兜底) - main.py:harness LLM 启用 stream_usage=True,流式响应才返回 token 用量 - quiz_generator/quiz_grader:改用 build_llm(uid),用量归属到用户真实凭据 影响范围:chat/quiz 用量统计链路,不改对外接口
- usage_repository.py:新增 get_by_model(模型维度聚合)、get_timeseries (按天聚合,无数据日期补零,兼容 SQLite/MySQL date 类型);get_summary 增加 total_prompt/completion_tokens、avg_cost_per_call、by_model - credentials.py:ProviderUsage/CredentialUsageItem 增加 prompt/completion 分项;新增 ModelUsage、UsageTimeseriesPoint;UsageSummary 增加分项与均次费用 - routers/billing.py:新增 GET /billing/by-model、GET /billing/timeseries 影响范围:计费查询接口(新增字段与端点,向后兼容)
- billing.tsx:汇总卡片增加输入/输出 token 分项与均次费用;新增用量趋势图 (双轴:Token 面积线 + 费用虚线)、模型明细表(输入/输出/调用次数/费用) - api.ts:新增 ModelUsage/UsageTimeseriesPoint 类型与 billingApi.getByModel/ getTimeseries;UsageSummary 补充分项字段 影响范围:计费面板可视化
- test_pricing.py(新增):价格表查找、费用估算、跨 provider 兜底、大小写 - test_usage_writer.py:重写为真缓冲批量写入测试(批量触发/定时/shutdown 排空) - test_usage_tracker.py:费用计算、零 token 仍记录 api_calls、attach_usage_tracking - test_usage_repository.py:by_model/timeseries/summary 聚合测试,修正旧 session_id 用例 影响范围:仅测试
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
用量统计长期失真:对话产生的 token 与费用始终为 0,且 provider/credential 归属错误(硬编码为
openai/ 系统默认)。本 PR 重写用量统计链路,使计费面板能真实反映各凭证、模型、服务商的 token 用量与估算费用。根因与修复
UsageTrackingCallback.on_llm_end跨线程写入失败(no current event loop in thread 'asyncio_0')run_coroutine_threadsafe投递回主 loopcallbacks被塞进 agent state(而非run_config),on_llm_end从不触发agent_run → dispatch → invoke → _invoke_locked全链路将 callbacks 作为显式参数进入run_configllm_output=None)build_llm启用stream_usage=Trueopenai、credential_id 硬编码Nonebuild_llm(uid)读取真实 credential/provider/modelqwen3-max,infer_provider不识别 dashscoperoute()接收 uid;delegate 工具经invoke_reentrant传 callbackbuild_llm(uid)新增能力
后端
GET /billing/timeseries— 按天聚合用量趋势(无数据日期补零)GET /billing/by-model— 模型维度明细GET /billing/summary增强:输入/输出 token 分项、均次费用、by_modelCredentialUsage表新增cost_estimate列(自动迁移)前端
基础设施
pricing.py价格表(openai/anthropic/deepseek/dashscope/moonshot)buffered_usage_writer.py重写为真缓冲批量写入(Queue + 后台 flush loop)token_count.py从 AI 消息提取 token(兜底)测试
新增/更新 4 个测试文件,101 项测试全部通过:
提交结构
[billing] feat: 用量统计基础设施(价格表/缓冲写入/追踪回调/token 提取)[billing] fix: 聊天与 Quiz 链路真实 credential 归属与跨线程用量写入[billing] feat: 完善计费统计 - 趋势/模型维度/输入输出分项[frontend] feat: 用量趋势图与模型明细表[billing] test: 补充用量追踪/写入/计费/聚合测试Test Plan
logs/app.log出现[USAGE_TRACKER] on_llm_end fired ... total=>0与[CHAT_ORCH] stream done: tokens=...🤖 Generated with Claude Code