跳到主要内容

348 篇博文 含有标签「observability」

查看所有标签

模型已经在直接与你的客户对话了

· 阅读需 12 分钟
Tian Pan
Software Engineer

在某处,此时此刻,一个 AI 助手正在向潜在客户解释你的产品。它引用的价格是你 18 个月前修改过的,推荐的集成是你上个季度停止支持的,并建议一个返回 410 Gone 的 API 端点。你永远不会看到这段对话。没有分析事件被触发。没有会话录像。潜在客户要么相信了错误答案并提交了一份困惑的支持工单,要么相信了错误答案,转而悄悄购买了模型随口提到的竞争对手的产品。

这不是一个假设的未来问题。AI 推荐已经占据了可观的流量 —— 对于某些技术和电子商务网站,这一比例高达 5–8% —— 而这些推荐背后的答案,是模型在任何时候吸收的关于你的任何信息生成的。你的营销团队花了十年时间学习如何监控品牌搜索、评论网站和社交媒体提及。几乎没有人正在监控增长最快的表面:当有人询问关于你的信息时,模型是怎么说的。

不存在的单一质量指标

· 阅读需 13 分钟
Tian Pan
Software Engineer

在你公司的某个地方,有一张幻灯片上写着一个数字。“AI 质量:87”。上个季度这个数字是 85,所以幻灯片是绿色的。与此同时,你的值班频道里塞满了截图,显示助手正在自信地为你的最大企业客户捏造退款政策。这两件事同时发生,而撒谎的是那张幻灯片。

这张幻灯片背后的管理层需求完全合情合理:给我一个可以追踪的分数,让我知道这玩意儿是在变好还是变坏。这在收入和可用性上行得通,但在 AI 功能上行不通。因为 AI 功能的质量不是一个标量 —— 它是在输入、用户和时间维度上的分布。将这种分布平均成一个数字并不能起到总结作用,反而精准地破坏了决策者所需的信息。

这篇文章讨论的是这两个事实之间的差距:为什么你的评估套件(eval suite)的平均值隐藏了那些真正伤害你的回归(regressions),你应该汇报什么,以及如何向董事会报告的受众展示一个本质上存在波动的指标,且不会在指标下降的第一周就毁掉你的信誉。

你的智能体记忆需要两个时钟

· 阅读需 12 分钟
Tian Pan
Software Engineer

在你的智能体记忆库的某个角落,存放着一个事实,比如“计费 API 返回 XML”。它读起来像是永恒的真理。但它实际上是焊接在一起的两个断言:该 API 在过去的某个窗口期返回了 XML,而你的智能体在某个时刻观察到了这一点——这可能是一个不同的窗口期,也可能是在迁移到 JSON 之后很久。记忆记录没有保留这两个时间戳。当智能体根据这一事实采取行动并导致故障时,你会在事故回顾(post-incident review)中问一个唯一重要的问题:智能体在行动的那一刻相信了什么? 而你的记忆层由于将两个时间轴压缩成了一个扁平的字符串,无法回答这个问题。

数据库工程师在几十年前就解决了这个问题,并给它起了一个平淡无奇的名字:双时态建模(bitemporal modeling)。每个事实都带有两个独立的时钟——它在现实世界中何时为真(有效时间,valid time)以及系统何时获知它(事务时间,transaction time)。金融系统、保险账本和审计级数据库多年来一直依靠这种区分来运行。智能体记忆系统几乎普遍忽略了这一点。这种疏忽现在成了导致一系列故障的根本原因,而我们却一直将其误诊为“幻觉”。

零温度并非确定性:复现那些你无法重新运行的事故

· 阅读需 11 分钟
Tian Pan
Software Engineer

模型给了客户一个错误的、代价高昂的回答。你打开复盘报告(post-mortem),将完全相同的提示词(prompt)粘贴回完全相同的端点,并将 temperature=0,结果你得到了一个不同的答案。不是更坏,也不是更好——只是不同。你本该找出根本原因(root-cause)的 bug 无法按需复现,而那个每个人都告诉你保证能复现的开关刚才却当面撒了谎。

就在这一刻,大多数团队发现“将 temperature 设置为 0”只是民间传说,而非工程控制手段。零 temperature 改变了模型的“采样”(sampling)方式——它强制进行贪婪解码(greedy decoding),始终选择概率最高的 token。它并不能保证两次计算得出的概率本身是完全一致的。而在生产环境的服务栈中,它们通常并不一致。

