“味来餐厅”厨房墙上挂着一块“出品监控大屏”,实时滚动每张订单的状态:下单时间、出餐时间、退菜记录。厨师长王姐每天在屏幕前站上十五分钟,就能看出今天哪些菜做慢了、哪些食材快断货、哪桌在投诉。遇到异常——比如晚市退菜率突然翻倍——她不会瞎猜,而是翻开“退菜记录本”按原因归类,再顺藤摸瓜找到是采购、切配还是炉台的环节出了问题。 这块大屏和记录本,就是LLM应用的可观测性监控体系。你的每一次模型调用就像一张订单;超时、截断、格式错误、内容违规,就是后厨的四种退菜原因;错误率是退菜率;异常检测是王姐那双“觉得今天不对劲”的直觉,只不过机器用数字说话;根因追踪则是顺着错误日志把源头揪出来。这篇文章将带你完整掌握:如何给LLM应用做错误分类、统计错误率、设计异常检测与告警、追踪根因,并最终搭起一套生产级的监控体系。

岗位关联

对AI从业者的价值:无论你是在搭建Agent、维护模型服务还是做AI平台,错误率与异常检测都是保障系统稳定性的基本功。掌握这套方法,你能从“四处救火”变成“未雨绸缪”,用工程化手段守住LLM应用的质量底线。

目录
  1. 可视化演示
  2. 错误类型分类
  3. 错误率统计
  4. 异常检测算法
  5. 告警机制设计
  6. 根因追踪
  7. 监控体系建设
  8. 工程实践
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

\u53ef\u89c6\u5316\u5c55\u793aLLM\u5e94\u7528\u7684\u9519\u8bef\u7c7b\u578b\u5206\u5e03\u3001\u9519\u8bef\u7387\u8d8b\u52bf\u4e0e\u5f02\u5e38\u68c0\u6d4b\u3001\u9519\u8bef\u6839\u56e0\u8ffd\u8e2a\u6d41\u7a0b\uff0c\u4ea4\u4e92\u5207\u6362\u89c2\u5bdfLLM\u670d\u52a1\u7a33\u5b9a\u6027\u76d1\u63a7\u4e0e\u5f02\u5e38\u544a\u8b66\u7684\u6838\u5fc3\u73af\u8282\u3002

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

LLM\u9519\u8bef\u7c7b\u578b\u5206\u5e03 \u8d85\u65f6\u3001\u622a\u65ad\u3001\u683c\u5f0f\u9519\u8bef\u3001\u5185\u5bb9\u8fdd\u89c4\u4e94\u5927\u7c7b\u578b \u6309\u7c7b\u578b\u5206\u522b\u7edf\u8ba1\u907f\u514d\u603b\u4f53\u63a9\u76d6 Rate = Errors / Total \u70b9\u51fb\u5207\u6362\u67e5\u770b\u8d8b\u52bf\u68c0\u6d4b

错误类型分类

“味来餐厅”的退菜记录本从不只写一个“退”字,而是写清原因:上菜太慢、中途断料、摆盘错乱、食材不新鲜。分得细,才能找到该负责的环节。LLM错误监控的第一步,同样是给错误分类。

一次LLM请求就像一张订单,最常见的四类故障是:响应超时(上菜等太久)、输出截断(菜做到一半没了食材)、格式错误(摆盘完全不对)、内容违规(端上不安全的食材)。四类错误的诱因和处置方式完全不同,必须分开计数。

超时是推理服务过载、网络抖动或模型推理过慢,客户端在等待上限内没等到结果;截断是输出Token数撞上max_tokens或上下文窗口上限,答案说到一半戛然而止;格式错误是模型没有按约定输出JSON或结构化文本,导致下游解析失败;内容违规则是输出涉黄、涉暴、涉隐私等不安全内容。只有分别统计这四类数字,才能判断该优先解决哪类问题。

如果记录本上“上菜太慢”占八成,王姐会改造出餐流程而不是怪供应商。同理,当截断占大头时,你要调大max_tokens或换更长上下文的模型,而不是盲目重试——分类,是一切监控和优化的地基。

