17. LLM 应用上线怎么做灰度发布和回滚?模型/Prompt 版本切换有什么不同?
整理 LLM 应用的灰度策略、回滚机制与版本切换设计。
简单回答
LLM 应用的灰度发布比传统服务复杂——要灰度的对象不只是代码,还有模型版本、Prompt 模板、RAG 索引、Agent 工具集等多个独立维度,每个维度都可能让回答质量产生显著变化。常见做法是按用户/租户/请求维度做流量切分(5% → 25% → 100%),每个版本独立监控关键指标(延迟、成功率、内容质量打分、用户反馈率),出现劣化立刻回滚。回滚要分两类:技术性回滚(指标恶化、错误飙升)秒级自动;质量性回滚(生成内容质量下降)需要 LLM judge 或人工抽检,发现到回滚通常要小时级甚至天级。所以灰度比例和暴露时长要按"质量信号需要多久能稳定收集到"来定。
详细解释
为什么 LLM 应用的灰度更复杂
传统服务的灰度对象主要是代码和配置,质量指标(错误率、延迟、业务转化)都是数值化、实时可观测的。一个 bug 引起 5xx 飙升几分钟内就能告警回滚。
LLM 应用要灰度的"东西"维度更多:
- 代码版本:和传统服务一样
- 模型版本:从 GPT-4 升级到 GPT-5、从 Claude 3.5 升到 Claude 4,或者自有模型权重重新训练
- Prompt 模板:System Prompt 改写、Few-shot 示例增减、输出格式调整
- RAG 索引:知识库重新切片、换 embedding 模型、改 chunk 策略
- Agent 工具集:增加/移除工具、修改工具描述
- 后处理逻辑:内容安全规则、格式校验
每一个维度独立改动都可能让回答的内容质量变化。而内容质量这个核心指标恰恰最难实时观测——一个回答"好不好"是主观判断,没法像 5xx 那样秒级量化。
更糟的是它们之间还有耦合。Prompt 模板针对老模型调优过,换新模型可能要重新调 Prompt;RAG 索引和模型的偏好不匹配会拖累答案质量。所以灰度时要小心"只改一个变量"——多个变量同时灰度出问题不知道怪哪个。
灰度的流量切分维度
按什么维度切流量影响很大。常见有几种:
按请求随机切分:每个请求按概率分发到新/旧版本。最简单,但同一用户连续两次请求可能落到不同版本,体验割裂——用户问完问题点"重新生成"得到的是另一个版本的回答。不适合多轮对话场景。
按用户/会话粘性切分:用户 ID 哈希后落到固定版本,整个会话保持一致。多轮对话场景必须用这种。代价是负载分布不均(有的用户活跃,灰度比例和实际请求比例对不上)。
按租户/产品线切分:B 端产品按租户分,先在内部租户灰度再到外部。可控性最高,反馈也最可靠。
按场景/路由分:先在低风险场景灰度(FAQ、知识查询),稳定后再扩展到高风险场景(金融建议、医疗咨询)。这是按"出错代价"做的灰度。
实际项目通常组合使用——按用户哈希做主要切分保证体验一致性,叠加场景维度的开关控制风险范围。
比例怎么涨
经典的灰度比例曲线是 1% → 5% → 25% → 50% → 100%,每个阶段稳定一段时间再涨。但 LLM 应用要重新审视每个阶段的"稳定时长"。
技术性指标(延迟、成功率、错误率)几分钟到几十分钟就能稳定收集到。如果灰度只看技术性指标,每阶段半小时就够。
但 LLM 灰度的核心信号是 内容质量 和 用户反馈。这些信号收集慢得多:
- LLM judge 自动评估能在几分钟内对一批样本打分,但需要灰度版本累积到一定样本量才有统计意义。1% 流量的应用一个小时可能就几百次调用,统计量不够。
- 用户主动反馈(点赞点踩、负反馈率)通常要小时级到天级才能反映出有意义的变化。
- 间接信号(用户重写率、复述率、追问率)也要类似时间。
所以 LLM 灰度的合理节奏是 按"质量信号收集所需时间" 来定每个阶段长度。一个典型节奏可能是 1% 半天 → 5% 一天 → 25% 两天 → 100%。这个比传统服务慢一个数量级。
哪些指标要看
每个灰度阶段要并行监控几类指标:
技术性指标(实时)
- 成功率(HTTP 2xx 比例、模型未拒答率)
- TTFT、TBT、端到端延迟
- 错误分类(超时、内容过滤、模型 API 失败、格式校验失败)
用量指标(实时)
- 平均输入/输出 token 数(新模型可能更啰嗦,成本会涨)
- 工具调用次数、工具调用成功率(Agent 场景)
- 调用模式变化(重试率、追问率)
质量指标(小时-天级)
- LLM judge 打分(建议用一个独立的强模型对样本批量评分)
- 用户主动反馈率(点踩/负面表情/投诉)
- 业务转化(如果是带商业转化的产品,转化率是终极指标)
- 安全过滤命中率(新版本可能在安全边界上不同)
业务指标(天级)
- 用户留存、对话深度、客服转人工率等
回滚机制
回滚要分两类设计:
技术性回滚(自动):错误率超过阈值、延迟突破 SLO、模型 API 持续报错——这种秒级到分钟级自动触发回滚。回滚动作就是把流量切分配置改回 100% 旧版本。
质量性回滚(半自动/人工):质量指标变差不一定来自 bug,可能是新版本"风格变了"。这种回滚需要:
- 自动化告警(LLM judge 分数下降超过 X、用户负反馈率上升超过 Y)触发人工评审
- 评审决定是回滚还是定向调优
- 回滚要保留足够多的失败样本供后续分析
回滚后不能直接结案——要还原"为什么变差"。常见方法是把回滚前后的样本对比交给 LLM judge 或人工标注,定位是 Prompt 没适配新模型、RAG 召回劣化、还是模型本身在某些 query 类型上变差了。
Prompt 和模型版本切换的特殊性
Prompt 灰度的几个特殊点:
- Prompt 改动很轻量(只是改字符串),但效果变化可能很大
- 一次改 Prompt 可能影响多个下游链路(同一个 System Prompt 被多个端点用)
- Prompt 和 Prompt Caching 强相关,改 Prompt 会让缓存失效,灰度期间成本可能短期上涨
模型版本切换的几个特殊点:
- 不同 Provider 的模型行为差异大(输出风格、refusal 倾向、JSON 格式遵守度)
- 自有模型权重更新和商业 API 升级时机不同——商业 API 可能 Provider 单方面升级("GPT-4 自动升级到 GPT-4-turbo"),灰度控制权部分丢失
- 模型切换可能要同步切换 tokenizer——长 Prompt 截断逻辑、Token 计费、限流配额都要重新对账
影子流量和金丝雀对比
对高风险变更,灰度之前还可以做 shadow traffic(影子流量)—— 把生产请求复制一份发给新版本,但不返回给用户,只采集结果做离线对比。
收益是零用户风险地积累质量数据,能在真灰度之前就发现"这个版本在 X 类型 query 上明显变差"。代价是双倍推理成本,且需要工程能力支持流量复制和异步对比。
商业 API 场景下双倍调用成本可能太贵,可以只对采样的低比例流量做 shadow(比如 1%)。自有推理服务有空闲算力的情况下可以更激进。
和监控、Prompt 版本管理的联动
灰度系统不是独立组件,要和本专题第 04 篇的可观测性、第 09 篇的 Prompt 版本管理打通。
每条调用日志要带 版本指纹:模型 ID、Prompt 模板版本号、RAG 索引版本号、代码 commit hash。出问题排查时能精确定位"这条失败的调用是哪几个版本组合产生的"。
Prompt 版本管理要支持回滚——不是改了再改回去,而是有显式的版本号和"激活某个历史版本"的能力。否则生产事故时还要从 Git 历史里翻代码,太慢。
面试时可以这样答
LLM 应用的灰度比传统服务复杂,因为要灰度的对象不只代码,还有模型版本、Prompt 模板、RAG 索引、Agent 工具集这些独立维度,每个都可能让回答质量产生显著变化。
流量切分维度上,多轮对话场景必须按用户/会话粘性切,避免同一用户两次请求落不同版本。B 端可以按租户切,先内部租户后外部。还可以按场景切,低风险场景先灰度。实际通常组合用。
比例曲线和传统服务节奏不一样。技术性指标几十分钟稳定,但 LLM 灰度的核心是内容质量和用户反馈,这些信号要小时到天级才有统计意义。所以每阶段时长按"质量信号收集所需时间"来定,1% 半天、5% 一天这种节奏,比传统服务慢一个数量级。
监控要分三层。技术性指标实时看(成功率、延迟、错误分类)。用量指标实时看(平均 token 数变化、工具调用成功率)。质量指标小时-天级看(LLM judge 打分、用户负反馈率、业务转化)。
回滚分两类。技术性回滚秒级自动——错误率超 SLO 就切回旧版。质量性回滚半自动——LLM judge 分数下降或负反馈率上升触发人工评审,再决定是否回滚。回滚后必须做样本对比定位变差的根因,不能直接结案。
特殊性上,Prompt 改动看起来轻量但影响可能很大,且会让 Prompt Caching 失效短期成本上涨。模型切换要同步切 tokenizer,长 Prompt 截断、Token 计费、限流配额都要重新对账。商业 API 可能被 Provider 单方面升级,灰度控制权部分丢失。
高风险变更可以先做 shadow traffic,复制生产流量给新版本但不返回给用户,零风险积累质量数据。每条调用日志要带模型版本/Prompt 版本/索引版本/代码 commit 的完整指纹,排查时能精确定位是哪个组合出的问题。
常见追问
- Shadow traffic 的成本怎么控制?商业 API 双倍调用真打不起。
- LLM judge 自己也是有偏置的,怎么验证 judge 的判断方向是对的?
- 多个变量同时变化(同时改了 Prompt 又升模型)的灰度怎么做?非要拆分吗?