ccusage 接入 Grok Build CLI:会话日志读取、聚焦报告与成本核算全指南
2026/9/21 16:29:25 网站建设 项目流程
  • AI 应用
  • CLI
  • 开发工具

【免费下载链接】ccusage

npx ccusage

项目地址:https://gitcode.com/gh_mirrors/cc/ccusage
点击查看免费下载

本文以 ccusage 的 Grok Build CLI 数据源适配器为主线,讲解它如何从本地~/.grok目录读取updates.jsonl会话日志,生成 daily / monthly / session 三类聚焦报告,并深入剖析 token 拆分、costUsdTicks记账成本与定价表回退的底层实现。读完本文,你将掌握ccusage grok系列命令的完整用法、GROK_HOME数据根解析规则,以及成本在display/auto/calculate三种模式下的计算路径,并能在数据缺失、成本为零等常见故障下快速定位原因。

Grok Build CLI:ccusage 的一个一等数据源

ccusage 可以将本地 Grok Build CLI 的会话日志作为受支持的数据源直接读取(对应文档 docs/guide/grok/index.md)。与 Claude Code、Codex、Gemini 等适配器一样,Grok 数据接入后复用 ccusage 统一的报告模型(unified report model)与聚焦报告模型(focused report model),这意味着你不需要学习一套新的报告语法——同一套 daily / monthly / session 视图、JSON 输出、成本模式和终端表格对 Grok 一视同仁。

在命令行入口处,Grok 适配器被挂载为顶层子命令:rust/crates/ccusage/src/adapter/mod.rspub(crate) use ccusage_adapter_grok as grok;rust/crates/ccusage/src/main.rsSome(Command::Grok(args)) => adapter::grok::run(args)ccusage grok ...分派到适配器的run函数。适配器本身的代码位于 rust/adapters/grok/,由四个模块组成:

  • paths.rs:数据根解析与sessions/**/updates.jsonl发现;
  • parser.rsturn_completed行准入、token 拆分、定价候选生成与成本计算;
  • loader.rs:并行读取、跨会话全局去重与has_data探测;
  • report.rs:daily / monthly / session 汇总形状。

快速上手:聚焦视图命令

大多数用户可以从统一报告(unified reports,例如ccusage daily,会汇总所有已检测数据源)开始。只有在需要把同一报告形状聚焦到 Grok 用量上时,才加grok命名空间:

# 按天汇总 Grok 用量 ccusage grok daily # 按月汇总 Grok 用量 ccusage grok monthly # 按 Grok 会话分组 ccusage grok session

三个视图分别聚合不同的维度:

聚焦视图描述参见
ccusage grok daily按日期聚合用量Daily Usage
ccusage grok monthly按月聚合用量Monthly Usage
ccusage grok session按 Grok 会话分组用量Session Usage

从源码看,这几种视图的差异集中在report.rssummarize_entries:daily 直接按entry.date分组(summarize_by_key);monthly 先算 daily 再按BucketKind::Monthly分桶;session 则用BTreeMap<String, SessionAccumulator>累积每个session_id的条目,从而把活动时间范围(first_activity/last_activity)和项目路径带到会话行上——这正是会话表格的 Last Activity 列与会话 JSON 输出的数据来源。

支持的选项

这些聚焦视图支持--json--compact--mode--offline等共享选项:

# JSON 输出,便于脚本消费 ccusage grok daily --json # 压缩输出 + 离线模式(使用内嵌定价快照) ccusage grok monthly --compact --offline # 强制从 token 数重新计价 ccusage grok session --mode calculate

--mode的三档取值(auto/calculate/display)在 Cost Modes 有全局说明;Grok 适配器对它们的特殊处理见下文「成本核算」一节。其他通用选项如--since/--until日期过滤、--timezone时区、--order排序、--breakdown模型细分等也适用于ccusage grok系列,详细清单见 Command-Line Options。

Cache Create 列的动态显隐