E=Ntimeout+Ntruncation+Nformat+NviolationNtotal×100%\displaystyle E = \frac{N_{\text{timeout}} + N_{\text{truncation}} + N_{\text{format}} + N_{\text{violation}}}{N_{\text{total}}} \times 100\%
这个公式把四类错误统一折算成整体错误率,就像把四种退菜原因汇总成一张“退菜率”报表,一眼看清出品健康度。
  1. 整体错误率E$E$ 表示统计周期内出错请求占总请求的比例。它回答的是“每100张订单里有几张出了问题”。
    E=NerrorNtotal\displaystyle E = \frac{N_{\text{error}}}{N_{\text{total}}}
  2. 分子四类错误计数之和:$N_{\text{timeout}}$、$N_{\text{truncation}}$、$N_{\text{format}}$、$N_{\text{violation}}$ 分别表示四类错误的次数,一次失败只归入一类,相加得到总错误数。
    Nerror=Ntimeout+Ntruncation+Nformat+Nviolation\displaystyle N_{\text{error}} = N_{\text{timeout}} + N_{\text{truncation}} + N_{\text{format}} + N_{\text{violation}}
  3. 分母总请求数:$N_{\text{total}}$ 是同一时间段内的全部调用次数,成功失败都算。分母必须用总请求量而非成功量,否则会人为抬高错误率。
    Ntotal=Nsuccess+Nerror\displaystyle N_{\text{total}} = N_{\text{success}} + N_{\text{error}}
  4. 百分比换算$\times 100\%$ 把0到1的小数转成百分比。$E=0.05$ 写成5%,更直观地传达“100次调用里有5次异常”。
    E%=E×100%\displaystyle E_{\%} = E \times 100\%

错误率统计

同样是“退菜率”,口径不同结论天差地别。按天算,周末晚市可能比工作日高一倍;按小时算,才能看到高峰期的真实压力。王姐看大屏时,永远先确认自己看的是哪一档数据。LLM错误率统计也一样:按请求数计还是按Token数计?窗口是1分钟、10分钟还是1天?口径不统一,数据无法跨团队、跨时段对比。

常用做法是“时间窗口 + 滑动平均”:把时间切成固定窗口(如每分钟),计算每个窗口的错误率 $E_t$,再对一个滑动窗口(如最近10分钟)取平均,得到平滑后的 $\bar{E}_t$。滑动平均能过滤瞬时抖动,避免一次突发的请求尖峰就触发误报。

此外还要做趋势分析:错误率是平稳、上升还是周期性波动?与上周同一时段对比,能区分“正常波动”和“真实劣化”。比如每天凌晨的批处理任务错误率本来就偏高,若与白天同一标准对比,就会得出错误结论。

王姐看大屏时,先看“近十分钟滑动退菜率”而不是某一张退菜单。如果滑动平均从1%爬到2.5%,她才会警觉:这不是运气问题,是系统性问题。滑动窗口的价值,正是把个案噪声过滤掉,留下值得决策的信号。

Eˉt=1n∑i=1nEt−i\displaystyle \bar{E}_t = \frac{1}{n}\sum_{i=1}^{n} E_{t-i}
$\bar{E}_t$ 是第 $t$ 个窗口的滑动平均错误率,相当于把最近 $n$ 个窗口的瞬时值“颠勺搅匀”,过滤噪声、还原趋势。
  1. 滑动平均错误率$\bar{E}_t$ 是当前时点的平滑值,$E_{t-i}$ 表示往前数第 $i$ 个窗口的原始错误率。像炒菜时看火候,不能盯着一秒的火焰,要看半分钟的均匀热度。
    Eˉt=1n(Et−1+Et−2+⋯+Et−n)\displaystyle \bar{E}_t = \frac{1}{n}\left(E_{t-1} + E_{t-2} + \dots + E_{t-n}\right)
  2. 求和运算$\sum_{i=1}^{n}$ 把从 $t-1$ 到 $t-n$ 共 $n$ 个最近窗口的错误率全部加起来。$n$ 是窗口宽度:太小滤不掉噪声,太大反应迟钝,一般取5~10个窗口。
    S=∑i=1nEt−i\displaystyle S = \sum_{i=1}^{n} E_{t-i}
  3. 取平均$\frac{1}{n}$ 将求和结果除以窗口宽度。平均之后,偶然一次高错误率不会让曲线剧烈跳动,只有持续劣化才会推动 $\bar{E}_t$ 明显上升。
    Eˉt=Sn\displaystyle \bar{E}_t = \frac{S}{n}

异常检测算法

王姐在餐饮行业干了二十年,“今天退菜有点多”是她的直觉。但直觉没法复制给新来的值班厨师,也写不成标准流程。监控系统需要的,是把这种直觉变成可计算的规则。

