跳到主要内容

APM 仪表盘不会告诉你:生产环境中的 LLM 可观测性

· 阅读需 12 分钟
Tian Pan
Software Engineer

你的 Datadog 仪表板显示 99.4% 的在线率,低于 500ms 的 P95 延迟,以及 0.1% 的错误率。一切都是绿色的。与此同时,你的支持队列却充满了抱怨 AI 给出了完全错误答案的用户。你毫无头绪,因为每个请求都返回了 HTTP 200。

这是传统可观测性与你在 LLM 系统中真正需要的可观测性之间的本质区别。语言模型可能会以标准 APM 工具无法留下痕迹的方式发生故障:幻觉事实、从错误的产品版本中检索文档、在代码更改修改了系统提示词后将其忽略,或者在模型更新后对特定查询类型静默降级。在你的延迟图表上,这些看起来都一切正常。

构建可观测的 LLM 系统需要一种不同的思维模型——这种模型始于你需要“理解”什么,而不仅仅是需要“监控”什么。

语义故障的沉默

传统软件的故障是响亮的。异常会向上抛出,超时会触发熔断器,HTTP 5xx 错误率会飙升。系统会告诉你它坏了。而 LLM 的故障则是悄无声息的。一个从错误的索引中检索文档的检索增强生成(RAG)管道,会以 200 OK 和完全可以接受的延迟返回一个自信且流畅的响应。你的 APM 工具中没有任何东西会标记它。

LLM 特有的几类静默故障包括:

无错误的质量降级。 供应商的模型更新(甚至是补丁版本)会在不触及 API 契约的情况下改变模型行为。上个月在某个检查点上运行良好的功能,可能会在新的检查点上发生回退,仅影响特定分布的查询。直到用户告诉你之前,你都不会知道。

提示词偏移(Prompt drift)。 当工程师触及无关代码时,系统提示词可能会静默发生变化。如果不追踪每个请求实际使用的提示词,你就无法将行为变化追踪到其根源。

智能体(Agent)中的错误工具选择。 智能体可以成功调用工具——返回 200 并记录调用——但仍然选错了工具。在基础设施看起来健康的同时,输出却是错误的。

复合检索错误。 在 RAG 管道中,退化的嵌入模型或配置错误的向量索引会返回相关性较低的文档。LLM 会根据这些文档生成连贯的响应。错误率:0%。

传统 APM 回答的是“它在工作吗?”。LLM 的可观测性则必须回答“它为什么会表现成那样?”。

追踪(Trace)究竟是什么样的

LLM 的遥测单元层级镜像了标准的分布式追踪,但增加了额外的层级:

  • Session —— 分组多个用户请求的多轮对话
  • Trace —— 系统中单个端到端的请求
  • Span —— Trace 中的一个逻辑工作单元
  • Generation —— 特定的 LLM 推理调用

对于一个典型的 RAG 管道,单个用户请求生成的树状结构看起来像这样:

Trace: user-request (root)
└── Span: retrieve-documents
└── Span: construct-prompt
└── Generation: chat gpt-4o
└── Span: execute_tool web_search
└── Span: guardrail-check

每个 generation span 应该捕获模型名称、输入 token 数、输出 token 数、temperature、结束原因(finish reason)和延迟。检索 span 应该记录返回了哪些文档及其相关性分数。工具调用 span 应该记录工具名称、参数以及是否成功。

OpenTelemetry GenAI 语义约定(2024 年通过 OTel GenAI SIG 稳定化)定义了规范的属性名称。几个关键属性包括:

  • gen_ai.operation.name —— 操作类型(chat, embeddings, retrieve, execute_tool)
  • gen_ai.provider.name —— 供应商标识符(openai, anthropic 等)
  • gen_ai.request.model —— 模型名称
  • gen_ai.usage.input_tokens / gen_ai.usage.output_tokens —— token 计数
  • gen_ai.usage.cache_read.input_tokens —— 从供应商缓存中提供的 token 数

内容属性——完整的提示词、消息、检索到的文档——是可选的(opt-in),默认情况下是禁用的。只有在隐私法规和数据驻留要求允许的情况下才启用它们。它们对于调试至关重要,但如果随意捕获,会带来合规风险。

