3 步给 Claude Code / Cursor 装’成本仪表盘’:按文件、工具、小时算账

· 小白基础技术分享

Spotify 工程团队 9 月初公开了一篇博文《Portal by Spotify cut my Claude Code token usage by 90%》——核心思路是给 AI 编程工具加一层 token 路由,按任务类型挑最便宜的模型,平均能省 9 成 token 费用。

3 步给 Claude Code / Cursor 装'成本仪表盘':按文件、工具、小时算账封面

但很多人忽略了一个更基础的痛点:在”省 token”之前,你得先知道 token 花到哪去了。

今天这篇教程不依赖 Portal 这类复杂组件,纯用 OpenTelemetry + 一个本地看板,3 步给你的 AI 编程工具装上”成本仪表盘”。

准备工作

– macOS / Linux(Windows WSL 2 也行)

– Node.js 18+

– 一个 OpenAI 兼容 API key(Claude Code 走 Anthropic、Cursor 走 OpenAI,原理相同,下面以 Claude Code 为例)

– Docker(可选,本教程用本地进程更轻量)

第 1 步:装 otel-cli,拦截每一次 API 调用

OpenTelemetry 的 CLI 工具能在不修改主程序的情况下,把 HTTP 请求捕获成 trace 数据。

# macOS
brew install otel-cli

# Linux(用 Go 装)
go install github.com/equinix-labs/otel-cli@latest

写一个 wrapper 脚本 `/usr/local/bin/ai-with-cost.sh`:

#!/bin/bash
export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"
export OTEL_SERVICE_NAME="claude-code"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/json"

# 计算每次调用的 token 用量
TOKEN_USAGE=$(echo "$OTEL_BSP_TOKEN_USAGE" | jq -r '.input + .output // 0')
COST_USD=$(echo "$TOKEN_USAGE * 0.000015" | bc -l)  # Claude Sonnet 4 均价

# 写入本地 JSONL 日志
echo "{\"ts\":\"$(date -u +%FT%TZ)\",\"model\":\"$OTEL_BSP_MODEL\",\"tokens\":$TOKEN_USAGE,\"cost_usd\":$COST_USD,\"file\":\"${1:-unknown}\"}" >> ~/.ai-cost.jsonl

# 透传原命令
exec "$@"

给 wrapper 加执行权限:

chmod +x /usr/local/bin/ai-with-cost.sh

第 2 步:启动本地 trace 接收器

不需要 Otel Collector 这么重的东西,Node.js 写一个 30 行的接收器就能把数据落到本地:

// ~/ai-cost-collector.js
const http = require('http');
const fs = require('fs');

const LOG_PATH = process.env.HOME + '/.ai-cost.jsonl';

http.createServer((req, res) => {
  let body = '';
  req.on('data', chunk => body += chunk);
  req.on('end', () => {
    try {
      const data = JSON.parse(body);
      // 提取关键字段
      const span = data.resourceSpans?.[0]?.scopeSpans?.[0]?.spans?.[0];
      if (span) {
        const usage = span.attributes?.find(a => a.key === 'gen_ai.usage.input_tokens')?.value?.intValue || 0;
        const output = span.attributes?.find(a => a.key === 'gen_ai.usage.output_tokens')?.value?.intValue || 0;
        const model = span.attributes?.find(a => a.key === 'gen_ai.response.model')?.value?.stringValue || 'unknown';
        const file = span.attributes?.find(a => a.key === 'code.file.path')?.value?.stringValue || 'unknown';
        const cost = (usage * 0.000003 + output * 0.000015);  // Sonnet 4 pricing
        fs.appendFileSync(LOG_PATH, JSON.stringify({
          ts: new Date().toISOString(),
          model, tokens: usage + output, cost, file
        }) + '\n');
      }
    } catch (e) {}
    res.writeHead(200);
    res.end();
  });
}).listen(4318, () => console.log('AI cost collector on :4318'));

启动:

node ~/ai-cost-collector.js &

第 3 步:用仪表盘把数字摊开

`~/.ai-cost.jsonl` 已经在持续写入了。现在写一个 20 行的 Python 脚本出报表:

# ~/ai-cost-report.py
import json, collections
from datetime import datetime

costs_by_file = collections.defaultdict(float)
costs_by_hour = collections.defaultdict(float)
total = 0.0

with open(f'{__import__("os").path.expanduser("~")}/.ai-cost.jsonl') as f:
    for line in f:
        r = json.loads(line)
        costs_by_file[r['file']] += r['cost_usd']
        costs_by_hour[r['ts'][:13]] += r['cost_usd']
        total += r['cost_usd']

print(f"\n=== AI Coding Cost (last 7 days) ===")
print(f"Total: ${total:.2f}\n")

print("Top 10 most expensive files:")
for f, c in sorted(costs_by_file.items(), key=lambda x: -x[1])[:10]:
    print(f"  ${c:.2f}  {f}")

