- AI 应用
- CLI
- 开发工具
【免费下载链接】ccusage
npx ccusage
ccusage 通过ccusage-adapter-qwen这一专用适配器,把 Qwen Code 本地项目与聊天 JSONL 文件转译为统一的用量条目(usage entries),进而复用整套 daily / weekly / monthly / session 报表视图。本文将结合该适配器的文档与源码实现,完整讲解其数据目录发现规则、JSONL 行级解析原理、推理与缓存 Token 的计价方式、四类报表的汇总逻辑,以及如何通过ccusage qwen命令在实战中查看 Qwen Code 用量。
Qwen 支持目前标记为 experimental,ccusage 与 Qwen Code 都在持续演进,相关行为可能发生破坏性变更。
适配器定位与模块划分
ccusage-adapter-qwen是 ccusage 众多来源适配器(adapter)之一,职责单一:把 Qwen Code 写入本地磁盘的 JSONL 聊天记录,转换成报表渲染所需的LoadedEntry。凡是与 Qwen 无关的通用能力——目录遍历、文件分块、并行读取、日期过滤、表格输出等——都被下沉到ccusage-core与ccusage-adapter-common,适配器自身只保留"来源特有"的逻辑。
从 rust/adapters/qwen/README.md 的 "Owns" 一节可以看到清晰的职责边界:
| 文件 | 职责 |
|---|---|
loader.rs | 读取数据源、去重、日期过滤的入口封装 |
parser.rs | 原始记录解析、Token 映射、模型命名与成本计算 |
paths.rs | 环境变量、默认目录、文件发现规则 |
report.rs | 与共享报表形状不同的 JSON / 表格结构 |
源码实际分为 src/loader.rs、src/parser.rs、src/paths.rs、src/report.rs 四个文件,由 src/lib.rs 统一导出。
对外公开接口(Public surface)
适配器向主 CLI 暴露了如下接口:
loader::load_entries— 加载全部用量条目;report::report_from_rows— 由汇总行生成报表 JSON;report::summarize_entries— 按报表类型汇总条目;run— 适配器的命令行入口;has_data— 检测当前环境是否存在可用的 Qwen 数据。
依赖方面,Cargo.toml 声明了ccusage-adapter-common、ccusage-core、jiff(时区/日期处理)、serde与serde_json,测试则依赖ccusage-test-support。构建上,该适配器属于adaptersCrane artifact 层,所有适配器在同一个 Cargo 调用中并行编译。
快速上手:聚焦报表视图
Qwen 数据源支持与 ccusage 其他来源完全一致的聚焦视图(focused views)。先查看帮助:
# bunx(推荐) bunx ccusage qwen --help # npx npx ccusage@latest qwen --help # pnpm pnpm dlx ccusage qwen --help可用的报表视图如下(其中weekly同样由 src/report.rs 支持,其通用行为可参考 docs/guide/weekly-reports.md 等文档):
| 聚焦视图 | 说明 | 参见文档 |
|---|---|---|
ccusage qwen daily | 按日期聚合用量 | docs/guide/daily-reports.md |
ccusage qwen monthly | 按月聚合用量 | docs/guide/monthly-reports.md |
ccusage qwen session | 按 Qwen 会话分组用量 | docs/guide/session-reports.md |
ccusage qwen weekly | 按周聚合用量 | docs/guide/weekly-reports.md |
这些视图通用支持:
--json:输出结构化 JSON;--compact:适配窄终端宽度;--offline:使用缓存的定价数据而非在线获取;- 从源码看还支持
--since / --until日期边界、--jq后处理、--order排序与--no-cost(见 src/lib.rs 中run的调用链)。
run的执行流程为:load_entries加载全部条目 → 若非 session 视图则按--since/--until过滤日期 →summarize_entries按报表类型汇总 → 排序 → 按--json/--jq输出 JSON,或打印标题为 "Qwen Token Usage Report" 的表格(src/lib.rs 的run函数)。需要说明的是,session 视图的日期过滤是在汇总之后基于last_activity进行的,与非 session 视图在条目级过滤不同。
数据目录与文件发现规则
默认目录结构
ccusage 读取 Qwen Code 的聊天 JSONL 文件,默认根目录为~/.qwen,目录结构如下:
~/.qwen/ └── projects/ └── {project}/ └── chats/ └── *.jsonl即:projects/{project}/chats/*.jsonl这一固定三层结构。适配器 README 中的表达式${QWEN_DATA_DIR:-~/.qwen}/projects/**/*.jsonl是对此的简写。
QWEN_DATA_DIR 环境变量
可以通过QWEN_DATA_DIR覆盖默认根目录,它既可以是单个目录,也可以是逗号分隔的多个目录(例如多份归档根目录),此时多个根会被分别扫描并合并结果:
QWEN_DATA_DIR="$HOME/.qwen,/backup/qwen" ccusage qwen daily在 src/paths.rs 中,环境变量按逗号切分、去空白、去重,且仅保留实际存在的目录(path.is_dir());未设置时回退到~/.qwen。也就是说,只要QWEN_DATA_DIR存在,默认目录便不再被扫描。
发现逻辑:严格三层路径
discover_chat_files的规则值得注意:它并非简单地递归收集所有.jsonl,而是只接受恰好三层的相对路径projects/{project}/chats/{file}.jsonl——project非空、第二层必须是字面量chats、文件以.jsonl结尾。路径层级不对的文件会被is_chat_file过滤掉。这意味着数据必须严格按上述目录布局存放。
项目名(project)则通过反向扫描路径窗口提取:找到projects/{project}/chats/模式的窗口,取其中的{project}段作为project_path,用于报表按项目归类;找不到时回退为"unknown"。
JSONL 行级解析原理
目标记录结构
Qwen 的聊天文件是 JSONL,每行一条记录。适配器只消费如下字段(其余字段由 serde 直接跳过):
{ "type": "assistant", "model": "qwen3-coder-plus", "timestamp": "2026-02-23T14:24:56.857Z", "sessionId": "session-json", "usageMetadata": { "promptTokenCount": 100, "candidatesTokenCount": 50, "thoughtsTokenCount": 10, "cachedContentTokenCount": 5, "totalTokenCount": 165 } }对应 src/parser.rs 中的QwenLine结构体(#[serde(rename_all = "camelCase")])。其中usageMetadata是 Gemini 风格(Gemini-style)的用量块,五个 Token 字段的含义如下:
| 字段 | 含义 | 映射结果 |
|---|---|---|
promptTokenCount | 输入 Token | input_tokens |
candidatesTokenCount | 输出 Token | output_tokens |
thoughtsTokenCount | 推理(思考)Token | extra_total_tokens,计入总 Token 并按输出 Token 计价 |
cachedContentTokenCount | 缓存命中读取 Token | cache_read_input_tokens |
totalTokenCount | 总 Token(可选兜底) | 见下文 fallback |
三道性能与健壮性设计
- 行级预过滤(LinePrefilter):每个可用的 Qwen 行都携带
usageMetadata键,因此读取文件时先用LinePrefilter::all(&[br#""usageMetadata""#])基于memmem子串匹配跳过不含该标记的行,在 JSON 解析之前就淘汰大量无效行(如纯用户消息),见 src/parser.rs 的read_chat_file。 - 宽容反序列化:所有字段都使用
ccusage-adapter-common提供的 lenient 反序列化器(lenient_u64、non_empty_string等)。Token 数若不是合法的非负整数会被视为0而不是让整行解析失败;字符串会被 trim 且空串视为缺失。这些行为在 src/jsonl.rs 中有完整测试佐证。 - 类型化反序列化:存活的行直接反序列化为
QwenLine类型化结构,避免中间serde_json::Value树的分配,未使用字段被跳过。
解析过滤与字段兜底
parse_line的过滤与兜底规则如下:
- 仅接受
type == "assistant"的行;缺usageMetadata的行直接放弃; - 若输入、输出、缓存读取、推理 Token 全部为 0,则该行被丢弃(零用量记录无意义);
- totalTokenCount 兜底:当各分项缺失而
totalTokenCount存在时,通过apply_total_token_fallback把总数作为输出 Token 兜底。parser 的单元测试falls_back_to_total_token_count_when_qwen_parts_are_missing验证了仅含{"totalTokenCount": 321}的记录会被解析为output_tokens = 321; - 时间戳兜底:
timestamp可解析则原样使用,否则回退到文件的修改时间(file_timestamp),文件元数据不可用时再回退到当前系统时间; - sessionId 兜底:缺失时生成
{project}-{文件名去掉扩展名}; - 模型名兜底:缺失时使用常量
unknown。
Token 计算与成本核算
计价口径
- 推理 Token 按输出计价:
billable_usage中output_tokens = display_usage.output_tokens + extra_total_tokens(即thoughtsTokenCount会计入可计费输出),同时保留独立的extra_total_tokens用于展示"总 Token"。 - 缓存 Token:
cachedContentTokenCount被当作缓存读取 Token;Qwen 日志目前不暴露缓存创建(cache creation)Token,因此该值恒为 0(见 src/parser.rs 的TokenUsageRaw构造)。
成本计算与模型候选
成本计算遵循"原始模型名 + Qwen 供应商前缀候选"的策略,qwen_model_candidates依次尝试:
- 原始模型名(如
qwen3-coder-plus); qwen/{model};alibaba/{model}。
在Display模式下不加载定价表、成本展示为 0;在计算模式下加载 LiteLLM 定价数据(支持--offline缓存与--pricing-overrides覆盖),一旦某个候选命中定价表中的条目即按其单价计算成本。若所有候选都未命中,成本为$0.00,并通过missing_qwen_pricing标记缺失定价的模型,便于后续向项目提交 alias 支持请求。
这里有一个细节:显式价格为 0 的条目与"无定价条目"是不同的——单元测试calculate_qwen_cost_returns_explicit_zero_price验证了当free-model显式定价为 0 而qwen/free-model定价为 1 时,原始名命中 0 价条目,成本正确返回0.0而非回退到前缀候选。
汇总与报表生成
汇总逻辑(report.rs)
summarize_entries按报表类型走不同的聚合路径(src/report.rs):
- Daily:以
entry.date为键直接聚合; - Weekly / Monthly:先聚合出 daily,再按周(以周日为边界)/ 按月分桶二次聚合;
- Session:以
session_id为键,用SessionAccumulator累积每条记录,最后生成会话汇总。
报表 JSON 形状
report_from_rows生成{ "daily" | "weekly" | "monthly" | "sessions": [...], "totals": {...} }的结构:行数组通过ccusage_core::agent_summary_json序列化,totals通过totals_json计算,无数据时totals为null。
lib.rs 的测试builds_qwen_daily_json_report_with_reasoning_in_total给出了一个可验证的 daily JSON 输出示例(对应上文示例记录,100 输入 + 50 输出 + 10 推理 + 5 缓存读取 = 165 总 Token):
{ "daily": [ { "date": "2026-02-23", "outputTokens": 50, "cacheReadTokens": 5, "totalTokens": 165, "modelsUsed": ["qwen3-coder-plus"], "modelBreakdowns": [ { "modelName": "qwen3-coder-plus", "inputTokens": 100, "outputTokens": 50, "cacheCreationTokens": 0, "cacheReadTokens": 5, "cost": 0.0 } ] } ], "totals": { } }注意totalTokens(165)包含推理 Token,这正是"推理 Token 计入总 Token"设计的直接体现。
并行读取与去重
文件读取复用ccusage-adapter-common的read_files_parallel:按文件大小做负载均衡分块(size-balanced chunking)后并行读取,结果按原始文件顺序归位;--single-thread可强制单线程。去重采用"首胜"策略:按发现顺序对每个条目计算entry_id(由 session id、时间戳、模型、输入/输出/缓存读取 Token、推理 Token 构成的 JSON 数组字符串),相同 id 只保留第一个。该设计保证并行读取与单线程读取的存活记录一致(src/parser.rs 的entry_id)。
与主 CLI 的接线
Qwen 适配器通过 rust/crates/ccusage/src/adapter/mod.rs 以pub(crate) use ccusage_adapter_qwen as qwen的方式注册,主入口 rust/crates/ccusage/src/main.rs 中Command::Qwen(args)直接调用adapter::qwen::run(args)。此外:
last_window.rs与timezone.rs会把 Qwen 命令纳入与其余来源一致的"最近窗口"与时区处理逻辑;has_data通过paths::discover_chat_files判断当前环境是否有可读取的 Qwen 数据,用于多来源的自动检测。
环境变量与故障排查
环境变量
| 变量 | 说明 |
|---|---|
QWEN_DATA_DIR | 覆盖数据根目录,支持逗号分隔的多个根目录 |
LOG_LEVEL | 调整日志详细程度(0 静默 … 5 trace) |
常见问题
- "No Qwen usage data found":确认数据位于
~/.qwen/projects/{project}/chats/这一严格三层结构下;若数据在其他位置或有多个归档根,请通过QWEN_DATA_DIR指定。 - 成本全部显示为 $0.00:模型不在 LiteLLM 定价数据库中,或
--offline缓存中缺失对应条目。此时适配器会尝试qwen/{model}、alibaba/{model}前缀候选,仍未命中则成本为 0,可向项目提交 issue 请求 alias 支持。
测试保障
适配器的正确性由三处测试共同保障:
- src/lib.rs 的集成级测试:加载真实 fixture 目录(通过
EnvVarGuard注入QWEN_DATA_DIR)验证条目字段映射、daily JSON 中推理 Token 计入总 Token、以及 session 视图的 ISO 日期边界过滤; - src/parser.rs 的单元测试:验证显式 0 价、totalTokenCount 兜底、含冒号字段的 entry_id 唯一性;
- src/jsonl.rs 的通用测试:验证预过滤跳过无标记行、宽容反序列化在异常类型下不丢整行。
这些测试既是适配器的行为契约,也是理解"Qwen 记录如何一步步变成报表行"的最佳注释。如果你想深入报表的通用形状与配置项,可继续阅读 docs/guide/configuration.md 与 docs/guide/json-output.md。
- AI 应用
- CLI
- 开发工具
【免费下载链接】ccusage
npx ccusage
相关推荐
ccusage Qwen 数据源接入指南:用 Qwen Code 聊天 JSONL 统计 Token 用量与费用
ccusage Qwen 数据源接入指南:用 Qwen Code 聊天 JSONL 统计 Token 用量与费用 本文面向使用 Qwen Code https:
AI 应用CLI开发工具ccusage 的 Claude Code 适配器(ccusage-adapter-claude)源码解析:JSONL 会话日志到使用量报表的完整链路
ccusage 的 Claude Code 适配器(ccusage adapter claude)源码解析:JSONL 会话日志到使用量报表的完整链路 ccus
AI 应用CLI开发工具ccusage 的 Amp 数据源适配器:线程 JSON 用量解析、缓存 Token 核算与报表命令详解
ccusage 的 Amp 数据源适配器:线程 JSON 用量解析、缓存 Token 核算与报表命令详解 导读 本文聚焦 ccusage 开源仓库中 Amp 数
AI 应用CLI开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考