跳到主要内容

299 篇博文 含有标签「observability」

查看所有标签

工具的默认参数其实是伪装的策略决策

· 阅读需 11 分钟
Tian Pan
Software Engineer

打开任何智能体运行的 trace(追踪),观察一次工具调用。你会看到工具名称以及模型选择传递的参数。你没看到的是它 没有 传递的所有内容。一个仅设置了 querysearch 调用,在运行时仍然具有页面大小、超时时间、结果排序和可见性范围。这些都不是智能体决定的。而是你在几个月前编写工具 schema 时决定的,当时你将这些参数设为可选并留下了默认值。

默认值并非为了方便。它是伪装成合理留白的策略决策。默认的页面大小限制了智能体在一次调用中能看到的范围。默认的超时时间决定了智能体何时放弃并开始即兴发挥。默认的可见性范围决定了“搜索文档”是指公共手册,还是包含未发布路线图在内的整个内部维基。默认的 dry_run 标志决定了智能体的行为是一场演习,还是生产环境中真实的、不可逆转的事件。

在智能体交接处中断的分布式链路追踪

· 阅读需 12 分钟
Tian Pan
Software Engineer

你打开一个失败运行的追踪(trace)。Span 树非常漂亮:用户请求、规划者 Agent 的推理、三次工具调用、Token 计数、延迟,所有这些都整齐地嵌套在一起。然后规划者交接给一个专家 Agent —— 追踪到此结束。并不是出现了错误 Span。它只是停止了。接下来的内容是来自专家 Agent 的另一个、无根的追踪,它从思考的中途开始,没有父级,没有可见的输入,也与导致它的请求没有任何联系。

Bug 就存在于那个间隙中。一直以来都是如此。交接是一个 Agent 的假设与另一个 Agent 的理解相遇的地方,也是你的追踪无法跟随的唯一地方。

这不是日志记录的问题。你的 Agent 可能在两端都正确地发出了 Span。问题在于追踪上下文(trace context)—— 将 Span 缝合成一个故事的线程 ID —— 没能在从调用者到被调用者的跳转中幸存下来。你技术栈中的每个 HTTP 客户端和 gRPC 存根都会免费传播该上下文。但你的 Agent 交接没有这样做,因为没有人告诉它去这样做。

停止并非一种状态:为什么智能体需要类型化的终端原因协议

· 阅读需 11 分钟
Tian Pan
Software Engineer

打开一个 Agent 集群(fleet)的仪表板,你会看到一个干净的数字:完成率,94%。在它下方是一系列运行记录,每条都标记着两种状态之一 —— 正在运行(running)或未在运行(not running)。那 6% “未在运行”的记录看起来完全一样。其中一些完美地完成了任务。一些在离完成还差两步时达到了步骤限制。一些捕获到了工具错误并放弃了。一些正确地判定任务是不可能的。还有一些则干脆断了思路,停止输出 token。

你的监控无法区分这些情况。它只知道流程不再运行了。它不知道 为什么,而“为什么”正是你在决定是否要呼叫(page)值班人员时唯一关心的事情。

当 Agent 出错时谁会被呼叫:针对非确定性系统的轮值制度

· 阅读需 10 分钟
Tian Pan
Software Engineer

值班轮换制度是建立在一个承诺之上的:故障是可以复现的。警报触发,你重新运行请求,观察 Bug 发生,找到错误的提交 (commit),然后回滚部署。这个循环的每一个环节都假设了确定性 (determinism)。同样的输入产生同样的输出,而输出要么是对的,要么是错的,其方式一目了然。

Agent 集群悄无声息地打破了这条链条上的每一个环节。故障发生了一次,其采样温度 (sampling temperature) 你无法重现,所处的上下文窗口 (context window) 也早已被垃圾回收。这里没有“错误的提交”,因为代码从未改变 —— 改变的是模型,或者是检索到的文档,再或者是用户措辞的方式超出了所有人的预料。你回滚了部署,但部署从来都不是问题所在。

于是警报发出了,一名工程师接手了。他们发现了在生产环境中运行 Agent 最令人不安的事实:他们拿到手的是一个无法单步执行 (single-step) 的系统,而摆在他们眼前的运行手册 (runbook) 却是为另一种完全不同的机器编写的。

先返回 200 然后失败的流式响应:中途错误如何破坏你的 SLO

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的可用性仪表盘显示 99.95%。你的用户却说回答在句子中间停住了。两者都是正确的,而这正是问题所在。

