跳到主要内容

Agent 的链路追踪采样:每日千万级 Span 中哪些值得保留

· 阅读需 12 分钟
Tian Pan
Software Engineer

一个 Web 服务请求在繁忙时段产生 5 个 Span。而一个现代的 Agent 会话产生 50 个,如果 Planner 决定递归,有时甚至会产生 1000 个。你们平台团队从微服务时代复制粘贴过来的 1% 均匀采样器,从定义上就会丢弃你真正关心的稀有故障——因为故障是稀有的,而均匀采样对稀有性没有任何判断力。

“我们对 Agent 拥有完全的可观测性”的真实版本听起来与营销版本不同。它听起来应该是:我们保留重要的 Trace,丢弃不重要的,并且我们预先知道哪些是哪些。这句话中的每一个词都至关重要,而那些在账单寄来之前一直忽视采样设计的平台团队,现在正被迫反向学习这一学科——在成本压力下,以及在经历了一个季度的故障之后,这些故障本应“在数据中”,但在有人查看之前就被剔除了。

这篇文章讨论的是同时驱动 Agent 追踪账单和故障 MTTR 的四个决策:在 Trace 开始时采样什么,在 Trace 结束时保留什么,如何分层以确保稀有群体不会消失,以及保留下来的数据要存多久。这些在技术上都不新颖——大多数都有 OpenTelemetry 的原语支持——但适用于无状态 API 的运行点并不适用于 Agent,沿用默认设置只会让团队最终得到一个既昂贵又单薄的可观测性堆栈。

为什么 Web 服务的采样默认设置对 Agent 失效

你继承的默认设置假设流量与 Trace 量之间存在大致的线性关系:更多的请求、更多的 Span、更多的存储,全部成比例扩展。一个典型服务发出的仪表化数据——入口 Span、几个下游调用、一次数据库访问——占用空间不到 1 KB,并能完整讲述请求的前因后果。

Agent 违反了这个模型的每一个部分。一条简单的用户消息会扇出到意图分类、检索、排序、带有推理的多轮 LLM 交互、多个各自产生重试的工具调用,以及最后的综合阶段。行业遥测数据估计,一个典型的 Agent Trace 大约为 25 KB——大约是传统 API Trace 的 50 倍——而一个中等繁忙的产品每天会产生 50 万个 Trace,底层承载着数百万个 Span。AI 工作负载产生的遥测数据是同等规模传统服务的 10 到 50 倍,而这个比例直接反映在可观测性的发票上。

下一个失效的默认设置是**基于头部(head-based)**的采样。TraceIdRatioBasedSampler 在 Trace 开始时抛硬币决定是保留后续所有内容还是全部丢弃——这虽然廉价、简单,但对 Agent 工作负载来说完全错误。Agent Trace 的有趣属性(是否出错、成本是否超出预期、评估分数是否下降、Planner 是否陷入循环)在 Trace 开始时是不可知的。一个 Agent 递归重试了 30 次格式错误的工具调用并烧掉 4 美元的 Trace,在第 0 个 Span 时看起来与第一次就正确回答的 Trace 完全一样。头部采样以相同的概率丢弃两者,而你只有在客户经理因为客户账单问题发起工单时,才会发现你真正需要的是哪一个。

第三个失效的默认设置是跨群体的**均匀(uniform)**采样。生产环境中的 Agent 服务于异构流量:少数企业租户每天产生数百万个会话,而数百个小租户只产生几十个。一个单一的 1% 采样器会保留大租户的数千条 Trace,而对长尾租户则一无所获——而你最需要调试的故障模式,例如某个租户的 Schema 与工具预期的输入不匹配,恰恰只存在于这些长尾中。

Trace 结束时,“有趣”意味着什么