3% 的回归不会让报警器响起:应对统计性故障的轮值工作

· 阅读需 12 分钟
Tian Pan
Software Engineer

你的轮值制度(on-call rotation)最初是为了捕获一种特定类型的故障,但绝非那种真正会让你的 AI 产品崩溃的故障。它监控的是停止响应的服务、飙升的延迟曲线、超过 1% 的错误率。这些都是阶跃函数(step functions):原本运行正常的东西突然失效了,这种不连续性足以在凌晨 3 点叫醒一名工程师。整个体系——阈值、运维手册(runbooks)、升级策略——都假设故障会自我宣告。

对于一个包含模型在环(model in the loop)的系统,真正关键的失效模式恰恰相反。上周二,你的提取流水线准确率为 94%。这周二,它变成了 91%。没有服务崩溃。每个请求都返回了 200。延迟平稳。输出依然是格式良好的 JSON。但你 3% 的用户现在得到了微妙的错误答案,而且他们不会提交 Bug,因为答案看起来是正确的。由于没有触发条件,寻呼机(pager)保持沉默。等到有人注意到时——通常是愤怒的客户,通常是在几周后——这种回归(regression)在整个过程中一直在静默地累积恶化。

从 Demo 到生产环境的“税收”:原型隐藏了 90% 的 AI 开发工作

· 阅读需 11 分钟
Tian Pan
Software Engineer

演示成功了。你输入了一个问题,智能体调用了三个工具,经过多步计划的推理,最后给出了一个让全场人都为之振奋的答案。有人说:“上线吧。”三个月后,你的产品依然没有上线,而且没人能解释时间都去哪儿了。

时间都花在了这里:演示只占了 10% 的工作,它只是大脑。剩下的 90% 是管道工程——那些在正常运作时无人喝彩,一旦出故障就是灾难性的评估(Evals)、护栏(Guardrails)、可观测性、成本控制和备用路径。这 90% 就是“从演示到生产的税”,而大多数团队在做预算时,却把它当成了一个可以忽略不计的舍入误差。

数据说明了另一番景象。MIT 2025 年的一项企业 AI 研究发现,95% 的生成式 AI 试点项目未能产生可衡量的损益(P&L)影响。另一项分析则更加直截了当:企业每启动 33 个概念验证(PoC)项目,只有 4 个能进入生产阶段。这意味着夭折率高达 88%,而死因几乎从未出现在模型身上,而是演示让你跳过的所有环节。

代理墙钟预算:一场与工具超时机制的赛跑

· 阅读需 12 分钟
Tian Pan
Software Engineer

有一种 Agent 漏洞,当你孤立地观察任何单个组件时,它都不会出现。模型没问题,工具没问题,重试策略也没问题。纸面上的超时值甚至可以说很慷慨。然而,一个通常在 8 秒内完成的工具,却总是在一个已经在 7.9 秒时将其宣告为失败的 Agent 面前折戟。Agent 围绕一个从未发生过的“错误”重新规划,并启动了第二次调用,而第一次调用的结果即将与其发生碰撞。

漏洞不在任何一个框框里。它存在于两个没人同意应该同步的时钟之间的缝隙中。

引用索引失效:当你的分块器开始添加行号前缀时,偏移了一位

· 阅读需 12 分钟
Tian Pan
Software Engineer

分块器开始在每个块前添加 [line N]。Eval 变绿了(通过了)。从那天起,模型生成的每一条引用都指向了实际证据前的一个段落,这种情况出现在该产品所服务的受监管行业的每一份文档中。团队并不是通过评估发现这个问题的,而是通过一位审计人员发现的。审计人员查看了引用的句子,阅读后指出,该句子与其本应支持的断言完全矛盾。

这种回归错误(regression)能躲过代码审查、对三个示例文档的手动 QA 测试以及功能开关(feature-flag)的逐步推送。孤立地看,这些检查都没有错。它们都在问同一个问题——在预期的地方是否出现了引用——但没有一个检查在问审计人员问的问题,即:引用是否指向了断言来源的那个句子。这两个问题之间的差距,正是那个“差一错误”(off-by-one)长期潜伏的地方。

这种失效模式之所以值得专门写篇文章,不在于 Bug 本身。差一错误是陈年旧事了。有趣的地方在于,这个失效是由两个系统共同产生的:它们在整数的结构上保持一致,却在整数的含义上产生了无声的分歧。

