☰
AI可观测性实战:用TaoToken把Trace、Cost、质量三合一串成一条链路
2026/10/7 7:58:46 网站建设 项目流程

1. 一次线上请求,为什么 Trace、Cost、质量总是对不上

线上 AI 应用跑起来之后,最让人头疼的不是模型答得不好,而是出了问题你根本不知道从哪查。用户投诉"回答变差了",你打开日志看到的是几百行 JSON;财务问"这个月为什么多花了三千块",你翻遍账单只能看到按天汇总的 token 数;老板问"我们的 AI 到底靠不靠谱",你只能拿几个 demo 案例硬撑。

这三个问题背后其实是同一件事:AI 可观测性没有把 Trace 链路、Token 成本、输出质量对齐到同一个请求 ID 上。传统 APM 能告诉你 HTTP 接口 P99 是多少,但它看不懂gen_ai.usage.input_tokens这种字段,也不知道一次 RAG 检索里 embedding 花了多少钱、rerank 拖了多少延迟、最终答案的 faithfulness 是 0.9 还是 0.6。

我试过最笨的办法:在业务代码里手动打点,把 trace_id、token 数、评分分别写进三张表,然后靠时间戳去 join。结果就是时间戳对不齐、采样率不一致、异步 judge 的评分回来时 trace 已经归档了。真正能落地的方案,是让一次请求从入口到出口只产生一个 trace_id,所有 span 都挂在这棵树上,成本和质量作为 span 属性或关联事件写入,这样回查时一个 ID 就能拉出完整链路。

这篇要解决的就是这个场景:你有一个已经上线的 AI 应用(不管是 Spring AI、LangChain4j 还是自己写的 Agent),现在要给它加上可观测性,让 Trace、Cost、质量三合一。我会给出可复制的采集配置、看板字段设计,以及用统一 Key/API 通道接入后,怎么用一次请求 ID 回查三段数据、验证成本归因和质量评分是否一致。

适合谁看:正在做 AI 应用上线后运维的工程师、需要给老板解释"钱花哪了"的技术负责人、以及被"回答质量下降"工单折磨的 on-call。不需要你之前用过 Langfuse 或 Phoenix,但需要你能看懂基本的 OpenTelemetry 概念和一段 YAML 配置。

核心检索词先明确:AI 可观测性是把 LLM 应用的分布式追踪、成本账本、质量评分统一到一套 telemetry 契约里;Trace回答"哪一步慢/失败",Cost回答"谁花了多少钱",质量回答"输出好不好"。三合一的意思就是这三个问题的答案挂在同一个请求 ID 下,5 分钟内能定位到根因。

下面从原问题拆解开始,一步步搭出可运行的链路。

2. TaoToken 统一通道:让 Trace 和 Cost 有同一个源头

2.1 为什么需要统一 API 通道

做可观测性最怕的就是数据源分散。如果你的应用同时调 OpenAI、Anthropic、通义千问,每个 SDK 的 usage 字段格式不一样,有的返回prompt_tokens,有的返回input_tokens,有的流式响应里根本不带 usage。你写三套解析逻辑,成本账本永远对不平。

统一通道的价值在于:所有模型调用都经过同一个网关,网关层统一注入gen_ai.*语义属性,统一记录 token 用量和费用。这样你的 trace 里每个 chat span 都有一致的字段,成本归因不需要在业务代码里做。

TaoToken 在这里扮演的就是这个统一入口。官网地址是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 端点是 https://taotoken.net/api 。它的作用是把不同厂商的模型调用收敛到一个 OpenAI 兼容的接口上,你只需要配一个 Base URL 和一个 Key,就能在 trace 里拿到统一的 usage 数据。

2.2 前置准备:拿到 Key 和确认模型 ID

在控制台创建 API Key,路径是 https://taotoken.net/console/api-keys 。创建后你会得到一个sk-开头的字符串,这个就是后面所有配置里的api_key。

模型 ID 需要确认一下你实际要用的。在模型对话页面 https://taotoken.net/models 可以看到当前支持的模型列表,常见的比如gpt-4o-mini、claude-3-5-sonnet这类。记下你要用的 Model ID,后面配置里会用到。

这里有个坑要注意:不同模型的价格不一样,成本归因必须按 model 维度分开算。如果你在 trace 里只记了总 token 数没记 model,后面算钱的时候只能拍脑袋。所以配置里gen_ai.request.model这个属性一定要写对。

2.3 三件套:Base URL + Key + Model ID