使用 OTel 约定的好处是可移植性。一次打点,即可导出到任何兼容的后端:Langfuse、Arize、MLflow 或 Datadog。Schema 不会改变。

你不能忽视的三个指标维度

延迟:不只是一个数字

LLM 的延迟由三个不同的部分组成,而你的 P95 数字将它们合并成了一个。

首字时间(Time to First Token, TTFT) 是感知的响应速度——即用户看到内容之前的延迟。对于交互式应用,TTFT P95 低于 800ms 是一个合理的起始 SLO,对于高度响应的聊天界面则为 200ms。TTFT 主要由排队时间和 prefill 阶段决定;它对提示词长度和并发负载非常敏感。

逐字时间(Time Per Output Token, TPOT) 是 decode 阶段的吞吐量——即第一个 token 之后 token 推流的速度。这决定了流式传输感觉平滑还是卡顿。在现代硬件(搭载 vLLM 的 H100)上,中等并发下可以预期约 120ms 的 TTFT;在较旧的部署中,方差会很大。

端到端延迟(End-to-end latency) 是包括检索、工具调用和后处理在内的整个管道时间。对于复杂的智能体管道,这是用户实际体验到的数字,也是你应该设定 SLO 的指标。

这三个指标都要测量。TTFT 的飙升和 E2E 的飙升可能有着完全不同的根源。

成本:按功能计费,而非按月计费

最危险的成本错误是将 LLM 支出视为单一预算项。当成本激增时,你需要知道是哪个功能、团队或使用模式导致的,而不仅仅是账单增加了。

在 Span 级别进行 Token 计数可以实现这一点。如果每次 LLM 调用都记录 gen_ai.usage.input_tokensgen_ai.usage.output_tokens,你就可以按任何维度进行汇总:功能标志(feature flag)、用户层级、智能体(agent)类型或模型。这种做法在现实中的影响非常显著 —— 一个记录在案的案例发现,在成本归因揭示了短查询会触发全页面网页抓取(从而在无形中增加了 Token 数量)后,每月 4.7 万美元的支出降至了 2.8 万美元。

缓存放大了成本可见性的杠杆作用。提供商级别的提示词缓存(prompt caching)可以将缓存 Token 的成本降低 50-90%。语义缓存(在应用层对近乎相同的查询进行去重)可以完全消除 31% 的企业查询,因为这部分查询在不同用户之间是语义相似的。如果没有 Token 级别的追踪,这两项优化都无法直观体现。

规范尚未捕获的成本指标 —— 即实际金额 —— 需要通过将 Token 计数乘以每个模型的定价,在外部推导出来。请务必将此逻辑集中维护。

质量:需要新流水线的指标

质量是 LLM 可观测性与传统 APM 完全不同的类别。你无法用计数器或计时器来衡量它,你需要运行评估(evaluations)。

实际的做法是进行在线评估:异步采样 5-10% 的生产流量,并使用 LLM 作为裁判(LLM-as-judge)或自定义 Python 逻辑进行评分。这在请求完成后运行,对用户路径增加的延迟为零。

需要跟踪的关键质量信号:

  • 落地性 (Groundedness) —— 对于 RAG,回答是否使用了检索到的上下文,还是凭空捏造?
  • 相关性 (Relevance) —— 检索到的文档是否真的匹配查询?
  • 幻觉率 (Hallucination rate) —— 事实性陈述是否可验证?
  • 安全通过率 (Safety pass rate) —— 在 PII(个人身份信息)、毒性和注入攻击(jailbreak)维度的清洁响应率。
  • 任务完成率 (Task completion rate) —— 对于智能体,智能体是否完成了用户的真实意图?

即使是简单的评分标准(对 5% 的样本进行 1-5 分的 LLM 评分),也能捕捉到在基础设施指标上看似正常的质量下降。像 LangSmith 和 Braintrust 这样的工具已经围绕这种模式构建了生产采样流水线。

多智能体追踪:比看起来更难

