尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

基于 OpenTelemetry 构建 Claude Code per-user 成本仪表盘

基于 OpenTelemetry 构建 Claude Code per-user 成本仪表盘 最近在给团队推广 Claude Code 时遇到一个很实际的问题AI 编程助手确实能提效但月底成本账单一出来老板问“这个月模型调用花了多少、每个同学分别用了多少、哪些项目消耗最高”我只能给出一个模糊的总数完全拆不到人。之后看到 Hacker News 上有一个项目叫 Aimeterly思路非常直接不额外埋点直接复用 Claude Code 内置的 OpenTelemetryOTel数据把每次调用的模型、token、用户、会话信息拉出来再汇总成 per-user 成本仪表盘。本文就把这套思路完整拆解一遍从 Claude Code 的 OTel 数据长什么样到如何搭一条采集管道最后落到 Grafana 看板适合准备把 Claude Code 落地到团队又想把成本管清楚的开发者参考。1. 为什么需要 per-user 成本仪表盘1.1 Claude Code 是什么Claude Code 是 Anthropic 推出的命令行 AI 编程工具它运行在终端里能读取项目文件、执行命令、修改代码并在多轮对话中完成“理解需求→改代码→跑测试→修问题”的闭环。对团队来说它的价值是让研发效率明显提升但它本质上是“按 token 消耗计费”的模型调用产品和传统 IDE 插件有本质区别。每位开发者在终端里敲下每一句指令背后都可能触发模型推理消耗的是真实的 tokens。当团队里有十几人、几十人同时使用时这些消耗会快速累积。如果没有一套按人、按项目、按模型维度的统计能力成本管控就是一句空话。1.2 只有总账单没法回答管理问题我见过很多团队的第一版做法订阅平台账号月底拉一次总账单然后按照人数平均摊。这样会带来几个问题公平性差有人一天 200 次调用有人一周只用 5 次平均分摊明显不合理。无法优化不知道是哪个模型、哪个场景消耗最高就无法决定是否切换便宜模型、是否需要限制某些操作。无法预警成本超支发生在月底才发现中间完全不可见。审计缺失如果某些操作涉及敏感数据事后想追溯“谁在什么时间请求了什么模型”没有数据可查。per-user 成本看板解决的就是这些问题。它把“团队总消耗”拆成“每个人、每个会话、每个模型”的明细让成本变成可观察、可追踪、可优化的指标。1.3 Claude Code 内置 OTel 是现成的数据源通常要给一个工具做用量采集需要工具本身提供 hooks 或插件机制。而 Claude Code 在较新版本中直接内置了 OpenTelemetry 支持也就是说它已经能够在内部生成标准的 trace 数据并通过 OTLP 协议导出到外部监控系统。这意味着我们不需要去逆向 CLI、不需要解析终端日志、也不需要让开发者手动上报数据。只要把 Claude Code 的遥测端点指向我们自己的 OpenTelemetry Collector就能拿到包含模型、token、用户等信息的数据。Aimeterly 正是基于这个能力把成本看板做成了“开箱即用”的产品。在往下操作之前先明确一个概念OpenTelemetry 是一套可观测性标准它统一了 metrics、logs、traces 三种信号的数据模型和采集方式。Claude Code 内置 OTel意味着它产出的不再是一堆“不可读的日志”而是结构化的 trace 数据理解这一点非常关键。2. 环境准备与 Claude Code 基础配置2.1 安装 Claude CodeClaude Code 是一个命令行工具官方推荐通过 npm 全局安装。需要本机已具备 Node.js 环境版本要求以官方文档为准。安装命令如下npm install -g anthropic-ai/claude-code安装完成后先验证版本claude --version首次运行需要登录。如果你使用的是 Claude 订阅账号直接在终端执行claude按提示完成登录即可。如果是团队场景通常建议走团队的统一订阅或企业订阅这样后续做成本归属时登录身份会更规范。需要注意Claude Code 更新频率很高不同版本的配置方式可能存在差异本文的所有配置示例以“标准 OTel 环境变量 OpenTelemetry Collector”为演示思路具体参数请以当前版本官方文档为准。2.2 配置 OTel 遥测导出要让 Claude Code 把内置 OTel 数据发出来需要配置导出端点。OpenTelemetry 生态里OTLP 协议是默认的导出协议支持 gRPC 和 HTTP 两种传输方式。这里我用标准环境变量做演示export OTEL_SERVICE_NAMEclaude-code export OTEL_EXPORTER_OTLP_ENDPOINThttp://127.0.0.1:4317 export OTEL_EXPORTER_OTLP_PROTOCOLgrpc如果当前版本支持 HTTP 导出也可以显式指定 traces 端点export OTEL_EXPORTER_OTLP_TRACES_ENDPOINThttp://127.0.0.1:4318/v1/traces配置完成后启动claude如果配置成功本机 4317 或 4318 端口就能收到来自 Claude Code 的 trace 数据。这一步是整个成本仪表盘的数据源头如果导出失败后面所有分析都是空谈。2.3 推荐的团队观测架构单机环境下Claude Code 直接把 OTel 数据发到本机 Collector 是可以的。但团队场景下推荐使用“客户端 → 服务端 Collector → 存储 → 展示”的架构每个开发者的 Claude Code 指向团队统一的 OTel Collector 端点。Collector 负责接收、校验、批处理数据。Collector 把数据写入 ClickHouse 这类列式存储。Grafana 从 ClickHouse 读取数据渲染成本看板。这样做的好处是数据集中在一个地方权限好控制后续可以按用户、项目、时间段自由查询也能和公司已有的可观测性体系打通。3. OTel 数据结构和成本计算原理3.1 Trace、Span 与 Attribute要读懂 Claude Code 导出的数据先要理解 OpenTelemetry 的几个核心概念Trace一次完整请求链路。在 Claude Code 场景中一次开发者指令可能会产生一个 Trace。Span链路中的一个操作单元。例如“调用模型”“读取文件”“执行命令”都可能是一个 Span。AttributeSpan 上的键值对记录元信息例如模型名称、token 数量、用户 ID。Resource描述产生数据的实体例如进程名、服务名。当我们把 Claude Code 的 OTel 数据导入 ClickHouse 后每条记录里一般会包含 trace_id、span_id、时间戳、resource 属性、span 属性等字段。成本计算需要的关键信息基本都在 span 属性里。3.2 需要关注的关键字段在 LLM 场景中OpenTelemetry 社区有 GenAI 语义约定的趋势例如gen_ai.usage.input_tokens、gen_ai.usage.output_tokens、gen_ai.request.model等字段。Claude Code 导出的字段未必完全一致所以我建议一个稳妥的做法先配置一个 debug exporter把原始数据打出来确认实际字段名再写具体的分析和 SQL。以常见场景为例我们关心这几类信息用户身份对应企业登录账号或user.id类似属性。模型名称用于区分不同模型的单价。输入 tokensPrompt 部分的 token 消耗。输出 tokens模型回答部分的 token 消耗。缓存命中 tokens如果使用了 prompt 缓存这部分价格通常更低。会话或项目标识用于把成本进一步归集到项目维度。这些字段不一定全部存在取决于 Claude Code 版本和配置所以在使用之前务必要做一次字段探查。3.3 成本计算模型成本计算并不复杂本质上是一个乘法每次调用成本 输入 tokens / 1000000 × 模型输入单价 输出 tokens / 1000000 × 模型输出单价如果存在缓存命中还要额外加上缓存 tokens 的成本项。模型的单价建议维护在独立的配置表或配置文件中而不是写死在 SQL 里因为模型价格会调整、新模型会发布集中管理能避免到处改代码。下面是一个简单的模型价目表设计思路CREATE TABLE model_pricing ( model String, input_price_per_1m Float64, output_price_per_1m Float64, cache_price_per_1m Float64 DEFAULT 0, updated_at DateTime DEFAULT now() ) ENGINE MergeTree() ORDER BY model;这里的单价字段用每百万 tokens 的价格作为单位方便后续计算。3.4 为什么不能只看总 token很多团队第一次做成本统计时只统计“总 token”然后按一个平均价估算。这个做法在量小的时候勉强能用模型一多就会失真。比如不同模型的输入输出价格差异很大缓存命中与未命中的价格差异也可能很大只看总 token 无法反映真实成本。所以成本看板至少要能拆到“模型 × token 类型 × 用户”三个维度这样才能回答“是不是有人把一个贵模型当默认模型用”这类问题。这也是 Aimeterly 这类项目强调 per-user 维度的原因。4. Aimeterly 项目拆解从 OTel 到用户成本看板4.1 Aimeterly 要解决什么问题Aimeterly 的定位很明确从 Claude Code 内置的 OTel 数据构建 per-user 成本仪表盘。它的核心价值不是重新发明数据采集协议而是把“Claude Code 已有的 OTel 数据”与“成本账单”打通让团队能直接看到每个用户的花费。从产品视角看它做对了几件事数据源零侵入复用 Claude Code 自带能力不需要改业务代码。用户维度聚合按 user 维度拆解成本满足团队管理需求。看板友好把指标组织成易于阅读的仪表盘而不是让用户自己写 SQL。4.2 数据流总览整个链路可以抽象成四个环节Claude Code │ OTLP ▼ OpenTelemetry Collector │ 导出 ▼ ClickHouse / 时序存储 │ SQL / 定时任务 ▼ Grafana 成本仪表盘采集层Claude Code 产生 trace发送到 Collector。传输层Collector 批量接收、预处理数据。存储层写入 ClickHouse保存较长时间跨度。展示层Grafana 查询聚合结果渲染用户、模型、项目成本看板。这套架构的好处是每一层都可以替换。比如存储层不用 ClickHouse用 Elasticsearch 或 Postgres 也可以展示层不用 Grafana用自研前端也可以。关键是数据流是标准化的。4.3 用户维度的设计per-user 成本看板的核心是“用户”。这里要注意几个细节用户身份从哪来成本归属要稳定最好使用企业统一账号而不是终端用户名。未知用户怎么处理如果某些请求没有携带用户信息建议归入unknown标签并在看板中单独展示方便发现采集缺口。用户与项目的关系同一个用户可以服务多个项目成本看板要支持“先按用户看总额再下钻到项目”的层级。4.4 看板的核心指标一个合格的成本仪表盘至少需要包含这些指标面板总成本趋势按天展示团队整体模型调用成本。用户成本排行展示每个用户近 7 天或 30 天成本。模型成本分布展示各模型消耗占比帮助决策是否需要切换模型。token 用量明细输入 token、输出 token、缓存 token 的分模型统计。会话/项目维度如果有会话信息可以进一步看哪些会话成本异常高。成本突增预警与前一天或前一周做对比发现异常增长。这些指标不一定要一次性做完可以先从“总成本趋势 用户成本排行”起步后续逐步补充。5. 实战自建一套 per-user 成本仪表盘下面我用一个最小可运行方案完整演示从零搭建成本看板的过程。整体依赖 Docker包含 OpenTelemetry Collector、ClickHouse、Grafana 三个组件。5.1 准备 docker-compose 编排项目目录结构如下cost-dashboard/ ├── docker-compose.yml ├── otel-collector.yaml ├── init-sql/ │ └── init.sql └── scripts/ └── daily_cost_report.sh先创建docker-compose.ymlversion: 3.8 services: otel-collector: image: otel/opentelemetry-collector-contrib:latest container_name: cc-otel-collector command: [--config/etc/otelcol-contrib/config.yaml] volumes: - ./otel-collector.yaml:/etc/otelcol-contrib/config.yaml ports: - 4317:4317 - 4318:4318 depends_on: - clickhouse clickhouse: image: clickhouse/clickhouse-server:24.8 container_name: cc-clickhouse ports: - 8123:8123 - 9000:9000 volumes: - ch_data:/var/lib/clickhouse - ./init-sql:/docker-entrypoint-initdb.d grafana: image: grafana/grafana:11.2.0 container_name: cc-grafana ports: - 3000:3000 environment: - GF_SECURITY_ADMIN_PASSWORDadmin volumes: - grafana_data:/var/lib/grafana depends_on: - clickhouse volumes: ch_data: grafana_data:需要说明的是镜像版本标签请按实际环境调整这里用的是演示版本。ClickHouse 的初始化脚本目录挂载到/docker-entrypoint-initdb.d会在首次启动时执行建库 SQL。5.2 配置 OpenTelemetry Collector创建otel-collector.yamlreceivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 processors: batch: timeout: 5s exporters: debug: verbosity: basic clickhouse: endpoint: tcp://clickhouse:9000 database: otel username: default password: ttl: 720h service: pipelines: traces: receivers: [otlp] processors: [batch] exporters: [debug, clickhouse]这里有几个关键点otlp接收器同时开启 gRPC 和 HTTP 端口Claude Code 无论用哪种协议都能接入。debugexporter 用来在控制台打印 trace方便排查数据是否到达。clickhouseexporter 会把 trace 写入 ClickHouse 的otel数据库它会按官方 schema 自动创建 trace 表通常名为otel_traces。生产环境必须修改默认密码并且不要将 Collector 直接暴露到公网。5.3 初始化 ClickHouse 数据库和业务表在init-sql/init.sql中创建成本看板所需的数据库和业务表CREATE DATABASE IF NOT EXISTS otel; CREATE TABLE IF NOT EXISTS otel.daily_user_cost ( report_date Date, user_id String, model String, total_input_tokens UInt64, total_output_tokens UInt64, cache_read_tokens UInt64 DEFAULT 0, estimated_cost_usd Float64 ) ENGINE MergeTree() ORDER BY (report_date, user_id, model); CREATE TABLE IF NOT EXISTS otel.model_pricing ( model String, input_price_per_1m Float64, output_price_per_1m Float64, cache_price_per_1m Float64 DEFAULT 0, updated_at DateTime DEFAULT now() ) ENGINE MergeTree() ORDER BY (model);daily_user_cost是我们后续做看板查询的主表它保存的是按天、按用户、按模型聚合后的成本数据。model_pricing用于维护模型单价初始数据用示例说明INSERT INTO otel.model_pricing (model, input_price_per_1m, output_price_per_1m, cache_price_per_1m) VALUES (demo-model-a, 3.0, 15.0, 0.3), (demo-model-b, 8.0, 24.0, 1.0);注意这里只是演示结构具体价格请以模型官方价格为基准不要使用示例值做真实结算。5.4 启动服务并确认数据到达执行以下命令启动所有服务docker compose up -d查看 Collector 日志确认没有报错docker logs -f cc-otel-collector然后在本机启动 Claude Code并确保 OTel 导出端点指向 Collector。在终端里随意发起几次对话例如让 Claude Code 读取一个文件、解释一段代码。如果配置正确Collector 日志中会出现类似Span #0的 trace 信息同时 ClickHouse 的otel_traces表开始有数据写入。这里我建议先用 debug exporter 观察字段。因为实际字段名会影响后面的 SQL 写法不同版本导出的属性可能不同。下面给出一个通用的字段排查思路SELECT span_attributes[user.id] AS user_id, span_attributes[gen_ai.request.model] AS model FROM otel.otel_traces LIMIT 10;如果span_attributes不是 Map 类型则用对应的 JSON 函数取值例如SELECT JSONExtractString(span_attributes, user.id) AS user_id FROM otel.otel_traces LIMIT 10;以实际表结构为准。先跑通这一步再继续后文。5.5 编写成本汇总 SQL当字段确认后就可以把原始 trace 数据按天聚合成成本数据。这里我写一个相对通用的 SQL 演示INSERT INTO otel.daily_user_cost SELECT toDate(timestamp) AS report_date, span_attributes[user.id] AS user_id, span_attributes[gen_ai.request.model] AS model, sum(toUInt64OrZero(span_attributes[gen_ai.usage.input_tokens])) AS total_input_tokens, sum(toUInt64OrZero(span_attributes[gen_ai.usage.output_tokens])) AS total_output_tokens, sum(toUInt64OrZero(span_attributes[gen_ai.usage.cache_read_tokens])) AS cache_read_tokens, total_input_tokens / 1000000 * 3.0 total_output_tokens / 1000000 * 15.0 cache_read_tokens / 1000000 * 0.3 AS estimated_cost_usd FROM otel.otel_traces WHERE toDate(timestamp) yesterday() GROUP BY report_date, user_id, model;这里使用toUInt64OrZero是为了避免某个字段为空时导致类型转换报错。价格部分先用固定示例值后续可以改成关联model_pricing表。实际项目里更好的做法是建一个定时任务每天把前一天的数据汇总到daily_user_cost而不是实时扫描全量 trace。下面是一个简单的脚本#!/bin/bash # scripts/daily_cost_report.sh docker exec cc-clickhouse clickhouse-client \ --query INSERT INTO otel.daily_user_cost SELECT ...再用 cron 每天凌晨 1 点执行。5.6 配置 Grafana 数据源和面板接着在浏览器访问http://localhost:3000默认账号admin密码admin。首次登录后修改密码然后添加数据源类型选择 ClickHouse。URL 填写http://clickhouse:8123。数据库填写otel。然后创建一个 Dashboard添加以下查询作为“用户成本排行”面板SELECT report_date, user_id, sum(estimated_cost_usd) AS cost_usd FROM otel.daily_user_cost WHERE report_date today() - INTERVAL 30 DAY GROUP BY report_date, user_id ORDER BY cost_usd DESC;再添加一个“模型成本分布”面板SELECT model, sum(estimated_cost_usd) AS cost_usd FROM otel.daily_user_cost WHERE report_date today() - INTERVAL 7 DAY GROUP BY model ORDER BY cost_usd DESC;如果 Grafana 配置了$__timeFilter可以直接使用它的时间范围变量方便在看板右上角切换时间区间SELECT report_date, user_id, sum(estimated_cost_usd) AS cost_usd FROM otel.daily_user_cost WHERE $__timeFilter(report_date) GROUP BY report_date, user_id ORDER BY cost_usd DESC;到这里一套最小可用的 per-user 成本看板就跑通了。虽然面板数量不多但“谁能看到成本、每个模型花了多少、每天的趋势如何”这些核心问题已经能回答。5.7 用 Python 实现更灵活的成本计算如果团队的价格表比较复杂或者想在写入看板前做额外处理比如过滤内部测试流量、给不同部门设置不同成本口径用 SQL 写会越来越吃力。这时可以把成本计算逻辑放到 Python 脚本里。先安装 ClickHouse 的 Python 驱动pip install clickhouse-connect下面是一个示例脚本它从 ClickHouse 读取昨天一整天的原始用量再按模型价目表计算成本并写回汇总表# scripts/calc_daily_cost.py from collections import defaultdict from datetime import date, timedelta import clickhouse_connect client clickhouse_connect.get_client( host127.0.0.1, port8123, databaseotel, ) # 从价目表读取模型单价避免硬编码在代码里 rows client.query( SELECT model, input_price_per_1m, output_price_per_1m, cache_price_per_1m FROM model_pricing ).result_rows pricing { model: { input: input_price, output: output_price, cache: cache_price, } for model, input_price, output_price, cache_price in rows } yesterday date.today() - timedelta(days1) raw_rows client.query( SELECT span_attributes[user.id] AS user_id, span_attributes[gen_ai.request.model] AS model, toUInt64OrZero(span_attributes[gen_ai.usage.input_tokens]) AS input_tokens, toUInt64OrZero(span_attributes[gen_ai.usage.output_tokens]) AS output_tokens, toUInt64OrZero(span_attributes[gen_ai.usage.cache_read_tokens]) AS cache_tokens FROM otel_traces WHERE toDate(timestamp) yesterday() , parameters{yesterday: yesterday.isoformat()}, ).result_rows summary defaultdict(lambda: [0, 0, 0, 0.0]) for user_id, model, input_tokens, output_tokens, cache_tokens in raw_rows: key (user_id, model) summary[key][0] input_tokens summary[key][1] output_tokens summary[key][2] cache_tokens if model in pricing: p pricing[model] else: p {input: 0.0, output: 0.0, cache: 0.0} cost ( input_tokens / 1000000 * p[input] output_tokens / 1000000 * p[output] cache_tokens / 1000000 * p[cache] ) summary[key][3] cost for (user_id, model), (input_tokens, output_tokens, cache_tokens, cost) in summary.items(): client.command( INSERT INTO daily_user_cost (report_date, user_id, model, total_input_tokens, total_output_tokens, cache_read_tokens, estimated_cost_usd) VALUES ({report_date:Date}, {user_id:String}, {model:String}, {input_tokens:UInt64}, {output_tokens:UInt64}, {cache_tokens:UInt64}, {cost:Float64}) , parameters{ report_date: yesterday.isoformat(), user_id: user_id, model: model, input_tokens: input_tokens, output_tokens: output_tokens, cache_tokens: cache_tokens, cost: cost, }, )这段脚本的思路是先把原始 token 聚合到内存再统一算出成本并写入汇总表。这样做的好处是价格表的调整不需要改 SQL只需要更新model_pricing表数据同时可以方便地加入“跳过某些用户”“对某个部门打标”等额外逻辑。需要注意的是span_attributes[user.id]这种 Map 取值方式以及 token 字段名都需要根据你实际采集到的数据做调整。如果你的字段是user_id或code.user_id对应改一下即可。6. 常见问题与排查思路6.1 高频问题汇总下面这张表总结了我实践过程中最容易遇到的几个问题问题现象常见原因解决思路Claude Code 启动过程直接退出提示process exited with code 3CLI 本地环境损坏、Node 版本不兼容或安装不完整先卸载重装 CLI检查 Node 版本和 npm 全局目录权限报错your organization has disabled claude subscription access for Claude Code组织管理员在控制台关闭了 Claude Code 订阅访问权限联系组织管理员开启 Claude Code 权限或使用个人订阅账号登录调用时报 529 错误服务端过载或触发限流等待片刻重试检查订阅额度是否耗尽Collector 日志里没有任何 traceClaude Code 的 OTel 导出端点未配置或协议不匹配确认环境变量已生效分别尝试 gRPC 与 HTTP 端点ClickHouse 里表存在但一直为空Collector 未写入或写入的目标库名不对打开 debug exporter确认 Collector 是否真的收到数据span_attributes字段取值报错表结构与示例不一致字段不是 Map 类型先执行DESCRIBE otel_traces查看真实字段类型成本金额与平台账单偏差大价格表未更新、未区分缓存 token、漏掉部分请求统一维护价目表按输入/输出/缓存分别计算和平台原始用量做对账6.2 配置了 OTel 但收不到数据怎么办这是最容易踩的坑排查顺序建议如下确认 Claude Code 配置是否真的生效。可以执行env | grep OTEL查看环境变量是否在当前终端进程里。确认 Collector 端口是否监听。在 Collector 机器上执行netstat -an | grep 4317或lsof -i :4317。查看 Collector 日志中的 debug exporter 输出。如果能看到 Span说明链路是通的。检查网络连通性。如果 Claude Code 和 Collector 不在同一台机器要确保防火墙放行了对应端口。确认协议一致。比如 Claude Code 使用了 HTTP 导出Collector 的 OTLP HTTP 接收器也必须开启且端口一致。6.3 用户维度为空或全是 unknown如果看板上用户全是 unknown大概率不是数据缺失而是字段名写错了。Claude Code 导出的用户属性可能与user.id不同可能叫user_id、claude.user或者嵌套在 resource attributes 里。遇到这种情况先用 debug exporter 把原始属性完整打印出来逐个字段核对再调整 SQL。6.4 成本统计不准确成本统计不准确的常见原因有三个一是模型价目表没有及时更新二是没有区分缓存 token 的单价三是某些请求在导出时失败或缺失。建议先与平台侧原始用量做一次“总量对账”确认采集覆盖率再核对单价口径。成本看板的价值在于趋势和相对差异绝对值即使有少量偏差也不影响对成本异常增长方向的判断。7. 最佳实践与工程建议7.1 成本归属字段要规范统一从第一天接入 OTel 时就要约定好用户标识字段。建议使用公司统一账号而不是终端系统用户名。如果开发者在本地起了不同的 shell 或使用了别名可能导致一个用户出现多个身份。可以在 Claude Code 的配置层面固定用户上下文确保成本归属的一致性。7.2 价格表必须集中管理模型价格会调整新模型会不断上线。把价格硬编码在 SQL 或 Python 里后续更新容易漏改。推荐把价格表放到 ClickHouse 的model_pricing表由管理员维护成本计算任务统一读取。还可以加入生效时间范围支持历史成本按当时价格回算。7.3 数据生命周期管理Trace 明细数据量会快速增长。OpenTelemetry Collector 的 clickhouse exporter 支持配置ttl例如720h表示保留 30 天。业务汇总表可以按需保留更长时间比如保留一年。这样既控制了存储成本又保留了看板所需的历史趋势。7.4 成本和隐私要分开看成本数据同时是“谁在什么时间用了什么模型”的行为数据这涉及隐私合规。建议这样处理看板访问权限严格按角色分配财务和管理角色看全量成本普通用户只看自己的成本。涉及敏感项目时可以先做脱敏只保留用户标识不保留具体 prompt 内容。不把原始 OTel trace 数据开放给所有开发者只开放汇总后的成本表。7.5 建立成本告警成本看板不能只是事后报表建议配合告警使用。在 Grafana 中简单配置即可当用户日成本超过阈值或者团队日成本较前 7 天平均值上涨超过 50% 时触发告警通知到相关负责群。这一步能有效避免月底账单突然超支的被动局面。7.6 先跑通 debug exporter 再完善看板最后一条建议非常实用不要一开始就追求完整的看板。先让 Claude Code 的 OTel 数据打到 Collector在 debug exporter 里看到真实字段再写一个最简单的“总数”指标最后再逐步加用户维度、模型维度、缓存 token 等细节。这样每一步都是可验证的排错成本会低很多。8. 总结与下一步Aimeterly 这个项目给我最大的启发是工具内置的标准化可观测能力其实是团队做成本治理最容易忽视的抓手。Claude Code 内置 OpenTelemetry意味着我们不需要等待官方出账单报表也不需要开发复杂埋点就能把每一次模型调用变成可控、可分析、可归属的数据。本文从 Claude Code 和 OTel 的基础概念讲起说明了 per-user 成本看板的管理价值并完整演示了“Claude Code → OpenTelemetry Collector → ClickHouse → Grafana”的搭建过程。你可能暂时不需要立刻部署完整看板但至少可以从今天开始让 Claude Code 的 OTel 数据先记录起来等团队用量上来后这份数据就是成本优化最可靠的依据。下一步可以做的事情有很多先在自己电脑上跑通数据采集管道确认字段结构然后接入团队 Collector统一采集最后再根据团队实际需要增加项目维度、部门维度和告警策略。如果团队用量还不大用 SQLite 或 Postgres 替代 ClickHouse 也完全可以思路是一致的。成本管理不是限制使用 AI 工具而是让每一分模型开销都花得明明白白。先把数据管起来再谈优化。
返回列表