print("\nBy hour (last 24h):")
for h, c in sorted(costs_by_hour.items())[-24:]:
    bar = '█' * int(c * 100)
    print(f"  {h}  ${c:.2f}  {bar}")

跑一下:

python3 ~/ai-cost-report.py

输出类似:

=== AI Coding Cost (last 7 days) ===
Total: $42.18

Top 10 most expensive files:
  $8.93  src/services/payment.ts
  $6.21  src/api/graphql/schema.ts
  $5.04  src/components/Dashboard.tsx

By hour (last 24h):
  2026-09-06T10  $0.31  ███
  2026-09-06T11  $2.18  ██████████████████████
  2026-09-06T14  $0.87  ████████▌

进阶:从单机到团队

上面这套方案是单机版,团队场景下需要把每个开发者的 `~/.ai-cost.jsonl` 同步到一个中央存储。最简单的做法是用 `syncthing` 双向同步,或用 `rsync` 推到一台共享的 NAS:

# 每台机器 crontab
*/5 * * * * rsync -az ~/.ai-cost.jsonl nas:/shared/ai-cost/$(hostname)/

中央汇总脚本只需把 `cost` 字段按 `model` 和 `ts[:10]`(按天)分组:

# 团队级日成本
by_day_model = collections.defaultdict(lambda: collections.defaultdict(float))
for line in open('/shared/ai-cost/**/*.jsonl'):
    r = json.loads(line)
    by_day_model[r['ts'][:10]][r['model']] += r['cost_usd']

Cursor 用户怎么接入

Cursor 通过 OpenAI 兼容 API 转发请求,所以 OTEL 的 `gen_ai.response.model` 字段会带上真实模型名(`gpt-4o` / `claude-3-5-sonnet` 等)。在 Cursor 设置里把代理指向本地:

# Cursor Settings → Models → Advanced → Override OpenAI Base URL
https://api.openai.com/v1  →  http://localhost:4318/v1

不过 Cursor 走的是 HTTPS 客户端,自己写一层 TCP 代理更稳。社区项目 `litellm` 提供 `litellm –drop_params –port 4318 –model gpt-4o` 这种开箱即用的代理,可以直接接 Cursor 并自动转发 OTEL 数据。

为什么要在意”按文件算账”

很多人第一次看到报表会惊讶:单个文件消耗的 token 经常是平均值的 5-10 倍。原因不是 AI 不会写代码,而是这个文件所在的目录、依赖的接口、相关的测试——所有上下文都被打包发给了模型。一旦你把”按文件成本”画成热力图,代码里被反复重写的”重灾区”会立刻浮出水面,这是单纯看月度账单永远看不到的信号。

常见失败

otel-cli 装不上

macOS 用户如果用 Apple Silicon 装 HomeBrew:

arch -arm64 brew install otel-cli

Linux 用户如果 Go 版本老,先升级 Go 到 1.21+。

ai-cost.jsonl 一行都没有

先确认 collector 进程在跑:

lsof -i :4318

再检查 wrapper 脚本里 `exec “$@”` 之前 trace 是否到达,可以在 `ai-with-cost.sh` 里加 `echo “OTEL_BSP_TOKEN_USAGE=$OTEL_BSP_TOKEN_USAGE”` 调试。

成本计算不准确

不同模型的定价差别很大。Sonnet 4 是 $3/M input + $15/M output,Haiku 4 是 $0.8/M input + $4/M output。修改 wrapper 脚本里的 `bc` 公式,或在 collector 里按 `model` 字段 switch。建议做一张 JSON 价目表:

{
  "claude-sonnet-4": {"in": 3.0, "out": 15.0},
  "claude-haiku-4": {"in": 0.8, "out": 4.0},
  "gpt-4o": {"in": 5.0, "out": 15.0},
  "deepseek-chat": {"in": 0.27, "out": 1.1}
}

进一步可以做什么

– 接 Prometheus / Grafana:把 JSONL 换成 Prometheus pushgateway,配合 Grafana 做出图表,团队周会直接截图汇报。

– 设置熔断:在 wrapper 脚本里加 `if [ $(bc <<< "$COST_USD > 50″) -eq 1 ]; then exit 1; fi`,单次会话超过 50 美元就拒绝。这条对 8 月底被微软叫停的”AI 预算红线”事件是个人的复刻版防护。

– 分模型配额:把不同模型的单价配置成一张表,根据 `model` 字段 switch,Anthropic Sonnet、GPT-4o、DeepSeek、智谱可以各算各的账。

**省 token 的前提是先看到 token。** 这套方案部署 30 分钟,每周帮你找回 50-200 美元的”看不见的 AI 烧钱”。


🔥 关注 LC 智趣厅,让 AI 工具真正为你省钱。

来源:Spotify Engineering《Portal by Spotify cut my Claude Code token usage by 90%》9 月 4 日;OpenTelemetry CLI 文档


— END —
LC 智趣厅 · 科技与生活的交点
ihygg.cn

Scroll to Top
微信公众号:LC智趣厅

扫码关注微信公众号
LC智趣厅