基于尾部(tail-based)的采样将保留/丢弃的决策推迟到 Trace 完成的时刻。Collector 在 Trace 的整个生命周期内缓冲 Span,在根 Span 关闭时评估策略,然后将整个 Trace 发送到长期存储或直接丢弃。其成本是真实存在的——缓冲内存、额外的 Collector 基础设施、运行有状态采样层的运维复杂性——但对于 Agent 来说,这是唯一能知道刚刚发生了什么的采样模式。

在生产环境下行之有效的策略大致分为四个桶:

  • 保留所有出错或超时的内容。 错误到目前为止是语料库中最有价值的 Trace,而且根据定义它们是稀有的。对 status=error 执行 100% 保留规则几乎不会增加存储成本,却能让你免于面对值班工程师的质问:为什么上周二出错的 Trace 不在系统里。
  • 保留所有超过成本阈值的内容。 将阈值定义为 Token 消耗量排名前 1% 到 5% 的 Trace,或者定义每个会话的绝对美元上限。Agent 在大声报错之前,往往会先昂贵地失败——Planner 在循环中空转了 30 秒的 Trace 就是你的事故,也是你的 CFO 下个季度会问起的 Trace。
  • 保留所有评估分数较低的内容。 如果你有在线评分或输出质量的启发式方法(拒绝率、JSON 解析失败、下游用户拒绝点击),请 100% 保留得分低于阈值的 Trace。这些 Trace 能教会你模型尚未掌握的知识。
  • 保留健康群体的分层切片。 对于其余部分,1% 到 5% 即可,但要按租户、功能、工具调用类型或用户群进行分层,以便样本保持原有形态。在不平衡的语料库上使用扁平的概率采样器,产生的样本与总体特征会完全不符。

第四个要点是大多数团队投入不足的地方,也是日后让他们付出代价的地方。错误和成本异常值能告诉你今天的事故。而分层的健康样本则是你的评估(eval)素材和分布基准——通过它,你才能在下个季度注意到第七大租户的平均工具调用延迟发生了偏移,或者新模型版本悄悄改变了特定任务类型的拒绝率。

分层是覆盖率与偏差的分水岭

Agent 处理的是符合幂律分布 (power-law distribution) 的流量。在幂律分布下,朴素的采样器产生的样本只会反映“头部”情况,而对“尾部”一无所知。补救措施是明确定义分层 (Strata) —— 租户层级、地域、任务类型、使用的工具 —— 并设定每层采样率或每层最小值。

“每层最小值”是唯一真正有效的方案。设定一个底线:无论全局采样率如何,每个租户每天至少保留 N 条 Trace,每种任务类型至少保留 M 条 Trace。那些“大象”(高流量租户)无论如何都会被过度代表,因为它们的体量太大了;而底线策略可以在不显式限制头部的情况下保护尾部。

这种分层还必须具备主体感知能力,这是传统模式所不具备的。在根 Span (root span) 标记,并透传到每一个子项 (child) 是不可逾越的准则:user_idtenant_idsession_idtask_typemodel_versionprompt_versiontool_set 必须在入口点挂载,并继承到每一次 LLM 调用、检索 Span 和工具调用中。如果没有这种透传,采集端的尾部采样器就无法做出针对每个租户的决策,而你在季度末需要的成本归因汇总也将无从谈起。

分层维度也是检测罕见失败的地方。包含真正新颖的 Agent 失败 —— 例如新的提示词注入向量、工具首次返回格式错误的 JSON、检索出的文档违反了内容策略 —— 的 Trace,从定义上就属于属性组合的“长尾”。一个目标是覆盖“属性组合”而非仅仅是“Trace 数量”的采样器,才能在这些问题公开化之前捕捉到它们。

你真正需要的存储层级体系

一旦尾部采样决定了保留哪些内容,下一个决策就是保留多久。将“保留”视为一种二元选择 —— 要么在存储中,要么彻底消失 —— 是团队会犯的第二个导致账单爆炸的错误。

