news 2026/9/26 17:01:05

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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上还能按Option+N快捷键唤起同样的面板。

这个命令的价值在于让你对“会话有多重”有个即时感知。比如说上下文占用已经显示到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_tokens=75200 output_tokens=4861

把这些行抓出来,就能拼出单次请求的精确消耗。如果你想让数据落盘而不是只在终端里滚过去,可以把输出重定向到文件:

claude --debug 2>&1 | 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_ascii=False) output_text = tool_response if isinstance(tool_response, str) else json.dumps(tool_response, ensure_ascii=False) 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(), key=lambda 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

起来之后,浏览器打开管理后台,做三步初始化:

  1. 添加渠道:渠道类型选Anthropic,填入官方API Key或其他兼容Anthropic协议的上游Key;
  2. 创建令牌:在令牌管理里生成一个全新的Key,形如sk-xxxxxx。这个Key是给Claude Code用的,它产生的所有用量都会归到这个令牌名下;
  3. 设置模型可用范围:把需要用到的Claude模型勾上,这样Claude Code里才能切换对应模型。

然后把Claude Code环境变量指到网关:

export ANTHROPIC_BASE_URL="http://127.0.0.1:3000" export ANTHROPIC_API_KEY="sk-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_URL="http://127.0.0.1:9000" export ANTHROPIC_API_KEY="sk-real-key" claude

这样Claude Code每次调用API时,代理都会在终端或日志里留下一行token记录,模型、输入token、输出token一目了然。

不过现实中的Claude Code请求通常是流式响应,也就是SSE,响应体不是一块返回,而是按行持续推过来。要精确记录流式响应的usage,需要在代理里按行解析,找到event: message_delta后面的usage字段值。这个处理比上面这段代码复杂不少,但核心思路不变。我用的是一个小技巧:流式响应的最后一条消息里通常带有usage总结,所以只需要在代理的响应流里做一个正则匹配,把带"usage"的JSON块单独摘出来。生产级别我再补上异常重试、数据落盘和按会话聚合,代码量也不会超过200行。

6. 账算清楚了,接下来怎么省Token

6.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,可能会变成下一块被日志撑爆的磁盘。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 17:00:59

【研发类-前端开发Skills】avalonia-viewmodels-zafiro 技能

使用Zafiro和ReactiveUI的Avalonia最佳ViewModel和向导创建模式。技能概述avalonia-viewmodels-zafiro 技能提供一套最佳实践和模式&#xff0c;用于在Avalonia应用程序中创建ViewModel、向导和管理导航&#xff0c;利用ReactiveUI和Zafiro工具包的强大功能。下载地址&#xff…

作者头像 李华
网站建设 2026/9/26 17:00:48

小团队自建永久在线CRM:Flask+PostgreSQL+Nginx实战

1. 为什么小团队需要一个"永久在线"的CRM做过小团队管理的人都有一个共同体会&#xff1a;客户信息散落在微信聊天记录、Excel表格、个人手机通讯录里&#xff0c;销售一走&#xff0c;客户跟着走。市面上成熟的SaaS CRM按人头收费&#xff0c;五个人一年下来少说几千…

作者头像 李华
网站建设 2026/9/26 16:57:15

Windows窗口自动排布工具:支持复合筛选与事件驱动的编排系统

1. 这不是普通窗口管理器&#xff1a;它专为“多任务并行”而生你有没有过这样的时刻&#xff1a;开着3个浏览器窗口查资料、2个Excel表格核对数据、1个微信窗口同步沟通、后台还挂着远程桌面和监控看板——结果一晃神&#xff0c;某个关键窗口被盖在最底下&#xff0c;找它得挨…

作者头像 李华
网站建设 2026/9/26 16:56:30

HIS系统部署与二次开发实战:从数据库初始化到挂号收费主链路

简介&#xff1a;一套面向小型诊所和医疗机构的轻量级HIS&#xff08;医院信息系统&#xff09;源码包&#xff0c;基于ASP.NET Web技术构建&#xff0c;覆盖病患管理、挂号、药品、收费、统计报表、医生排班和患者追踪等核心模块。压缩包共451个文件&#xff0c;约7.05MB&…

作者头像 李华
网站建设 2026/9/26 16:56:26

训练数据投毒原理与防御:从后门攻击到供应链安全

1. 先搞清楚&#xff1a;训练数据投毒到底是怎么“毒”到模型的很多人一听到“训练数据投毒”这六个字&#xff0c;第一反应是黑客往数据库里塞病毒脚本&#xff0c;或者在训练集里混入一堆恶意图片让模型崩溃。半对。往训练集里塞恶意样本是真的&#xff0c;但“毒”的逻辑远比…

作者头像 李华
网站建设 2026/9/26 16:56:15

Trae一键生成系统架构图:用TaoToken统一Key打通AI出图链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华