聚焦终端表格的一个细节是:当选中的 Grok 行没有记录任何 cache-creation token 时,表格会省略Cache Create列;一旦选中的行出现非零值,该列重新出现。这一行为在 lib.rs 的table_options中实现——show_cache_creation: rows.iter().any(|row| row.cache_creation_tokens > 0),并有对应单测hides_cache_creation_when_selected_rows_are_zero/shows_cache_creation_when_any_selected_row_is_nonzero佐证。无论表格如何显示,JSON 输出 的稳定报告 schema 中始终保留cacheCreationTokens字段,不会因值为零而缺失。

数据源:会话目录布局与发现规则

Grok 适配器读取的是 Grok 主目录下各会话中的updates.jsonl(每行一条会话更新事件),只统计其中「已完成回合」的记录。目录布局如下:

$GROK_HOME/ # 或 ~/.grok └── sessions/ └── <url-encoded-cwd>/ └── <session-uuid>/ ├── updates.jsonl # 主数据源(turn_completed + usage) └── summary.json # 可选元数据

要点:

  • 主数据源是updates.jsonl:只会计入sessionUpdate == "turn_completed"且带有可用 usage 拆分的行。进行中的回合(in-progress turns)在完成之前不会出现;中途被 kill 的会话永远不会写入turn_completed,因此其用量无法被报告。
  • logs/unified.jsonl不被使用:该日志没有逐请求(per-request)的模型 id,token 无法定价或归属到具体模型,故适配器完全忽略它。这一点在loader.rs的测试has_data_is_false_when_the_home_has_no_sessions中也有体现——只有logs/unified.jsonlhas_data()返回false

根目录解析(优先级从高到低)

  1. 非空的GROK_HOME(Grok 官方环境变量,单一根目录);
  2. ~/.grok

paths.rsresolve_root()的实现完全对应这条规则:先读GROK_HOME,只有在该变量存在且 trim 后非空、且路径是目录时才采用;否则回落到用户主目录下的.grok。配套测试覆盖了空值回退(empty_grok_home_falls_back_to_default_home)、缺失根(missing_roots_yield_empty_discovery)以及GROK_HOME指向非目录(non_directory_grok_home_yields_empty_discovery)等边界情况。

发现过程(discover_session_files)递归扫描根下的sessions目录,收集所有命名为updates.jsonl的 JSONL 文件(忽略events.jsonl等同目录下的其他 JSONL),并顺带探测同目录的summary.json作为可选元数据;结果按路径排序,保证多次运行加载顺序稳定。

# 数据不在默认位置时,显式指定根目录 GROK_HOME="$HOME/.grok" ccusage grok daily

summary.json虽然是可选的,但它能显著改善报告的归属质量:其中的info.id提供规范化会话 id(行内params.sessionId缺失时使用),info.cwdgit_root_dir提供项目路径(优先info.cwd),current_model_id提供默认模型。当updates.jsonl行内没有modelUsage明细时,顶层 usage 字段会以该默认模型命名。若完全没有 summary 和默认模型,顶层 usage 会被标记为模型unknown(见parser.rsload_session_meta与测试names_top_level_usage_unknown_when_summary_has_no_default_model)。

另一个值得注意的实现细节:当 summary 缺失时,项目路径取自会话目录的父目录名,该目录名是 URL 编码的 cwd(例如D%3A%5Cwork%5Cproj),适配器用url_decode_lightweight做字节级百分号解码(D%3A%5Cwork%5CprojD:\work\proj),并正确处理多字节 UTF-8 路径(如%2Fhome%2F%C3%A9projet/home/éprojet),遇到非法字节时降级为替换字符而非崩溃。

报告计算逻辑:token 拆分、推理 token 与成本

Token 用量:把 OpenAI 风格计数拆成 ccusage 字段

Grok 记录的是 OpenAI 风格的 usage,其中inputTokens已经包含缓存。适配器(parser.rssplit_input_tokens/split_tokens)按以下规则拆分:

Grok 字段ccusage 字段规则
inputTokens − cachedReadTokensinput_tokens(未缓存输入)缓存读数被钳制为 ≤ input
cachedReadTokenscache_read_input_tokens缓存读取
outputTokensoutput_tokens原样记录
reasoningTokens丢弃(不计入总额)已是outputTokens的子集
cacheCreationTokenscache_creation_input_tokens从未缓存余量中再切出

拆分的核心约束是保证三个部分之和恰好等于inputTokens:先uncached = input − min(cached, input),再cache_creation = min(cache_creation, uncached),最后uncached -= cache_creationloader.rs的测试loads_session_tree_with_uncached_split给出了一个直观例子:inputTokens=100, cachedReadTokens=40时,报告为未缓存输入 60 + 缓存读取 40,extra_total_tokens为 0。

modelUsage是一个「模型 id → 该模型 usage」的映射。若一行turn_completed携带了modelUsage,适配器会为其中每个模型各生成一条条目(测试multi_model_turn_emits_one_entry_per_model验证了这一点);只有modelUsage缺失时才回退到顶层 usage 字段。

Reasoning tokens:已经包含在输出中,绝不重复计费

Grok 的reasoningTokensoutputTokens的子集,因此它们已经计入总数。适配器不会把它们加到 output 之上——无论是 token 数还是成本。parser.rs在构造LoadedEntry时硬编码extra_total_tokens: 0,并附注说明:Grok 的totalTokens == inputTokens + outputTokens,若把 reasoning 再次计入总 token 数,就会造成二次计费。测试does_not_add_reasoning_tokens_to_the_total专门验证了「只有 reasoningTokens=42、其余为 0」的回合最终 input/output/extra 全为 0。

预计算成本:costUsdTicks就是账单金额

Grok 在每条turn_completed上记录costUsdTicks,单位为 1e-10 USD(即 1 tick = 1e-10 美元)。parser.rs中常量COST_USD_TICKS_PER_USD: f64 = 1e10cost_usd_from_ticks将 ticks 换算为美元。注释中说明该换算已用 Grok CLI 1.0.0 的 58 条回合数据验证:每条costUsdTicks / 1e10都能精确还原 xAI 对xai/grok-4.5的列表价。

ccusage 把costUsdTicks视为发票成本(invoice cost),因此:

  • display模式和默认的auto模式报告的就是 Grok 实际收取的金额(display直接返回 ticks 换算值;auto在 ticks 存在时也优先使用它);
  • calculate模式,以及auto模式下没有记录 ticks 的回合,才回退到定价表估算。

定价回退:候选模型 id 与长上下文分层

当需要按定价表估算时(parser.rspricing_candidates),适配器会为原始模型 id(如grok-4.5-build)生成一串候选:

  1. 去掉可选的[grok]前缀并 trim;
  2. 保留原始形式:grok-4.5-build
  3. 加上xai/前缀:xai/grok-4.5-build
  4. 加上x-ai/前缀:x-ai/grok-4.5-build
  5. 再对去掉尾部-build的规范化形式重复上述三种:grok-4.5xai/grok-4.5x-ai/grok-4.5

查找时先做精确匹配(pricing.find_exact,确保用户通过--pricing-override提供的精确覆盖不会被模糊命中遮蔽),全部候选精确匹配失败后才进入子串模糊匹配。测试exact_raw_model_pricing_override_beats_normalized_fallbackprices_via_the_stripped_candidate_when_the_build_form_is_missing分别覆盖了这两种路径。若所有候选都未命中定价表,成本保持为零,并记录missing_pricing_model警告(测试reports_an_unpriced_model_as_missing_pricing_instead_of_dropping_it)。

长上下文分层:xAI 的长上下文费率会在回合的完整上下文(新鲜输入 + 缓存读取 + 缓存写入)超过模型边界时生效——grok-4.5grok-4.6的边界是 200K token。以 cost.rs 中的注释与测试为例,grok-4.5基础费率为输入 $2 / 输出 $6 / 缓存读取 $0.3(每百万 token),超过 200K 上下文后变为 $4 / $12 / $0.6;分层依据的是请求携带的整个上下文,而不是未缓存输入——因为对提示缓存激进的 Agent 来说,大量上下文以缓存读取形式存在。由于一条turn_completed行聚合了多个 API 请求,分层只能按回合而非按请求选择,因此估算结果只是对账单的近似。

