跳到主要内容

299 篇博文 含有标签「observability」

查看所有标签

把自己调度进维护窗口的 Agent

· 阅读需 11 分钟
Tian Pan
Software Engineer

凌晨两点值班的资深工程师不会在 Sev-2 事故中跑 schema 迁移。他们不会在发布冻结开始前十分钟重新部署支付服务。他们不会在邮件服务商状态页飘红的时候发起一波营销邮件投放。这些都不写在 JD 里。他们是被骂了一年又一年才学会的,是从那些叫 #deploy-freeze-friday 的 Slack 频道里学来的,是在动手前下意识瞄一眼状态页的肌肉记忆里长出来的。这种上下文不在任何 runbook 里,因为没人觉得它值得被写下来。

现在把同样的活交给一个 Agent。Agent 有工具。Agent 有多步计划。Agent 拥有你愿意写进 system prompt 的每一条策略。Agent 没有的,是那种半下意识的觉察——这个世界现在正着火。所以它就执行计划了。干净利落,信心满满。一头扎进维护窗口。事后复盘里那句话会变成一个新的固定句式:"Agent 没办法知道。"

多模态追踪:当各种模态必须共享一个 ID

· 阅读需 12 分钟
Tian Pan
Software Engineer

一位用户拨通了你的客服 Agent。他们说话,Agent 倾听,用户在通话中途上传了一张错误截图,Agent 同时对图片和转写文本进行推理,最后通话以一封总结修复方案的邮件收尾。三天后用户投诉过来:修复没有生效,邮件也从未送达。你打开可观测性栈,发现三个独立 UI 里躺着三条互不相干的追踪。语音流水线给你一条 ASR 追踪。视觉流水线给你一段图片上传的 span。LLM 调用给你一条带 token 数和工具调用的聊天追踪。这些仪表盘里没有任何东西告诉你:它们其实是同一次对话。

这就是没人愿意写的那种复盘。不是因为数据缺失——每一个模态都老老实实记录了它该记录的东西——而是因为跨模态的"接合"从来就没建起来。每条流水线都从自家模型供应商默认配置里长出了自己的追踪约定,而把它们绑在一起的那一次对话轮次,只存在于设计这个 Agent 的那位工程师的脑子里。

一路重试穿过你限流器的 agent

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的网关给每个 tenant 干净利落地强制执行每秒 100 次请求的限制。dashboard 显示每个 tenant 都舒舒服服地在那个上限之下。但模型 provider 寄来的账单告诉你,你的支出上限照样被打穿了。rollout 电话会议上没有人能给出一个干净的解释。

答案在于限流器和账单衡量的是不同的东西。当用户点击一个按钮时,限流器看到的是一次"用户请求"。而 provider 看到的是一次 planner 调用、三次工具结果反思、一次因更严格 JSON schema 触发的格式修正重试,以及一次最终综合——每一次都带着自己的内部重试预算,在瞬时 429 或 500 回来时就会触发。一次点击可以扇出成三十次模型调用。限流器只数到一次。桶以它被设计容量的三十倍漏水。

在 HTTP 边界上对 agentic 系统做限流,就像在高速公路入口立速限标志,而入口里面的车却在自我繁殖。除非限流器理解了这个循环,否则循环就会绕过它。

长出胳膊和腿的缓存提示词前缀

· 阅读需 11 分钟
Tian Pan
Software Engineer

六个月前,你的提示词前缀是 4,000 tokens。它稳定、缓存预热,几乎可以摊销到不计成本——系统指令的每次调用附加费,相比每次响应的成本,只是一个舍入误差。今天那个前缀变成了 11,000 tokens,你的缓存命中率从 92% 滑到了 31%,你的推理账单上升了 4 倍。团队里没有人能指出是哪个 PR 干的。没有一条 commit message 写着"将提示词增加 7,000 tokens"。每一次修改都很小,每一次修改都有理有据,每一次修改都干干净净地合入了。

提示词前缀长出胳膊和腿,就像地下室积攒纸箱一样。一个团队需要注入用户的订阅等级,这样 agent 才能解释套餐限制。另一个团队需要用户时区的今天日期,这样"明天提醒我"才能工作。第三个团队把当前 A/B 变体名硬塞进去,这样 eval traces 才能切片。市场团队加进了当前促销 banner,这样 agent 才能适时提及它。合规团队加进了功能标志清单,这样模型才能拒绝那些不在灰度名单里的用户访问 beta 功能。每一条都是一行的添加。每一条单独看都站得住脚。但加起来摧毁了你的缓存。