异常检测要回答的是:当前错误率“不正常”到什么程度?最简单的是固定阈值——错误率超过5%就报警。但问题在于:系统平时错误率是0.5%还是4%,对固定阈值来说都一样。阈值设死,要么误报多,要么漏报多。

更鲁棒的做法是动态基线:取最近一段历史数据算出均值 $\mu$ 和标准差 $\sigma$,再用 Z-score 衡量当前值偏离基线几个标准差。$x$ 离 $\mu$ 越远、相对 $\sigma$ 越大,说明越异常。Z>3 意味着当前值在正态分布假设下属于极小概率事件,值得告警。此外还可以用EWMA(指数加权移动平均)给近期数据更高权重,更快捕捉趋势变化。

有了Z-score,王姐的“直觉”就变成清晰规则:Z>3 就报警。新来的值班厨师不需要二十年经验,只要看屏幕上Z值有没有变红,就知道该不该冲进后厨。这就是把专家经验工程化的力量。

Z=x−μσ\displaystyle Z = \frac{x - \mu}{\sigma}
$Z$ 是“偏离了几个标准差”的量化值。$x$ 是当前错误率,$\mu$ 和 $\sigma$ 来自历史基线。Z 越大,越不像正常波动。
  1. 当前观测值x$x$ 是本窗口刚算出的错误率,比如最近1分钟错误率4.2%,则 $x=0.042$。它是“当下正在发生的事”。
    x=Et\displaystyle x = E_t
  2. 基线均值μ$\mu$ 是过去一段时间(如最近7天同一时段)错误率的平均值,代表“正常该是什么水平”。就像王姐知道晚市退菜率通常约2%。
    μ=1m∑j=1mEj\displaystyle \mu = \frac{1}{m}\sum_{j=1}^{m} E_j
  3. 基线标准差σ$\sigma$ 刻画正常波动的剧烈程度。$\sigma$ 小说明系统很稳,$\sigma$ 大说明系统本来起伏就大,对偏离的容忍度也应更高。
    σ=1m∑j=1m(Ej−μ)2\displaystyle \sigma = \sqrt{\frac{1}{m}\sum_{j=1}^{m}\left(E_j - \mu\right)^2}
  4. 标准化偏离度Z$\frac{x-\mu}{\sigma}$ 把差值除以标准差,得到“偏离了几个σ”。Z=2 通常算警告,Z=3 以上为严重异常。
    Z=x−μσ\displaystyle Z = \frac{x - \mu}{\sigma}

告警机制设计

后厨的报警器从来不止一种响法:传菜口的小铃铛响,只是提醒“菜好了”;厨师长的对讲机响,是“某桌催菜”;消防警铃响,才是全员疏散。如果所有问题共用同一个警铃,大家很快就会麻木。

LLM错误监控同样需要分级告警。Z-score 刚超过2,发一个WARN让值班同学瞄一眼;Z-score 超过3,或错误率短时间翻倍,才发CRITICAL、打电话叫醒负责人。告警纪律的核心是:让每条告警都有信息量,而不是变成“狼来了”。

实际设计中,告警规则由三部分组成:触发条件、静默期、通知渠道。触发条件如“$E > \mu + 3\sigma$ 且持续2个窗口”;静默期控制同一条告警多久内不重复发;通知渠道区分IM、电话、工单。同时必须做去重与聚合:同一trace_id下的多个错误合并成一条,多实例同时告警聚合成一条,避免告警风暴淹没真正的问题。

王姐给后厨定的规矩是:小问题记本子,大问题动警铃。LLM告警分级同理——不是所有异常都要半夜打电话。分级、去重、聚合做到位,值班人才会在真正的大火面前第一时间惊醒。