稳健的层级体系至少包含三层:

  • 热存储层,24 到 72 小时。 完整的 Trace Payload,已索引且可查询,用于实时调试。这是值班工程师在处理事故时访问的层级,每 GB 成本很高。大多数 Trace 应该在此处过期。
  • 温存储层,30 天。 成本较低的完整 Payload(使用带有查询层的对象存储,或像 ClickHouse 这样能对 Agent Trace 实现 10 到 50 倍压缩的列式 OLAP 系统)。这是你的评估团队和微调数据管道读取数据的层级。它的价格足够便宜,足以持续保留分层后的健康样本以及所有带错误标记的内容。
  • 冷存储层,永久保留,仅限显式提升的 Trace。 与调查中的事故相关的 Trace、为法律或合规性保留而标记的 Trace、作为评估黄金集 (eval gold-set) 成员筛选出的 Trace。每 GB 成本极低,但查询成本高。提升机制 —— 事故响应提升 Trace、评估团队提升 Trace,此外别无他法 —— 是确保冷存储层不会变成第二个热存储层的纪律约束。

还有一个值得设计的第四层:仅限元数据的索引,它在 Payload 过期后依然存在。每条 Trace 的元数据 —— 耗时、总成本、错误状态、顶级用户/租户标签、评估分数 —— 与 Trace 本身相比微乎其微,保留 90 天的元数据几乎不需要成本。当客户询问两个月前的会话而 Payload 已消失时,元数据仍然可以告诉你该 Trace 曾经存在、运行时间、成本以及是否成功 —— 这足以让你决定是结束话题,还是在答案很重要的情况下安排重新执行。

元数据索引也是让“针对每个租户”的承诺保持诚实的关键。“我们没有 Trace,但我们有收据”是针对长尾问题的真实回答。“我们不知道这个 Trace 是否存在过”则是会终结客户关系的回答。

谁都不想开启的财务对话

承诺“我们记录一切”的平台团队,是在 Agent 案例量足够小、承诺既真实又廉价时做出的保证。当每天的 Trace 达到 50 万到 1000 万之间时,这个承诺就成了问题 —— 在这个拐点,你的可观测性供应商账单开始展现出与推理账单相同的威力,CFO 也会开始询问每一项支出的明细。

战略回撤虽然令人不适,但不可避免。诚实的更新应该是:我们将保留 100% “重要”的 Trace,并对“重要”给出明确定义,同时我们会透明地告知丢弃了哪些内容。采样策略变成了一份文档化的契约 —— 经过版本化、评审并由专人负责 —— 而不是某人在 2024 年设置后就再也没人碰过的默认配置。

保留期限数据应该与推理预算出现在同一份评审文件中。两者都是随使用量扩展的存储成本,且都面临相同的权衡:花更多钱以获得更高保真度的事故后复原,或者花更少钱并接受某些事故只能通过日志和指标来调试。将它们视为统一的可观测性预算 —— 并将分层策略、层级转换、冷存储提升标准和元数据索引保留期限全部记录在案 —— 这正是那些在 Agent 成本转型中幸存下来的平台团队与那些仍在复盘会 (retro) 上为此争论不休的团队之间的区别。

采样现在是决定可观测性的关键决策

这四项中的模式——开始采样什么、最后保留什么、如何分层、保留多长时间——表明采样不再是一个设置一次后就可以高枕无忧的旋钮。对于 Agents 而言,采样是你可观测性战略的支柱性环节。你在采样层做出的决策,决定了下个季度的事故调查是 45 分钟的复盘,还是为期三天的“考古项目”;也决定了你的评估流水线(eval pipeline)获取的是具有代表性的数据,还是某个租户使用情况的有偏切片。

那些稳定交付的团队已经趋向于一种公认的模式:收集器端的尾部采样(tail-based sampling)、带有每个租户最低限额的分层保留、具有明确升级标准的三级存储、寿命长于有效载荷(payload)的元数据索引,以及一份由值班工程师、评估团队和财务合作伙伴共同签署的文档化政策。这些做法本身并不稀奇。稀奇的是在账单迫使你开启这段对话之前就付诸行动,而不是在事后。

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