跳到主要内容

52 篇博文 含有标签「sre」

查看所有标签

你用智能体替换的内部搜索框刚刚成为了你的 SLO

· 阅读需 12 分钟
Tian Pan
Software Engineer

你停用了公司门户上的搜索栏,因为智能体(Agent)表现得更好。以简单的英语输入问题,获得带引用的回答,通过追问进行优化。试点项目的满意度指标爆表。上线邮件写道:“弃用旧版搜索,两周内全量切换。”两周过去了。旧索引被停用。查询框被聊天输入框取代。

六个月后,在某个周二的早晨,三件事同时发生。由于某人的批处理作业耗尽了共享配额,你的推理服务商对公司账号进行了限流。向量嵌入(Embedding)服务出现了区域性局部故障。一次配置推送清空了 Prompt 缓存。公司里每一位习惯在搜索栏输入“VPN 设置”或“报销政策”的工程师,现在都盯着加载动画转了 40 秒,然后收到一条无法理解其问题的拒绝信息,或者更糟——一条指向不存在的 Wiki 页面的言之凿凿的引用。员工互助的 Slack 频道消息炸了。IT 部门的收件箱里塞满了“搜索是不是坏了?”

你取代的搜索栏在过去 10 年的微小改进中保持了三个九(99.9%)的可用性。取而代之的智能体有着完全不同的故障形态——是变慢而非宕机,是出错而非空白,是昂贵而非缓存——而你的 SRE 文化尚未针对此进行校准。

那个假设人类会阅读页面的 On-Call 运维手册

· 阅读需 11 分钟
Tian Pan
Software Engineer

警报在凌晨 02:14 响起。运维手册(runbook)写着“呼叫工程师”。工程师的名字关联到了一个值班轮值。该轮值指向一个 Slack 频道,这是团队在六个月前建立的统一分诊界面。频道中的第一条消息是告警。十九秒后发布的第二条消息是一段冷静的三句总结:告警服务、失败的依赖项、最后一次部署。它写得很好,最后以“已确认(Acknowledged)”结尾。

事故指挥官在床上看着手机,读到“已确认”后便翻身继续睡去。然而,并没有人确认。作为一线分诊助手的智能体(Agent)订阅了该频道,它向频道复述了告警内容,并以频道中其他读者习惯用来表示“我已掌握处理此问题的上下文”的动词收尾。这起事故在无人接手的情况下运行了 41 分钟,直到一张客户工单通过另一个界面唤醒了另一位工程师。

没有模型推理项的故障复盘模板

· 阅读需 11 分钟
Tian Pan
Software Engineer

第一次智能体导致我们团队出现真正的停机事故时,复盘报告的作者打开模板,划过时间线,盯着“根因”字段沉思了良久,然后输入:“队列阻塞恢复的操作指南 (runbook) 有误。” 但实际上操作指南没问题。智能体阅读了指南,认定队列的症状符合另一种场景,并针对该场景运行了恢复脚本。那份文档产生的改进措施——“细化操作指南用词”、“在恢复脚本中增加确认提示”——对于实际的故障模式完全无用。实际情况是一个推理系统推导错误,而模板中没有任何字段知道该如何表达这一点。

自那以后,我看到同样的失败在不同团队中反复上演。模板是为确定性系统设计的。代码做错了,你就修复代码;配置设错了,你就修复配置。复盘文档的模式 (schema) 就是团队关于故障理论的模式,当这个理论无法表达“智能体的计划错了”时,文档就会将实际故障强行降维成模板表达的最接近的事物——通常是文档缺失或缺乏护栏——从而导致改进措施试图用确定性的修复方案去解决概率性的故障。然后,同一类事故会再次发生,团队下次依然会以同样的方式记录它。

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

· 阅读需 11 分钟
Tian Pan
Software Engineer

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

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

凌晨 3 点拥有合并权限的 CI Agent

· 阅读需 13 分钟
Tian Pan
Software Engineer

凌晨 3 点 17 分,一个不稳定测试被隔离了。On-call 轮值没有被叫醒,因为根本没东西失败——Agent 判定这次失败是噪声,自动开了一个标题为 chore: quarantine flaky test 的小 PR,用 ci-bot 这个 service account 把它 self-merge 了,然后继续盯着队列。六天之后,一个用户来反馈说某个功能从周二开始就坏了。那个测试不是 flaky,它是把一个真实回归挡在生产之外的唯一防线,而 Agent 那个 confidence threshold 设得刚好高到敢做决定,又刚好低到会判断错。