HTTP 时代的可靠性技术栈建立在一个假设之上:状态码在请求结束时到达,并总结其命运。200 意味着成功。5xx 意味着重试。负载均衡器计算比例,SLO 仪表盘进行聚合,告警则根据消耗率(burn rate)触发。技术栈的每一层都会读取并信任这个 Header。

流式传输(Streaming)反转了这一假设。当你的服务器刷新第一个 token 的那一刻,它就已经承诺了一个 200 状态码。在那之后发生的任何错误 —— 在第 400 个 token 时的供应商超时、段落中间触发的内容审查过滤、TCP 连接断开、格式错误的工具调用(tool-call)片段 —— 都是在结果已经判定且无法撤回之后发生的。请求失败了,但状态码却说它成功了。而你的可靠性工具中没有任何一部分是为了察觉这种差异而构建的。

具有两种延迟的 AI 功能:你衡量的是一种,用户感知的是另一种

· 阅读需 10 分钟
Tian Pan
Software Engineer

传统的 HTTP 请求只有一个关键的延迟:从请求到响应的时间。那个数字的 p95 就是契约。SRE 监视它,SLO 是针对它编写的,当它退化时就会有人收到告警。一个数字,一个仪表盘,一个真相。

流式 AI 功能在响应变为流的一刻就打破了这一模型,而大多数团队还未察觉。现在有了两种延迟,而且它们是发散的。首字延迟(Time-to-first-token) 是用户在任何事情发生前盯着加载图标的时间。完成时间(Time-to-completion) 是直到回答完全写完的时间。它们受不同力量的影响,由不同的杠杆修复,并且用户感受到的情感权重完全不同 —— 而几乎每个团队都只衡量第二个指标,因为那是 HTTP 框架免费提供给他们的数字。

Agent 调试器没有断点:为什么追踪优先工作流正在取代单步执行

· 阅读需 11 分钟
Tian Pan
Software Engineer

当你第一次尝试像调试服务那样调试 Agent 时,你会发现以往的肌肉记忆完全派不上用场。你设置了一个假设的断点——虽然 IDE 中没有面板可以放置它,但你在脑海中想象了一个——就在 planner 选错工具的那一步。你使用相同的输入重新运行。这一次,planner 选择了正确的工具。你再次运行。它又选了一个你从未见过的第三种工具。Bug 是真实存在的,你的同事今天早上复现了两次,而你用了十五年的调试器突然间变成了博物馆里的陈列品。

这里失效的心智模型并不是“使用调试器”,而是背后更深层的假设:即一个程序在给定相同输入的情况下,会产生相同的执行过程。现代调试器中的每一项功能——断点、单步跳过 (step-over)、观测表达式 (watch expressions)、条件断点、热重载——都是建立在这种确定性之上的。你暂停执行是因为暂停是有意义的。你向前单步执行是因为下一步是可预知的。你检查一个变量是因为它的值是一个事实,而不是从某种分布中随机抽取的结果。

拒绝“大声失败”的 Agent:过度补偿的回退机制如何掩盖生产环境的质量回退

· 阅读需 12 分钟
Tian Pan
Software Engineer

你的状态页显示为绿色。你的错误率为零。你的 p95 延迟看起来比上周略好。而在上周二,eval-on-traffic 指标在悄无声息中下降了四个点,整整九天都没人发现原因。因为当质量回退最终突破告警阈值时,已经有四个交织在一起的根因叠加在一起,团队已经无法分辨是哪一个最先引发了下滑。

这是 2026 年成熟智能体系统的主要故障模式,它不是任何单一组件的 bug。它是团队刻意构建的防御栈——那些出于好心、一个接一个添加的安全网——所产生的累积效应。主模型返回了垃圾内容;重试成功了。重试失败了;更便宜的回退(fallback)模型给出了答案。回退模型的输出格式错误;包装器(wrapper)将其重写为看起来合理的形状。包装器记录了一个软告警(soft warning)。没有人针对软告警设置告警。用户收到一个看似正确、交付流畅,但实际上比系统设计初衷要差的答案。

鲁棒层起作用了。质量表现却崩塌了。而告警机制是为鲁棒层存在之前的世界构建的。

AI 功能的自带密钥 (BYOK):没人预估过成本的销售驱动型架构重构

· 阅读需 11 分钟
Tian Pan
Software Engineer