模型标签

显示用的模型标签就是原始的modelUsagekey(例如grok-4.5-build),不做改写。在统一报告中,Agent 列(Agent column)负责标识 Grok 来源,模型列则保留原始 id,便于和 Grok 侧日志一一对应。

环境变量

变量描述
GROK_HOMEGrok 官方配置/数据主目录(单一根目录)
LOG_LEVEL调整日志详细程度(0 静默 … 5 跟踪)

GROK_HOME只接受单个根目录(不像CODEX_HOME等支持逗号分隔列表),完整的环境变量清单与默认值见 Environment Variables。LOG_LEVEL的六档取值(0 静默 / 1 警告 / 2 普通 / 3 信息(默认)/ 4 调试 / 5 跟踪)在脚本管道和 CI 场景下很常用,例如LOG_LEVEL=0 ccusage grok daily --json获得干净的纯 JSON 输出。

配置:grok命名空间

与其他聚焦数据源一样,grok命名空间支持同一套共享报告选项,可写入 ccusage 配置文件(如~/.config/claude/ccusage.json或项目级.ccusage/ccusage.json,优先级见 Configuration):

{ "grok": { "defaults": { "offline": true }, "commands": { "session": { "json": true } } } }

语义规则:

  • grok.defaults应用于所有 Grok 报告;
  • grok.commands.dailygrok.commands.monthlygrok.commands.session分别提供报告级覆盖(同名项覆盖 defaults);
  • 数据根目录只从GROK_HOME~/.grok发现,从 ccusage 配置中读取——配置只能控制报告选项,不能指定数据目录。

故障排查

没有找到 Grok 用量数据

# 确认根目录下存在已完成回合 ls ~/.grok/sessions/**/updates.jsonl # 数据在其他位置时显式指定 GROK_HOME=/path/to/grok-home ccusage grok daily

进行中的回合要等turn_completed写入后才会出现。若目录里只有logs/unified.jsonl而没有sessions/**/updates.jsonlhas_data()返回 false,报告自然为空——这是设计行为而非 bug。

成本显示为 $0.00

Grok 开始记录costUsdTicks之前写入的回合没有携带成本,display模式对它们显示为零。此时改用定价表为这些回合计价:

ccusage grok daily --mode calculate

若某个模型在定价表中缺失,成本同样保持为零,并可能出现 missing-pricing 警告(可通过--debugLOG_LEVEL=4观察)。你也可以用--pricing-override为私有或代理模型补充精确价格,适配器会优先做精确匹配。

回合进行中时总数低于预期

v1 只统计已完成的回合。等待回合结束(turn_completed写入)后重新运行报告即可:

ccusage grok daily

深入阅读

想继续探索该适配器的实现与验证,可以按需阅读:

  • 数据根解析与会话发现:paths.rs(含GROK_HOME回退、updates.jsonl 筛选、嵌套会话树测试)
  • 行准入与 token/成本计算:parser.rs(turn_completed过滤、usage 拆分、costUsdTicks换算、定价候选与长上下文分层)
  • 加载与去重:loader.rs(并行读取、跨会话按eventId|model全局去重、按时间戳排序)
  • 报告形状:report.rs(daily/monthly/session 汇总、会话活动范围)
  • 适配器总体说明与测试方式:rust/adapters/grok/README.md
  • 成本模式语义:Cost Modes;命令行选项:Command-Line Options;配置方式:Configuration
  • AI 应用
  • CLI
  • 开发工具

【免费下载链接】ccusage

npx ccusage

项目地址:https://gitcode.com/gh_mirrors/cc/ccusage
点击查看免费下载

相关推荐

上一篇:PiliPlus视频画质选择功能:自适应码率与清晰度切换终极指南
下一篇:WinUI 3 文本服务框架(TSF)配置深度解析:TSF1/TSF3 的选择逻辑与源码实现

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询