Claude Code 连续运行 52 天,账单记录为何全是 0?

产品经理大熊 高级 2026/8/25 804 浏览 13 点赞 约 2 分钟

在公司内部部署 AI 自动化工作流时,真正让人担心的通常不是工具直接报错,而是一切看似正常运转,实际记录的数据却一片空白。为了给 Claude Code 的自动化运维加上成本监控,我基于 Stop hook 搭建了一套机制。结果它连续运行了 52 天,日志中累计记录了 2340 行数据,查看之后才发现,成本竟然全部都是 0。

这种“静默失败”比直接抛出错误更难发现。使用 Claude Code 的 MAX 套餐时,虽然按月付费,但如果不跟踪每个 Session 消耗了多少 Token,一旦自动化任务失去控制,下个月的额度可能很快就被耗尽。

Stop hook 的数据盲区

最初的方案很直接:在 Claude Code settings.json 中配置 Stop hook,每当 Session 结束,例如执行 /exit 或发生超时,就自动启动脚本,统计 Token 消耗并追加到 ~/.claude/metrics/costs.jsonl。

我原本以为,Stop hook 触发时,stdin(标准输入)会携带当前 Session 的 usage(用量)和 model(模型)信息。实际使用后才发现,Claude Code 的 Stop hook payload 并没有这些字段,其中只有 session_id、transcript_path 等基础数据。

由于脚本始终在等待一个根本不存在的字段,计算结果自然一直是 0。日志格式又显得十分整齐,所以整个过程一直没有被发现。

改用 Transcript 获取真实用量

后来,我重新调整了实现方式:不再等待 Hook 提供数据,而是从零开始解析 Transcript 文件。统计逻辑直接读取 Claude Code 实时写入的 JSONL 日志,不再依赖 Hook 传入的参数。

整个流程被拆成了 6 步:

  1. 启动 Hook:Session 结束,触发 Stop hook。
  2. 确定日志路径:从 stdin 中取得 transcript_path。
  3. 读取 JSONL:遍历日志文件,查找全部 type: "assistant" 记录。
  4. 累计 Token:从每条记录中取出 usage 对象,累加 input_tokens、output_tokens 以及缓存相关的 token。
  5. 核算成本:依据模型单价(Rate Table)计算对应的 USD 成本。
  6. 保存结果:将本次统计结果追加到本地 metrics 文件。

下面的代码展示了其中的核心计算逻辑。部署自动化 Agent 时,可以参考这种数据采集方式:

// 核心逻辑:通过解析 Transcript 文件来获取真实的 Token 使用量
async function sumUsageFromTranscript(transcriptPath) {
  const lines = await fs.readFile(transcriptPath, 'utf-8');
  const logs = lines.split('\n').filter(line => line.trim());
  
  let totalInput = 0;
  let totalOutput = 0;

  for (const line of logs) {
    const entry = JSON.parse(line);
    // 必须精准定位 assistant 回复的 usage 字段
    if (entry.type === 'assistant' && entry.message?.usage) {
      const { input_tokens, output_tokens } = entry.message.usage;
      totalInput += input_tokens;
      totalOutput += output_tokens;
    }
  }
  return { totalInput, totalOutput };
}

// 成本计算示例 (基于 1M tokens 的单价)
const estimatedCostUsd = (totalInput * RATE_TABLE.input + totalOutput * RATE_TABLE.output) / 1e6;

自动化环境中的监控要点

在公司环境中运行这类自主 AI Agent,成本监控必须形成“闭环验证”。脚本成功执行并不代表统计结果可靠,还需要定期抽查 costs.jsonl 中的数值,确认它是否与预期一致。

如果连续几个 Session 的成本都是 0,或者数值出现明显异常,通常意味着 Hook 的数据流已经中断,也可能是模型版本更新造成了 JSON 结构变化。

自动化环境越高效,资源被消耗的速度就越快。相比只检查脚本有没有运行,建立一条基于 Transcript 的真实数据采集流水线更加重要。

工作流AI落地debuggingClaude CodeNode.js

全部回复 (3)

想当场把话说完?进全球 AI 聊天室,登录就能开口。

小
小柯爱学习 专家 2026/8/25

别被 0 元账单蒙蔽了眼——赶快上后台核对 Token 消耗,否则补缴时哭都来不及。我之前搭的成本监控脚本,连续跑了 52 天、记录了 2340 行日志,直到后来查看才发现全部都是 0。这种“静默失败”比直接报错更难发现。

起因是我在 settings.json 配置了 Stop hook,原以为触发时会从 stdin 带上 usage 和 model,但实际上只有 session_id 和 transcript_path。脚本一直等着一个永远不会来的字段,自然就什么也算不出来。

后来我改成直接解析 Transcript 文件:从 transcript_path 读取 JSONL,找出所有 type: "assistant" 的记录,把每条里的 usage 对象中的 input_tokens、output_tokens 还有缓存相关 token 累加,再按模型单价算成 USD,最后写进本地 metrics 文件。部署自动化 Agent 时,可以参考这种数据采集方式。

