[控场AI]
· 16 分钟阅读· 8,124 字

OpenTelemetry LLM 追踪:该采什么、该丢什么

OpenTelemetry LLM 追踪:该采什么、该丢什么

LLM 追踪要采模型差异、token、TTFT 等高价值信号,丢弃 chunk、全量载荷等噪声。

LLM 应用在生产中会产生海量追踪数据,传统 APM 靠 HTTP 状态码无法识别幻觉、拒答和 Agent 卡死。文章基于 OpenTelemetry GenAI 语义约定,梳理了应采集的高价值信号:请求与实际响应模型差异、标准化 token 计数、首 token 时间(TTFT)、Prompt 模板版本、工具调用参数与租户成本归属,并为客户端、检索、工具、Agent 四类 Span 给出关键属性。同时指出四类必须砍掉的噪声:流式逐 chunk 建 Span、全量载荷采集、嵌入向量入属性、框架内部管线微 Span。治理层面强调尾部采样保留 100% 错误与回退 Trace,仅对正常请求留 1%–2% 基线,并在 Collector 集中脱敏 PII;最后给出 AI 网关统一遥测的思路与一份可用的 Collector 配置示例。

OpenTelemetry LLM 追踪:该采什么、该丢什么

OpenTelemetry LLM 追踪:信号与噪声的取舍

LLM 应用在生产环境中会不断堆积分布式追踪数据,云账单和可观测性管道往往先撑不住,而工程师仍然说不清 Agent 为什么卡住。OpenTelemetry 提供了统一的 GenAI 遥测规范,但未经筛选的埋点只会制造噪声,反而把真正有用的失败信号淹没。这篇内容围绕一个核心问题展开:在一个 LLM 应用里,哪些字段值得进 Span,哪些应该直接丢弃。

传统 APM 为什么管不住 LLM

传统 APM 靠 HTTP 状态码、进程内存和端点延迟分布判断系统健康。在普通微服务里,一个 HTTP 200 加亚秒级延迟基本等于一切正常。LLM 应用不是这样:模型可以返回 HTTP 200,内容里却是一次严重幻觉、一个无依据的计算、一次拒答,或者一次空的工具调用。

标准请求指标看不出来应用是否检索到了合适知识片段、多步推理烧掉了多少 token、内部 Agent 是否陷入无限重试。于是很多团队转向默认的自动埋点包,结果撞上另一个极端——遥测洪水。一个用户提问在现代 AI 编排框架里可能生成几十个嵌套 Span,一旦涉及 Agent 或迭代式 RAG,每一步都会成倍放大 Span 数量。未经筛选的管道会把大量重复文本、内部序列化过程和冗余中间件钩子直接写入存储后端,成本涨了,根因却没找到。

什么是分布式追踪 Span:Span 是分布式追踪的最小工作单元,代表一次有开始时间、结束时间和元数据的操作。多个 Span 通过父子关系或链接组合成一条 Trace,还原单个请求跨服务、跨组件的完整调用路径。每个 Span 通常携带名称、属性(键值对)、状态码和事件。在 LLM 应用里,一次用户提问往往对应一条 Trace,内部的模型调用、向量检索、工具执行各自是一个子 Span。理解 Span 的粒度是判断「该采什么、该丢什么」的前提:粒度太粗会丢失排障所需的细节,粒度过细则会产生大量微秒级 Span,把真正有价值的失败信号淹没在噪声中。

OTel GenAI 规范里的核心 Span 类型

OpenTelemetry GenAI 语义约定由 CNCF 维护,在 gen_ai.* 命名空间下定义了模型参数、token 计数和操作类型的标准属性名。它把生成式 AI 交互建模成几类离散 Span:

  • 客户端与网关 Span(gen_ai.client / gen_ai.gateway):记录对模型提供方的边界调用,包含请求的模型、目标服务器、token 消耗与响应元数据。
  • Agent 与编排 Span:建模更高层的推理序列,比如 Agent 评估用户目标、选择外部工具、复核结果。
  • 向量检索 Span:捕获向量数据库查询、嵌入模型操作、相似度阈值和文档分块引用。
  • 工具与执行 Span:记录外部函数调用、传入参数、执行时长和工具输出。

值得一提的是,一致化的属性命名能让一个服务产生的 Trace 与下游代理或数据层发出的 Span 无缝串联——这正是判断「谁拖慢了这次请求」的前提。