那个谁也不敢从注册表里删掉的死工具

· 阅读需 12 分钟
Tian Pan
Software Engineer

一个工具在你共享的 agent 目录里已经躺了十四个月。它是某位早已离职的工程师为两次组织重组前就被砍掉的工作流接上的,对接的后端服务的归属如今也没人说得清。这个工具定义占 380 个 token。它会出现在组织里每一个 agent、每一轮对话的系统提示中,因为没人能证明它没在被使用,而一旦证明错了,代价比永远扛着它还高。

这个工具就是那个没人敢删的数据库字段,就是那个日志早已轮转干净的定时任务,就是那条你 grep 不到任何引用、但因为 eval() 存在所以你不敢动的死代码。Agent 版本的这个问题更糟,因为持有成本不只是磁盘上的几个字节——它是用 token、用选择准确率、用安全攻击面付出的,而且是在你平台跑的每一次推理里付出。

你的 Agent 读不懂的生产日志

· 阅读需 10 分钟
Tian Pan
Software Engineer

你把事故响应 agent 接入了 Splunk。你在系统提示里给了它查询语法,给了它执行 SPL 的工具,还有一个新鲜的 API token。第一次真正处理告警时,它拉了错的日志,总结了错的服务,信誓旦旦地报了错的客户。集成做得完美无缺,agent 却一文不值。

你忘了什么。十五年的日志惯例、没文档的字段名、跨越三次重组从 ERR 漂移到 error 再到 ERROR 的告警级别字符串、把 customer_id 在认证服务里变成 cust_id_v2_actual、在计费服务里变成 tenant.user.id 的团队特定后缀——这些东西没有一条出现在 prompt 里。你给了 agent 对 API 的访问权,但你没有给它访问那些让 API 变得有用的机构知识的权力。

这种失败的形状比 Splunk 大得多。任何把查询语言暴露给 agent、而底层语料是团队手工塑造了十年的工具,都会撞上这堵墙。Agent 拿到了动词,没拿到名词。

你的智能体审计日志记录了一切,唯独没有记录原因

· 阅读需 12 分钟
Tian Pan
Software Engineer

合规部门给你转发了一张工单。三周前,一名客户的退款请求被你的支持代理拒绝了,他们发起了申诉,现在需要有人解释这一决定。你对此感到很淡定,因为你记录了一切。每一次提示词、每一次工具调用、每一段检索到的内容、每一个 Token 计数、每一项延迟数据——所有这些都在追踪记录(trace)中,你可以在几秒钟内调出它们。

你调出了记录。你可以看到代理收到了退款请求。你可以看到它调用了 get_order_history,接着是 check_return_window,然后是 lookup_policy。你可以看到它检索到的确切政策文本。你可以看到它发送的最后一条消息:拒绝退款。追踪记录是完整的。每一个 span 都是绿色的。但你仍然无法回答那个问题,因为追踪记录显示代理拒绝了退款,并向你展示了它查看过的所有内容,但它没有向你展示为什么这些输入叠加在一起的结果是“不”。原因存在于模型如何权衡上下文,而这种权衡从未成为一种产物(artifact)。它从未在任何地方被记录下来。

这就是追踪记录与解释(explanation)之间的差距,几乎所有声称“我们拥有完全可观测性”的团队都还没有意识到,他们只构建了前半部分。

你的评估集里只有你已经解决的问题

· 阅读需 10 分钟
Tian Pan
Software Engineer

在过去一个季度,你的评估分数从 0.81 上升到了 0.87。团队上线了一个路由器 (router),在困难意图上更换了更强大的模型,微调了系统提示词 (system prompt),并从“处理时间超过一天的工单”中提取并添加了 40 个新的测试用例。仪表盘显示系统变得更好了。NPS 持平。活跃用户数下降了 2%。

有一个简洁的故事可以解释这两个数字,但你可能并不想听:你的评估集只包含你已经解决的问题。那些失败得如此彻底,以至于用户从未提交工单、从未回来、甚至从未出现在你 grep 的任何日志中的查询 —— 它们不在你的测试套件中。它们不在任何人的套件中。评估分数的上升不仅与你在可见的事物上做得更好相一致,也与你在可见的事物上做得更好、但在不可见的事物上依然糟糕透顶相一致。