你正在对接的采购团队最终会提出一个重置你架构的问题:“我们可以自带模型 API 密钥吗?”回答“可以”能赢得订单。但回答“可以”同时也意味着你的信任边界、成本边界和运营边界发生了转移 —— 而大多数产品团队只有在合同签署、第一个月的使用产生了一个没人知道如何回答的服务工单后,才会发现这一点。

BYOK 在公司内部推销时被视为一个开关。客户粘贴一个密钥,你的代码从保险库(Vault)读取它而不是从你自己的账户读取,然后推理流程照常进行。但这并不是一个开关。这是一场由销售驱动的架构重构,它会波及成本分摊、安全事件响应、可观测性、速率限制、模型版本锁定以及值班问责。那些在没有意识到这一点的情况下就交付产品的团队,最终会在一年后为了修复这些问题而重构整个平台层,而付费企业客户则在焦急等待。

延迟感知工具选择:当“当下的足够好”优于“未来的最出色”

· 阅读需 11 分钟
Tian Pan
Software Engineer

你智能体系统提示词中的工具描述是一个六个月前的评估产物(eval artifact)。它说 search_pricing 返回“带有结构化定价的最新库存数据”,规划器(planner)对此深信不疑,因为自描述调优的那天起,提示词中的任何内容都没有更新过。而实际上,在过去的 40 分钟里,search_pricing 端点的 p95 延迟一直保持在 11 秒,因为上游供应商正在对你的账户进行限流。而那个被提示词描述为“可能略微陈旧”的更便宜的 search_cache 工具,只需 200 毫秒就能返回同样的答案。但规划器还是选择了 search_pricing,因为描述读起来仍和评估时一样,且规划器没有任何关于目前调用这两个工具成本的信号。

这就是静态工具描述的结构性失效。规划器是在根据一个已经发生变化的世界快照做出路由决策。工具选择实际上并不是一个能力问题——大多数生产环境中的智能体都有两三个在回答内容上高度重合的工具——它本质上是一个“等待成本”问题,而等待成本正是你的提示词模板所看不见的东西。

凌晨 3 点处理一个没有报 500 错误的 AI 功能报警

· 阅读需 13 分钟
Tian Pan
Software Engineer

传呼机在凌晨 3:02 响起。你眯起眼睛盯着手机,预料着那些常见故障:数据库故障转移、CDN 边缘节点失联,或者是某个八个月没人碰过的服务出现了 500 报错峰值。然而,警报显示的是:summarizer.eval-on-traffic.helpfulness rolling-1h: 4.21 → 4.05 (Δ -0.16)。没有 HTTP 错误。没有延迟峰值。没有服务宕机。系统在过去一小时内处理的每一个请求都返回了 200,并且响应体解析正常。然而,情况显然比午夜时分变糟了,而值班轮换要求你查明原因。

这种值班任务是标准的运维手册中从未提及的。出故障的东西并没有“坏掉”——它只是退化(regress)了。你多年来追踪的错误预算是以可用性和延迟来衡量的,而触发此次报警的故障模式在两者中都不可见。报警是真实的,客户受到的影响也是真实的,而你通常的诊断循环——检查部署日志、检查依赖图、查找错误的发布版本、执行回滚——在你意识到那个“错误的发布”可能只是昨天下午 4 点上线的一个 30 行系统提示词(system-prompt)的修改时,便碰了壁。在代码审查中,那次修改看起来完全无害。

重复问题检测:你的单轮评估无法察觉的会话级盲点

· 阅读需 12 分钟
Tian Pan
Software Engineer

用户打开你的聊天窗口,提了一个问题,得到一个评估套件打分为 4.6(满分 5 分)的回答。接着,他们换了一种说法问了同样的问题。同样的回答,同样的分数。他们又试了一次,这次用了人们在怀疑机器没在听时常用的套话——“我实际上想做的是……”——然后他们关闭了标签页。从模型的视角来看,这是三个干净的问答轮次。从仪表盘的视角来看,这是一个活跃的会话。但从用户的视角来看,这是一个连续三次失败的产品,而且以后再也不会打开了。

这就是“单轮评估”(per-turn evaluation)无法察觉的失效模式。孤立来看,每一轮对话似乎都是正确的。裁判(Judge)给了赞。幻觉检测器保持沉默。相关性评分很高。然而,整个对话作为整体并没有解决任何问题——而这正是用户真正评估你的单位。