语义约定为何重要:语义约定(Semantic Conventions)是 OpenTelemetry 为特定领域预先定义的属性命名规范,规定了字段名、数据类型和含义。没有它,不同团队会用 model_name、llm_model、model_id 等多种写法记录同一个概念,导致跨服务查询和仪表盘聚合失效。GenAI 语义约定把模型参数、token 用量、操作类型统一到 gen_ai.* 命名空间,使一个团队用 OpenAI 客户端、另一个团队用 Anthropic 客户端产生的 Span 保持字段一致。这也是后文强调用 AI 网关统一遥测的底层原因:命名一致是跨提供方对比延迟、成本和错误率的前提。

高价值信号:必须采集的字段

排障时,值班工程师不会先去读上千段文本交互,而是先找量化异常、结构性断裂和回归指标。真正值得采集的信号可以归纳为几类。

模型标识与回退。同时记录 gen_ai.request.model(应用请求的模型)和 gen_ai.response.model(实际服务的检查点)。如果网关因限流或故障把流量悄悄路由到了备用模型,这个差异正好解释响应风格的突变。

标准化的 token 计数。记录输入 token、输出 token,以及可用的推理或缓存读取 token。这些数字既支撑单位经济核算,也能暴露未受控的对话历史带来的 token 膨胀。

首 token 时间(TTFT)。对流式响应来说,总时长只讲了一半故事:一个十秒返回最终 token 的请求,可能 350 毫秒就吐出了第一个 token(体验很好),也可能先卡了八秒才出内容(体验很差)。这两者的排障方向完全不同。

Prompt 模板版本。代码部署有 git commit 可查,Prompt 模板却常常独立更新。没有 prompt.version 属性,要判断一次回归是代码推送还是 Prompt 改写引起的,只能靠人工比对。

工具调用与参数。Agent 调外部函数或 MCP 工具时,记录工具标识、参数结构和 HTTP 返回状态,才能区分错误源自模型推理还是外部 API 依赖。

租户、虚拟密钥与成本归属。挂上租户标识或网关虚拟密钥,才能计算单客户毛利、执行部门级限流。

Span 类型目标操作关键属性诊断价值
gen_ai.client直接模型推理请求/响应模型、输入输出 token、结束原因追踪提供方延迟、token 用量、成本归属与模型路由
retrieval向量库/知识库db.system、集合名、top_k、返回文档数、最低分揭示上下文检索是否失效或召回了无关片段
tool.executeMCP 或 Agent 工具工具名、调用 ID、rpc.system、error.type区分外部工具失败与模型幻觉
agent.step迭代式 Agent 循环迭代序号、最大迭代数、目标 ID、决策类型发现无限推理循环、重复调用与 Agent 停摆

纯噪声:四类必须砍掉的埋点

遥测噪声指那些体量大、价值低的数据,它们消耗带宽、推高数据库账单、拖慢查询界面,还带来合规风险。以下几种做法在 AI 应用里尤其容易制造灾难级噪声。

反模式一:流式响应逐 chunk 建 Span

消费 SSE 流式端点时,一些自动埋点或自定义封装会为每个返回的 token chunk 开一个 Span。一次生成 1500 个 token 的响应,就会为单个 HTTP 交互产生 1500 个 Span,本地内存缓冲被撑爆、Collector 直接崩溃。正确做法是流式操作使用单个父 Span,在内部记录 chunk 时序、用事件或属性标记首个 chunk(TTFT),流关闭时结束 Span。

反模式二:不加筛选地全量采集载荷

对每一条生产请求都存完整 Prompt 和补全文本,是把可观测性管道变成成本黑洞的最快方式。一个日处理数千万 token 的高吞吐服务会产生数 GB 非结构化字符串。更麻烦的是,原始 Prompt 往往夹带 PII、专有源码或凭证密钥,直接触碰 GDPR、HIPAA 这类隐私法规。全量内容采集在生产环境应默认关闭,只在通过动态采样或在预发环境时开启。

反模式三:把嵌入向量塞进 Span 属性

嵌入模型把文本块转成 768、1536 甚至更高维的浮点向量。把 1536 个浮点数存进 Span 属性,在 Trace 面板里读不出任何人类可理解的信息,只会膨胀报文、增加序列化开销、耗尽下游存储引擎内存。记录维度大小、嵌入模型名和文本哈希就够了,永远不要序列化原始浮点数组。