从 Bug 到行为率:没有复现步骤的 AI 事后分析

· 阅读需 10 分钟
Tian Pan
Software Engineer

用户提交了一个工单。智能体告诉一位付费客户,他们的退款将在 7 小时内处理,而文档中记录的 SLA 是 7 天。附带了截图。你调取了追踪记录,找到了准确的提示词(prompt)、准确的工具调用、准确的模型和种子值(seed)。你进行了复现。模型说是 7 天。你再次复现。7 天。你复现了 100 次。其中 98 次说是 7 天,2 次说是“今天结束前”,但从未说过 7 小时。截图是明确无误的。复现结果却不一致。周五截止的复盘报告现在有一个“根本原因”栏,但你却填不出任何根本原因。

这就是大多数进入复盘阶段的 AI 事故的形态。不是那种明显的宕机——那些会有堆栈追踪和 500 错误率图表,并以每个 SRE 都受训过的方式恢复。棘手的是那些产生了一个错误输出、留下了受害者、在退出时抹除了自身条件,且在你召唤它时拒绝再次出现的单次事件。你使用过的每一个复盘模板都假设存在一个可复现用例。但智能体并不给你提供这些。

演示成功是因为有人在看:会话长度是你的评测套件遗漏的那个维度

· 阅读需 11 分钟
Tian Pan
Software Engineer

你发布会幻灯片上的可靠性数字,来自一些和用户实际使用的会话完全不像的对话。演示是五轮的:打开、提问、看到一个干净的回答、再细化一次、然后在高音上收尾。而你的核心用户昨天跑的那个会话有三十一轮长,包含两次工具失败(智能体用乐观主义掩盖了过去),最后用户放弃并提交了一张工单。两个会话出自同一个模型。第一个发了新闻稿。第二个被归档为"边缘情况"。

会话长度是评测的一个维度,而演示文化系统性地低估了它。我们衡量单轮准确率,是因为单轮准确率能放进幻灯片里,然后当单会话成功率从一个我们从未在任何图表上画过的悬崖上掉下来时,我们感到惊讶。这个悬崖既不是随机的,也不是尾部事件——它是误差累积、注意力漂移以及那些模型不会重新审视的已承诺假设的可预测后果。每个团队应该问的问题不是"这个模型有多好",而是"在我们已经在第一到第二十七轮说过那些话之后,这个模型在第二十八轮有多好"。

填充式工具调用:当智能体在表演勤奋而不是真正干活

· 阅读需 11 分钟
Tian Pan
Software Engineer

打开任何一个生产环境智能体的 trace,看一看在用户提问和第一个真正有用的动作之间到底跑了哪些工具调用。你会看到一个 get_user_profile 返回了一个根本没人用的名字、一个 check_status 返回绿色然后再也没被引用、一个 list_recent_orders 的结果被总结成"ok"然后直接丢掉。这些调用没有一个改变了最终答案。但每一个都花了真金白银的钱、真实的延迟,以及在 trace 里真实占一行。你的智能体已经学会了表演勤奋——而表演勤奋如今是你最大的单一浪费来源。

这就是填充式工具调用:智能体发出一个动作,不是因为它需要那个结果,而是因为"先想一想,再行动"的整体模式在训练时被反复奖励,多到模型现在会把"显得周全"当作回答任何问题的副作用来执行。这是一个 LLM 版本的初级分析师,故意打开五个根本不会读的标签页,好让坐在对面的高级同事看到自己很忙。区别只在于:初级分析师会累。智能体永远不会。

那些由于模型选择了不同的 Token 而无法复现的 Bug

· 阅读需 11 分钟
Tian Pan
Software Engineer

用户提交了一个 bug。你的智能体生成的摘要掉了一段关键内容,或者 JSON 返回格式错误,或者回答一本正经地胡说八道。你打开工单,复制请求,然后重放(replay)。结果正常。你又重放了一次。依然正常。于是你把工单标记为“无法复现”并继续处理其他事情。

Bug 依然在那儿。真实用户依然在遇到它。你之所以关闭工单,是因为你的调试工具链默认了固定的输入会产生固定的输出——而你正在调试的组件实际上是从概率分布中进行采样的。