轨迹采样:头部采样删掉的,恰恰是你需要的那些运行。
在每次运行开始时抽取 10%,你就只留下了 10% 的失败——在 2% 失败率、每月十万次运行的规模下,这意味着你只能靠两百个样本去推断系统最糟糕的行为,同时还在为两千次长得一模一样的成功付存储费。这个决定必须挪到运行的末尾,也就是结果已知的时刻。而一旦接受了这一点,第二件事随之而来:这份存档就是你未来的评测集,所以保留期是一个数据集决策——而它眼下正由财务替你做着。
智能体轨迹不适用日志那套心智模型,原因就在算术里。
团队按请求日志的经验来估轨迹预算,然后会错上一到两个数量级——因为轨迹不是"每个事件一行",它是整个上下文,一遍又一遍。
- 载荷随步数的平方增长。模型是无状态的,所以第二十步会把第一到十九步的一切重新发一遍。如果你在每一步都记录提示词与补全——而你必须记,否则轨迹无法回放——一次二十步的运行存下来的文本量接近两百个"单步等价"。驱动智能体成本的那个平方项,同样驱动着存储账单。
- 载荷把结构碾压的倍数,没有人第一次能猜对。span 骨架——名称、时序、状态、token 数、工具名——每次运行是几 KB。而提示词、检索到的文档与补全是几 MB。它们默认被存在一起,而它们的价值曲线完全不同。
- 检索让情况更糟。一个每步拉二十个切片、并把检索内容记下来的智能体(要调试一个错误答案就必须记),会把载荷再乘一遍;而这些切片,在每一次检索到它们的运行里都被复制了一份。
- 所以你一定会采样。这不是设计偏好,而是算术后果。唯一真正的问题是哪些运行活下来——而这个问题有一个明确正确的答案,多数系统的默认配置恰好答错。
默认是头部采样,而它与你想要的东西负相关。
头部采样在轨迹开始时就做决定,那时什么都还没发生。它在多数埋点方案里是默认,因为它是唯一能廉价且本地做出的决定——而它扔掉信息的方向,恰恰错得离谱。
- 失败本就稀少,均匀采样让它更稀少。一项保留十分之一运行的控制,也只保留十分之一的事故。你真正要研究的那个总体——坏轨迹——与你正被淹没的那个总体按同样的倍数缩小,这与预期效果正好相反。
- 钱和危险都在尾部。p99 的那次运行比中位数贵好几个数量级,而它通常是一个永不终止的循环。均匀采样保留其中 1%,于是你最需要看到的那次失控,恰好是你没留下的那次。
- 轨迹开始时没有任何东西能预测结果。这才是结构性的要点。在传统服务里,端点与客户等级在请求跑起来之前就告诉了你不少。而在智能体里,两次输入完全相同的运行会在第四步分岔,有意思的那次在第零步无从辨认。
- 临时打开"调试模式"救不了场。客户投诉之后再给这个租户开全量追踪,你拿到的是未来的运行,不是他们投诉的那一次——而投诉针对的,通常是上周的某次运行。
在选任何方案之前,先按你自己的系统算一遍:月运行数 × 失败率 × 采样率,就是你将要据以工作的坏轨迹数量。如果这个数字不到几百,你做不了回归检测,也建不出有代表性的评测集,而且没有任何看板会告诉你原因——它只会一片安静。
在末尾做决定:先把运行缓冲住,再按结果决定去留。
尾部采样把轨迹先攒着,等运行结束再决定;代价是一个缓冲区,换来的是"以已发生之事为条件"的能力。对智能体而言,这不是一项优化,而是"可用的存档"与"昂贵的存档"之间的分界。
- 凡是出了问题的,100% 留下。报错、超时、撞上步数上限而终止、护栏拒绝、工具调用失败循环、人工接管与驳回、低评分会话。这个总体按定义就很小,所以全留得起——而它正是这份存档存在的全部意义。
- 结果信号是运行的形状,不是一个标签。生产环境没有真值,所以要用"不靠裁判也能观测到"的东西来定义"有意思":撞上步数上限、同一个工具重试了三次、终止时没有产出预期产物、成本高于 p95、延迟高于 p95,或者用户立刻又问了一遍。这些正是质量回归检测所依托的那些指标,而且在运行结束时计算它们很便宜。
- 成功样本要分层留,不要均匀留。你需要正常运行来做对照,但不需要按比例——按任务类型、租户与模型版本对成功做分层抽样,好让稀有任务类别保持有代表。均匀抽样给你的是最常见工作流的一万份副本,以及那个只在月末跑的工作流的零份。
- 无论采样与否,每次运行的骨架都要留。从样本算出来的指标带抽样误差;从每一次运行的 span 结构算出来的不带。这个切分,正是下一步之所以重要的原因。
- 为缓冲区留预算。一个长跑的智能体可能把轨迹在内存里攒上几分钟。给缓冲区设上限、溢出时落盘,并想清楚满了之后怎么办——通常是留骨架、丢载荷,并把"这么做了"记下来。
在 collector 处把轨迹一分为二,配两套保留期。
结构与载荷的价值曲线不同、隐私暴露不同、成本也不同;把它们存在一处,就强行套上了一套对两者都不合适的保留策略。
- 结构性遥测很便宜,而且好用好几年。步数、工具名、时长、token 数、模型版本、结果码。趋势分析、容量规划,以及"换了模型之后 p95 步数变了没有"都跑在这上面。留久一点——它小到"删掉它"这个论证根本站不住。
- 载荷很贵,而它的调试价值以周为单位衰减。没人会去调试四个月前的某一条具体轨迹。然而它的数据集价值完全不衰减——这正是下一步要谈的张力。
- 在 collector 处分流,而不是在厂商那里。一跳 collector,把结构性 span 分流到你的指标存储、把载荷分流到你自己拥有的存储——正是这一改动让此后每个决定都可逆,也正是 OpenTelemetry GenAI 语义约定那一页就埋点整体所作的论证。脱敏也该放在这里。
- 在入口处脱敏,因为规模化的追溯脱敏做不到。提示词里的密钥、凭据与个人数据,一旦写进只追加的存储就是永久的。在 collector 处做检测,留一个哈希以便仍能区分两次运行,并接受"损失一些保真度"是"存档能留得住"的代价。
保留期是一个数据集决策,而它与你的删除义务正面相撞。
这部分往往是被顺手定下来的。某人为了控成本设了 30 天保留期,十八个月后团队才发现:黄金轨迹、回归基线,以及"系统在最近三次模型迁移之前是什么样"的唯一记录,全没了。
- 你的轨迹存档,就是你还没建起来的那个评测集。真实的生产轨迹是评估驱动开发最高价值的输入,而且它们无法再生——产出它们的模型版本、索引与流量都已不在。删掉它们不是一次存储决策,而是删掉了唯一能反映你真实用户的训练与评测数据。
- 刻意留一份永久的、经过策展的切片。几千条轨迹,按覆盖度而不是按新鲜度挑选,从采样管线里晋升出来,成为一个有自己生命周期的数据集。一旦晋升,一条轨迹就不再是遥测——它是一份固定装置,理应熬过任何一次保留期清扫。
- 在晋升任何东西之前,先与删除与法律保全对齐。轨迹含有用户内容,所以一次删除请求也必须触达那份策展集——这意味着晋升那一步必须保住与数据主体的关联,否则你造出的是一份删不掉的语料。反过来,法律保全必须能暂停采样器的删除,而一个已经把那次运行丢掉的采样器无从遵从。两个方向都在保留与法律保全里被逐一走通。
- 定保留期时,让评测的负责人也在场。一年后需要这批数据的人,不是眼下在优化可观测性账单的人;如果会议室里只有其中一位,答案是可以预料的。
把它运营起来:度量你丢掉了什么,并证明你还回放得了。
采样策略是无声失败的。存档不再具有代表性时,没有任何东西会告警;看板照常渲染,数字照常好看。
- 在每次运行上记下采样决定及其理由。因失败而留、因基线而留、已丢弃、缓冲溢出。没有它,你无法为从存档算出的指标做重新加权,而由它推导出的每个数字都在悄悄偏向失败。
- 对构成告警,而不是对体量告警。信号是比例——如果"因失败而留"的轨迹从存档的 2% 跳到 9%,说明有东西回归了;如果它掉到近乎为零,那要么是系统变好了,要么是探测器坏了,而这两者需要不同的应对。
- 演练回放。每季度从你声称还保留着的最老那一层里取一条轨迹,真的照它把那次运行重建出来。工具 schema 缺失、模型版本不可复得、脱敏抹掉了承重的东西——否则这些都会在事故当中被发现,而那是最糟糕的时机。
- 按"每完成一个任务"给存档定价,而不是按 GB。只占推理支出百分之几的可观测性开销不值得优化;而一份逼近模型账单的轨迹账单,说明你在存那些本该被采样掉的载荷——这个比较比任何绝对阈值都更有用。
- 永远不要对评测环境采样。评测与红队运行量小且信息量最大。整条留下、永久留下,并与生产采样分开——代价可以忽略,而反面是一个你无法审计的评测。
这周就改一件事:别在运行开始时做决定。缓冲到运行结束,把每一次失败、撞上限、被接管或超贵的运行按全保真度留下,然后把成功样本狠狠砍掉——多数团队会发现,成功留到 1–2% 就够,而存档比过去更大更有用,成本还更低。接着在 collector 处把结构性 span 分流出去,那部分留上几年。你删掉的那条轨迹不是一行日志,它是一个"你的系统在生产中失败"的带标签样本——最贵的那类数据,也是唯一你早已拥有的那类。
相关:追踪与可观测性——一条轨迹该包含什么;生产反馈信号——如何把运行路由进评测集;评估的成本——这份账单的另一半;以及审计轨迹与来源——采样绝不能碰的那些记录。