深入解构Claude Code - 第 8 篇 · 数据放哪、钱怎么算:用 TaoToken 统一 Key 看清 JSONL 会话与用量账本 1. 从一次“账单对不上”说起Claude Code 的 JSONL 会话与用量账本到底存在哪你大概率遇到过这种场景用 Claude Code 连着改了两小时代码/cost显示花了 3 块多但你去后台一看实际扣费是 5 块出头。差的这两块钱去哪了是缓存没命中还是某个工具返回了超长内容把输入撑爆了想查清楚就得先知道 Claude Code 把数据写到了哪里、按什么口径记账。这篇就干一件事把 Claude Code 的本地数据落盘结构和费用归因逻辑拆开给你看。核心检索词先摆出来——Claude Code 的 JSONL 会话记录、~/.claude目录结构、worktree 隔离目录、token 用量账本这几个东西串起来你才能回答“数据放哪、钱怎么算”。适合谁看已经在用 Claude Code 写代码、想搞清楚本地文件都存了什么的人想把 endpoint 和auth.json统一改到一个入口、方便对账的人以及被/cost和实际扣费差异搞懵、想自己写脚本核对的人。我试过最笨的办法——直接ls -la ~/.claude然后一个个文件点开看结果被一堆 JSONL 行刷屏。后来才理清楚Claude Code 的数据分两层一层是“会话流水”一层是“用量累计”。会话流水按行追加写进 JSONL用量累计则散落在会话文件和配置里。搞懂这两层对账就是个体力活写个脚本就能干。下面按“目录结构 → JSONL 字段 → 用量口径 → 改 endpoint 统一对账 → 排错”的顺序走。每一步都给可复制的命令和脚本你跟着敲就行。先给结论省得你翻到最后Claude Code 的会话数据默认落在~/.claude/projects/下按项目路径编码成目录名每个会话一个.jsonl文件用量信息藏在每条 assistant 消息的usage字段里worktree 模式下会多一层隔离目录。把ANTHROPIC_BASE_URL和auth.json指到 TaoToken 后你可以在一个后台里看到所有调用的账本和本地 JSONL 累加出来的数字对照口径一致就说明没漏记。2. 前置准备TaoToken 统一 Key 与 Claude Code 的接入位置在拆数据之前得先把“入口”统一了否则你本地记的账和后台记的账对不上排查起来是双重麻烦。这一步的目标是让 Claude Code 的所有请求都走同一个 endpoint、用同一个 Key这样后台账本就是唯一真相源。TaoToken 在这里的角色是统一入口。官网在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 这个不加 UTM。你需要的东西就三样Base URL、API Key、Model ID。这三件套在 Claude Code、Cline、Codex 里都是通用的配置逻辑只是文件位置不同。先说 Claude Code 的配置位置。它读两个地方环境变量和~/.claude/settings.json或项目级.claude/settings.json。环境变量优先级更高适合临时切换settings 文件适合长期固定。我建议长期用的话写进 settings临时调试用环境变量覆盖。拿 Key 的路径进控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 在 API Keys 页面创建一个。创建时注意权限范围如果你只是自己用给最小必要权限就行。创建完复制那串 Key它只显示一次丢了只能重建。模型对话的入口在 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 你可以在这里先确认要用的 Model ID 拼写别到时候配置里写错了模型名请求直接 404。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有各客户端的配置示例遇到字段不确定就翻它。如果你是要长期跑编码任务或者 AgentCoding Plan 在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 这个适合高频调用场景比按次计费更可控。ClaudeCodeAnthropic 的专用说明在 https://taotoken.net/claudecode?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecodeutm_campaignrewrite Claude Code 用户重点看这个。前置准备做完你应该手里有一个 API Key、确认好的 Model ID、以及知道 Base URL 是https://taotoken.net/api。接下来进配置环节。3. 可复制配置settings.json、auth.json 与 worktree 目录结构这一节给可直接复制的片段。分三块Claude Code 的 settings、Codex 的 auth.json如果你也用 Codex、以及 worktree 隔离目录长什么样。3.1 Claude Code 的 settings.json路径~/.claude/settings.json全局或项目/.claude/settings.json项目级。项目级会覆盖全局。内容如下{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: sk-你的Key粘贴在这里, ANTHROPIC_MODEL: claude-sonnet-4-20250514 } }三个字段对应三件套ANTHROPIC_BASE_URL是 Base URLANTHROPIC_AUTH_TOKEN是 KeyANTHROPIC_MODEL是 Model ID。Model ID 换成你在模型对话页面确认过的那个别照抄我这里的示例。注意ANTHROPIC_AUTH_TOKEN和ANTHROPIC_API_KEY是两个不同的变量Claude Code 认前者。写错了会一直 401这个坑我踩过。如果你不想把 Key 写进文件多人共用机器时可以用环境变量export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_AUTH_TOKENsk-你的Key export ANTHROPIC_MODELclaude-sonnet-4-20250514写进~/.bashrc或~/.zshrc就能持久化。环境变量优先级高于 settings 文件临时切换时改环境变量即可。3.2 Codex 的 auth.json如果你同时用 Codex它的配置在~/.codex/auth.json{ OPENAI_API_KEY: sk-你的Key, OPENAI_BASE_URL: https://taotoken.net/api }Codex 用的是 OpenAI 兼容格式所以字段名是OPENAI_前缀但值指向同一个 TaoToken 入口。Model ID 在 Codex 的 config 里单独配通常是~/.codex/config.tomlmodel claude-sonnet-4-20250514 model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key OPENAI_API_KEY这样 Codex 和 Claude Code 走同一个入口后台账本统一。3.3 worktree 隔离目录结构Claude Code 在 worktree 模式下会开一个平行工作区。目录结构大致是这样~/.claude/ ├── projects/ │ └── -Users-you-code-myproject/ │ ├── session-id-1.jsonl │ ├── session-id-2.jsonl │ └── worktrees/ │ └── worktree-name/ │ └── session-id.jsonl ├── settings.json └── statsig/projects/下的目录名是项目绝对路径编码来的把/换成-。每个.jsonl是一个会话。worktree 的会话单独放在worktrees/name/下和主工作区的会话分开记。这就是为什么你在 worktree 里干活主目录的会话列表里看不到——它记在另一个子目录。提示想快速定位当前项目的会话目录用ls ~/.claude/projects/ | grep 你的项目名。路径编码后不好认grep 关键词最快。配置写完下一步验证请求能不能通以及数据有没有正确落盘。4. 验证请求与成功结果JSONL 字段解析脚本与用量核对配置改完先发一个最小请求确认连通再看 JSONL 里记了什么。4.1 验证连通在项目目录下启动 Claude Code随便问一句“11 等于几”。如果配置对了会正常返回。如果报错先看第 5 节的排错。连通后找到刚才这个会话的 JSONL 文件ls -lt ~/.claude/projects/ | head -5按修改时间排序最新的那个目录就是当前项目。进去看最新的.jsonlls -lt ~/.claude/projects/-Users-you-code-myproject/*.jsonl | head -34.2 JSONL 字段解析脚本JSONL 每行是一个 JSON 对象。核心字段有这么几个type消息类型、message消息体、timestamp时间戳、sessionId会话 ID。用量信息在 assistant 类型消息的message.usage里。写个 Python 脚本把用量累加出来import json import sys from pathlib import Path def parse_session(jsonl_path): input_tokens 0 output_tokens 0 cache_read 0 cache_creation 0 model None msg_count 0 with open(jsonl_path, r, encodingutf-8) as f: for line in f: line line.strip() if not line: continue try: obj json.loads(line) except json.JSONDecodeError: continue if obj.get(type) ! assistant: continue msg obj.get(message, {}) usage msg.get(usage) if not usage: continue msg_count 1 model msg.get(model, model) input_tokens usage.get(input_tokens, 0) output_tokens usage.get(output_tokens, 0) cache_read usage.get(cache_read_input_tokens, 0) cache_creation usage.get(cache_creation_input_tokens, 0) return { model: model, assistant_messages: msg_count, input_tokens: input_tokens, output_tokens: output_tokens, cache_read_input_tokens: cache_read, cache_creation_input_tokens: cache_creation, total_input_side: input_tokens cache_read cache_creation, } if __name__ __main__: path sys.argv[1] if len(sys.argv) 1 else None if not path: print(用法: python parse_usage.py session.jsonl) sys.exit(1) result parse_session(path) for k, v in result.items(): print(f{k}: {v})跑一下python parse_usage.py ~/.claude/projects/-Users-you-code-myproject/session-id.jsonl输出类似model: claude-sonnet-4-20250514 assistant_messages: 12 input_tokens: 45230 output_tokens: 3891 cache_read_input_tokens: 120400 cache_creation_input_tokens: 8900 total_input_side: 174530这里的关键是total_input_side——它把普通输入、缓存读取、缓存创建加起来这才是你实际被计费的输入侧总量。很多人只看input_tokens忽略了缓存部分导致对不上账。4.3 和后台账本对照去 TaoToken 控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 的用量页面看这个时间段的总 token 数。把本地脚本算出来的total_input_side和output_tokens加起来和后台数字比。如果一致说明口径对上了本地记录没漏。如果本地少、后台多可能是有并发会话没算进来、或者有请求失败了但后台记了用量。如果本地多、后台少检查是不是有缓存命中没被正确归类。注意缓存读取的单价通常远低于普通输入所以对账时不能只看总 token 数要分项比。后台一般会分“输入/输出/缓存读/缓存写”四项逐项对。4.4 多会话汇总一个项目下可能有几十个会话文件逐个跑太慢。写个批量脚本for f in ~/.claude/projects/-Users-you-code-myproject/*.jsonl; do echo $f python parse_usage.py $f done或者用jq一行搞定如果你装了 jqcat ~/.claude/projects/-Users-you-code-myproject/*.jsonl \ | jq -r select(.typeassistant) | .message.usage | \(.input_tokens) \(.output_tokens) \(.cache_read_input_tokens // 0) \(.cache_creation_input_tokens // 0) \ | awk {i$1; o$2; cr$3; cc$4} END {print input:,i,output:,o,cache_read:,cr,cache_create:,cc}这个能快速把整个项目的用量汇总出来和后台对总数。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth配置和验证过程中最容易撞的几个错逐个说清楚。5.1 401 Unauthorized最常见。原因通常是 Key 写错、或者变量名用错。Claude Code 认ANTHROPIC_AUTH_TOKEN如果你写成ANTHROPIC_API_KEY它读不到就会 401。排查步骤echo $ANTHROPIC_AUTH_TOKEN确认输出的是你的 Key不是空。如果是空说明环境变量没生效检查~/.bashrc有没有 source或者 settings.json 里的字段名对不对。还有一种情况Key 本身没问题但 Base URL 末尾多了斜杠。https://taotoken.net/api/和https://taotoken.net/api在某些客户端里行为不同去掉末尾斜杠再试。5.2 local proxy failed这个报错通常出现在你本地配了代理、但代理没起来或者端口不对的时候。Claude Code 会尝试走本地代理连不上就报这个。排查env | grep -i proxy看有没有HTTP_PROXY、HTTPS_PROXY之类的变量。如果有且你不需要代理直接 unsetunset HTTP_PROXY HTTPS_PROXY http_proxy https_proxy然后重启 Claude Code。如果你确实需要走某个网络配置确认端口和地址写对了。5.3 reading choices 报错这个一般出现在响应格式不符合预期时。Claude Code 期望的是 Anthropic 格式的流式响应如果 endpoint 返回的是 OpenAI 格式解析choices字段就会失败。检查你的 Base URL 是不是指向了正确的兼容端点。TaoToken 的https://taotoken.net/api对 Claude Code 提供 Anthropic 兼容格式对 Codex 提供 OpenAI 兼容格式路径可能不同。翻一下接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 确认当前客户端该用哪个路径。5.4 OAuth 相关报错如果你之前用官方账号登录过Claude Code 可能缓存了 OAuth token改配置后它还在用旧的。清掉缓存rm -rf ~/.claude/statsig rm -f ~/.claude/.credentials.json然后重新启动。注意这会清掉登录态你需要重新用 Key 认证。5.5 三件套检查清单出现任何连接问题先按这个清单过一遍检查项正确值常见错误Base URLhttps://taotoken.net/api末尾多斜杠、写成首页地址Key 变量名ANTHROPIC_AUTH_TOKEN写成ANTHROPIC_API_KEYModel ID控制台确认过的完整 ID拼写错误、用了不存在的模型代理变量不需要时清空残留旧代理配置这三件套Base URL Key Model ID在 Claude Code、Cline、Codex 里逻辑一致只是文件位置和字段名不同。Cline 的 MCP 配置里也是这三个值Codex 的auth.json里也是。记住这个通用结构换客户端时不用重新学。6. 把账本用起来从 JSONL 到统一用量视图数据位置和计费口径搞清楚之后你能做的事就多了。第一自己写个定时脚本每天把~/.claude/projects/下所有 JSONL 的用量汇总存成 CSV。这样你有自己的历史账本不依赖任何后台。脚本核心就是第 4 节那个解析函数加个 cron 就行。第二把 worktree 的会话也纳入统计。worktree 目录在~/.claude/projects/项目/worktrees/下批量脚本里加个-r递归就能覆盖。别漏了这部分否则并行开发时账会少算。第三用后台的用量视图做交叉验证。TaoToken 控制台的用量页面按时间维度展示你可以按天、按模型筛选。本地脚本算出来的数字和它对照差异超过 5% 就值得查。常见差异来源并发请求的时间戳归属、缓存命中的归类、失败请求是否计费。第四如果发现某次对话输入异常高去 JSONL 里定位那条消息。看它的usage.input_tokens和cache_read_input_tokens比例。如果缓存读取占比很低说明缓存没命中可能是系统提示变了或者上下文被截断导致缓存失效。这时候可以考虑调整上下文策略减少重复输入。第五长期跑编码任务的话Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 比按次计费更适合因为你有稳定的用量预期套餐制能把成本锁住。配合本地账本你能算出自己的月均用量选套餐时心里有数。最后说个实操细节JSONL 文件会越来越大尤其是长会话。定期归档旧的会话文件别让~/.claude/projects/无限膨胀。归档前先跑一遍汇总脚本把用量数据存下来原始 JSONL 可以压缩或者移到冷存储。这样既保留了账本又不占主目录空间。数据放哪、钱怎么算本质是两个问题落盘位置决定你能不能查到计费口径决定你查到的数字对不对。把~/.claude的结构摸清、把 JSONL 的usage字段解析出来、把 endpoint 统一到 TaoToken这三步做完你的账本就是可信的。