阿伦开了一家全自动机器人餐厅,后厨的核心是一台叫「小智」的炒菜机器人。小智的工作方式很简单:尝一口锅里的菜(感知),判断要不要加盐(决策),伸手翻炒两下(执行),再尝一口确认味道(反馈),然后进入下一轮——这就是一个每天运转上千次的闭环循环。可麻烦的是,它也会出状况:舌头上的传感器突然失灵、锅铲卡住不动、火候莫名其妙飙到危险值。如果没人管,一锅菜糊掉是小事,整个后厨烧起来才是大事。 于是阿伦给小智设计了一整套「故障自愈系统」:先学会分辨哪些是异常,再决定什么时候该果断关火(熔断)、什么时候该把菜倒掉重做(回滚)、什么时候换个菜谱继续营业(降级),同时在后厨装上摄像头和温度计(可观测监控),实在搞不定就呼叫大厨(人工介入)。这套从厨房总结出的生存法则,正是 AI 闭环系统(Loop Engineering)里的故障检测与恢复机制。下面我们跟着阿伦的厨房,把这套「自愈之道」一层层拆开。

岗位关联

学会这套故障自愈设计,你就能像给厨房装保险丝一样,让 AI 闭环系统在无人盯守时也能自我修复——这正是 SRE 与平台工程师从「救火队员」升级为「系统设计师」的核心能力。

目录
  1. 可视化演示
  2. 故障全景图:先看清后厨里的百种事故
  3. 异常识别:舌头如何判断「太咸了」
  4. 熔断策略:锅冒烟就果断关火
  5. 状态回滚:糊了就重做,别硬救
  6. 自动恢复:等待、换锅、换菜谱
  7. 可观测监控:后厨的摄像头与仪表盘
  8. 人工介入:请大厨出山
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示NLP文本分类的完整处理流水线:从分词、词嵌入、编码到池化和分类,逐步演示文本如何被转化为分类结果。

本节配有交互动效(进入视口后自动加载,约 3KB)。

分词阶段 将输入文本切分为Token序列 BPE/WordPiece子词分词器常用 tokens=Tokenize(text) 分词是NLP流水线的第一步,将文本转为可处理的离散单元

故障全景图:先看清后厨里的百种事故

有一天晚上,阿伦的后厨同时出了好几件怪事:盐罐卡住出不了盐、灶台火苗忽大忽小、出水阀滴漏打湿了电路板。小智手忙脚乱,一会儿去拍盐罐,一会儿去调火,结果哪件都没处理好。阿伦赶回来第一件事不是修设备,而是掏出一个本子,把这些事故分门别类记下来:是原料问题、加工问题,还是出菜问题?每类有多严重?源头在哪?这就是故障检测的第一步——先看清故障全景,而不是头痛医头。

在 Loop 系统中,「故障全景图」同样是从三个层次观察闭环:输入型故障(数据源中断、传感器漂移)、处理型故障(模型推理错误、逻辑死循环)、输出型故障(执行器失效、下游拒绝服务)。每一类故障还要评估影响面:是单次循环失败,还是会让整个闭环越跑越偏?定位源头后,要把故障记录进台账,方便后续统计规律。

衡量一个闭环系统健康程度,最直观的指标是故障率。假设一天内小智完成 1000 轮炒菜,其中 15 轮出了岔子,那故障率就是 1.5%。

有了这份故障台账,阿伦才敢说「我心里有数了」。对 AI 闭环系统来说,故障全景图的意义不是消灭故障,而是把「未知的混乱」变成「已知的分类」,为后面的自动检测和恢复打下基础。

F=CfailedCtotal\displaystyle F = \frac{C_{\text{failed}}}{C_{\text{total}}}
故障率等于失败轮次除以总轮次,它就像后厨的事故率,告诉我们系统一天有多少比例的时间在「带病工作」。
  1. 统计失败轮次$C_{\text{failed}}$ 表示观测窗口内循环执行失败的次数,比如小智炒糊或漏料的轮数。
    Cfailed=失败次数C_{\text{failed}} = \text{失败次数}
  2. 统计总轮次$C_{\text{total}}$ 表示窗口内所有循环次数,等于成功与失败之和,是分母。
    Ctotal=Csuccess+CfailedC_{\text{total}} = C_{\text{success}} + C_{\text{failed}}
  3. 计算故障率两者相除得到 $F$,$F$ 越接近 1 说明系统越不稳定,越接近 0 说明越健康。
    CfailedCtotal\frac{C_{\text{failed}}}{C_{\text{total}}}