不管你用什么框架,接入统一通道都是这三件套:

配置项值说明
Base URLhttps://taotoken.net/apiOpenAI 兼容端点,注意不要加 UTM
API Keysk-xxxxxx控制台创建,权限按需最小化
Model IDgpt-4o-mini等按实际使用的模型填

如果你用的是 Claude Code 这类工具,配置方式略有不同,需要设置ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY,具体可以参考接入文档 https://taotoken.net/doc 。但核心逻辑一样:所有请求走同一个通道,usage 数据在网关层统一。

2.4 在 trace 里注入租户和功能标签

光有 model 和 token 还不够,成本归因要能回答"哪个租户、哪个功能花了钱"。所以业务代码里要往 span 上打两个标签:app.tenant_id和app.feature。

这两个字段是低基数还是高基数取决于你的业务。租户 ID 如果是几百个,算低基数,可以放 span attribute;如果是几万个,建议放高基数属性或者单独的事件。功能标签一般就几十个,放 attribute 没问题。

配置好之后,一次请求的 trace 树大概长这样:

session_trace (root) ├── guardrail_span (12ms) ├── retrieve_span (85ms, top_k=8) │ ├── embed_span (22ms) │ └── vector_search_span (41ms) ├── rerank_span (120ms) ├── chat_span (TTFT 620ms, TPOT 38ms, tokens in/out) │ ├── tool_call get_order (45ms) │ └── tool_call get_logistics (38ms) └── async_judge_span (faithfulness 0.89)

每个 span 上都带着gen_ai.system、gen_ai.request.model、gen_ai.usage.input_tokens、gen_ai.usage.output_tokens这些属性。成本计算就是把这些 token 数乘以对应 model 的单价,质量评分挂在async_judge_span上。

2.5 成本公式和看板字段

成本公式很简单,但要把所有环节都算进去:

cost_usd = in_tok/1e6 * price_in + out_tok/1e6 * price_out + embed_tok/1e6 * price_embed + gpu_sec * gpu_rate_per_sec

如果你用的是托管 API,最后一项 GPU 成本已经包含在 token 单价里了,不用单独算。但如果你自己部署了 vLLM 做 embedding 或 rerank,那 GPU 时间要单独归因。

三合一看看板的核心字段(按 feature × 天聚合):

featuresessions$/task P50TTFT P99faith P50拒答率采纳率
cs_bot1.2M$0.0167720ms0.908%61%
checkout_assist80k$0.0429980ms0.863%54%

这张表就是 on-call 的入口:哪一列异常就下钻哪一列。TTFT 涨了查 chat span,faith 掉了查 retrieve 和 judge,$/task 涨了查 model 分布和 token 用量。

2.6 质量评分怎么挂进 trace

质量评分分在线和离线两种。在线用规则或小模型做实时低价判断,离线用 LLM-as-judge 做秒级评分。推荐的做法是5% 会话异步 judge,faithfulness < 0.8 自动打标quality_incident。

异步 judge 的结果回来时,通过 trace_id 关联到原始请求。这里要注意:judge 本身也是一次 LLM 调用,也会产生 token 成本,这部分成本要单独归因到quality_judge这个 feature 下,不能混进业务成本里。

配置好之后,你就能用一次请求 ID 回查三段数据了。下一节给出具体的可复制配置。

3. 可复制配置:OpenTelemetry + 统一通道接入

3.1 环境变量配置

先把三件套写进环境变量,避免硬编码:

# .env TAOTOKEN_BASE_URL=https://taotoken.net/api TAOTOKEN_API_KEY=sk-your-key-here TAOTOKEN_MODEL_ID=gpt-4o-mini # OpenTelemetry 导出配置 OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 OTEL_SERVICE_NAME=ai-app OTEL_TRACES_SAMPLER=parentbased_traceidratio OTEL_TRACES_SAMPLER_ARG=0.1

采样率设 0.1 是头部采样,10% 的请求全量记录。错误请求要 100% 采集,这个在 Collector 层做 tail sampling。

3.2 Spring AI 埋点配置

如果你用 Spring AI,通过ObservationRegistry注入:

@Configuration public class ObservabilityConfig { @Bean public ChatClient chatClient(ChatClient.Builder builder, ObservationRegistry registry) { return builder .defaultAdvisors(new SimpleLoggerAdvisor()) .build(); } @Bean public ObservationRegistry observationRegistry() { return ObservationRegistry.create(); } }

调用时手动加租户和功能标签:

@Autowired private ObservationRegistry registry; public String ask(String question, String tenantId, String feature) { return Observation.createNotStarted("chat.completion", registry) .lowCardinalityKeyValue("gen_ai.request.model", "gpt-4o-mini") .lowCardinalityKeyValue("app.feature", feature) .highCardinalityKeyValue("app.tenant_id", tenantId) .observe(() -> chatClient.prompt() .user(question) .call() .content()); }

3.3 OpenTelemetry Collector 配置

Collector 负责接收、处理、导出。关键配置:

# otel-collector-config.yaml receivers: otlp: protocols: http: endpoint: 0.0.0.0:4318 processors: batch: timeout: 5s send_batch_size: 512 # PII 脱敏:手机号、身份证打码 attributes: actions: - key: gen_ai.prompt action: delete - key: app.user_phone action: hash # 尾部采样:错误全采,正常 10% tail_sampling: decision_wait: 10s policies: - name: errors type: status_code status_code: status_codes: [ERROR] - name: slow type: latency latency: threshold_ms: 5000 - name: random type: probabilistic probabilistic: sampling_percentage: 10 exporters: otlphttp/langfuse: endpoint: http://langfuse:3000/api/public/otel headers: Authorization: "Basic ${LANGFUSE_AUTH}" prometheus: endpoint: 0.0.0.0:8889 service: pipelines: traces: receivers: [otlp] processors: [attributes, tail_sampling, batch] exporters: [otlphttp/langfuse] metrics: receivers: [otlp] processors: [batch] exporters: [prometheus]

3.4 成本归因的 JSON 配置

成本单价表单独维护,方便更新:

{ "models": { "gpt-4o-mini": { "price_in_per_1m": 0.15, "price_out_per_1m": 0.60, "price_embed_per_1m": 0.02 }, "claude-3-5-sonnet": { "price_in_per_1m": 3.00, "price_out_per_1m": 15.00, "price_embed_per_1m": null } }, "gpu_rate_per_sec": 0.00012, "quality_judge_model": "gpt-4o-mini" }

这个表放在配置中心,Collector 的 transform processor 读取它来算cost_usd属性。

3.5 看板字段映射

Grafana 看板的字段映射:

{ "panels": [ { "title": "三合一总览", "targets": [ { "expr": "sum(rate(gen_ai_cost_usd_total[5m])) by (feature)", "legendFormat": "{{feature}} $/s" }, { "expr": "histogram_quantile(0.99, sum(rate(gen_ai_ttft_ms_bucket[5m])) by (le, feature))", "legendFormat": "{{feature}} TTFT P99" }, { "expr": "avg(gen_ai_faithfulness) by (feature)", "legendFormat": "{{feature}} faith" } ] } ] }

3.6 Claude Code 接入配置

如果你用 Claude Code 做开发辅助,配置方式:

export ANTHROPIC_BASE_URL=https://taotoken.net/api export ANTHROPIC_API_KEY=sk-your-key-here export ANTHROPIC_MODEL=claude-3-5-sonnet

这样 Claude Code 的调用也会走统一通道,usage 数据能被采集到。具体可以参考 https://taotoken.net/doc 里的接入说明。

配置完成后,启动应用发一次请求,就能在 Langfuse 或 Phoenix 里看到完整的 trace 树了。下一节验证请求和成功结果。

4. 验证请求:用一次请求 ID 回查三段数据

4.1 发一次带 trace 的请求

用 curl 模拟一次请求,带上 traceparent 头:

TRACE_ID=$(openssl rand -hex 16) SPAN_ID=$(openssl rand -hex 8) curl -X POST https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -H "traceparent: 00-${TRACE_ID}-${SPAN_ID}-01" \ -d '{ "model": "gpt-4o-mini", "messages": [ {"role": "user", "content": "帮我查一下订单 882 的物流状态"} ], "stream": false }'

响应里会带 usage:

{ "id": "chatcmpl-xxx", "choices": [{"message": {"content": "订单 882 已发货..."}}], "usage": { "prompt_tokens": 2400, "completion_tokens": 180, "total_tokens": 2580 } }

4.2 在 trace 里回查

打开 Langfuse,用TRACE_ID搜索,能看到完整的 span 树。每个 span 上挂着属性:

chat_span gen_ai.system: openai gen_ai.request.model: gpt-4o-mini gen_ai.usage.input_tokens: 2400 gen_ai.usage.output_tokens: 180 gen_ai.response.finish_reasons: stop app.tenant_id: shop_882 app.feature: checkout_assist cost_usd: 0.000468

