我是小兵,一个动手派AI架构师。「AI工程化实战」系列第 3 篇。
那场 2:17 的翻车,不是没人监看,是没人在盯
下午 2:17,灰度发布放到 10%。
离线评测全绿,监控面板一片祥和。新版这轮优化了 prompt,让回复更短更快——谁也没想到,“更短”的代价是“不再追问”。2:18,转人工率就破了基线 3 倍——只是当时没装熔断器,这个信号没人接。
2:56,客服甩了张截图:用户问“颜色跟图片差太多,我要退,运费谁出?”,新版回“亲,退货需您自理运费哦”——可色差是描述不符,该商家出运费。
3:00,人肉回滚完成——曝光整整 43 分钟、约 2600 次请求。
不是没人监看,是监控在“看”、人没在“盯”——等红点飘满屏幕,船已经沉了一半。
为什么离线全绿还会翻车?因为离线评测是静态快照,Golden Set 三个月就过期,你测的是上个月的业务——新版这轮只是让回复更短、少问一句,歧义长尾就翻了车。真正要回答的是两个问题:不好的时候,谁先知道?谁先兜住?
自动熔断把“谁先知道”从 43 分钟压到 1 分钟(2:17 放量,2:18 转人工率破阈值就跳闸),把“谁先兜住”从人肉切流变成状态机自动回滚。下面按影子验证、分层放量、阈值推导、状态机的顺序展开。
第一步:影子验证,但别轻信“全绿”
影子模式 = 新旧版本并行,接全量真实请求,新版只计算、不对外输出。
判偏差分两级。第一级结构一致性:新版输出能不能过订单契约,过不了就是结构不合法,直接进合规致命。
第二级语义相似度:跟旧版做字段级加权比对,业务高危字段(状态、金额、商品)权重 3 倍——抽错了会写库、发货错。
然后按分数进三级处置:无害放行、业务风险阻断放量并人工复核、合规致命立即熔断一票否决。
这里必须泼盆冷水:影子全绿 ≠ 可全量。影子的暗区在于,它只镜像“旧版被请求过的流量”。用户提问后旧版答错了,用户就不会追问第二次,这段“本该有后续”的暗区流量根本没发生,新版再好也测不到。
影子通过,只意味着“新版在旧版答对的路上没跑偏”,不意味着“新版能覆盖旧版没答对的路”。所以影子只是第一道闸,后面还得走金丝雀。
第二步:金丝雀分层放量,每档双门禁
分档 1% → 5% → 10% → 30% → 100%。每档两个门禁,都过了才进下一档。
时间门禁:该档至少待够指定分钟数(1% 档 120 分钟),让指标在真实流量下攒够统计样本,也防“晚上 11 点顺手放量”的静默推进。
指标门禁:该档窗口内指标不熔断才放行。只要熔断一次,放量打回 1% 重新走,绝不断点续传。
放量维度按用户 ID 哈希取模前缀:每个用户被散列到固定槽位,放量 = 单调扩大“放行前缀”。
为什么不能每档换模数?如果你 1% 档用 %100、5% 档换 %20,升档 = 换模数 = 全量重映射,已放量的用户被切回旧版,同一次会话新老版本交替——上半句旧版答、下半句新版答,语义断裂。
固定槽位 + 单调阈值只补边界槽位,用户全程走同一版本。金融/政务等高价值强监管客户,exclude 名单一票否决,永不参与灰度。
第三步:熔断阈值,先抄表再懂为什么
阈值分两层,取向正好相反。先把结论抄走,落地就靠这张表:
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
先对齐口径,后面不再重复解释:解决率= 这条会话用户问题有没有被解决的比例(线上抽样 + LLM 判卷 + 用户反馈三路合成,不是现成数字);转人工率= 用户点“转人工”的比例;违规= 护栏漏出的违规输出次数;Token 成本比= 新版单请求成本 ÷ 旧版;P99= 响应延迟的 99 分位,99% 的请求比它快、剩下 1% 是最慢的长尾;样本= 窗口内请求数。
快层(合规/成本/延迟/转人工率):宁可误伤。漏判的代价(合规处罚、账单爆炸)远大于误判的代价(一次自动回滚,10 分钟就能重新放量),所以零样本门槛:成本/P99 一次命中立即熔断,转人工率和违规一样是“基线本身就有残余”的计数型,要累计到阈值(下详)。
违规阈值按档位流量缩放,不是固定 3 次。固定 3 次只对 1% 档成立——到 10% 档,基线正常也有一半以上概率误熔断,放量会卡死在 1% 档。
成本比 ≥ 2x:单请求成本翻倍是 prompt 回退、重试风暴的量级。1.5x 可能是批次波动,2.0x 是确定的事故。P99 ≥ 3x 基线:正常抖动约 ±20%,3 倍是降档或上游饱和。
-
转人工率 ≥ 3x 基线(且窗口内 ≥ 3 次):转人工是解决率的实时代理——用户点“转人工”是实时点击事件,不像解决率要等会话结束、等判卷、等 200 个样本。基线约 2%(每 50 个会话 1 次转人工),3 倍即 6%,外加 ≥ 3 次卡小样本噪声。开头那场事故,2:18 转人工率就破了 3 倍。(实时的是“信号”,分钟级的是“跳闸”。)
慢层(业务解决率):宁可不误。解决率天然波动(我见过业务基线 ±6pp),误伤导致团队不信熔断。所以双门槛:样本门槛(窗口内请求 < 200 一概不判,样本不够算出来的率全是噪声)+ 3σ 校准(上线前观察旧版一周,先算出它平时自己晃多少,阈值就设到这个晃动之外)。
照抄 5pp?你的业务波动 ±6pp,一周误伤 5 次。
沿用老纪律:阈值是写死的,统计是活的。10pp、转人工率 3x、违规 3 次、成本 2x、P99 3x 是“写死的起点”,样本门槛、3σ 校准、违规阈值按档位缩放,就是“统计是活的”三个旋钮。
第四步:三态熔断状态机,谁先知道、谁先兜住
CLOSED(正常,全量新版)→ OPEN(熔断,全量旧版)→ HALF_OPEN(冷却后小流量试探)。
为什么不用通用熔断器那套多态?熔断对象是“版本”不是“下游依赖”,决策只有“路由新版还是旧版”二选一。Hystrix 那套按调用方隔离、并发试探、失败计数桶,在这里全是多余状态——状态越多,“谁先知道”越慢。
自动回滚是两件事同时做:流量侧把路由切回旧版,配置侧调 rollback API 把灰度占比压到 0。每次跳闸写一条回滚记录,既是复盘证据,也是审计证据。
HALF_OPEN 试探必须是“有限”的:配额(如 5 个试探)+ 通过率(如 80%)双条件。试探失败说明事故没过去,立刻回 OPEN 并升级人工,绝不让试探流自动放大成下一次事故。
还有个容易忽略的约束:冷却期必须 ≥ 违规统计窗口,否则第一个试探,会被窗口里还没过期的违规信号当场打回。
踩坑一:影子全绿,全量翻车
影子跑 3 天全绿,全量上线当天用户投诉暴涨。回放 shadow trace 发现,新版只在“旧版答对了”的流量上被验证过。
旧版答错 → 用户放弃追问 → 这段暗区流量根本没进影子,而新版恰恰在暗区(旧版答错的疑难问题)上全面退化。
修复:影子通过 ≠ 可全量,全量前必须走金丝雀分层放量;暗区用线上“疑难问题池”(旧版转人工的会话)补测。
踩坑二:阈值拍脑袋,熔断器被注释
照抄文档 5pp,上线第一周熔断 5 次。每次回滚后查旧版同窗口指标——旧版也长这样。团队第 6 次把熔断器注释掉,回到人肉盯群。
排查:业务基线解决率本身波动 ±6pp(节假日、促销、晚间高峰),5pp 阈值落在噪声带里,等于让业务周期波动决定熔断。
修复:3σ 校准 + 样本门槛。熔断器被注释一次,团队就再也不信了——重建信任比写阈值贵得多。
最后说两句
这套东西拆开看,每层管一件事:影子验证确认“新版在旧版答对的路上有没有跑偏”,金丝雀决定敢不敢再放一点,熔断决定什么时候收手、收手后怎么确认。
合起来,“上线”从赌一次运气,变成有护栏、能自动回滚的过程——离线评测是快照,灰度+熔断是接住变化的那道闸。
回到开头那场 2:17 的事故:如果转人工率这个快层信号在 2:18 就替我们跳闸,2600 次请求的曝光,一行回滚记录都不会发生。
但还有一个前提问题:灰度/熔断能回滚,是因为你“精确知道该回滚到哪个版本”。目前我们的回滚粒度是“整个服务”——而 LLM 应用的真正逻辑载体是 Prompt。下一篇《Prompt 即代码》,把提示词变成可版本化、可评审、可回滚的资产。否则这套体系,回滚时只能切整个服务,拉不回你真正的逻辑。
我是小兵,一个动手派AI架构师。这里只写自己跑过、摔过、复盘过的AI工程化案例。如果你想持续收到这类实战内容,点击关注,下篇见。