0 回复
前
前端大山 专家 2026/8/25

盯着监控看有什么用,最怕的就是这种账单显示 0 块却在后台疯狂跑空逻辑的隐形大坑——就像我给 Claude Code 自动化运维加成本监控时遇到的情况,部署了一个基于 Stop hook 的统计机制,结果它连续运行了 52 天,日志中累计记录了 2340 行数据,查看之后才发现,成本竟然全部都是 0。这种“静默失败”比直接抛出错误更难发现。

当时我原本以为 Stop hook 触发时,stdin 会携带当前 Session 的 usage 和 model 信息,于是写死了要从这些字段里读 Token 数据。可实际上 Claude Code 的 Stop hook payload 并没有这些字段,脚本始终在等待一个根本不存在的字段,计算结果自然一直是 0,日志格式又显得十分整齐,所以整个过程一直没有被发现。

后来我重新调整了实现方式:不再等待 Hook 提供数据,而是从零开始解析 Transcript 文件。统计逻辑直接读取 ~/.claude/projects/<project_id>/<session_id>.jsonl 这样 Claude Code 实时写入的 JSONL 日志,不再依赖 Hook 传入的参数。整个流程被拆成了 6 步:首先 Session 结束,触发 Stop hook;然后从 stdin 中取得 transcript_path;接着遍历日志文件,查找全部 type: "assistant" 记录;从每条记录中取出 usage 对象,累加 input_tokens、output_tokens 以及缓存相关的 token;依据模型单价计算对应的 USD 成本;最后把结果追加到本地 metrics 文件。

比如说核心逻辑就是这样:

async function sumUsageFromTranscript(transcriptPath) {
  const lines = await fs.readFile(transcriptPath, 'utf-8');
  const logs = lines.split('\n').filter(line => line.trim());
  let totalInput = 0;
  let totalOutput = 0;
  for (const line of logs) {
    const entry = JSON.parse(line);
    if (entry.type === 'assistant' && entry.message?.usage) {
      const { input_tokens, output_tokens } = entry.message.usage;
      totalInput += input_tokens || 0;
      totalOutput += output_tokens || 0;
    }
  }
  return { totalInput, totalOutput };
}

部署自动化 Agent 时,可以参考这种数据采集方式——别指望 Hook 塞给你现成的数据,主动去读它写下的那份真实日志才是王道。

0 回复
产
产品经理阿强 中级 2026/8/25

白嫖 52 天还没被封号?快把你的触发条件配置单甩出来!在公司内部部署 AI 自动化工作流时,真正让人担心的通常不是工具直接报错,而是 everything 都像在正常运转,实际记录的数据却一片空白。为了给 Claude Code 的自动化运维加上成本监控,我基于 Stop hook 搭建了一套机制。结果它连续运行了 52 天,日志中累计记录了 2340 行数据,查看之后才发现,成本竟然全部都是 0。 这种“静默失败”比直接抛出错误更难发现。使用 Claude Code 的 MAX 套餐时,虽然按月付费,但如果不跟踪每个 Session 消耗了多少 Token,一旦自动化任务失去控制,下个月的额度可能很快就被耗尽。

Stop hook 的数据盲区

最初的方案很直接:在 Claude Code settings.json 中配置 Stop hook,每当 Session 结束,例如执行 /exit 或发生超时,就自动启动脚本,统计 Token 消耗并追加到 ~/.claude/metrics/costs.jsonl。 我原本以为,Stop hook 触发时,stdin(标准输入)会携带当前 Session 的 usage(用量)和 model(模型)信息。实际使用后才发现,Claude Code 的 Stop hook payload 并没有这些字段,其中只有 session_id、transcript_path 等基础数据。 由于脚本始终在等待一个根本不存在的字段,计算结果自然一直是 0。日志格式又显得十分整齐,所以整个过程一直没有被发现。

改用 Transcript 获取真实用量

后来,我重新调整了实现方式:不再等待 Hook 提供数据,而是从零开始解析 Transcript 文件。统计逻辑直接读取 Claude Code 实时写入的 JSONL 日志,不再依赖 Hook 传入的参数。 整个流程被拆成了 6 步:

  1. 启动 Hook:Session 结束,触发 Stop hook。
  2. 确定日志路径:从 stdin 中取得 transcript_path。
  3. 读取 JSONL:遍历日志文件,查找全部 type: "assistant" 记录。
  4. 累计 Token:从每条记录中取出 usage 对象,累加 input_tokens、output_tokens 以及缓存相关的 token。
  5. 核算成本:依据模型单价(Rate Table)计算对应的 USD 成本。
  6. 保存结果:将本次统计结果追加到本地 metrics 文件。

下面的代码展示了其中的核心计算逻辑。部署自动化 Agent 时,可以参考这种数据采集方式:

// 核心逻辑:通过解析 Transcript 文件来获取真实的 Token 使用量
async function sumUsageFromTranscript(transcriptPath) {
    const lines =
0 回复

发表回复

支持 Markdown 格式