← 返回目录
ap7.5实操⏱ 约 12 分钟

灰度与回滚:1% 灰度只是让少数人替你踩雷

实测——严重问题 1% 灰度只有 6% 概率发现;轻微退化几乎发现不了

🔎 最后验证 2026-08📚 来源:本节为可复现的本地模拟(固定随机种子);分流与统计功效均可用本节脚本复算🧰 Python
为什么学这个

AP5 的门禁挡住了评测集能测出来的退化。但有些问题只有真实用户能发现:真实的提问分布、真实的脏输入、真实的使用节奏。

所以要灰度。但灰度不是"先放 1% 试试"这么简单——

  【新版本失败率从 2% 涨到 10%(严重问题)】
    总流量    灰度比例   灰度组样本   能发现的概率
      1000       1%           10           6%
      1000       5%           50          90%
      1000      20%          200         100%

总流量 1000、灰度 1% 的情况下,一个严重问题只有 6% 的概率被你发现。剩下 94% 的情况里,你会得出"灰度很稳,放量吧"的结论——然后全量翻车。

灰度太小,不是谨慎,是让少数人替你踩雷而已。

💡 打个比方

新配方的菜先给一桌客人试。一桌里只有 3 个人吃了,其中 1 个说"还行"——你能得出"新配方没问题"吗?

不能。你只是没听到抱怨,而不是证明了没问题。这两件事的差别,就是这一节的全部内容。

一、分流必须"粘住"用户

  500 个用户 × 10 次访问,共 4500 次「相邻两次是否换了版本」
  随机分流:翻转 817 次
  哈希分流:翻转 0 次

随机分流(每次现掷骰子)是初学者最常写的一行代码:

if random.random() < 0.1:      # ❌ 每次调用都重新决定
    use_new_version()

后果有两个:

  1. 用户体验错乱:上一句还是新版风格,下一句变回旧版——用户会觉得"你们这个 AI 时好时坏";
  2. 数据被搅浑:同一个人的行为被同时算进两组,A/B 结论直接失效

正确写法——按稳定的 key 哈希:

def bucket(user_id, pct, salt="exp_prompt_v3"):
    h = hashlib.md5((salt + ":" + user_id).encode()).hexdigest()
    return (int(h[:8], 16) % 100) < pct          # ✅ 同一个用户永远落在同一边

user_id(没登录就用设备 id 或会话 id)。salt 的作用:换一次实验就换一次 salt,否则同一批"倒霉用户"会被你每一次灰度都选中

二、灰度比例:多大才看得出问题

  【新版本失败率 10%(严重)】          【新版本失败率 4%(轻微)】
    1000 流量  1% 灰度 →   6%             1000 流量  1% 灰度 →   1%
    1000 流量  5% 灰度 →  90%             1000 流量  5% 灰度 →  34%
    1000 流量 20% 灰度 → 100%             1000 流量 20% 灰度 →  43%
   10000 流量  1% 灰度 →  98%            10000 流量  1% 灰度 →  36%
   10000 流量  5% 灰度 → 100%            10000 流量  5% 灰度 →  44%
   10000 流量 20% 灰度 → 100%            10000 流量 20% 灰度 →  48%

三条实用结论:

① 决定发现能力的是"灰度组的绝对样本量",不是百分比。1% × 10000 = 100 个样本(98% 能发现),1% × 1000 = 10 个样本(6% 能发现)。同样是 1%,天差地别。所以流量小的产品应该用更大的灰度比例——20%、甚至 50%。

② 轻微退化极难发现。失败率 2% → 4% 这种变化,即使 20% 灰度、10000 流量,发现概率也只有 48%。这正是 AP5 门禁存在的理由:能在评测集上测出来的,就别指望线上灰度替你发现。

③ 灰度要配"最少观察量"。上线前先算:要发现 X 大小的退化,需要多少样本?样本不够就别放量,也别宣布成功。

# 一个够用的经验法则
最少观察量 = max(200, 基线失败次数 × 20)      # 至少 200 个请求
最短观察时长 = 覆盖一个完整的使用周期          # 至少跨过一次早/晚高峰

"最短观察时长"经常被忽略:早上 10 点放灰度、11 点看着没事就全量,你完全没测到晚高峰的流量和另一批用户

三、说好的 1%,实际是多少

  设定  1%  →  实际  1.15%(23/2000 用户)
  设定  5%  →  实际  4.75%(95/2000 用户)
  设定 10%  →  实际  9.45%(189/2000 用户)
  设定 50%  →  实际 50.05%(1001/2000 用户)

小比例灰度天然有偏差。上线后核对一次实际分流比例,别只信配置里写的数——如果实际是 3% 而你以为是 1%,你的风险敞口是三倍。

回滚:改配置,不发版

CONFIG = {
    "prompt_version": "v3",            # 提示词版本(ap2.4)
    "model": "deepseek-chat",          # 模型版本
    "index_version": "kb_2026_08_01",  # 检索索引版本(ap4.7)← 最容易忘记版本化的一个
    "canary_pct": 10,
    "canary_salt": "exp_prompt_v3",
    "kill_switch": False,              # 一键全量回退到稳定版
}

回滚 = 把 canary_pct 改成 0,或 kill_switch 改成 True——秒级生效,不用发版。

如果你的回滚方式是"改代码 → 提交 → 构建 → 部署",那么在最需要它的那几分钟里,你只能干等

三样东西必须一起版本化:

版本忘了会怎样
提示词最容易记得的一个
模型换了模型没换回来,行为完全不同
检索索引最容易忘——只回滚提示词而索引还是新的,你回到的是一个从来没测过的组合