你的 Agent 每一轮都在重新生成对话摘要,只因缓存键包含了一个时间戳

· 阅读需 12 分钟
Tian Pan
Software Engineer

一个只被写入却从未被读取的缓存算不上缓存。它只是一个增加了额外延迟、按 KB 计费的日志系统。而这种失效模式最残酷的版本是,从每个角度看缓存都是健康的:set 调用成功,get 调用返回迅速,键(key)格式正确,值(value)有效,TTL 设置合理。唯一的问题是,没有任何一次 get 调用能找到之前 set 调用写入的键,因为键中的一个字段在每次计算时都会发生变化。

这是一个关于调试过程的故事:为了“能分辨出我正在看的是哪条缓存记录”,一位工程师在缓存键中添加了一个时间戳。结果,在没人察觉的两个星期里,系统悄悄地为每场对话多支付了 14 次额外的 LLM 调用费用。

那个将你的系统提示词泄露到客户审计日志中的调试日志器

· 阅读需 11 分钟
Tian Pan
Software Engineer

一位具有安全意识的客户拉取了其租户的审计导出文件,打开 JSON,从一个名为 llm.request.system 的字段中读到了逐字记录的拒绝策略、检索流水线结构以及一些内部产品标识符。没有漏洞利用。没有提示词注入。没有越狱。仅仅是你的平台团队在六个月前添加的一个日志字段,目的是让工程师能够将提示词版本与事件关联起来——结果通过你的企业团队出于 SOC 2 合规原因单独向租户开放的摘要(feed)泄露了出来。

泄露发生在周三下午。你的安全团队是由客户呼叫(paged)的,而不是报警系统。事件时间线显示泄露当天并没有部署——错误配置是在审计摘要扩大其字段白名单的那天发布的,那是另一个团队、另一个迭代周期(sprint)和另一张工单。两名评审员都批准了他们所看到的内容。但没有人从全局组合的角度去审视。

那场无需部署就让你检索召回率减半的 Embedding 弃用事件

· 阅读需 12 分钟
Tian Pan
Software Engineer

在一个 RAG 系统中,可能上线的代价最高昂的嵌入 (embedding) Bug,是那种你的代码库没有任何变化、检索代码没变、索引没变、查询路径也没变的 Bug。然后在第六周的某个周二,有人注意到答案的质量不如从前了。

服务商为你十二个月前构建索引时所使用的嵌入系列发布了停用公告。平台团队将其归档在了一个拥有一年缓冲期的停用仪表盘中,然后就继续处理其他事情了。停用路径并不是一个生硬的截止——而是一个悄无声息的质量退化:被停用的端点开始路由到一个“兼容性”继任者,它返回相同维度的向量,但语义几何空间却有微妙的不同。查询嵌入开始与你一年前嵌入的语料库发生漂移。在六周的时间里,你的常规评估中的 Recall@10 下降了 47%。团队直到一个无关的质量仪表盘达到阈值时才追溯到原因,迫使一名高级工程师进行根因分析,最终发现问题指向了一个在这一年里没人动过的嵌入端点。

团队上线了新提示词模板,评估框架却还在测昨天的旧版本

· 阅读需 10 分钟
Tian Pan
Software Engineer

事件时间线清晰可见。9:02,你的平台团队将 prompt-template@v38 推送到了配置服务。11:14,你的仪表板显示一切正常。16:51,支持团队有人标记了升级件数的激增。17:03,你打开了评估套件,发现回归分数为 0.34,于是进行了回滚。复盘报告称:“在 8 小时内捕获,除了 0.04% 看到该问题的客户外,未造成进一步损害。”工程领导层对响应速度表示赞赏。

但这是错的。回归在 0 小时内就被捕获了。17:03 运行的评估套件与 09:03 运行的是同一个。它一直指向的是 v37。评估框架在进程启动时从配置服务加载了模板,将渲染后的 Prompt 以 Python 对象的形式缓存到了模块级作用域中,并且从未重新读取源文件。你的线上流量在上午 9 点切换到了 v38。而你的评估直到 17:03 有人重启了 Worker 池来“重新运行回归”时才发生变化。在长达 8 小时的时间里,客户交互是基于从未经过评估打分的 Prompt 进行的,而评估系统却一直在给生产环境中根本没人在用的 Prompt 打分。