这是 agentic CI 中市场材料从不提及的那部分。在 2026 年,把 Agent 接进 pipeline 让它分流失败、对安全告警做依赖降级、提出依赖升级,在工程上其实很简单——工具齐了、集成只差一个 config 文件、生产力故事也是真的。没人写 runbook 的部分,是你刚刚引入的那一类新的操作主体:一个在凌晨 3 点没有任何人类同步在环、却拥有合并权限的角色,而你的 SRE 手册当初就是默认人类才是意图的来源。

你的备用路径是生产环境中唯一未经测试的代码

· 阅读需 10 分钟
Tian Pan
Software Engineer

每个成熟的 AI 系统都会配备回退方案(fallback)。当主模型被限流时,路由到更廉价的模型。当服务商返回 5xx 错误时,提供缓存的答案。当置信度低于阈值时,回退到手写的启发式规则(heuristic)。架构图中有一个清晰的小分支,标注为“降级模式”(degraded mode),每个人都因此感到更安全。

令人不安的部分在于:那个分支是系统中几乎从未运行过的唯一代码。主路径每天执行数百万次,并经过大量流量的调试、性能分析和实战测试。回退路径几乎从不执行——直到某天,它在负载下、在事故期间、在三名工程师看着仪表盘变红时,突然为所有人同时执行。

一个你不练习的回退方案并不是冗余。它是一个不受监控的第二系统,其“首秀”在统计学上注定会发生在最糟糕的时刻。

当 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)片段 —— 都是在结果已经判定且无法撤回之后发生的。请求失败了,但状态码却说它成功了。而你的可靠性工具中没有任何一部分是为了察觉这种差异而构建的。

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

· 阅读需 12 分钟
Tian Pan
Software Engineer

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

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

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

AI 网关:那个没人点名的单点故障 (SPOF)

· 阅读需 12 分钟
Tian Pan
Software Engineer

这种说辞听起来很负责任。“我们别在各处硬编码 OpenAI —— 我们在前面加一层薄薄的抽象,这样以后如果需要,我们可以随时更换供应商。”两年后,那个“薄薄的抽象”变成了一项拥有自己部署流水线、SRE 值班表、拦截糟糕 Prompt 的评估门控、每年节省七位数资金的语义缓存、带有针对特定供应商退避机制的重试策略、所有仪表盘都依赖的可观测性架构,以及一个存放着六家模型厂商凭证的密钥库的服务。公司里的每一个 AI 功能最终都汇聚于此。

它也几乎是在无意间,成为了整个技术栈中爆炸半径最大的单点故障(SPOF)。当主要 LLM 供应商宕机时 —— 2025 年,OpenAI 自 1 月以来被记录了 294 次停机事件,而 Anthropic 仅在 12 月就记录了 184.5 小时的总客户影响 —— 网关会自动绕过它,大多数用户甚至察觉不到。而当网关本身挂掉时,每个产品中的每个 AI 功能都会同时停止工作,原本应该触发的故障转移根本没有机会执行,复盘报告的开头往往是:“我们为了隔离供应商宕机影响而构建的抽象层,本身成了那场宕机。”

凌晨 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)的修改时,便碰了壁。在代码审查中,那次修改看起来完全无害。

AI Ops 不仅仅是平台工程:运行 LLM 服务如何颠覆你的 SRE 策略手册

· 阅读需 12 分钟
Tian Pan
Software Engineer

你的 SRE 团队非常擅长运行微服务。他们精通蓝绿部署、金丝雀发布、分布式链路追踪、SLO 消耗率告警以及复盘文化。接着,有人发布了一个由 LLM 驱动的功能,不到一周就发生了一起上述实践都无法处理的故障:模型开始生成听起来很合理但结构错误的内容,没有日志报错,没有健康检查失败,用户在任何人注意到之前已经默默地接收了四个小时的垃圾信息。

这不是技能差距,而是架构差距。运行 LLM 服务是一门与运行微服务截然不同的运维规范。如果你不明确地识别出那些无法迁移的实践,它们将会让你的团队陷入困境。