单轮 LLM 调用相对容易进行插桩。但多智能体流水线引入了需要显式设计的挑战。

核心问题在于:一个复杂的智能体可能会为单次用户请求执行 15 次以上的 LLM 调用,并涉及多个模型。如果没有分层 Span 链接,你将无法知道是哪次调用引入了质量问题,哪个子智能体消耗了 80% 的成本,或者慢速请求的瓶颈是在检索还是推理阶段。

解决方法是跨智能体边界维护父级 Span 关系。每个子智能体的调用都应该记录其父级 Span ID,以便事后重建完整的执行树。如果你的智能体是异步通信或跨进程通信的,则需要显式传递追踪上下文(trace context)。

需要监控的智能体特定指标:

  • 每个智能体的工具调用成功率 —— 此指标下降通常预示着质量失败。
  • 链深度 (Chain depth) —— 一个请求跨越了多少次智能体间的跳转;无限循环在表现为超时之前,通常会先表现为深度异常。
  • 每个完成目标的成本 —— 这是智能体相关的基本单位,因为完成任务的 10 次 LLM 调用比未完成任务的 3 次调用更有效率。
  • 连续工具失败 —— 针对 5 分钟内出现 3 次以上失败进行告警;这通常在基础设施监控发现之前,就预示了外部依赖的损坏。

一个生产案例:两个智能体在循环中互相调用。基础设施指标仅显示请求变慢,而 Span 深度监控在 3 分钟内就通过链深度超过 8 的告警捕获了该问题。

可观测性税

在现有的 APM 平台中添加 AI 监控并非免费。RAG 流水线每次请求产生的遥测数据比传统 API 调用多 10-50 倍 —— 每个请求都涉及检索、提示词构建、推理、工具调用和后处理,每个环节都会产生 Span 和指标。如果在不调整插桩策略的情况下添加 LLM 工作负载,Datadog 和 Splunk 等工具的基于容量的定价会导致账单增加 40-200%。

缓解方案:

  • 采样:并非每个追踪都需要存储。对常规请求进行 5-10% 的采样;对错误和低质量评分的追踪保持 100% 记录。MLflow 的追踪包支持可配置的采样率。
  • 专用工具:Langfuse(可自托管,MIT 协议)、Helicone(基于代理,极简配置)和 MLflow 轻量级的 mlflow-tracing 包都是围绕 LLM 遥测模式设计的,可以避免线性容量定价陷阱。
  • 选择性内容捕获:选择性开启的内容属性(完整提示词、检索到的文档)存储成本最高。仅为调试环境和采样的生产流量开启这些属性,而非针对每个请求。

一个实用的切入点

你不需要一次性实现所有功能。分阶段的方法可以降低风险,并逐步体现价值:

第 1 周: 为每个请求分配 trace_id。记录每次 LLM 调用的输入/输出 token 数量。按功能跟踪端到端(E2E)延迟和成本。仅此一项就能揭示大部分意外的成本支出。

第 1 个月: 使用 OTel GenAI 规范为检索、推理和工具调用添加 span 层级结构。构建可靠性仪表板:TTFT P95、错误率、token 使用量以及每个请求的成本。在达到月度目标的 80% 时设置预算警报。

第 2 个月: 对 5-10% 的生产流量添加在线评估。跟踪 RAG 流水线的准确性(groundedness)和相关性。为安全检查添加护栏 span。为低分 trace 创建人工审核的标注队列。

持续进行: 对提示词(prompt)进行版本管理。将有问题的生产 trace 捕获为回归数据集。将质量评估作为模型更新部署门禁的一部分。如果没有最后一步,供应商的模型更新将成为不可见的风险。

目标不是全面的遥测 —— 而是可落地的遥测。一个关于幻觉率超过阈值的警报,比一百个延迟图表更有价值。在调试错误答案时,一个显示检索了哪些文档及其评分的生产 trace,比单独的系统提示词更有价值。

当你的用户投诉时,你的 APM 仪表板可能仍然显示绿色。构建那个能解释原因的流水线。

References:Let's stay in touch and Follow me for more thoughts and updates