ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Claude Code token消耗监控与省钱指南:从日志到网关的四种统计方案

Claude Code token消耗监控与省钱指南:从日志到网关的四种统计方案 1. 为什么Claude Code像“吞金兽”先搞懂token都消耗在哪些环节1.1 一次看似普通的对话到底烧掉了多少令牌很多同学对token的认知是“我发一句话模型回一句话按两边的字数算钱”。在实际用Claude Code之前我也是这么想的直到第一次看到月度账单才反应过来原来它每问一个问题都要把当前会话里的几乎全部内容重新发给模型算一遍。Claude Code的工作方式决定了一件事它没有“增量问答”这种美事。每次你让它改代码、读文件、跑命令它都要把以下内容作为上下文的固定开销重新传输一遍系统提示词——Claude Code自己内置的那一大段指令规定它怎么操作终端、怎么使用工具、遵循什么开发规范工具定义——所有内置工具加上你接入的MCP server工具每个工具的名称、描述、参数Schema都会变成可计费的token历史对话——当前会话中你问过的每一句、它回答过的每一段、中途产生的工具调用记录用户本次输入——你新发的那句话工具执行结果——比如Bash跑出来的终端输出、Read读进来的整个文件内容。所以你可以这么理解单次请求的token消耗 ≈ 系统提示词 工具定义 完整历史记录 本次输入 本次输出。这就意味着越长的会话、越大的工具输出、越多的MCP插件单次请求就越贵。而且模型输出token的单价通常远高于输入token聊high了让它一口气写几百行代码那部分费用是最扎眼的。举一个我自己的实测数据给你找找感觉。某个下午我用Claude Code做一个中等规模的TypeScript重构会话持续了三个多小时中间多次让它读文件、跑测试、反复修改同一个模块。最终聊天记录显示这个会话累计消耗了约60万输入token和4万输出token。当时用的还是主力模型档次按输入约0.003美元/千token、输出约0.015美元/千token粗略一算这个下午就烧了差不多250元人民币。而我自己当时只觉得“好像也没让它干多少活”。1.2 不同模型组合的成本差异如果你以为所有模型的token都一个价那就更要仔细看这段了。Claude Code支持在会话中用/model切换模型不同档位的模型价格差距能到5到20倍。模型档位输入价格示意输出价格示意适合场景高端推理约15美元/百万token约75美元/百万token复杂架构设计、跨模块重构、疑难Bug定位主力日常约3美元/百万token约15美元/百万token日常增删改查、写测试、改样式轻量快速约1美元/百万token约5美元/百万token简单问答、小段代码生成、格式化这里不给绝对价格因为各家渠道、优惠策略、模型版本更新太快你在配置聚合网关时看到的计费才是准的。这份表格只想说明一个关键点选错模型档位的浪费可能比滥用工具还严重。比如你只是让Claude帮忙重命名一个变量结果它也启动了满血推理模型这个操作的成本就是轻量模型的十几倍而产出几乎没有任何差别。有了这个基础认知你就知道为什么“监控token”不是小气而是工程管理的一部分。下面四种方法我按从简单到复杂、从个人到团队、从只读日志到全量埋点的顺序来写你完全可以根据自己的场景挑需要的用。2. 方法一零成本快速统计Claude Code自带功能就够用2.1 /status与/context会话内的实时“体检表”如果你只想先搞清楚“当前这个会话到底烧了多少”不需要任何额外工具。Claude Code会话中直接输入/status它会输出当前模型、上下文占用百分比、大概的累计token数量、费用估算。Mac上还能按OptionN快捷键唤起同样的面板。这个命令的价值在于让你对“会话有多重”有个即时感知。比如说上下文占用已经显示到80%以上了那就算你之后只问一句“这个函数哪里写得有问题”模型也要先把那80%的上下文重新过一遍这一问的成本就已经很高了。通常我只要看到这个数字超过60%就会认真考虑是继续聊还是重开一个话题单元。/context命令则更细一点它会把当前上下文中占用量比较大的项目列出来比如某个文件内容占了多少、某个MCP server返回的记录占了多少、历史对话占了多少。它没法直接给你一个“每条Prompt花多少钱”的明细但能告诉你哪些东西正在吃掉上下文空间这其实比货币金额更容易指导你优化行为。比如它显示某个大文件占了40%的空间那你心里就有数了下次别动不动就整文件喂进去。2.2 debug日志里藏着每次请求的用量明细/status适合实时看但它只覆盖当前会话退出之后你再想追忆某个小时烧了多少就不行了。更原始也更权威的数据藏在Debug日志里。启动时加--debug参数claude --debug在Debug模式下终端会打印出每一次API请求的响应摘要包括请求路径、耗时、状态码以及token用量类似这样Request: POST /v1/messages 200 OK (1500ms) input_tokens75200 output_tokens4861把这些行抓出来就能拼出单次请求的精确消耗。如果你想让数据落盘而不是只在终端里滚过去可以把输出重定向到文件claude --debug 21 | tee ~/claude-debug-$(date %Y%m%d).log想统计当天总量直接配合日志做文本处理就行。我用一个简单思路grep -E input_tokens|output_tokens ~/claude-debug-20250601.log | gc这个方法的问题也很明显--debug的输出非常啰嗦每个请求都会打一整屏请求体和响应摘要开一天生成的日志能到几百MB不适合日常常驻而且日志里的token数据是“请求级别的原始数据”没有按项目、按会话聚合的报表你得自己二次加工。所以我的建议是它更适合做“临时排障”或“某一天突然想核对用量”时用而不是长期统计方案。3. 方法二Hook脚本自动记账精准到每把工具3.1 Claude Code的hook事件是什么Claude Code支持一套hook机制简单说就是当特定事件发生时客户端会调用你在配置文件里指定的外部命令。对我来说最有用的是PostToolUse事件——它会在每个工具调用完成之后触发。也就是说每当Claude读取了文件、跑了Bash、改了代码你的脚本都能收到一份关于这次工具调用的JSON描述里面有工具名、工具输入、工具输出等关键字段。这个机制的价值在哪儿它让我们有机会统计“哪类工具在烧钱”。比如你可以用脚本统计出一周之内Read工具读了多少次、Bash命令产出了多少字符、Edit改了多少行。有了这份数据你就知道下一次该优先控制什么是让Claude少读大文件还是别在生产服务器上跑一堆无意义的查询。PostToolUse事件从配置层面支持得非常简单用户级配置文件在~/.claude/settings.json项目级配置文件在项目根目录的.claude/settings.json。两边配置格式一样用户级会全局生效项目级只对当前项目生效。3.2 落地一个PostToolUse统计脚本我先写了段Python脚本它不做任何复杂计算就是把每次工具调用的时间、工具名、输入大概字符数、输出大概字符数追加到一个CSV文件里。#!/usr/bin/env python3 import sys, json, csv, os, time from datetime import datetime payload json.load(sys.stdin) tool_name payload.get(tool_name, ) tool_input payload.get(tool_input, {}) tool_response payload.get(tool_response, ) # 粗略估算中英混合场景下约3到4个字符折算1个token def estimate_tokens(text): return max(1, len(text) // 3) input_text json.dumps(tool_input, ensure_asciiFalse) output_text tool_response if isinstance(tool_response, str) else json.dumps(tool_response, ensure_asciiFalse) row [ datetime.now().isoformat(), os.environ.get(CLAUDE_PROJECT_DIR, ), tool_name, len(input_text), len(output_text), estimate_tokens(input_text), estimate_tokens(output_text), ] csv_path os.path.expanduser(~/.claude/logs/token-usage.csv) if not os.path.exists(csv_path): header [time, project, tool, input_chars, output_chars, approx_input_tokens, approx_output_tokens] with open(csv_path, w) as f: csv.writer(f).writerow(header) with open(csv_path, a) as f: csv.writer(f).writerow(row)然后在~/.claude/settings.json里挂上这个脚本{ hooks: { PostToolUse: [ { matcher: *, hooks: [ { type: command, command: python3 ~/.claude/hooks/token_logger.py } ] } ] } }matcher支持用正则匹配工具名。你只想记录耗资源较大的工具时可以改成Read|Grep|Bash|Edit这类减少脚本执行频率。脚本运行完CSV里就积累了每次工具调用的估算值。我一般每周跑一次汇总看看工具使用排行python3 - EOF import csv from collections import defaultdict tools defaultdict(lambda: [0, 0, 0]) with open(/Users/me/.claude/logs/token-usage.csv) as f: for row in csv.DictReader(f): tools[row[tool]][0] 1 tools[row[tool]][1] int(row[approx_input_tokens]) tools[row[tool]][2] int(row[approx_output_tokens]) for tool, (count, tin, tout) in sorted(tools.items(), keylambda x: -x[1][1]): print(f{tool}: 次数{count}, 估算输入token{tin}, 估算输出token{tout}) EOF需要提醒的是hook拿到的数据是“工具输入输出的内容量”不是模型计费时返回的精确usage。模型本身还有系统提示词、工具定义和历史对话的开销这部分hook看不到。所以这份统计适合回答“哪些工具把上下文撑大了”不适合回答“我今天精确花了多少钱”。想要精确到模型计费层面得往下面两节说的方案走。4. 方法三API网关统一记账团队场景的正确打开方式4.1 网关能记什么账如果是一个团队共用一个Anthropic账号或者你自己同时接了好几个模型渠道那上面两种方法就不够用了。因为大家共用一个API Key出问题根本分不清是谁烧的这时候就要把请求流量统一导到一个API网关层。这里说的网关指one-api、new-api这类开源API管理项目。它们做了一件很朴素的事把各种AI服务商的接口统一成一个入口你在这个入口里可以配置多个上游渠道创建很多个下游令牌每个令牌的用量和费用都会被记录下来。Claude Code只需要把API请求地址指到这个网关它自然就成了统一的“记账本”。网关的统计维度非常清楚我从实际查询经验来看主要几类统计维度能回答的问题按令牌谁的API Key消耗最大是不是有人拿它去跑别的项目了按模型高端模型的使用占比合不合理能不能把一部分任务切到轻量模型按日期哪一天的用量异常是不是有人把测试脚本挂了一夜按渠道官方渠道和替代渠道的价格、稳定性对比哪些上游值得留下4.2 把Claude Code接到网关的配置步骤部署网关这里我快速带过因为官方文档写得很清楚。日常开发环境用Docker Compose一条命令就能拉起来docker compose up -d起来之后浏览器打开管理后台做三步初始化添加渠道渠道类型选Anthropic填入官方API Key或其他兼容Anthropic协议的上游Key创建令牌在令牌管理里生成一个全新的Key形如sk-xxxxxx。这个Key是给Claude Code用的它产生的所有用量都会归到这个令牌名下设置模型可用范围把需要用到的Claude模型勾上这样Claude Code里才能切换对应模型。然后把Claude Code环境变量指到网关export ANTHROPIC_BASE_URLhttp://127.0.0.1:3000 export ANTHROPIC_API_KEYsk-you-create-in-gateway claude如果你的Claude Code版本能正常读取ANTHROPIC_BASE_URL那么会话里所有请求都会打到网关网关里就能看到每次请求的模型、token、费用和状态码。团队用这个方案特别省心因为你还可以顺手做“预算上限”控制——令牌余额用完了直接拒绝请求从机制上避免账单失控。但这个方案不是没有副作用。网关多一跳网络延迟会上升体感上就是Claude Code每次响应前转圈的时间变长。另外网关默认日志会一直写跑一周就能攒下不少数据建议定时清理或按天归档否则它自己就会成为一个磁盘占用大户。5. 方法四自建轻量级统计代理完全掌控统计口径5.1 统计代理的基本思路网关方案虽然方便但它太重了。如果你只想要一个“既能精确记录token又不想部署一堆依赖和服务”的方案可以自己写一个十几行的HTTP代理挂在本地。思路其实很朴素你本地起一个HTTP端口Claude Code把请求发到这个端口这个代理收到请求后原样转发给真正的Anthropic API端点。代理夹在中间的唯一目的就是从请求和响应里把usage字段截下来写进日志。优点是你不需要额外引入任何商业服务或重组件统计口径完全由你自己定义缺点是你得自己处理超时、错误、流式响应这些问题。所以我的建议是这个方案适合“想看懂每一分钱花在哪”的开发者不太适合无编程经验的人。5.2 一个最小可跑的Node.js代理示例下面这个示例核心逻辑是代理POST请求并在收到响应后尝试解析usage字段。为了让你好理解我先展示非流式情况下的处理const http require(http); const https require(https); const UPSTREAM_HOST api.anthropic.com; const PORT 9000; http.createServer((req, res) { const chunks []; req.on(data, c chunks.push(c)); req.on(end, () { const body Buffer.concat(chunks); const options { hostname: UPSTREAM_HOST, path: req.url, method: req.method, headers: { ...req.headers, host: UPSTREAM_HOST } }; const upstream https.request(options, upstreamRes { const resChunks []; upstreamRes.on(data, c resChunks.push(c)); upstreamRes.on(end, () { const raw Buffer.concat(resChunks); try { const json JSON.parse(raw.toString()); if (json.usage) { const project req.headers[x-project-dir] || ; console.log(JSON.stringify({ time: new Date().toISOString(), project, model: json.model, input_tokens: json.usage.input_tokens, output_tokens: json.usage.output_tokens })); } } catch (e) { /* 非JSON或解析失败就跳过 */ } res.writeHead(upstreamRes.statusCode, upstreamRes.headers); res.end(raw); }); }); upstream.write(body); upstream.end(); }); }).listen(PORT, () { console.log(token stats proxy listening on ${PORT}); });启动后给Claude Code指过来node token-proxy.js export ANTHROPIC_BASE_URLhttp://127.0.0.1:9000 export ANTHROPIC_API_KEYsk-real-key claude这样Claude Code每次调用API时代理都会在终端或日志里留下一行token记录模型、输入token、输出token一目了然。不过现实中的Claude Code请求通常是流式响应也就是SSE响应体不是一块返回而是按行持续推过来。要精确记录流式响应的usage需要在代理里按行解析找到event: message_delta后面的usage字段值。这个处理比上面这段代码复杂不少但核心思路不变。我用的是一个小技巧流式响应的最后一条消息里通常带有usage总结所以只需要在代理的响应流里做一个正则匹配把带usage的JSON块单独摘出来。生产级别我再补上异常重试、数据落盘和按会话聚合代码量也不会超过200行。6. 账算清楚了接下来怎么省Token6.1 从数据里读出的几个常见浪费盲区做了统计之后你会发现很多浪费不是因为你“用得太频繁”而是因为你“每次用得都很大”。我从自己的统计数据里总结出几个高频浪费点长时间会话不清一个会话聊到上百轮上下文里有大量已经没用的话。每次新提问这些旧话都跟着重新算一遍。我统计过某些长会话单次请求的input_tokens能到8万以上其中有效信息可能不到20%。大文件整读让Claude直接Read一个几千行的文件文件内容全量进入上下文。更聪明的做法是先让它wc -l看行数、grep查关键函数在哪再针对性读片段。挂了一堆MCP server每个工具定义都会进入系统提示词。模型每轮请求都会带上这一大串工具Schema就算一个都不用钱也在花。我见过最多的一位同事挂了6个MCP server光系统占用就涨了好几千token。小任务开大模型有些人习惯性用/model选满血版不管任务是改一行代码还是查一个类型定义。从我的记账数据看轻量模型完成这类任务的输出质量几乎一致费用却差一个数量级。6.2 我实测有效的几条省token习惯账算清楚之后省token其实就不是玄学了就是几个固定的好习惯。我实测下来最管用的几条任务前写清楚边界。在提示里明确说“只改utils/format.ts里第20行附近不要读取其他文件”Claude就不会自己去翻整个项目。这个习惯对上下文占用的改善比任何设置都明显。善用/compact而不是硬撑。当上下文太长了与其继续在一个巨型会话里硬聊不如让它把上下文压缩成摘要再继续。这是Claude Code内置的能力保留关键信息的同时踢掉一大半冗余。按任务拆会话。一个会话只做一个任务做完就/clear。人的直觉总觉得“继续聊方便”实际上每多一条无关消息后面所有请求都要为它买单。把统计脚本纳入日常。我现在的节奏是每周三和月末各跑一次汇总看一眼工具消耗排行和模型使用分布基本就能判断最近有没有“大手大脚”。这比等到账单出来了再复盘切实用得多。我个人目前的组合是本地开发用Hook做工具级统计团队共享账号走网关统一记账偶尔需要精确核对费用时用自建代理跑一个下午。三种方案各管一段token消耗彻底从“黑洞”变成了“透明账本”。最后再分享一个容易忽略的小细节给统计脚本和代理日志都配上简单的按天轮转否则你省下来的token可能会变成下一块被日志撑爆的磁盘。
返回列表