异常识别:舌头如何判断「太咸了」

小智的舌头其实是一排传感器,能测出菜汤的咸度。可「咸」和「太咸」之间没有绝对标准——小智是靠什么判断的呢?它记得前十几锅菜的咸度大概都在 4 到 6 之间,平均值是 5。当某一锅突然测出咸度 9,跟平时的差距大到离谱,它就判定:出问题了。这个「跟平时比差多少」的思路,就是异常识别的核心。

技术上说,异常识别需要在滑动窗口内维护一个「正常基线」——用最近 N 个样本的均值和标准差刻画。当前新样本如果偏离均值太远(用 Z 分数衡量),就标记为异常。这就像小智不是拿一个死标准比,而是动态参考「最近一段时间的口味」,今天客人偏淡就跟着调,明天偏咸也跟着变。

这套动态基线的另一个好处是能捕捉「缓慢漂移」——比如小智的传感器随着老化,测出的咸度每天偏高一丁点,固定阈值永远发现不了;而滑动窗口跟着真实历史走,漂移累积到一定程度自然就超过 $\unicode{0.3em}$ 标准差了。阿伦常说:好的舌头不是死记一个咸度,而是知道「最近正常是什么样」。

μ=1N∑i=1Nxi,σ=1N∑i=1N(xi−μ)2,z=∣x−μ∣σ\displaystyle \mu = \frac{1}{N}\sum_{i=1}^{N} x_i,\qquad \sigma = \sqrt{\frac{1}{N}\sum_{i=1}^{N}(x_i - \mu)^2},\qquad z = \frac{|x - \mu|}{\sigma}
先算出窗口内样本的均值 μ 和标准差 σ,再算新样本偏离均值多少个标准差(Z 分数)。Z 分数超过预设阈值 τ,就判为异常。
  1. 计算窗口均值把所有样本加起来除以个数,得到平均值 $\mu$,它就是「最近口味的中心」。
    μ=1N∑i=1Nxi\mu = \frac{1}{N}\sum_{i=1}^{N} x_i
  2. 计算标准差每个样本与均值之差的平方求平均再开方,得到波动幅度 $\sigma$。
    σ=1N∑i=1N(xi−μ)2\sigma = \sqrt{\frac{1}{N}\sum_{i=1}^{N}(x_i - \mu)^2}
  3. 计算 Z 分数新样本与均值之差除以标准差,得到它以多少个标准差偏离基线。
    z=∣x−μ∣σz = \frac{|x - \mu|}{\sigma}
  4. 阈值判定当 $z > \tau$(如 $\tau=2.5$)时判定为异常,否则继续正常循环。
    z>τ⇒异常z > \tau \Rightarrow \text{异常}

熔断策略:锅冒烟就果断关火

小智有一次翻炒时发现锅底冒起了浓烟——油温已经失控。它没有继续硬着头皮翻下去,而是第一时间拧灭了燃气灶。阿伦事后表扬它:火都烧起来了还翻什么锅?先关火,最多损失这一锅菜;继续翻下去,厨房都得烧没。这就是熔断策略的直觉:与其带病硬扛导致整个系统雪崩,不如先停下来保护大局。

在 Loop 工程里,熔断器只有三种状态,像燃气灶的熄火保护开关一样自动流转:

  • CLOSED(关闭):一切正常,请求照常放行;
  • OPEN(熔断):连续失败达到阈值,直接拒绝继续执行循环,快速失败;
  • HALF-OPEN(半开):熔断一段时间后放一两个试探请求,成功就恢复,失败就再次熔断。

半开探测是熔断器最聪明的设计。小智关火后不是干等着,而是等锅凉了,小心翼翼地拧开小火苗试一下,如果火苗稳住了,就恢复正常大火;如果又冒烟,立刻再次关火并拉长等待时间。对 AI 闭环系统来说,这个「试探」避免了两个极端:要么恢复得太急导致二次雪崩,要么永远不敢恢复导致服务长期瘫痪。