level(E)={0,E≤μ+2σ(正常)1,μ+2σ<E≤μ+3σ(警告)2,E>μ+3σ(严重)\displaystyle \text{level}(E)=\begin{cases}0, & E \le \mu + 2\sigma \quad \text{(正常)}\\1, & \mu + 2\sigma < E \le \mu + 3\sigma \quad \text{(警告)}\\2, & E > \mu + 3\sigma \quad \text{(严重)}\end{cases}
这是一个分段函数:错误率落在哪个区间,就触发哪个告警级别。就像后厨警铃分黄灯、红灯和火警三层。
  1. 正常区间当 $E \le \mu + 2\sigma$,错误率在正常波动范围内,level=0,不打扰任何人。这相当于后厨一切正常,警铃不响。
    level=0ifE≤μ+2σ\displaystyle \text{level}=0 \quad \text{if} \quad E \le \mu + 2\sigma
  2. 警告区间当 $E$ 介于 $\mu+2\sigma$ 与 $\mu+3\sigma$ 之间,level=1,发IM消息提醒值班人员观察。对应传菜口的小铃铛:有人注意,但不必停下所有工作。
    level=1ifμ+2σ<E≤μ+3σ\displaystyle \text{level}=1 \quad \text{if} \quad \mu + 2\sigma < E \le \mu + 3\sigma
  3. 严重区间当 $E > \mu + 3\sigma$,level=2,立即电话告警、全员响应。对应消防警铃:优先处理,其他一切靠后。
    level=2ifE>μ+3σ\displaystyle \text{level}=2 \quad \text{if} \quad E > \mu + 3\sigma

根因追踪

晚市结束后,王姐拿着当天的退菜明细开始“破案”:食材是早上采购的,切配是下午完成的,烹饪是晚市高峰进行的,传菜是另一拨人。要找出20桌退菜的共同点,必须把整条链路从头到尾翻一遍。

LLM应用的问题链路更长:用户请求先过网关,再做RAG检索、拼装Prompt,调用大模型,最后做输出解析返回。超时可能发生在任何一环;格式错误可能是模型抽风,也可能是Prompt模板写错。没有线索,就只能像在整本菜单里找一根头发丝。

工程上的核心手段是“全链路追踪”:为每次请求生成唯一 trace_id,贯穿网关、RAG、LLM、后处理所有环节,所有日志都带上它。出问题时,用 trace_id 拉出整条调用链的日志,按环节对比耗时与状态,就能定位是检索太慢、模型超时还是解析失败。再配合错误贡献度分析,统计各类错误占比,优先修复占比最大的环节。

王姐按贡献度排序:“上菜慢”占75%就先加备菜、优化炒菜顺序;“食材断供”只占5%就暂缓。LLM根因追踪同理:用 trace_id 还原现场,用贡献度排序投入产出比,把力气花在最大的短板上。

Ci=Nerror,iNerror\displaystyle C_i = \frac{N_{\text{error},i}}{N_{\text{error}}}
$C_i$ 是第 $i$ 类错误占总错误数的比例。贡献度分析帮我们把有限的修复资源投入最影响大局的环节。
  1. 第i类错误数$N_{\text{error},i}$ 是第 $i$ 类错误的计数,它来自监控系统的分类统计,是根因分析的输入。
    Nerror,i=该类型在周期内的发生次数\displaystyle N_{\text{error},i} = \text{该类型在周期内的发生次数}
  2. 总错误数$N_{\text{error}}$ 是全部类型的错误总数。作为分母,让 $C_i$ 成为可横向比较的比例。
    Nerror=∑i=1mNerror,i\displaystyle N_{\text{error}} = \sum_{i=1}^{m} N_{\text{error},i}
  3. 贡献度计算$C_i$ 表示第 $i$ 类错误占总体比例。$C_i=0.6$ 意味着它贡献了60%的问题,应作为首要排查对象。
    Ci=Nerror,iNerror\displaystyle C_i = \frac{N_{\text{error},i}}{N_{\text{error}}}

监控体系建设

王姐的大屏不只显示一个数字。她同时盯四块面板:每桌等餐时长、退菜率趋势、食材库存水位、今日营业额。单看任何一块都会误判——比如退菜率很低,但等餐时间全超30分钟,那依然是大问题。

LLM监控体系同样要围绕“黄金指标”建立,业界常用四个维度:延迟(Latency,响应够不够快)、错误率(Error Rate,请求成功与否)、吞吐(Throughput,单位时间处理量)、饱和度(Saturation,资源是否接近极限)。错误率只是其中一环,与另外三环配合才能看清全局。

有了指标,还需要SLO(服务等级目标),例如“月度错误率≤1%、P95延迟≤3秒”。SLO是团队对外承诺的质量线,也是告警阈值的依据。然后用仪表盘把指标可视化:趋势折线、错误类型饼图、延迟分位数柱状图、按服务拆分的热力图。监控体系的终极形态是:所有角色打开一个页面,就能回答“现在有没有问题、问题是什么”。

王姐把大屏从“退菜记录本”升级成“经营驾驶舱”,覆盖出餐、客流、库存全局。LLM监控同理——不要只盯错误率数字,要用延迟、错误率、吞吐、饱和度四块面板拼出完整的服务质量视图,再用SLO把目标钉死。

A=1−E=NsuccessNtotal\displaystyle A = 1 - E = \frac{N_{\text{success}}}{N_{\text{total}}}
$A$ 是可用性(Availability),它与错误率之和恒等于1。成功率与错误率是同一枚硬币的两面。
  1. 可用性定义$A$ 表示服务可用性,行业常要求“三个九”(99.9%)或“四个九”(99.99%)。它回答“请求整体上有多大概率是成功的”。
    A=NsuccessNtotal\displaystyle A = \frac{N_{\text{success}}}{N_{\text{total}}}
  2. 成功请求数$N_{\text{success}}$ 是周期内成功且合规的请求数。注意“成功”指返回了预期结果且质量合规,不是“没报错就行”。
    A=NsuccessNsuccess+Nerror\displaystyle A = \frac{N_{\text{success}}}{N_{\text{success}} + N_{\text{error}}}
  3. 与错误率互余因为 $N_{\text{total}} = N_{\text{success}} + N_{\text{error}}$,所以 $A = 1 - E$。错误率每升1个百分点,可用性就降1个百分点。
    A=1−E\displaystyle A = 1 - E

工程实践

王姐发现,再好的监控也不能替代现场的救火机制。她给后厨立了规矩:发现食材断货,切配组立刻启动备用菜单;某道菜被连续退,炉台马上停售排查。这些规则让异常发生时系统能自我修复,而不是等客人投诉才反应。

LLM应用同样需要“自愈”能力。Agent调用外部工具失败时,不能直接摆烂返回错误,要触发容错逻辑:判断错误类型,超时则重试一次,格式错误则修复JSON或重新解析,内容违规则走安全兜底回复。

工程实践的核心是“重试 + 退避 + 熔断”。重试必须限次:单次失败概率为 $p$ 时,尝试 $k$ 次至少成功一次的概率是 $1-(1-p)^k$。但重试有代价——超时重试会加重服务压力,所以要加指数退避(第一次等1秒、第二次等2秒、第三次等4秒);错误率持续超阈值时触发熔断,直接快速失败保护下游。配合告警值守(轮换、升级)和定期复盘(看错误趋势、优化监控规则),就形成持续改进的闭环。

王姐的周会上,会把上周的退菜记录和溯源日志摊在桌上,逐条确认改进措施有没有生效。LLM工程实践也一样:告警值守负责及时发现,容错重试负责自动修复,周会复盘负责防止复发。三者闭环,错误率监控才能从“看板上的数字”变成驱动系统持续变好的引擎。

Pk=1−(1−p)k\displaystyle P_k = 1 - (1 - p)^k
若单次失败概率为 $p$,最多试 $k$ 次(含首次)后,至少有一次成功的概率为 $1-(1-p)^k$。它量化了重试策略的收益边界。
  1. 单次失败概率p$p$ 是单次调用的失败概率,例如错误率5%时 $p=0.05$。它来自前文讲的错误率统计,是重试策略的输入参数。
    p=E\displaystyle p = E
  2. 连续失败概率$(1-p)$ 是单次成功概率,$(1-p)^k$ 是连续 $k$ 次全部失败的概率。只要失败就继续尝试,所以“全失败”才是最终失败。
    Pfail=(1−p)k\displaystyle P_{\text{fail}} = (1-p)^k
  3. 至少一次成功$1 - (1-p)^k$ 是 $k$ 次尝试内至少成功一次的概率。例如 $p=0.2, k=3$ 时,$1-0.8^3=0.488$,三次尝试能把最终失败率从20%压到约51%。
    Pk=1−(1−p)k\displaystyle P_k = 1 - (1-p)^k

AI 应用场景

LLM服务稳定性保障

阶段:模型服务监控与运维

解决的问题:传统做法靠人工盯日志、等用户投诉才发现异常,发现晚、定位慢。引入错误率统计与Z-score异常检测后,错误率刚有上升苗头就自动告警,从“事后救火”变成“事前预警”。

具体案例:某智能客服平台每天处理百万级请求。某次模型版本升级后,格式错误率从0.3%悄悄爬到2.1%,但整体错误率仍在阈值内。得益于按错误类型分别统计,团队发现JSON解析失败贡献度 $C_i=0.7$,通过 trace_id 定位到新版本Prompt模板中一个字段名拼写错误,半小时内回滚修复,避免了一场大规模线上事故。

Agent异常处理

阶段:代理运行时容错

解决的问题:Agent调用搜索、数据库等外部工具时,工具超时或返回异常会导致任务链断裂。通过错误分类和重试退避策略,Agent可以对超时自动重试、对格式错误自动修复,并把失败记录连同 trace_id 写入日志,供事后根因分析。

具体案例:一个办公助手Agent调用内部API查询请假余额,API偶发500错误。Agent识别出这是可重试错误,采用指数退避重试2次,任务成功率从92%提升到99%。同时每次失败都带着同一 trace_id 落日志,运维据此发现网关连接池偏小,调整配置后彻底解决。

生产环境质量监控

阶段:发布评估与质量门禁

解决的问题:LLM应用迭代快,但模型输出具有非确定性,新版本可能在部分场景悄悄变差。传统人工抽样评测覆盖面不足。通过在灰度流量上对比新旧版本的错误率、延迟、内容违规率,可以在发布前自动拦截劣化版本。

具体案例:某内容生成产品做A/B实验,灰度新模型。监控系统对比两组错误率,发现新版内容违规率比旧版高出0.4个百分点且持续2个窗口,触发质量门禁自动暂停灰度。团队用 trace_id 拉出违规样本,发现新模型在特定主题上约束不足,加上安全提示词后重新发布,违规率回落正常。

Python 演示

python62 行
# -*- coding: utf-8 -*-"""LLM error rate statistics and Z-score anomaly detection demo."""import randomimport statisticsfrom collections import deque WINDOW_SIZE = 10      # 滑动窗口大小, 单位: 分钟Z_THRESHOLD = 3.0     # 异常判定阈值 def simulate_requests(minutes=120):    """生成模拟的每分钟请求数与错误数"""    requests, errors = [], []    for t in range(minutes):        qps = random.randint(40, 60)        err_rate = 0.02 + random.uniform(-0.005, 0.005)        if 90 <= t <= 95:      # 第90到95分钟注入故障            err_rate = 0.18        requests.append(qps)        errors.append(int(qps * err_rate))    return requests, errors def build_error_rates(requests, errors):    """计算每分钟错误率序列"""    return [errors[i] / requests[i] for i in range(len(requests))] def detect_anomaly(rates, window=WINDOW_SIZE, z_thr=Z_THRESHOLD):    """用滑动窗口Z-score检测异常"""    anomalies = []    hist = deque(maxlen=window)    for minute, rate in enumerate(rates):        if len(hist) >= window:            mean = statistics.mean(hist)            stdev = statistics.stdev(hist)            if stdev > 0:                z_score = (rate - mean) / stdev                if z_score > z_thr:                    anomalies.append((minute, rate, z_score))        hist.append(rate)    return anomalies def main():    reqs, errs = simulate_requests()    rates = build_error_rates(reqs, errs)    total_req = sum(reqs)    total_err = sum(errs)    print("=== LLM Error Rate Statistics ===")    print(f"total requests: {total_req}, total errors: {total_err}")    print(f"overall error rate: {total_err / total_req * 100:.2f}%")    print(f"average per-minute error rate: {statistics.mean(rates) * 100:.2f}%")    print("\n=== Anomaly Detection (Z > 3) ===")    found = detect_anomaly(rates)    if found:        for minute, rate, z in found:            print(f"minute {minute}: rate {rate * 100:.1f}% (Z={z:.1f})")    else:        print("no significant anomaly detected")    print(f"\n=== Contribution of injected fault ===\n"          f"errors in minute 90-95: {sum(errs[90:96])}, "          f"share: {sum(errs[90:96]) / total_err * 100:.1f}%") if __name__ == "__main__":    main()
目的:一键模拟LLM服务的请求-错误数据流,演示“统计整体错误率→滑动窗口Z-score检测→定位异常区间”的完整监控流水线。
  1. def simulate_requests(minutes=120)生成模拟流量,前90分钟正常、第90到95分钟注入高错误率,模拟一次线上故障。
  2. err_rate = 0.02 + random.uniform(-0.005, 0.005)构造正常波动:错误率在2%上下小幅浮动,就像平稳期的后厨。
  3. if 90 <= t <= 95: err_rate = 0.18在固定区间把错误率抬到18%,模拟故障注入。
  4. errors.append(int(qps * err_rate))由请求数和错误率算出错误数,保持“总请求 = 成功 + 失败”的约束。
  5. def detect_anomaly(rates, window=WINDOW_SIZE, z_thr=Z_THRESHOLD)核心检测函数,输入错误率序列,输出异常点列表。
  6. hist = deque(maxlen=window)用双端队列维护滑动窗口,窗口满了自动弹出最旧的数据。
  7. mean = statistics.mean(hist)计算窗口内均值 $\mu$,作为动态基线。
  8. stdev = statistics.stdev(hist)计算窗口内标准差 $\sigma$,衡量正常波动幅度。
  9. z_score = (rate - mean) / stdev正文公式的直接落地:$(x-\mu)/\sigma$。
  10. if z_score > z_thr:超过3个标准差即判为异常,对应“Z>3 拉响严重告警”。
  11. print(f"overall error rate: {total_err / total_req * 100:.2f}%")输出整体错误率,对应监控大屏顶部的汇总数字。
  12. sum(errs[90:96]) / total_err计算故障区间的错误贡献度,当示例故障占比较高时,根因方向一目了然。

常见误区

误区每天看监控屏,错误率一直维持在0.5%以下,于是觉得系统非常健康,不再关注监控细节。

正解平均错误率低不代表没有局部风险。如果某个Agent子任务失败率高达30%,但它在总请求中占比很小,整体错误率依然很低。必须按服务、按错误类型、按时间段拆分统计,警惕“平均数的陷阱”。就像餐厅整体退菜率1%,但“周末晚市烤鸭退菜率30%”,那烤鸭这道菜必须马上处理。

为何常见:人脑习惯用单一平均数概括复杂系统,而整体数字好看会带来安全感,忽略了“平均之下暗流涌动”。

误区看到超时就重试,第一次超时等1秒、第二次等2秒……无限重试下去,总觉得“再试一次说不定就成了”。

正解重试是有代价的:每次重试都在消耗系统资源,服务雪崩时还会火上浇油。必须设置最大重试次数,配合指数退避和熔断。错误率已超阈值时,正确的做法是快速失败、保护下游。重试只对瞬时故障有效,对持续故障无效——就像菜炒糊了,重炒一百遍还是糊,不如先关火检查灶台。

为何常见:重试是实现成本最低的容错手段,写几行代码就行,容易让人忽略资源消耗和故障放大效应。

误区特地把Z-score阈值设为1.0,认为任何风吹草动都应该告警,宁可多报也不能漏报。

正解阈值过低会产生大量误报,值班人员很快习惯性忽略告警,真出大事时反而没人响应,这叫“告警疲劳”。阈值要在召回率和精确率之间平衡。Z=3是常用起点,再根据实际误报率调整,并配合持续时长、静默期过滤抖动。就像后厨警铃如果连汤锅煮沸都响,真起火时没人会当回事。

为何常见:“宁可错杀三千”的心态,加上低估了误报对值班注意力的持续损耗。

误区模型偶尔输出不合法JSON,那是模型的锅。应用层只要把报错抛出去,让上层处理就好,不需要额外处理。

正解格式错误的根因常常出在应用侧:Prompt指令不够明确、输出schema示例缺失、温度设置过高。而且即使模型有错,应用层也必须兜底——做鲁棒的JSON解析(提取代码块、修复截断括号)或触发重试。把格式错误当“模型抽风”而不处理,等于把一次可自愈的小波动变成用户可见的故障。

为何常见:报错信息确实显示"JSONDecodeError",很容易让人归咎于外部模型,忽略了系统设计层面的责任。

误区搭好仪表盘、配好告警、接入钉钉机器人,就认为问题一出现,系统会自动告诉我“哪里坏了”。

正解告警只告诉你“出事了”,不告诉你“为什么出事”。根因定位还需要配套的 trace_id 全链路追踪、结构化日志、错误样本留档。没有这些信息,收到告警后依然要人工大海捞针。监控、告警、追踪三者缺一不可,且必须提前设计,事后补的成本很高。就像烟雾报警器响了,你只知道有火,不知道哪个灶台、烧糊了什么——还得靠摄像头回放。

为何常见:厂商演示总把“告警→定位→修复”渲染成自动流水线,让人误以为可观测性等于自动定位。

面试题

Q1. 以下哪一项不属于LLM应用常见的错误类型?

单选题 · easy

  • A.请求超时错误
  • B.输出截断错误
  • C.输出格式错误
  • D.磁盘空间不足错误← 正确答案

答案:D。LLM常见四类错误是超时、截断、格式错误、内容违规。磁盘空间不足属于基础设施错误,不是LLM应用特有的错误分类。就像后厨退菜记录只记“出餐慢、断料、摆盘错、食材坏”,不会记“电灯坏了”。

Q2. 计算整体错误率时,分母应该使用?

单选题 · easy

  • A.出错请求数
  • B.总请求数← 正确答案
  • C.成功请求数
  • D.Token使用数

答案:B。错误率等于错误请求数除以总请求数,错误率与成功率之和恒为1。用成功数作分母会放大错误比例,就像用上桌菜数而不是下单菜数计算退菜率,算出来的数字毫无意义。

Q3. Z-score公式 (x-μ)/σ 中,σ 表示什么?

单选题 · mid

  • A.当前错误率
  • B.历史基线均值
  • C.历史基线标准差← 正确答案
  • D.滑动窗口长度

答案:C。σ是历史基线错误率的标准差,衡量正常波动的幅度;μ是均值,x是当前观测值。Z=3表示当前值偏离均值3个标准差。就像后厨平均退菜率1%且波动极小,某天突然3%,Z会非常高。

Q4. 使用trace_id做根因追踪,主要目的是?

单选题 · mid

  • A.加密用户请求数据
  • B.串联全链路各环节日志← 正确答案
  • C.降低模型推理成本
  • D.提升模型输出质量

答案:B。trace_id在请求入口生成,贯穿网关、RAG、模型调用、后处理等所有环节,使每行日志都带统一ID。出错时用trace_id拉出整条链路日志,即可定位是哪一环节出了问题。它不负责加密、降成本或提高模型质量。

Q5. 内容违规错误通常指的是?

单选题 · easy

  • A.响应时间超过阈值
  • B.输出包含有害或敏感内容← 正确答案
  • C.输出JSON解析失败
  • D.请求参数缺失报错

答案:B。内容违规指模型输出了涉政、涉黄、涉暴、隐私泄露等不安全内容,需要安全过滤器或人工审核识别。A是超时,C是格式错误,D是请求侧问题。这相当于后厨端出食材不安全的菜,属于最严重的一类问题。

Q6. 可用性与错误率的关系是?

单选题 · easy

  • A.可用性等于错误率
  • B.可用性等于1减错误率← 正确答案
  • C.可用性与错误率无关
  • D.可用性是错误率的倒数

答案:B。因为总请求等于成功加失败,成功率与失败率互补,所以A=1-E。错误率1%时可用性为99%,对应“两个九”。这与后厨“出菜成功率=1-退菜率”完全同构。

Q7. 以下哪些做法能有效减少告警轰炸?

多选题 · mid

  • A.同一trace_id错误去重← 正确答案
  • B.设置告警静默期限频← 正确答案
  • C.统一提高所有告警阈值
  • D.多实例错误聚合发送← 正确答案

答案:ABD。去重(同一链路故障只发一条)、静默期(同告警限频)、聚合(多来源合并)都是标准手段。统一提高所有阈值会大幅增加漏报风险,属于错误做法。就像后厨不会因为怕吵就把火警铃音量调低,而是优化分级与触发逻辑。

Q8. 关于异常检测方法,以下说法正确的是?

多选题 · mid

  • A.固定阈值适合稳定场景← 正确答案
  • B.动态基线能自适应波动← 正确答案
  • C.Z-score需历史数据支撑← 正确答案
  • D.固定阈值完全不需要配置

答案:ABC。固定阈值实现简单但需人工调参,适合波动小的场景;动态基线和Z-score利用历史均值和标准差自适应变化。固定阈值也需要配置,D错误。这像后厨的退菜率红线,若营业量翻倍还死守原数值,判断必然失真。

Q9. 以下哪些属于有效的根因追踪手段?

多选题 · hard

  • A.trace_id贯穿全链路← 正确答案
  • B.结构化日志统一格式← 正确答案
  • C.按错误类型算贡献度← 正确答案
  • D.仅靠平均错误率分析

答案:ABC。trace_id串联、结构化日志、贡献度分析都是根因定位的有效手段。仅看平均错误率会掩盖局部问题,不是根因追踪手段。就像只记总退菜数而不记环节,永远不知道是采购还是炉台的问题。

Q10. 单次失败概率p=0.2时,最多尝试3次(含首次)的最终成功率是?

单选题 · hard

  • A.约48.8%← 正确答案
  • B.约60.0%
  • C.约75.2%
  • D.约87.5%

答案:A。根据公式 $P_k = 1-(1-p)^k$,$1-0.8^3 = 1-0.512 = 0.488$。三次尝试将最终成功率提升到48.8%,失败率从20%降到约51.2%。D选项对应“重试两次”的常见误算,公式的k要包含首次调用。