跳转到主要内容

你的 APM 正在悄悄丢弃 LLM 遥测数据,而 Bug 就隐藏在这些缝隙中

阅读需 1 分钟Tian PanTian Pan

目前你的系统中有一个损坏的 prompt 影响了约 3% 的流量,但你的仪表盘根本察觉不到它的存在。p99 延迟图表是绿色的。错误率保持平稳。模型调用成功率指标高达四个九。唯一的故障迹象出现在一张平台团队无法复现的客户支持工单中,而等这张工单进入调试环节时,相关的 trace 已经因为采样而被丢弃了。

这不是监控缺失,而是一个分类错误。你正在运行的 APM 是为维度受限(如 endpointstatus_coderegionservice)的世界设计的,在这种情况下,增加一个标签的成本最多只是增加几个新的时间序列。LLM 工作负载完全不符合这种模式。真正有趣的维度是用户的 prompt、检索到的 context ID、工具调用序列、模型版本、prompt 模板版本、租户(tenant)、语言区域(locale),以及请求所属的 eval bucket。每一个维度都是高基数(high-cardinality)的,只要你用其中任何一个子集来标记 span,指标存储瞬间就会爆炸。

团队的反应每次都如出一辙:聚合掉那些有问题的字段。为了防止成本曲线翻倍,放弃按租户细分的视图。从指标中剥离 prompt_hash,以阻止时间序列数量持续攀升。每一个决定在局部看都是理性的,但在全局看却是灾难性的,因为刚刚被移除的正是唯一能让故障可见的维度。聚合后的 p99 对一个群体取了平均值,在这个群体中,简单的查询总是通过,而困难的查询总是失败;损坏的 prompt 正隐身在“总是失败”的尾部,而这个尾部恰恰被平滑处理掉了。

为什么 LLM 遥测具有产品分析类的基数特征

典型的服务发出的遥测数据看起来像是一个低秩矩阵(low-rank matrix)。通常只有几百个端点、少数几个状态码、几个区域以及同时运行的少数几个服务版本。将它们相乘,你会得到数万个唯一的标签组合。Prometheus、Datadog 以及其他的指标栈正是为此设计的,且表现极其出色。只要每个维度的唯一值保持在大约一百个以内,单位基数的成本曲线是平缓的。

LLM 遥测则完全不同。每个 prompt 都是唯一的字符串。检索层为几乎每个请求返回不同的文档 ID 组合。工具调用的 trace 是一棵树,其形状取决于模型的决策。Prompt 模板本周在 eval 套件中已经更新到了第 14 个版本。模型本身有三个版本同时在线,因为金丝雀、对照和影子评估(canary, control, and shadow eval)正在同步运行。租户集包含数千个客户。语言区域集有几十个。将所有这些相乘,你得到的不是数万个序列,而是一个实际上无界的结果 —— 它更接近点击流分析(clickstream analytics),而非服务指标。

一个典型的检索增强生成(RAG)流水线 —— 向量查询、重排序(rerank)、模型调用、后处理 —— 发出的遥测数据量是同等无状态 API 调用的 10 到 50 倍,且遥测数据以高基数维度为主。这些基数没有一个是“多余的”。每个字段都是工程师调试特定类别故障时必须切分的维度。检索团队需要知道哪些文档 ID 出现在 context 中。Prompt 团队需要知道哪个模板版本处于激活状态。模型团队需要知道是哪个版本给出的回答。产品团队需要知道是哪个租户在投诉。剥离其中任何一个都不是优化,而是在有计划地破坏某人所需的信号。

指标层的悄然崩塌

这种失败在实践中很少表现为宕机。它是一种缓慢的漂移,仪表盘保持绿色,而操作人员虽然嘴上不说,但内心逐渐不再信任它们。通常会依次发生三件事。

首先,指标存储预算超支,告警层开始丢弃序列。在大多数平台上,这是静默发生的。Datadog 的自定义指标超额费用随基数线性增长,增加一个具有 1000 个唯一值的标签可能会使指标数量翻万倍,账单每月每项指标增加数千美元。一个简单的 prompt.template_id 标签(包含 200 个模板)加上一个 tenant_id 标签(包含 500 个租户)就会为一个指标创建 10 万个序列。财务团队往往比运维团队更早察觉到账单异常,而非数据丢失。

其次,团队通过聚合来应对。高基数维度从标签变成了丢弃规则,从丢弃规则变成了“我们会把它们留在日志里”,从日志变成了“我们会把它们留在采样率为 1% 的 trace 里”。每一步都保留了全局指标,却摧毁了细分指标。仪表盘上的数据形状保持不变,但它能回答的问题却随着每一次迭代而变得越来越窄。

最后,长尾变得不可见。当一个模板针对某个特定租户在特定语言区域下损坏时,全局质量指标不会波动,因为该故障仅占总请求量的一小部分。故障只有在客户投诉升级时才会浮出水面,而投诉转交到的团队,其工具链已被静默配置为不显示刚才发生的情况。平台团队开始说“我们无法复现”,因为他们确实无法复现 —— 采样层在他们介入之前就已经把 trace 丢弃了。

会员专享

余下内容仅对会员开放。

会员可读完整内容 —— 每一个公开发布的观点背后,那些框架、决策与推理的全貌。

  • 完整文章,包含未公开存档的部分
  • 可落地的工作框架,附带权衡与决策依据
  • 新文章抢先看,先于公开发布

随时取消 · 一次订阅,畅读全部

参考资料

保持联系,关注我获取更多内容

阅读需 12 分钟

下午 3 点和凌晨 3 点的同一个 Prompt 并不是同一个 Prompt:LLM 评估中的昼夜漂移

LLM 调用的行为取决于挂钟时间 —— 批次大小、缓存状态和路由层级会随着供应商负载而变化。凌晨 2 点运行的评估是在生产环境永远不会遇到的条件下进行校准的。这里有五个实践,可以缩小非高峰期评估与高峰期现实之间的差距。

insider
ai-engineering
阅读需 10 分钟

被反向代理剥离的 SSE Keep-Alive,以及你支付了两次费用的 Prompt

LLM 流式响应看起来像是从模型到用户的通畅管道 —— 直到一次 35 秒的工具调用导致反向代理断开连接,你的客户端针对无状态 API 重试整个 Prompt,最终用户的账单为同一个响应支付了两次费用。

insider
ai-engineering
阅读需 8 分钟

供应商配额在你的全球流量从未选中的时区重置

供应商配额按照供应商的时间重置,而不是客户的时间。当周期的临界结束点与你的流量峰值时区重叠时,429 错误看起来就像是随机噪声 —— 而 UTC 仪表板掩盖了背后的真相。

insider
llm-ops
阅读需 12 分钟

你的后端基础设施并非为流式响应而设计

流式传输在传输层赢得了用户的信任,但同时也悄然改写了你的负载均衡器、追踪流水线、自动伸缩器和成本模型原本遵循的契约。

insider
streaming
阅读需 10 分钟

重跑反模式:为什么再次运行并不能发现 Bug

重跑失败的 AI 提示词(prompt)感觉像是在进行方差探测,但实际效果却如同幸存者偏差 —— 在消耗预算外 token 的同时掩盖了确定性的 Bug。取而代之的应该是追踪优先调试和 N-of-K 准则。

insider
ai-engineering