Rfail=failuresattempts≥θ⇒OPEN\displaystyle R_{\text{fail}} = \frac{\text{failures}}{\text{attempts}} \geq \theta \Rightarrow \text{OPEN}
当一段时间内的失败率(失败次数除以尝试次数)达到阈值 θ 时,熔断器从 CLOSED 跳闸到 OPEN。
  1. 统计失败次数记录当前窗口内失败的调用次数 failures,比如小智连续翻炒失败几次。
    failures=窗口内失败次数\text{failures} = \text{窗口内失败次数}
  2. 统计尝试次数记录窗口内总尝试次数 attempts,它是计算失败率的分母。
    attempts=窗口内总尝试次数\text{attempts} = \text{窗口内总尝试次数}
  3. 失败率超限判断两者相除得到失败率 $R_{\text{fail}}$,当它大于等于阈值 $\theta$ 时,熔断器跳闸。
    failuresattempts≥θ⇒OPEN\frac{\text{failures}}{\text{attempts}} \geq \theta \Rightarrow \text{OPEN}

状态回滚:糊了就重做,别硬救

有一次小智把一整锅红烧肉炒糊了,锅底的焦味直冲天花板。小智没有试图往糊菜里加糖掩盖,而是直接把菜倒进垃圾桶,从备菜阶段重新开始——还好它在每道菜下锅前都拍了一张「备菜记录表」,照着记录重新切配,十分钟后一锅崭新的红烧肉又出锅了。这个「倒掉重做」的动作,就是状态回滚。

AI 闭环系统在高负荷运转中会不断产生中间状态:模型参数更新到一半、队列里积压了半成品、外部服务已经收到了部分请求。如果直接继续跑,系统会在一个「半坏」的状态上越走越歪。正确做法是像小智一样,定期把「备菜记录表」保存下来——这就是检查点(checkpoint)/ 快照。一旦发现状态异常,立刻回滚到最近一个完好的检查点,从那里重新开始。

需要注意的是,回滚不是万能药。如果配料已经被其他菜用掉了——也就是外部依赖已经在旧状态上产生了副作用——那单纯回滚本地状态并不能还原世界。所以在设计回滚机制时,一定要提前想好哪些状态可以安全回滚、哪些已经「泼出去的水收不回来」。

S←Ck,Δt=tnow−tk\displaystyle S \leftarrow C_k,\qquad \Delta t = t_{\text{now}} - t_{k}
系统状态 S 被恢复为最近一个有效检查点 C_k,回滚损失的时间窗口是当下时刻与检查点保存时刻之差。
  1. 选择检查点在所有已保存的检查点里选出最近且有效的那个,记作 $C_k$。
    Ck=最近的有效检查点C_k = \text{最近的有效检查点}
  2. 恢复系统状态把当前系统状态 $S$ 覆盖为检查点内容,让系统从那一刻的干净状态重新出发。
    S←CkS \leftarrow C_k
  3. 计算回滚窗口用当前时刻减去检查点时间,得到 $\Delta t$,它代表这段时间内的工作全部作废。
    Δt=tnow−tk\Delta t = t_{\text{now}} - t_{k}

自动恢复:等待、换锅、换菜谱

回滚只是把系统拉回「能重新开始」的状态,真正的挑战在于怎么重新开始。小智第一次恢复时栽过跟头:它刚从检查点恢复,立刻把火开到最大猛炒,结果锅又糊了。第二次它有经验了——先等三秒,再试;还是不行,等六秒;再不行,等十二秒。每一次重试的间隔翻倍,给系统留出喘息时间。这就是指数退避。

自动恢复流程通常分三个层次:第一层是有限重试,不能无限循环重试,否则失败的请求会把系统压垮;第二层是指数退避,随着失败次数增加,等待时间成倍拉长;第三层是服务降级,如果重试多次仍然失败,就不再死磕炒菜,而是临时改做凉拌菜,保证餐厅还能营业。恢复成功后,系统还要主动确认:连续几次正常循环,才算真正「出院」。

阿伦给小智定了条规矩:每次降级都要在工作日志上记一笔,等客流少的时候再研究怎么把炒菜功能修好。对 AI 系统来说,降级不是失败,而是「留得青山在」的生存智慧——推荐系统挂了大不了推热门榜单,支付闭环断了先走人工收款,保住主流程才能换来修复的时间。