成本计算:2400/1e6 * 0.15 + 180/1e6 * 0.60 = 0.00036 + 0.000108 = 0.000468。和 trace 里记录的一致。

4.3 质量评分关联

异步 judge 完成后,会在同一个 trace 下挂一个async_judge_span:

async_judge_span gen_ai.request.model: gpt-4o-mini app.trace.quality.faithfulness: 0.89 app.trace.quality.relevance: 0.92 judge_cost_usd: 0.000021

这样一次请求 ID 就能拉出三段数据:Trace 链路(哪些 span、各耗时多少)、Cost(业务成本 + judge 成本)、质量(faithfulness、relevance)。

4.4 验证成本归因一致性

把 trace 里的 cost_usd 按 feature 聚合,和网关侧的 spend_logs 对比:

-- 从 trace 聚合 SELECT feature, SUM(cost_usd) as trace_cost FROM traces WHERE date = '2025-07-14' GROUP BY feature; -- 从网关 spend_logs 聚合 SELECT feature, SUM(cost_usd) as gateway_cost FROM spend_logs WHERE date = '2025-07-14' GROUP BY feature;

两边差异应该小于 1%。如果差异大,检查是不是有请求没走统一通道,或者采样率导致 trace 侧少算了。

4.5 验证质量评分一致性

在线 judge 和离线 judge 的评分要定期校准。每周抽 200 条人工标注,对比 judge 分数:

指标在线 judge人工标注差异
faithfulness P500.890.87+0.02
relevance P500.920.90+0.02

差异超过 5% 就要检查 rubric 或换 judge 模型。

4.6 成功结果长什么样

配置正确的话,你会看到:

  • Langfuse 里每次请求都有完整 span 树,属性齐全
  • Grafana 三合一看看板实时更新,$/task、TTFT、faith 三列并排
  • 用 trace_id 能在 trace、spend_logs、quality_scores 三处查到同一请求
  • 成本归因误差 < 1%,质量评分和人工校准差异 < 5%

到这一步,可观测性链路就通了。下一节讲常见报错排查。

5. 常见报错排查:401、local proxy failed、reading choices、OAuth

5.1 401 Unauthorized

最常见的报错,通常是 Key 配错或没生效。

{"error": {"message": "Invalid API key", "type": "invalid_request_error"}}

排查步骤:

第一,确认TAOTOKEN_API_KEY环境变量真的被读到了。在代码里打印一下前 8 位,看是不是sk-开头。

第二,确认 Base URL 没写错。正确的是https://taotoken.net/api,不要加 UTM 参数,不要多写/v1(有些 SDK 会自动加)。

第三,确认 Key 没过期或被禁用。去控制台 https://taotoken.net/console/api-keys 看一下状态。

第四,如果用的是 Claude Code,确认ANTHROPIC_API_KEY和ANTHROPIC_BASE_URL都设了,且没有和其他环境变量冲突。

5.2 local proxy failed

这个报错通常出现在你本地起了代理但配置不对的时候:

Error: local proxy failed: dial tcp 127.0.0.1:7890: connect: connection refused

排查:检查你的 HTTP_PROXY / HTTPS_PROXY 环境变量是不是指向了一个没启动的本地端口。如果不需要代理,直接 unset 掉:

unset HTTP_PROXY HTTPS_PROXY http_proxy https_proxy

然后重新发请求。注意:统一通道本身不需要额外代理配置,直接访问即可。

5.3 reading choices 报错

流式响应解析时常见:

Error: reading choices: unexpected end of JSON input

这个通常是流式响应的 chunk 解析问题。排查:

第一,确认stream: true时你的解析逻辑能处理data: [DONE]结束标记。

第二,确认没有在流式响应中途关闭连接。有些 HTTP 客户端默认超时太短,长响应会被截断。

第三,如果用的是 OpenAI SDK,确认版本兼容。老版本 SDK 对某些字段的解析可能有问题,升级到最新版。

第四,检查 trace 里gen_ai.response.finish_reasons是不是stop。如果是length,说明输出被 max_tokens 截断了,不是解析问题。

5.4 OAuth 相关报错

如果你用 Claude Code 或类似工具,可能遇到:

OAuth error: invalid_grant

这个通常是 token 过期或配置冲突。排查:

第一,确认你用的是 API Key 模式而不是 OAuth 模式。统一通道走的是 API Key,不需要 OAuth 流程。