反模式四:为框架内部管线建微 Span

现代 Agent 库会构造很深的调用栈,涉及输入校验、Schema 解析、JSON 序列化和内部钩子触发。把每次字典变换或正则校验都包一个 Span,会让 Trace 视图塞满几十个微秒级 Span。工程师想知道一次 LLM 调用为什么花了六秒,却得先翻过几百个无关的框架 Span。埋点应聚焦边界:网络调用、数据库查询、外部工具调用。

遥测元素保留(高价值)丢弃(低价值)裁剪原因
流式输出单个 Span + 总 token + TTFT 事件每个 token chunk 单独 Span防止 Collector 内存耗尽与 Span 爆炸
载荷数据模板 ID、模板哈希、token 用量、结束原因100% 成功请求的完整 Prompt 与补全规避 PII 泄露、降低存储成本
嵌入向量模型名、token 数、维度、分块 ID原始多维浮点数组浮点不可检索且放大序列化开销
工具执行工具名、参数键、延迟、错误信息中间框架序列化调用消除 Trace 杂乱,聚焦真实 I/O 边界
Agent 循环迭代步数、决策状态、工具选择意图每次内部状态机跳变与变量赋值避免多轮执行下深不可读的 Trace 树

数据面治理:采样、脱敏与成本

保持 OpenTelemetry 管道高效,关键在于数据面管理。Collector 充当应用运行时与存储后端之间的代理,是集中过滤、采样和脱敏的合适位置。

尾部采样留住高影响 Trace

头采样在请求开始时做决定(比如统一保留 5%),这在 LLM 应用里会失效:超时、限流、极端延迟这些关键边界情况都落在长尾里,统一 5% 会丢掉 95% 你想调试的罕见失败。尾部采样在整条 Trace 生命周期结束后再决定是否落盘,可以配置为:保留 100% 含 4xx/5xx 或 Span 错误的 Trace、保留 100% 出现 p95/p99 延迟尖峰的 Trace、保留 100% 触发回退路由的 Trace,再对正常且快速的 HTTP 200 请求留 1%–2% 做基线对照。

头采样与尾部采样的取舍:头采样在 Trace 的第一个 Span 创建时即决定是否保留,实现简单、资源开销低,但决策时看不到请求最终结果,极端慢请求和错误 Trace 容易被按固定比例丢弃,而这些恰是 LLM 应用中最需要调试的对象。尾部采样需在内存中缓冲整条 Trace 直到满足决策条件(如错误状态、延迟阈值或超时窗口结束),因此对 Collector 内存和缓冲区配置要求更高,文中 decision_wait、num_traces 和 memory_limiter 正是为此设置。生产环境常用组合是:对高吞吐正常流量用低比例头采样,对错误和慢请求启用尾部采样兜底。

集中式 PII 脱敏

与其要求每个应用开发者手工清洗 Prompt 字符串,不如在 Collector 里部署脱敏处理器。通过正则匹配或实体识别,把信用卡号、邮箱和 API 密钥在落盘前替换成掩码 token。即使为排障临时开启了全量载荷采样,合规姿态依然完整。

用网关统一遥测

给每个服务、微服务和 Agent 脚本分别装本地 OpenTelemetry SDK,很容易造成命名约定不一致、采样规则分叉和维护摩擦。把标准遥测采集前移到网络层、由 AI 网关统一处理,能解决这种不一致。

Bifrost 是一个用 Go 编写的开源 AI 网关,直接位于应用与上游模型提供方之间。据其官方基准,在每秒 5000 请求的持续负载下每个请求只增加约 11 微秒开销。所有经过网关的请求都会被归一化为 OpenTelemetry GenAI 语义约定,应用只需把 OpenAI、Anthropic 或 LangChain 客户端指向网关即可。它统一通过 OTLP 导出 Trace,内置 Prometheus 指标,并提供 Datadog 连接器;当执行跨提供方自动回退或语义缓存命中时,这些事件会被记录为一类 Span 属性。Bifrost Edge 还把同样的治理策略延伸到员工机器上的 AI 流量,让桌面工具、本地编码 Agent 和终端脚本遵循与主网关一致的应用与 MCP 治理策略。