tn=tbase×2n+jitter\displaystyle t_n = t_{\text{base}} \times 2^{n} + \text{jitter}
第 n 次重试前的等待时间等于基础等待时间乘以 2 的 n 次方,再加上一个随机抖动,避免所有请求在同一时刻扎堆重试。
  1. 设置基础等待$t_{\text{base}}$ 是第一次重试前的等待时间,比如小智的 3 秒。
    tbase=基础等待时间t_{\text{base}} = \text{基础等待时间}
  2. 计算指数级间隔$2^{n}$ 让等待时间随重试次数指数增长——第 0 次等 1 倍,第 1 次等 2 倍,第 2 次等 4 倍。
    tbase×2nt_{\text{base}} \times 2^{n}
  3. 加入随机抖动加上 jitter 随机项,让大量客户端不要在同一秒同时重试,避免「重试风暴」。
    tn=tbase×2n+jittert_n = t_{\text{base}} \times 2^{n} + \text{jitter}

可观测监控:后厨的摄像头与仪表盘

小智的自愈能力再强,阿伦也不会完全不管它。他在后厨装了一整套监控:角落的摄像头记录每一锅菜的操作录像,灶台上方的温度计画出火候曲线,小智自己还写工作日志——每轮循环尝到什么咸度、加了什么料、翻炒了几秒。有了这些,小智报「出错了」的时候,阿伦只要回放录像和曲线,三分钟就能定位是传感器失灵、火候失控还是调料耗尽。

对应到 AI 闭环系统,可观测性有三大支柱:

  • 日志(Logs):每条循环的详细记录,像小智的工作日记,适合排查具体问题;
  • 指标(Metrics):可聚合的数值画像,比如循环成功率、平均响应时长、熔断次数,适合看趋势;
  • 链路追踪(Traces):一次请求从感知到执行的完整路径,适合定位慢在哪一环。

监控不只是「看看」,它要驱动告警。告警必须分级,如同后厨的黄灯和红灯:黄灯是「留意一下」,由小智自动处理;红灯是「立刻上报」,必须马上打断值班人员。比如 5 分钟内错误次数超过阈值,就要拉响红色告警。

阿伦的监控原则是「先能看见,再能控制」。如果小智没有日志、没有指标曲线,那它喊的每一声「救命」都是无意义的噪音。可观测体系的意义在于:让一次故障从「一个模糊的坏事」变成「一条可以定位到具体环节的线索链」。