灰度期间该盯什么

1① 先过 AP5 的回归门禁 —— 评测集能发现的问题,别拿用户去试
2② 算最少观察量,定灰度比例(流量小就用大比例)
3③ 按 user_id 哈希分流,记下 salt;上线后核对实际比例
4④ 盯四个指标的分组对比
business_ok、P95、单次成本、用户负反馈率
5⑤ 达到最少观察量 + 跨过一个完整使用周期,再决定放量

第 ④ 步的关键是"分组对比"而不是"看绝对值":线上指标本来就在波动(ap2.5 的噪声地板),只有新旧两组在同一时间窗口内的对比才有意义

🔧 动手做:给你的产品做一次灰度(20 分钟)

  1. 跑本节代码,看1% 灰度在小流量下只有 6% 的发现概率,和随机分流的 817 次体验翻转
  2. 写你的 bucket() 函数(哈希分流 + salt),并写一个测试确认同一 user_id 多次调用结果稳定
  3. 把提示词/模型/索引三个版本号放进一份配置,配置能热更新(数据库/配置中心/环境变量 + 定时重载)。
  4. 加 kill_switch,并演练一次:从"决定回滚"到"线上生效"用了多久?超过 1 分钟就要改。
  5. 算你自己的最少观察量:按当前流量,发现一个"失败率翻倍"的问题需要多少样本、多长时间?
  6. 在日志里加 variant 字段(control / canary),否则你没法做分组对比(ap7.4)。

做到这里你应该有:稳定哈希分流 + 三版本一体的热配置 + kill_switch(演练过)+ 最少观察量 + 日志里的 variant 字段。

为什么:AI 产品的改动比传统软件更难预测——改一句提示词,可能在你没测到的那类输入上完全崩掉(AP2 那三次"改了但没用"和 ap5.5 那次"更便宜但更差"都是例子)。灰度是你在门禁之后、全量之前的最后一道缓冲。

但这一节最该记住的是它的局限:灰度只能发现"明显的、大的"问题。轻微退化、长期效应、罕见场景——它都发现不了别把灰度当成免测金牌。

❓ 测验
总流量 1000、灰度 1% 时,一个「失败率从 2% 涨到 10%」的严重问题只有 6% 的概率被发现;而总流量 10000、同样 1% 灰度时是 98%。这说明什么?
⚠️ 避坑灰度组和对照组必须同时在线,不能先跑旧版再跑新版

一个常见错误:周一跑旧版收集数据,周二换新版收集数据,然后对比。

这不是 A/B,是"周一 vs 周二"——中间混进了流量结构变化、用户构成变化、上游模型的波动、甚至天气。ap2.5 实测过:同一个提示词跑 5 轮,分数本身就有 ±0.5 的波动;线上环境的波动只会更大。

正确做法:同一时间窗口内,两组并行,只比同期数据。

另外两条:① 别在灰度期间改别的东西——同时改了提示词和检索参数,出问题你分不清是谁干的;② 灰度组的用户要能反馈——ap5.6 的负反馈信号在灰度期尤其宝贵,它比指标更早告诉你不对劲。

🤖 让 AI 帮你设计灰度方案
我的 AI 产品日活【X】、日请求量【X】,当前失败率约【X%】。我要上线的改动是【描述:改提示词/换模型/换检索方案】。请帮我:1) 计算发现「失败率翻倍」和「失败率涨 50%」各需要多少灰度样本,据此给出灰度比例和最短观察时长建议;2) 写哈希分流函数(含 salt 管理);3) 列出灰度期间要分组对比的指标和判定标准(考虑噪声);4) 设计配置结构,让提示词/模型/索引三个版本能一起回滚;5) 一份放量节奏表(每一档的观察量和放行条件)。
✅ 小结

灰度三句话:按 user_id 哈希分流(随机分流实测造成 817 次体验翻转)决定发现能力的是绝对样本量不是百分比(小流量产品要用大比例)回滚靠改配置不靠发版,且提示词/模型/索引三者要一起回

还有一条要记住:灰度只能发现大问题——轻微退化即使 20% 灰度也只有 48% 的发现概率,那是 AP5 门禁的活。

下一节把东西真正放上公网:部署形态怎么选、并发怎么配、成本怎么控

下一节 → 部署与成本控制:把它真正放到公网上
🔎 来源与核验· 3 条,点开核对
本节每个关键论断都对应一个可追溯的来源 —— 这是本课程"靠谱、不过时"的底线。
「分流方式模拟:500 用户 × 10 次访问,随机分流产生 817 次版本翻转,哈希分流 0 次」
📚 canary.py 模拟(2026-08,固定种子)✓ 已核验 2026-08
「统计功效模拟(失败率 2%→10%):总流量 1000 时 1%/5%/20% 灰度的发现概率分别为 6%/90%/100%;总流量 10000 时为 98%/100%/100%。失败率 2%→4% 时,即使 20% 灰度 + 10000 流量,发现概率仅 48%」
📚 canary.py 模拟(2026-08,400 次重复实验)✓ 已核验 2026-08
「哈希分流均匀性:2000 用户下,设定 1%/5%/10%/50% 实际分别为 1.15%/4.75%/9.45%/50.05%」
📚 canary.py 模拟(2026-08)✓ 已核验 2026-08
智图软件的赞赏码
都看到这了,打个赏呗!
接下来 · ap7.6
部署与成本控制:放上公网,然后算清一笔账
继续读下一节 →