成本追踪 是做什么的?
使用此技能来从指标日志中分析 Claude Code 成本和用量历史,该日志由 ECC 的 stop:cost-tracker 钩子写入。
数据存储位置
追踪器会在每次会话停止时向 ~/.claude/metrics/costs.jsonl 追加一个 JSON 对象。每一行是该会话的累积快照,因此要计算总花费,你需要取每个 session_id 最新的行并在所有会话之间求和——对每一行都求和会造成重复计数。
行结构:
| 字段 | 含义 |
|---|---|
timestamp | 快照的 ISO 时间戳 |
session_id | Claude Code 会话标识符 |
transcript_path | 会话转录文件的路径 |
model | 使用的模型 |
input_tokens / output_tokens | 令牌计数 |
cache_write_tokens / cache_read_tokens | 提示缓存令牌计数 |
estimated_cost_usd | 预先计算的会话累积成本(美元) |
优先使用 estimated_cost_usd 而非手动计算定价——模型和缓存价格会变化,而追踪器是唯一事实来源。
使用时机
- 用户询问“我花了多少钱?”、“这个会话成本是多少?”或“我的令牌用量是多少?”
- 用户提到预算、支出限额、超支或成本控制。
- 用户希望按模型、会话或日期查看成本明细,或导出为 CSV。
工作原理
首先验证日志是否存在(使用 node,而非 sqlite3——追踪器写入 JSONL,而 node 是跨平台的):
node -e 'const fs=require("fs"),os=require("os"),p=require("path");const f=p.join(os.homedir(),".claude","metrics","costs.jsonl");console.log(fs.existsSync(f)?"cost log found":"cost log not found: "+f)'
如果日志缺失,不要捏造用量数据。告诉用户成本追踪会在启用 stop:cost-tracker 钩子后,在第一个会话结束时才会生成数据。
示例——汇总、按模型、最近 7 天
node -e '
const fs=require("fs"),os=require("os"),path=require("path");
const f=path.join(os.homedir(),".claude","metrics","costs.jsonl");
if(!fs.existsSync(f)){console.log("cost log not found: "+f);process.exit(0);}
const rows=fs.readFileSync(f,"utf8").split(/\r?\n/).filter(Boolean).map(l=>{try{return JSON.parse(l)}catch{return null}}).filter(Boolean);
const bySession=new Map();
for(const r of rows){const k=r.session_id||r.transcript_path||r.timestamp;const p=bySession.get(k);if(!p||String(r.timestamp)>String(p.timestamp))bySession.set(k,r);}
const latest=[...bySession.values()];
const cost=r=>Number(r.estimated_cost_usd)||0, day=r=>String(r.timestamp||"").slice(0,10), sum=a=>a.reduce((s,r)=>s+cost(r),0), f4=n=>"$"+n.toFixed(4);
const today=new Date().toISOString().slice(0,10), yest=new Date(Date.now()-864e5).toISOString().slice(0,10);
console.log("today: "+f4(sum(latest.filter(r=>day(r)===today)))+" | yesterday: "+f4(sum(latest.filter(r=>day(r)===yest)))+" | total: "+f4(sum(latest))+" ("+latest.length+" sessions)");
const m=new Map();for(const r of latest){const k=r.model||"(unknown)";m.set(k,(m.get(k)||0)+cost(r));}
console.log("by model:");[...m.entries()].sort((a,b)=>b[1]-a[1]).forEach(([k,v])=>console.log(" "+f4(v)+" "+k));
'
如需会话下钻或 CSV 导出,对同一个 latest 集合(或原始行)进行迭代,并打印所需字段。
报告指南
在呈现成本数据时,应包括当日花费与昨日对比、所有会话的总计、按模型的分解以及会话数量。少于 1 美元的金额格式化为四位小数,较大金额格式化为两位小数。
反模式
- 不要对每一行求和——它们是按会话累积的;必须先按
session_id缩减到最新行。 - 当
estimated_cost_usd存在时,不要根据原始令牌计数估算成本。 - 不要假设日志存在而不进行检查。
- 不要在面向用户的回答中硬编码当前模型定价。
- 不要推荐安装未经审核的钩子或可执行任意代码的插件。
相关
/cost-report- 通过同一指标日志实现的命令式报告。cost-aware-llm-pipeline- 模型路由和预算设计模式。token-budget-advisor- 上下文和令牌预算规划。strategic-compact- 上下文压缩以减少重复令牌消耗。