alert={1if count(error,5 min)≥τ,0otherwise\displaystyle \text{alert} = \begin{cases} 1 & \text{if } \text{count}(\text{error}, 5\,\text{min}) \geq \tau, \\ 0 & \text{otherwise}\end{cases}
告警触发的条件:在 5 分钟窗口内统计到的错误次数大于等于阈值 τ,就发出告警;否则保持安静。
  1. 统计窗口内错误滑动统计最近 5 分钟的错误发生次数 count(error),这是判断的依据。
    count(error,5 min)\text{count}(\text{error}, 5\,\text{min})
  2. 与阈值比较当错误次数达到预设阈值 $\tau$,说明系统出了问题且可能正在恶化。
    count(error,5 min)≥τ\text{count}(\text{error}, 5\,\text{min}) \geq \tau
  3. 输出告警信号条件成立时 alert 置 1 并通知值班人员,不成立则置 0 保持静默。
    alert=1 or 0\text{alert} = 1 \ \text{or} \ 0

人工介入:请大厨出山

自动恢复做得再完备,也总有机器搞不定的事:比如小智连续熔断五次、降级也救不回来,或者它遇到了从未见过的食材,完全不知道该怎么处理。这时候系统应该做什么?答案是:停止自救,呼叫大厨。小智的求救按钮连着一个分级告警系统——黄灯自己消化,红灯响铃加震动,直接通知阿伦的手机。

人工介入最讲究的是「边界」:不是所有小波动都要惊动人类,否则值班的人会被告警淹没,真正出大事时反而麻木了。正确的边界是:自动机制能处理的,绝不上报;自动机制明确失败的,立刻上报;上报时必须附带完整的上下文——哪一环出的问题、已经尝试了哪些恢复手段、当前系统处于什么状态。阿伦接管后,他和小智之间还有权限约定:关键时刻人可以强制接管,但每次接管都要留痕,方便事后复盘。

衡量人工介入效率的指标是 MTTR(平均修复时间)。它由三段时间组成:发现故障的时间、处理故障的时间、事后复盘的时间。

阿伦把每次「出山救火」的经验都写进小智的菜谱知识库,让它下次遇到类似问题能自己处理。人工介入的最终目的,恰恰是让自己越来越少被惊动——每一次成功的救火,都应该变成自动恢复系统的一次迭代升级。

MTTR=Tdetect+Thandle+Treview\displaystyle \text{MTTR} = T_{\text{detect}} + T_{\text{handle}} + T_{\text{review}}
平均修复时间等于故障被检测出来所花的时间、人工或自动处理所花的时间、以及事后复盘总结所花的时间之和。
  1. 检测耗时$T_{\text{detect}}$ 是故障从发生到被发现的时间,监控和告警越灵敏,这段越短。
    Tdetect=故障发现时刻−故障发生时刻T_{\text{detect}} = \text{故障发现时刻} - \text{故障发生时刻}
  2. 处理耗时$T_{\text{handle}}$ 是从接手到恢复服务的时间,包括熔断、回滚、重试等操作。
    Thandle=恢复时刻−故障发现时刻T_{\text{handle}} = \text{恢复时刻} - \text{故障发现时刻}
  3. 复盘耗时$T_{\text{review}}$ 是事后分析根因、改进监控与代码的时间,它决定了下次同类故障会不会更快恢复。
    Treview=复盘结束时刻−恢复时刻T_{\text{review}} = \text{复盘结束时刻} - \text{恢复时刻}

AI 应用场景

电商推荐系统的实时闭环守护

阶段:模型部署与反馈闭环

解决的问题:推荐系统每时每刻都在跑「推荐 → 用户反馈 → 模型更新」的闭环,一旦深夜新上线的模型出现 bug,点击率可能断崖式下跌。传统做法等第二天数据分析师发现报表异常,早已损失了整晚的流量。

具体案例:某电商平台给推荐闭环配置了滑动窗口异常检测,实时监控点击率的 Z 分数。某次凌晨 2 点点击率骤降触发告警,熔断器自动将流量切回上一个稳定模型版本,并在指数退避后尝试重新上线新模型。整个自愈过程只用了 4 分钟,值班工程师收到告警时服务已自动恢复。

自动驾驶感知闭环的安全降级

阶段:感知-决策-执行闭环执行

解决的问题:自动驾驶车辆是一个高实时性的闭环系统:传感器 → 融合感知 → 规划决策 → 底盘执行。如果激光雷达在高速上突然失效,系统必须在一瞬间决定是继续开、减速还是靠边停。

具体案例:某自动驾驶公司的感知模块在雨天出现帧丢失率升高,异常检测立刻识别到融合置信度滑出基线,熔断策略切断了低置信度的视觉输入通路,系统降级为「雷达 + 保守限速」模式,同时向安全员发出分级告警。司机接管后,后台利用链路追踪定位到摄像头进水问题,事后通过复盘将雨天规则写回了系统。

LLM 智能体工作流的自愈设计

阶段:Agent 工具调用闭环

解决的问题:大模型智能体(Agent)在执行多步任务时,本身就是一个「推理 → 调工具 → 看结果 → 再推理」的闭环。当外部 API 连续报错,Agent 往往会陷入反复调用同一个失败工具的「空转死循环」,白白消耗 token 和时间。

具体案例:某智能客服 Agent 在调用天气 API 时连续失败 3 次,熔断器触发后停止调用该工具,自动回滚对话状态到「询问用户目的地」这一步,并降级为「回答常识性问题 + 留下联系电话」的兜底策略。半开探测成功后,Agent 恢复正常服务,全程无需人工介入。

Python 演示

python110 行
# -*- coding: utf-8 -*-"""Loop闭环故障检测与自愈模拟器 模拟对象: 机器人炒菜闭环感知(尝味) -> 决策(调味) -> 执行(翻炒) -> 反馈(再尝)当火候失控时, 依次展示:异常识别 -> 熔断保护 -> 状态回滚 -> 自动恢复"""import mathimport randomfrom collections import deque  class RollingDetector:    """滑动窗口检测器: 均值加Z分数识别异常"""     def __init__(self, limit=2.5, size=12):        self.limit = limit        self.buffer = deque(maxlen=size)     def is_anomaly(self, value):        self.buffer.append(value)        if len(self.buffer) < 6:            return False        mean = sum(self.buffer) / len(self.buffer)        var = sum((x - mean) ** 2 for x in self.buffer) / len(self.buffer)        std = math.sqrt(var)        if std == 0:            return False        return abs(value - mean) / std > self.limit  class CircuitBreaker:    """熔断器: 连续失败达到上限后跳闸, 停止放行请求"""     def __init__(self, fail_limit=3):        self.fail_limit = fail_limit        self.fail_count = 0        self.is_open = False     def ok(self):        self.fail_count = 0        self.is_open = False     def fail(self):        self.fail_count += 1        if self.fail_count >= self.fail_limit:            self.is_open = True  def backoff(attempt):    """指数退避: 0.2s, 0.4s, 0.8s... 附带随机抖动"""    return 0.2 * (2 ** attempt) + random.uniform(0, 0.05)  def stir(value):    """执行翻炒动作, 火候超限时抛异常"""    if value > 90:        raise RuntimeError("锅铲卡住: 火候超限")    return value * 0.99  def main():    detector = RollingDetector()    breaker = CircuitBreaker()    backup = 55.0    attempt = 0     print("===== Loop闭环故障检测与自愈模拟 =====")    for tick in range(60):        if 30 <= tick < 48:            real_value = 50 + (tick - 30) * 3.0        else:            real_value = 50 + 10 * math.sin(tick * 0.6)         sensed = real_value + random.uniform(-2, 2)         if detector.is_anomaly(sensed):            print("[异常识别] tick=%02d 火候偏离基线, 记录警告" % tick)         if breaker.is_open:            delay = backoff(attempt)            print("[熔断] tick=%02d 循环暂停, 回滚到备份值 %.1f, 等待 %.2fs 后重试"                  % (tick, backup, delay))            breaker.fail_count = 0            attempt += 1            if attempt >= 4:                print("[降级] tick=%02d 多次重试未果, 降级为凉菜方案" % tick)                breaker.is_open = False            continue         try:            stir(sensed)            breaker.ok()            backup = sensed            attempt = 0        except RuntimeError:            breaker.fail()            if breaker.is_open:                print("[熔断] tick=%02d 连续失败, 熔断器跳闸, 状态回滚到 %.1f"                      % (tick, backup))            else:                print("[重试] tick=%02d 翻炒失败, 剩余容忍次数 %d"                      % (tick, breaker.fail_limit - breaker.fail_count))     print("===== 模拟结束: 系统已自愈 =====")  if __name__ == "__main__":    main()
目的:完整模拟一个 AI 闭环从正常运转、异常识别、熔断跳闸、状态回滚到自动恢复的整个自愈流程,跑一遍就能直观看到每个机制在什么时刻被触发。
  1. self.buffer.append(value)新感知到的样本进入滑动窗口,旧的自动被挤出,保持窗口大小固定。
  2. return abs(value - mean) / std > self.limit这就是 Z 分数判定:偏离超过阈值就判定为异常。
  3. if self.fail_count >= self.fail_limit: self.is_open = True连续失败达 3 次,熔断器跳闸。
  4. return 0.2 * (2 ** attempt) + random.uniform(0, 0.05)指数退避的核心实现:间隔翻倍,还加了抖动。
  5. breaker.ok(); backup = sensed翻炒成功后更新熔断器状态,并把当前值记为新的备份基准。
  6. if breaker.is_open:熔断期间不再执行翻炒,直接回滚到备份并等待退避。
  7. attempt += 1` 与 `if attempt >= 4重试超过 4 次仍失败,触发降级方案,避免无限重试拖垮系统。

常见误区

误区「我把 Z 分数阈值设成 0.5,这样系统稍微有点风吹草动我就能发现,肯定更安全!」

正解阈值过小等于让小智每一锅菜都喊「异常」——客人口味自然波动、传感器一丁点噪声都会触发警报。结果熔断器频繁跳闸,正常请求大量被拒,系统从「偶尔生病」变成「长期瘫在 ICU」。阈值是灵敏度与误报率的平衡,通常 Z 分数取 2.5 到 4 之间,宁可漏掉一些微小波动,也别让系统被误报折磨到瘫痪。

为何常见:人天生对「风险」敏感,总觉得发现得越早越好,却忽略了告警和熔断本身都有成本,过度灵敏会导致「狼来了」效应。

误区「熔断后应该马上重试,多试几次不就恢复了吗?等太久客人岂不是等急了?」

正解锅还烫着就去掀盖子,只会再被烫一次。熔断期间外部依赖往往还没恢复,立刻重试会形成「所有请求同时冲击还在冒烟的系统」的重试风暴,反而加重故障。正确做法是走指数退避:等 1 秒、2 秒、4 秒……给系统留出恢复窗口;再用半开探测放行少量试探请求,确认真好了才全量放开。

为何常见:「积极重试 = 积极修复」的直觉在单机场景成立,但在分布式高并发场景下,盲目重试会让故障像雪崩一样放大。

误区「只要我有检查点,回滚之后系统就跟故障前一模一样,啥都没损失。」

正解回滚只能还原「系统内部的本地状态」,还原不了「系统外部的副作用」。就像炒糊的菜倒掉重做容易,但腌好的酸菜已经被隔壁桌吃掉了,这盘菜就再也无法用那种配料还原。外部 API 已经发出的请求、用户已经收到的推送、数据库里已被其他事务消费的记录,都无法靠回滚撤销。所以设计回滚方案时必须区分「可回滚状态」与「不可回滚副作用」,必要时做补偿操作。

为何常见:人们习惯用「撤销键」的思维理解回滚,但分布式系统没有全局撤销键,只有「尽力回到最近一致点」。

误区「系统都全自动了,还配什么值班人员?让 AI 自己玩去,坏了它自己会好。」

正解自动恢复解决的是「已知故障的标准动作」,但系统总会遇到没见过的新情况——就像小智遇到一种全新的海鲜,它连该不该焯水都不知道。此时必须有人工接管。而且自动恢复本身也需要人监督:如果熔断-回滚-重试的循环反复触发,恰恰说明系统里有更深的隐患需要人去复盘修复。人工介入是自动机制的「安全底线」,不是可有可无的摆设。

为何常见:看到「自动化」三个字就联想到「无人化」,忽略了自动化系统本身也是需要治理和迭代的一个环节。

面试题

Q1. AI 闭环系统(Loop)的核心循环结构是?

单选题 · easy

  • A.感知、决策、执行、反馈← 正确答案
  • B.输入、处理、输出、存储
  • C.请求、响应、缓存、日志
  • D.训练、验证、测试、部署

答案:A。闭环的灵魂是反馈回路——系统把执行的结果重新喂回输入端,形成「感知 → 决策 → 执行 → 反馈」的循环。好比小智尝一口菜再决定加不加盐,尝味就是反馈。B 是普通流水线,C 是 Web 请求链路,D 是模型开发流程,它们都没有「用结果调整下一步」的闭环特征。

Q2. 熔断器的三种典型状态是?

单选题 · mid

  • A.开启、半开、关闭
  • B.关闭、半开、熔断← 正确答案
  • C.运行、暂停、终止
  • D.正常、警告、致命

答案:B。熔断器状态机是 CLOSED(关闭放行)→ OPEN(熔断拒绝)→ HALF-OPEN(半开试探)。「关闭」指电路闭合、正常放行,「熔断」指跳闸拒绝,「半开」指试探性放行少量请求。A 把「关闭」和「开启」搞反了,C 是进程生命周期,D 是告警级别,都不是熔断器的状态模型。

Q3. Z 分数异常检测中,z 值代表什么?

单选题 · mid

  • A.当前值偏离均值的标准差倍数← 正确答案
  • B.当前值与最大值的百分比差距
  • C.样本窗口中最大值与最小值之差
  • D.样本均值相对方差的波动方向

答案:A。z = |x - μ| / σ,分子是当前值与均值的差距,分母是标准差,因此 z 表示「偏离了几个标准差的幅度」。好比小智判断咸度 9 离平均咸度 5 差了 4,而平时波动只有 1,那它偏离了 4 个「平时波动单位」。B 用的是最大值而不是均值,C 是极差概念,D 把均值与方差的关系说反了。

Q4. 状态回滚一般依赖什么机制?

单选题 · easy

  • A.定期保存的检查点快照← 正确答案
  • B.实时同步的日志副本
  • C.云端存储的数据备份
  • D.内存中的临时变量缓存

答案:A。回滚需要一个「可信的还原点」,这就是检查点快照——定期把系统完整状态保存下来,故障时恢复到最近一个快照。像小智的备菜记录表,照着它能重做一锅菜。B 日志副本用于追溯而非还原状态,C 备份是容灾概念,D 临时缓存恰恰是故障时最不可靠的东西。

Q5. 指数退避重试的核心思想是?

单选题 · mid

  • A.固定间隔反复重试直到成功
  • B.重试间隔随次数成倍增长← 正确答案
  • C.失败次数越多重试就越快
  • D.每次重试时随机等待一个时长

答案:B。指数退避让等待时间按 2 的 n 次方增长:第 0 次等 1 倍、第 1 次等 2 倍、第 2 次等 4 倍。这就像小智第一次等 3 秒、第二次等 6 秒、第三次等 12 秒,给系统留出越来越长的恢复窗口。A 固定间隔容易凑成节律性冲击,C 与退避方向相反,D 少了「指数增长」这个核心。

Q6. 可观测性三支柱通常包含哪些?

多选题 · mid

  • A.日志(Logs)← 正确答案
  • B.指标(Metrics)← 正确答案
  • C.追踪(Traces)← 正确答案
  • D.告警(Alerts)

答案:ABC。可观测性三支柱是日志、指标、链路追踪,分别对应「具体记录」「聚合画像」「全链路定位」。好比后厨的工作日记、温度曲线和一道菜从下单到上桌的完整路径。告警(D)是建立在三支柱之上的消费动作,本身不是观测手段。

Q7. 熔断后系统进入半开状态时,通常怎么做?

单选题 · mid

  • A.放行少量试探请求验证恢复← 正确答案
  • B.立即放行全部请求测试
  • C.继续拒绝所有请求不测试
  • D.直接重启整个服务进程

答案:A。半开状态的目的就是「小成本试错」:放行少量请求过去,如果成功就转回关闭状态,如果失败就再次熔断。好比小智等锅凉了先拧一点小火苗试试,火稳住了再开大火。B 全部放行等于没熔断,C 永远不试就恢复无望,D 重启进程是粗暴手段,与半开探测无关。

Q8. 设计自动恢复流程时,合适的手段包含哪些?

多选题 · hard

  • A.有限次重试并配合指数退避← 正确答案
  • B.失败时切换降级方案继续← 正确答案
  • C.无限循环重试直到碰巧成功
  • D.恢复成功后进行状态确认← 正确答案

答案:ABD。好的恢复流程讲究「有节制的自救」:有限次重试加退避避免重试风暴;重试无果时降级保住主流程;恢复后还要连续若干次成功来确认真好了。C 无限重试等于让小智对着冒烟的锅反复翻炒,只会把系统拖向雪崩,是大忌。

Q9. 告警分级的核心目的是?

单选题 · easy

  • A.按影响程度安排响应优先级← 正确答案
  • B.减少告警系统的运维成本
  • C.确保所有告警都由人工处理
  • D.统一记录故障发生的时间地点

答案:A。分级让系统把有限的注意力花在刀刃上:黄灯自动处理,红灯才响铃震动人。好比后厨的小警灯分黄红两色,小智自己能搞定的不吵醒大厨,真出大事必须立刻上报。B 是附带效果,C 与分级初衷相反(分级恰恰是为了减少不必要的人工打扰),D 只是记录功能。

Q10. 回滚到检查点时,哪些情况可能造成「假恢复」?

多选题 · extreme

  • A.外部依赖已经消费了旧状态← 正确答案
  • B.检查点数据本身已损坏← 正确答案
  • C.回滚后日志记录完整无缺
  • D.并发请求正在持续写新状态← 正确答案

答案:ABD。假恢复指「状态看似回到干净点,实际仍带着病」。A 是典型的不可回滚副作用——酸菜已被隔壁桌吃掉,重做的菜无法还原;B 是检查点本身不可信,恢复到坏备份等于白费功夫;D 是回滚期间还有并发请求在污染新状态,刚回滚完又被写乱。C 恰好是好事,日志完整有利于排查,不会造成假恢复。