说明本文讨论的是 AI 应用的服务等级目标怎么定与怎么维护属于 AI 运维话题不涉及具体模型版本与价格。AI 领域版本迭代极快凡涉及版本号、价格、可用性请以你阅读时的官方页面为准。文中代码为结构示意请按自己的技术栈调整后再上生产。一、可用性在 AI 应用上会给出错误答案传统服务的可用性口径只有两个量请求成功率和响应时间。对读写业务库的服务这个口径大体够用返回成功就等于业务做成。AI 应用不满足这个前提返回成功只说明请求被受理、产出了内容内容对不对可用性指标不知道。1.1 可用性的定义域里没有对错这个概念可用性回答的是服务有没有接住请求不回答接住之后给的东西能不能用。这两个问题在传统业务里高度重合在 AI 应用里可以完全脱钩。于是会出现一个看起来矛盾的组合可用性长期停在 99.9%用户侧却持续反馈答案不能用。两者不冲突量的是不同的东西。延迟分位同理它量的是等待时长不是等待的价值——一个 200 毫秒返回的错答案在延迟指标上比一个 3 秒返回的好答案好看得多。结论先行可用性要保留但它不能当 AI 应用的唯一目标。至少并行维护三类质量、延迟、成本。1.2 六种在监控上看不出来的失败失败形态监控上长什么样用户侧实际感受归属目标答非所问200输出长度正常延迟正常内容不可用质量结构崩掉200但下游消费方解析失败流程中断质量静默截断200结束标记正常内容不完整结论缺一半质量依赖兜底200实际走了降级分支结果明显变差质量变慢200延迟分位上移等待过长延迟变贵200用量上移无感事后对账才发现成本对照传统口径只有后两行会反映到可用性与延迟指标上前四行在可用性、响应时间、错误率上全是绿的。这就是可用性骗人的机制——定义域覆盖不到这些失败。1.3 三类目标与一条前置条件质量、延迟、成本三类各自独立度量互不替代。把三者压成一个综合分是这套体系里最常见的第一处错误第 2 章讲为什么。还有一条前置条件每个目标都要能被自动测量测量结果要能落进同一个固定窗口的口径里。做不到自动测量的目标会退化成口号——写进文档没人能判断有没有达成也就没人会为它做取舍。二、质量 SLO从可自动判定的代理指标起步质量的定义本身是主观的同一条回答换个用户、换个场景判定可能相反。所以质量目标不能直接定要先找到与质量相关、又能自动算出来的代理指标。2.1 什么是合格的代理指标一个代理指标要同时满足三个条件缺一不可与质量单调相关指标变差时用户感知的质量大概率也变差不能反过来。可自动判定判定过程不需要人在环否则做不成门禁。有稳定基线同一批流量正常情况下的波动范围有限波动能被识别成异常。常见错误是把代理指标当成质量本身。它的作用是发现质量下降不是证明质量合格——这个定位要提前跟消费这个指标的人说清楚否则质量出事后一定有人追问为什么指标没报警。2.2 四个可以起步的代理指标代理指标怎么算能抓到什么抓不到什么解析成功率返回能被下游结构消费的请求数除以总请求数结构崩掉、空返回内容对不对拒答率明确拒答与转人工的数量除以总请求数可用性收缩拒答是否合理引用可解析率引用能定位到真实来源的条数除以总引用条数来源被编造来源是否支撑结论人工抽检一致率抽检样本中人工判定合格的数量除以抽检样本数内容层面的整体质量单条问题的归因四个指标分工互补解析成功率和拒答率覆盖能不能用引用可解析率覆盖依据是否真实人工抽检一致率覆盖内容层面。引用可解析率怎么校验是另一个话题这里只把它当一个可自动算的比值。拒答率要双向看它升高时质量类风险下降但同时说明服务在收缩——用户没拿到东西等价于一次失败。所以拒答率的目标是区间不是单边上下限。2.3 为什么不能只用一个总分把四个代理指标加权合成一个 0 到 1 的总分看着好看实际会引入三个问题方向相反被抵消拒答率上升拉低可用性感知却可能拉高某些质量项加权后互相抵消总分纹丝不动。量级不对等被掩盖解析成功率涨 1 个点可以掩盖引用可解析率跌 5 个点后者对用户信任的破坏更严重。归因失效总分掉下来不知道该动哪一段工程上只能靠猜。做法是把总分降级成看板排序依据不进发布门禁。门禁逐项读任何分项低于目标值都拦住发布或要求随发布附一份降级方案。总分只回答哪个方向先看不回答能不能发。⚠️ 代码待验证# 质量代理指标计算示意分项各自统计不合成单一总分defquality_proxies(window_events):totallen(window_events)iftotal0:returnNoneparsed_oksum(e[downstream_parsed]foreinwindow_events)refusedsum(e[is_refusal]foreinwindow_events)ref_totalsum(e[ref_count]foreinwindow_events)ref_oksum(e[ref_resolvable]foreinwindow_events)return{parse_success:parsed_ok/total,# 解析成功率refusal_rate:refused/total,# 拒答率看区间不看单边ref_resolvable:(ref_ok/ref_total)ifref_totalelseNone,# 引用可解析率sample_size:total,# 样本量必须一起返回}# 判据样本量低于阈值时只记录趋势不出结论避免小样本噪声进发布门禁MIN_SAMPLE200# 示意值按自己的流量规模与窗口长度调整三、延迟 SLO首字与端到端分开定延迟是三类目标里最好量的一类也是最容易被一个均值糊弄过去的一类。定延迟目标之前先要确定量的是哪一段。3.1 首字延迟与端到端延迟是两种体感首字延迟指用户看到第一个字的时间端到端延迟指任务完成的时间。流式输出把两者彻底分开首字可能很快用户觉得响应及时也可能首字很慢后端还在正常生成用户已经在找关闭按钮。影响因素也不同首字主要受排队位置、输入长度与预填充影响端到端还叠加输出长度、工具调用次数与重试次数。优化手段不同就不能合成一个目标——合成后首字变慢会被端到端变快抵消而用户感知恰恰是变差的。判据一个改动让首字延迟下降、端到端延迟上升算不算改进取决于场景是交互式还是批处理。这一点要写在目标定义里不能留给事后讨论。3.2 分位数选哪个均值在延迟上几乎没用一小撮很慢的请求被大量快请求摊平均值看着正常那一小撮用户却已经把体验做坏了。用分位数并且分层用50 分位看典型体感回答多数请求大概等多久。95 分位主要目标值覆盖到足够多的用户样本量也足够稳定。99 分位只做观察不进发布门禁。样本少、抖动大作为门禁会频繁误伤发布把团队逼到调阈值而不是改问题。这里只引用分位数的概念怎么测出来、压测怎么设计属于另一套话题不在本文展开。3.3 长任务用完成时间不用请求时间异步与批处理任务上请求时间这个量直接失效请求早返回了真正的工作在后面慢慢跑。这时要看两个分开的量排队时长和执行时长。任务类型该看什么不该看什么理由流式对话首字与端到端分开只报端到端首字决定等待体感单轮问答端到端 95 分位均值均值掩盖长尾工具链多轮单次工具往返加全链路只报首字大部分时间花在工具等待异步批任务排队时长与执行时长分开请求时长请求早已返回量不到真实等待排队时长要单独定目标它受并发水位影响执行时长受任务本身影响。合成一个完成时间目标就会出现队列积压拉高完成时间、执行环节却没问题的误判。⚠️ 代码待验证# 延迟目标定义示意首字与端到端分开异步任务拆排队与执行latency_slo:-item:first_token# 首字延迟交互式场景的主要体感channel:streamingquantile:95window:28dgate:true# 进发布门禁阈值按测量窗口的基线分位定-item:end_to_endchannel:streamingquantile:95window:28dgate:true# 与首字分开统计超阈值计数互不冲抵-item:end_to_endchannel:streamingquantile:99window:28dgate:false# 只观察样本少、抖动大进门禁会误伤发布-item:async_completechannel:batchsplit:[queue_time,exec_time]# 排队与执行分开避免队列问题算成执行问题window:28dgate:true四、成本 SLO按每完成一件任务定目标成本目标最容易定错的地方是分母。分母选错目标就会奖励错误的行为。4.1 每次调用与每件任务是两个不同的分母按每次调用定成本数字看起来干净但它奖励的是削减单次调用不是削减完成任务的代价。重试、工具调用、多轮改写都会让单次调用便宜、整体更贵。按每完成一件任务定口径是窗口内的总用量除以窗口内成功完成的任务数。失败任务和重试产生的用量必须留在分子里否则成本会被成功样本稀释看起来越来越便宜实际是失败被藏进了另一个统计口径。判据某一周成功任务数下降、单次调用成本不变时按每件任务算出的成本一定上升。这个上升是正确的信号不该被平滑掉。4.2 成本与质量互相牵制成本和质量的张力不是意外是结构性的。下表列出四类常见动作对三个目标的方向影响用于在定目标时提前说清取舍动作质量影响成本影响延迟影响增加检索轮次通常上升上升上升加大上下文边际上升很快趋平明显上升上升失败重试上升上升上升长尾更明显裁剪上下文降级下降下降下降这张表逼着定目标的人在纸上先选一次而不是等出事时现场吵。降级动作要提前定义触发条件质量分项未跌破下限、成本分项连续两个窗口超目标时触发并记录质量一旦跌破下限降级立即停止。不要让降级自己决定要不要降级。4.3 目标值怎么给先测基线再定目标顺序不能反。做法是上线后先只观测跑一个完整的测量窗口本文按 28 天示意。按任务类型分别取基线分布记下 50 分位与 75 分位。目标值定在基线与更优之间留一段缓冲不拍整数。目标值与基线一起记录注明定值时间方便复核。成本目标要区别任务类型。把短问答和长文档处理混在一个目标里长任务拉高目标短任务的实际消耗被掩盖。账单归因与分账是另一套话题这里只定目标值与门禁。五、错误预算怎么算、烧完之前做什么三类目标定好之后还需要一个把它们和发布节奏绑定的东西。错误预算就干这个它把目标值翻译成一份可以消耗的额度。5.1 预算怎么算预算的定义很简单目标值的补集。质量目标允许失败的样本数、延迟目标允许超阈值的请求数、成本目标允许超支的额度都是预算。有一条换算必须遵守预算要换算成绝对量不要只留百分比。百分比在决策时没用——它不告诉你还剩多少。换算完再把额度按时间摊到窗口上才有可比的消耗速度。窗口用滚动窗口本文按 28 天示意好处是预算会自然回补不会因为月初一次事故把整月判死。5.2 烧毁速率与动作分档只有剩余比例不够用还要看消耗速度。同一个剩余比例平稳消耗和三天烧掉一半是两个完全不同的事件。烧毁速率就是当前消耗速度与允许速度的比值。烧毁速率区间示意值判断动作小于 1消耗慢于允许速度不动继续观察1 到 2消耗偏快尚未失控记入发布评审暂停非必要变更2 到 5明显异常存在持续劣化冻结发布定位窗口内最近的变更大于 5预算将在窗口内耗尽回滚最近变更同时启动保底降级四档动作里只有最后一档改运行态前三档只影响发布节奏。这个设计是刻意的预算管节奏不管故障处置。5.3 预算与发布门禁怎么挂钩门禁读分项预算不读综合分规则可以简化成三条所有分项剩余高于阈值正常发布。剩余低于阈值但最近一次变更与该分项无关可发布需附降级方案与回滚点。剩余低于阈值且最近一次变更与该分项直接相关拦住先复核再发。还有一条容易忽略短窗烧得快、长窗没动时先别动门禁去查那个短窗里发生了什么。短窗波动经常来自流量结构变化不是真劣化。⚠️ 代码待验证# 错误预算与烧毁速率分项各算一份不合成总分defburn_rate(consumed,allowed,window_fraction):ifallowed0:returnNoneexpectedallowed*window_fraction# 该时间点允许消耗的量ifexpected0:returnNonereturnconsumed/expected# 短窗看突变长窗看趋势长短窗都要看避免被单次抖动带偏SHORT_WINDOW1h# 示意值LONG_WINDOW6h# 示意值BUDGET_WINDOW28d# 示意值滚动窗口预算会自然回补完整版资料清单本文用到的错误预算计算示例与烧毁速率对照表都整理在里面了扫码即可获取六、SLO 与告警的分工SLO 和告警都盯着同一批信号但它们回答的问题不同。混着用两个都会失效。6.1 两者看的时间尺度不同SLO 看趋势尺度在天到周回答的是这个服务最近是不是在变差、要不要调整工程节奏与发布计划。告警看短窗口尺度在分钟到小时回答的是现在有没有东西需要立刻处理。两种误用都会出问题拿 SLO 当告警预算还在正常范围服务在缓慢劣化因为没到阈值没人知道。拿告警当 SLO短窗一抖就触发天天有通知长期趋势却平稳团队被训练成忽略通知。6.2 边界怎么划维度SLO告警时间尺度天到周分钟到小时依据目标值与错误预算单个或少数几个窗口内的信号输出要不要改变发布与工程节奏现在要不要有人介入影响范围发布与排期即时响应定错的代价要等一个窗口才发现纠正慢反复打扰降低响应意愿这张表只划边界告警怎么分级、怎么抑制重复属于另一套话题。这里强调的是不要把预算趋势接进即时通知它变化慢接进分钟级通道只会变成噪声稀释真正需要即时响应的信号。6.3 两个方向的抬升判断边界划清之后还有两个方向要显式判断否则两边会各自以为是对方的问题告警反复触发、预算没动告警阈值与当前流量结构不匹配。回看短窗的触发原因分布而不是去调 SLO 目标值。预算持续下降、告警没响覆盖缺口这条劣化路径没有对应的短窗信号。补一条能反映该分项的短窗判据并验证它能被触发。每轮预算复盘时对一次表把预算下降的时段与告警触发记录并排放看有没有跨窗口的空白段。⚠️ 代码待验证# SLO 与告警的分工两条链路读不同的窗口与数据源slo:window:28d# 趋势判断服务于发布门禁source:budget_ledgerfeeds:release_gate# 输出给发布门禁不产生即时通知alerting:window:5m# 即时判断只看短窗口source:short_window_metricsfeeds:incident_flowexcluded_sources:# 预算趋势不进即时通道避免噪声稀释信号-budget_trend七、目标值怎么定与怎么维护最后一章讲这套东西怎么落地以及上线之后怎么维护。7.1 先测量再定值上场就定一个目标值是最常见的返工来源。定值前必须先有一个测量窗口只观测、不出结论、不设门禁跑满一个完整窗口本文按 4 周示意。测量窗口结束之后按下面三步定值按任务类型分别取分项指标的分布记下 50 分位与 75 分位。目标值取在基线的偏优一侧留出缓冲并把缓冲大小写进定义。每个目标值都注明定值时间与当时的基线值方便下次复核时对照。不要拍整数。一个看起来整齐的目标值往往离真实基线很远结果要么长期不达标、门禁形同虚设要么长期轻松达标、什么也拦不住。7.2 分层按档位、按租户、按任务类型一个目标值管不了全部流量。分层的常用维度有三个按档位不同服务等级对应不同的质量与延迟目标。档位之间要有明确判定条件否则会成为扯皮入口。按租户租户之间用量结构差异大混在一起会让大租户拉偏整体目标。分租户看也要有一套整体口径对外说明。按任务类型长任务与短任务的质量、延迟、成本分布差别明显分开定是基本要求。分层的陷阱是层级太细一个目标底下只剩很少的样本量指标抖动就会淹没真实变化门禁变成随机拦截。判据某层在一个窗口内的样本量低于最小阈值时该层只观测不设门禁向上合并到上一层。7.3 变更之后必须重定并复核目标值不是一次定完就不动的。触发重定的变更有三类要重看的指标也不同模型换代质量与延迟都要重看成本通常同时变化。提示词或流程大改重点看质量分项尤其是拒答率与引用可解析率。依赖换代重点看延迟与成本质量可能滞后一个窗口才体现。复核动作固定成一条变更上线后重测一个完整窗口把新基线与旧目标值对照决定调目标还是改实现。不要把复核做成一次性动作它要进发布流程、和变更绑定否则一定被跳过。⚠️ 代码待验证# 目标值维护要看的观测项示意指标名按自己的监控系统改写 slo_objective{targetquality, itemproxy_name} # 当前目标值按层拆开 slo_actual{target, item} # 窗口内实际值 slo_gap{target, item} # 目标与实际的差值 error_budget_remaining_ratio{target, item} # 剩余预算比例 burn_rate{target, item, windowshort} # 烧毁速率长短窗各一份 slo_layer_sample_size{layertier} # 分层样本量 slo_review_total{reasonmodel_change} # 复核触发计数 # 复核清单变更上线后重测一个完整窗口再决定目标值是否要调整。 # 分层样本量低于最小阈值时该层只观测不设门禁向上合并到上一层看。完整版资料清单本文用到的三类 SLO 目标模板与错误预算复盘清单都整理在里面了扫码即可获取附表 A关键取舍一览取舍本文结论判断依据位置可用性能不能当 AI 应用的唯一目标不能定义域里没有内容对错的判定第一章质量目标用什么承载可自动判定的分项代理指标质量主观无法直接定值第二章拒答率的目标形态区间不是单边上限升高说明服务在收缩第二章质量分项要不要合成总分不合成总分只看板排序合成会抵消、掩盖、破坏归因第二章首字与端到端能否合成一个目标不能影响因素不同合成会互相抵消第三章延迟目标取哪个分位主要取 95 分位样本量与稳定性兼顾第三章异步任务看请求时长还是完成时长看完成时长且拆排队与执行请求早已返回量不到真实等待第三章成本的定值分母每完成一件任务按次调用会奖励削减单次开销第四章失败与重试的用量要不要计入分子要不计入会让成本被成功样本稀释第四章错误预算按百分比还是绝对量管绝对量百分比不告诉你还剩多少第五章预算趋势要不要接即时通知不要变化慢进分钟级通道只会变噪声第六章目标值先拍还是先测先测一个完整窗口再定拍出来的值离基线远门禁失效第七章分层样本量不足怎么办只观测不设门禁向上合并噪声会淹没真实变化第七章目标值要不要随变更重定要与变更绑定不绑定一定被跳过第七章附表 B术语速查表术语含义SLO服务等级目标一个可测量的服务质量目标值与窗口的组合代理指标与质量相关、可自动判定、有稳定基线的间接指标用于发现质量下降解析成功率返回结果能被下游结构消费的请求占总请求的比例拒答率明确拒答与转人工的请求占总请求的比例通常按区间定目标引用可解析率给出的引用能定位到真实来源的条数占引用总条数的比例首字延迟从请求发出到用户看到第一个输出片段的时间端到端延迟从请求发出到任务完成的时间与首字延迟分开统计完成时间异步任务从入队到执行结束的时间通常拆成排队时长与执行时长错误预算目标值的补集换算成绝对量后可用于消耗的额度按滚动窗口回补烧毁速率当前错误预算消耗速度与允许速度的比值分短窗与长窗各算一份发布门禁发布前逐项检查错误预算与目标值的规则集合读分项不读总分分层目标按档位、租户或任务类型拆分的独立目标值样本量不足时向上合并写在最后这篇用到的资料写这篇文章时我把几个模型的官方文档、参数表和实测记录都对了一遍顺手整理成几份配套的东西大模型学习路线图从 LLM 基础到 Agent 开发各阶段该学什么、用什么资料大模型全套教程按主题分好的视频与文档清单大模型实战好书24 本附每本适合的阶段资料是我自己整理的放在下面这个码上扫码即可获取添加时备注「大模型」优先通过。拿到之后建议先看学习路线图那一份先定位自己在哪个阶段再决定学什么比一上来就啃框架效率高得多。