第二,检查~/.claude/settings.json或对应的配置文件,确认没有残留的 OAuth 配置。

第三,如果同时设了ANTHROPIC_API_KEY和 OAuth token,可能会冲突。清掉 OAuth 相关的环境变量。

5.5 Codex auth.json 配置

如果你用 Codex 类工具,配置文件在~/.codex/auth.json:

{ "base_url": "https://taotoken.net/api", "api_key": "sk-your-key-here", "model": "gpt-4o-mini" }

三件套要写全:Base URL、Key、Model ID。少任何一个都会报错。改完配置后重启工具生效。

5.6 Cline MCP 配置

Cline 通过 MCP 接入时,配置在cline_mcp_settings.json:

{ "mcpServers": { "taotoken": { "command": "npx", "args": ["-y", "@taotoken/mcp-server"], "env": { "TAOTOKEN_BASE_URL": "https://taotoken.net/api", "TAOTOKEN_API_KEY": "sk-your-key-here", "TAOTOKEN_MODEL_ID": "gpt-4o-mini" } } } }

同样三件套要全。注意 MCP 直连生产库是禁止的,这里只是模型调用通道。

5.7 CC Switch 配置

CC Switch 用于切换不同通道,配置里要写全三件套:

{ "providers": { "taotoken": { "base_url": "https://taotoken.net/api", "api_key": "sk-your-key-here", "model_id": "gpt-4o-mini" } } }

切换后确认 trace 里的gen_ai.system和gen_ai.request.model正确。

5.8 trace 断链排查

如果发现 trace 树不完整,某些 span 没挂上:

第一,确认 W3C traceparent 头在全链路透传。入口生成 trace_id 后写进 MDC,跨服务调用时带上。

第二,确认异步任务(比如 judge)也传了 context。Java Reactor 用 context 传播,Python asyncio 用 contextvars。

第三,确认采样率一致。如果入口采了但下游没采,trace 会断。

第四,检查 Collector 的 tail_sampling 配置,确认没有误丢。

5.9 成本对不平排查

trace 侧成本和网关侧 spend_logs 差异大:

第一,检查是不是有请求没走统一通道。直连厂商的调用不会进 trace。

第二,检查采样率。如果 trace 只采了 10%,聚合时要乘以 10 才是全量。

第三,检查流式响应的 usage 是否被记录。有些流式响应最后一个 chunk 才带 usage,如果没解析到就会漏算。

第四,检查 judge 成本是否被混进业务成本。judge 应该单独归因到quality_judgefeature。

5.10 质量评分异常排查

faithfulness 突然掉:

第一,看 retrieve span 的cosine_top1是不是也掉了。如果掉了,是检索问题。

第二,看 embedding 模型版本有没有变。embed 模型升级但索引没重建,会导致检索质量下降。

第三,看 judge 模型有没有换。换 judge 模型后评分标准会变,要重新校准。

第四,看输入分布有没有变。用户问的问题类型变了,faithfulness 自然会波动。

排查完这些,基本能覆盖 90% 的线上问题。最后一节给出 CTA 分流。

6. 接入与排障入口

如果你在配置过程中遇到问题,或者想先验证模型调用是否正常,可以按下面的路径走。

排障和接入配置:先看接入文档 https://taotoken.net/doc ,里面有各框架的配置示例。如果报 401 或 local proxy failed,去 API Keys 页面 https://taotoken.net/console/api-keys 确认 Key 状态和权限。

验证模型调用:在模型对话页面 https://taotoken.net/models 直接发一条消息,确认通道正常、usage 数据能返回。这一步能排除大部分配置问题。

长期编码和 Agent 场景:如果你要把这套可观测性用在日常开发或 Agent 工作流里,Coding Plan 页面 https://taotoken.net/coding-plan 有更详细的接入说明和配额管理。

API 端点:https://taotoken.net/api ,所有模型调用走这个地址,OpenAI 兼容格式。

配置的核心就三件套:Base URL 用https://taotoken.net/api,Key 从控制台创建,Model ID 按实际用的填。三样写全,trace 里的gen_ai.*属性就能正常采集,成本和质量数据也能对齐到同一个请求 ID 上。

最后给一个实用技巧:先在 staging 环境把采样率设成 100%,跑一周确认数据完整,再降到 10%。这样能避免上线后发现 trace 断链却查不到原因。错误请求的 tail sampling 策略一定要配,不然出问题时刚好没采到就尴尬了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询