AI 网关在可观测性中的角色:AI 网关位于应用与模型提供方之间,是网络路径上的必经节点,天然适合承担标准化遥测的职责。它可以在转发请求时注入模型、token、延迟和回退等标准属性,并把各提供方各异的原始响应字段归一化为 gen_ai.* 语义约定。相比在每个微服务里安装独立的 OpenTelemetry SDK,网关方案避免了命名分叉、采样规则不一致和升级维护成本,同时也便于集中执行 PII 脱敏和成本归属。代价是网关成为单点,需要关注其自身性能和可用性。

一个可用的 Collector 配置长什么样

一个稳健的管道由应用运行时、AI 网关和 OpenTelemetry Collector 共同组成。下面这份 otel-collector-config.yaml 展示了如何为 LLM 工作负载配置尾部采样、属性归一化与安全批量导出:

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  # 负载下不让 Collector 越界
  memory_limiter:
    check_interval: 1s
    limit_percentage: 75
    spike_limit_percentage: 15

  # 从属性中脱敏敏感凭证
  redaction:
    allow_all_keys: false
    attributes:
      - action: replace
        key: gen_ai.prompt
        pattern: '(?i)(bearer\s+[a-z0-9_\-\.]+)|(api[_-]?key[_-]?=\s*[a-z0-9_\-\.]+)'
        replace: "[REDACTED_SECRET]"

  # 保留高价值异常,丢弃例行噪声
  tail_sampling:
    decision_wait: 10s
    num_traces: 10000
    expected_new_traces_per_sec: 2000
    policies:
      # 策略 1:保留全部错误
      - name: drop_errors_policy
        type: status_code
        status_code: { status_codes: [ ERROR ] }
      # 策略 2:保留延迟离群(超过 5 秒)
      - name: latency_outliers_policy
        type: latency
        latency: { threshold_ms: 5000 }
      # 策略 3:保留发生提供方回退的 Trace
      - name: fallback_routing_policy
        type: numeric_attribute
        numeric_attribute: { key: "bifrost.fallback_triggered", value_condition: { equal_to: 1 } }
      # 策略 4:对正常请求保留 2% 基线样本
      - name: probabilistic_baseline
        type: probabilistic
        probabilistic: { sampling_percentage: 2.0 }

  batch:
    send_batch_size: 512
    timeout: 5s

exporters:
  otlp:
    endpoint: "trace-backend.internal:4317"
    tls:
      insecure: false

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, tail_sampling, redaction, batch]
      exporters: [otlp]

这套配置保证异常和故障切换被完整保真地保留下来,而例行成功执行在存储成本累积之前先被降采样。

常见问题

OpenTelemetry 官方为 LLM 定义的语义约定是什么? 是 gen_ai.* 命名空间下的 GenAI 语义约定,由 CNCF 维护,规定了模型名、token 消耗、推理参数和工具调用的 Span 格式、指标乐器与事件结构。

生产 Trace 该不该存完整 Prompt 和响应体? 默认不该。对 100% 流量存完整对话载荷会推高网络与数据库成本,并暴露 PII 合规风险。载荷只应在预发环境或针对性的错误样本中采集。

OpenTelemetry 如何跨提供方衡量 token 用量? 通过 gen_ai.usage.input_tokens 和 gen_ai.usage.output_tokens 等通用 Span 属性。各提供方在原始 HTTP 响应中上报方式不同,合规的插桩库和网关会将其归一化为标准字段。

头采样与尾部采样在 LLM 应用中的区别? 头采样在请求开始时即做决定,按固定比例丢弃调用,不知道最终结果;尾部采样在完成后评估整条 Trace,可以保留 100% 的错误、回退和慢请求,同时对重复的成功调用降采样。

怎么在不压垮 Collector 的前提下追踪流式响应? 为整条流式 HTTP 连接维护单个父 Span,不为单个 token chunk 建 Span;把首个 token 到达的时长记录为 Span 事件或属性来衡量 TTFT,流结束后关闭 Span。

AI 网关如何简化 OpenTelemetry 埋点? 网关位于网络路径上,自动为每个请求发出标准化的 OpenTelemetry Span,省去了在多种微服务代码库里安装配置独立自动埋点库的工作,并保证跨提供方的属性命名与指标采集一致。

#OpenTelemetry LLM 追踪#LLM 可观测性#gen_ai 语义约定#AI 网关#尾部采样#OpenTelemetry Collector#LLM 监控
分享:

相关推荐