一、引言:评测过了,为什么上线还是出事?
上一期我们建好了多 Agent 评测体系:四层下钻、三类基准集、R1 当裁判,理论上"变更必过评测"就能守住质量。但实际线上还是出过这么一件事:评测全绿、CI 通过、影子评测也正常,结果灰度切到 10% 流量之后,用户投诉率直接翻倍------因为评测集里没有覆盖"用户连续问了五个问题、中途切换话题"这种长会话场景,而新版本的编排策略恰恰在这种场景下把会话上下文传丢了。
评测能发现"已覆盖场景"的问题,但覆盖不到的长尾场景,只有真实流量能暴露。这就是为什么多 Agent 系统必须做灰度发布:不是不相信评测,而是评测和灰度是两道不同的防线------评测管"已知场景不回归",灰度管"未知场景不炸线"。
多 Agent 系统的变更比单 Agent 危险得多:一个子 Agent 的 prompt 改动、一次模型版本升级、一条路由规则调整,都可能顺着链路级联放大。更麻烦的是,多 Agent 会话是有状态的------用户和编排者聊了五轮,上下文散落在各个子 Agent 之间,你没法像重启服务那样"回滚会话"。所以这一期我们聊多 Agent 的灰度发布与渐进式上线:四个灰度维度、影子模式、金丝雀、自动回滚,以及在 Dify + 华为云 Flexus 环境里的完整落地。这是《华为云Flexus+DeepSeek征文》系列的第二十篇。
二、为什么多 Agent 系统不能"一把梭"升级
先说说为什么不能像单 Agent 时代那样:改完直接全量上线,出问题再回滚。多 Agent 系统有三个特性,让"直接全量"变成高危操作。
2.1 特性一:级联失败会被放大
单 Agent 出问题,影响范围就是那一个模型调用。多 Agent 出问题,一个子 Agent 的异常输出会被编排者采信、传给下一个 Agent、再被下一个 Agent 加工,错误沿着链路逐级放大。哪怕只有一个 Agent 的新版本有 bug,整条链路的任务完成率都会断崖式下跌。你甚至很难第一时间判断是哪个环节引起的------这和上一期讲的"错误传播、责任难定位"是同一件事,只不过发生在线上。
2.2 特性二:会话状态跨 Agent 分布
多 Agent 系统是有状态的,而且状态是"分布式"的:编排者维护对话历史,子 Agent 各自维护任务上下文,知识库检索结果在链路里传递。传统回滚(重启服务、切回旧版本代码)只能解决"无状态"的部分,已经进行到一半的会话没法回滚------用户刚提交了退货申请,你这边把编排策略回滚了,新请求走了旧逻辑,但用户会话里的上下文还是新逻辑的产物,两边对不上,用户看到的就是"客服突然失忆了"。
2.3 特性三:编排策略与模型深度耦合
多 Agent 系统的行为 = 模型能力 × 编排策略 × 工具配置 三者叠加。模型升级了(比如 DeepSeek-R1 换新版本),行为可能大变------同样一段 prompt,新模型更"爱"调用工具,单次任务成本涨 30%;或者新模型更谨慎,该路由到人工的没路由。策略和模型是耦合的:只灰度模型不灰度策略,或者反过来,都可能组合出从未测试过的行为。所以多 Agent 的灰度要同时管住多个变更维度。
记住一个原则:多 Agent 灰度要"四维控制"------流量、功能、模型、策略,每个维度独立可调、独立可回滚。
三、灰度四维度:流量、功能、模型、策略
先建框架:多 Agent 系统的每次变更,都可以拆到四个维度上分别灰度。
3.1 维度一:流量灰度(谁在用新版本)
流量灰度的核心是"控制新版本覆盖的用户/会话/任务范围",粒度从小到大:
- 用户级:按用户 ID 哈希分流。最符合业务直觉------同一用户始终走同一版本,体验一致。适合 B 端系统(按租户灰度)、C 端系统(按用户灰度)。
- 会话级:按会话 ID 分流。同一用户的不同会话可以走不同版本,灰度速度更快、更细,但用户体验可能不一致(这个会话新逻辑、下一个会话旧逻辑)。
- 任务级:按任务类型分流。比如"查订单"走新版本、"退换货"走旧版本。适合按业务域隔离风险的场景。
流量灰度的关键是要稳定分流:同一用户/会话在灰度期间始终落在同一版本,不能这次请求新、下次请求旧------会话上下文会错乱。实现上用一致性哈希或用户 ID 取模,别用随机数。
3.2 维度二:功能灰度(特性开关)
流量灰度决定"谁用新版",功能灰度决定"新版的哪个功能开没开"。多 Agent 系统的特性开关通常放在几个位置:
- 子 Agent 的开关:某个子 Agent 用新 prompt 还是旧 prompt;
- 工具/插件的开关:新接入的工具(比如新的订单查询插件)先关着,验证完再开;
- 编排分支的开关:编排者是否启用"多轮追问"分支、"主动推荐"分支。
特性开关是"最小变更单元"------一次发布只开一个开关,出问题就关那一个,不用整条链路回滚。开关配置要独立于代码:Dify 里可以用环境变量 + 应用变量管理,切换开关就是改配置、热生效,不用重启服务。
3.3 维度三:模型灰度(模型版本升级)
模型升级是最高频也最危险的变更。模型灰度要回答三个问题:
- 升级哪个模型:编排者模型(影响最大,所有决策都过它)、某个子 Agent 的模型(影响局部)、还是全链路统一升级;
- 新旧版本怎么共存:路由层同时挂新旧两个模型端点,按流量比例分发,而不是直接替换;
- 怎么判定新版本更好:不能只看评测分,要看线上真实指标------任务完成率、平均轮次、单任务成本、人工接管率。模型灰度必须有"新旧对照"能力:同一批请求随机分到新旧两个模型,统计对比(这就是 A/B 测试)。
模型灰度的典型坑:新模型在评测集上分数更高,但线上"更啰嗦"------回答质量没变,token 消耗涨了 40%。所以模型灰度必须同时盯质量和成本两组指标,别只盯一组。
3.4 维度四:策略灰度(路由规则、Prompt 版本)
策略灰度管的是"编排者怎么决策":路由规则(意图 A 走哪个 Agent)、Prompt 模板版本、工具选择逻辑、终止条件。策略变更通常和模型变更一起出现(新模型配新策略才有效果),但必须分开灰度------先灰度策略(模型不变),确认策略本身没问题,再灰度模型,最后组合验证。一起变,出了事你分不清是模型的锅还是策略的锅。
策略灰度在 Dify 里落地很自然:工作流本身是版本化的,一个 Agent 应用可以有多个已发布版本,路由层指定走哪个版本即可。
四、影子模式:先观察,不切换
灰度四维度的第一站是影子模式(Shadow Mode)。影子模式不把真实用户流量切给新版本,而是把线上请求"复制"一份发给新版本,新版本的结果只记录、不返回给用户。用户感知不到,你却能拿到"新版本在真实流量上的表现"。
真实用户 ──→ 线上旧版本 ──→ 返回结果给用户
│
└──(复制请求)──→ 影子新版本 ──→ 只记录结果,不返回
影子模式的价值:
- 零风险暴露:新版本跑飞了也不影响用户;
- 真实流量覆盖长尾:评测集覆盖不到的场景,影子模式全部能覆盖------之前引言里的"长会话切话题"场景,影子模式第一天就能暴露;
- 可以长期并行:新版本可以挂在影子模式下跑一周,积累足够多的对比样本再决定是否转正。
影子模式的落地要点:
- 流量复制要脱敏:请求里可能带用户隐私,进影子环境前要脱敏(脱掉姓名、手机号等字段),这是合规底线;
- 影子环境要独立:别让影子请求污染线上数据(比如影子请求真的去查了订单库、发了通知,那就不是影子了)。影子 Agent 的写操作要 mock 掉,只读操作可以放行;
- 对比要有基线:新旧版本结果成对记录,跑完批量对比------正确率差异、轮次差异、成本差异、延迟差异。用上一期的评测体系做"批量离线裁判"。
什么时候影子模式算通过:连续 3-5 天,影子版本与线上版本在任务完成率、正确率上持平或更优,且成本、延迟没有明显劣化。通过之后进入金丝雀。
五、金丝雀发布:小流量真实用户
金丝雀(Canary)是把新版本放给一小部分真实用户,让真实流量做最终验证。多 Agent 金丝雀的典型节奏是 5% → 20% → 50% → 100%,每档观察 1-3 天,指标稳定才升档。
5.1 金丝雀的指标看板
金丝雀期间要盯的指标分三组:
- 业务组:任务完成率、端到端正确率(抽样评测)、人工接管率、用户投诉率;
- 性能组:P95/P99 延迟、平均轮次、超时率;
- 成本组:单任务 token 消耗、单任务成本、工具调用次数。
新旧版本要同时看:金丝雀不是"看新版本好不好",是"看新版本相对旧版本好不好"。同一指标两组对照,差异超过阈值(比如新版本成本高 20%,或完成率低 2%)就要停下来排查,而不是继续升档。
5.2 金丝雀怎么"切人"
推荐用户级灰度 + 动态开关:金丝雀用户由配置中心动态指定(可以按用户 ID 段、租户、地域),随时能加人减人。别写死在代码里------发现新版本有问题,你要能在 1 分钟内把金丝雀用户全部切回旧版本,而不是改代码重新部署。
5.3 金丝雀的退出条件
升档前必须满足全部条件(用上一期的评测流水线做自动判定):
- 业务组三项指标不劣于旧版本(完成率、人工接管率、投诉率);
- 性能组延迟在预算内(P95 不超过旧版本 1.2 倍);
- 成本组单任务成本不高于旧版本 1.1 倍(和 08-14 的成本治理衔接);
- 至少覆盖了 3 天完整业务周期(工作日/周末行为差异要都覆盖到)。
金丝雀最常见的失败:指标波动被当成"偶发",凑合着升档。多 Agent 链路长、抖动大,单日指标没有统计意义------至少看 3 天的趋势,波动大的指标要设"连续 N 小时超阈值才告警"的防抖逻辑。
六、蓝绿部署与全量切换
金丝雀走到 100%,是不是直接删掉旧版本?不是。多 Agent 系统要保留蓝绿两套完整环境:
- 蓝环境(当前线上) 、绿环境(新版本):金丝雀验证完成后,绿环境承接 100% 流量,但蓝环境不销毁,保持可随时切回的状态;
- 回滚 = 切流量:流量入口(网关/路由层)从绿切回蓝,1 分钟完成,不需要重新部署;
- 蓝绿共存期:全量切换后保留蓝环境 3-7 天,确认新版本稳定(无长尾问题、无数据异常)后才销毁蓝环境。
蓝绿的关键点:
- 两套环境的数据要隔离或可迁移:多 Agent 系统往往有会话状态、知识库、缓存。蓝绿切换时,如果会话状态存在各自环境里,切回蓝环境会"失忆"。生产级做法是状态存共享存储(Redis/数据库),蓝绿只切换"计算层"(编排服务 + 模型路由 + Agent 实例),状态层共用;
- 缓存要预热:切换流量前,绿环境的语义缓存、知识库索引要先预热,否则切过去的第一波请求全是缓存 miss,延迟和成本都会飙升;
- 入口层做双写或流量镜像:切换初期保留一小部分镜像流量到蓝环境做对照,双保险。
七、Dify 落地:环境隔离与版本管理
上面讲的是方法论,落到 Dify + 华为云 Flexus 环境,具体怎么做?四个动作。
7.1 动作一:环境隔离(开发/测试/生产)
多 Agent 应用至少分三套环境,用不同的 Dify 实例或同一实例的不同工作空间:
- 开发环境:随便改,接测试模型端点(或小模型 mock);
- 测试环境:跑评测流水线、影子模式(接影子流量);
- 生产环境:只有经过评测 + 金丝雀验证的版本才允许发布到这里。
环境隔离的关键是配置分离:模型 API Key、知识库连接、工具端点地址都要按环境配置,绝不能把测试环境的 Key 带到生产。Dify 的环境变量功能 + 每环境独立的 .env 文件可以搞定;模型路由可以用华为云 MaaS 的多个推理端点(新版本模型开新端点,旧版本保留旧端点),灰度期间两个端点并存。
7.2 动作二:应用版本管理
Dify 的 Agent/工作流应用天然支持版本:每次编辑发布都会生成新版本,可以回滚到任意历史版本。要把版本管理用起来:
- 发布规范:每个版本对应一次明确的变更(改了什么 Agent、什么策略),版本号 + 变更说明写清楚;
- 回滚演练:定期演练"回滚到上一版本",确保回滚路径真的可用(很多团队从没演练过,真出事时发现旧版本根本起不来);
- 版本与流量绑定:路由层记录"当前各版本流量占比",灰度升档就是改这个绑定关系。
7.3 动作三:模型路由改造
多 Agent 灰度需要"同一模型位置、多版本端点、按比例分发"。Dify 原生支持在模型配置里切换,但做灰度建议在编排入口加一层轻量路由(一个 Python 服务或 API 网关即可):
# 模型路由:按用户/会话稳定分流 + 按比例灰度
import hashlib
GRAY_RATIO = 0.05 # 金丝雀比例 5%
def route_model(session_id: str, user_id: str):
# 金丝雀白名单优先
if user_id in CANARY_WHITELIST:
return "new_model_endpoint"
# 稳定哈希分流,同一会话始终同一版本
h = int(hashlib.md5(f"{user_id}:{session_id}".encode()).hexdigest(), 16)
if h % 100 < int(GRAY_RATIO * 100):
return "new_model_endpoint"
return "old_model_endpoint"
要点:哈希分流的 key 要包含稳定标识(用户/会话),不能每次请求都随机------否则同一会话内新旧模型混用,上下文行为会错乱。
7.4 动作四:自动化灰度看板
把上一期的评测流水线接进灰度流程:金丝雀期间每天自动跑一次评测(金丝雀用户的新旧版本请求各抽一批,R1 当裁判对比打分),评测结果 + 线上指标汇总成一个看板,达到升档条件自动升档,触发降级条件自动回滚。这就是第八节讲的自动回滚的输入。
八、自动回滚:什么时候必须"一键切回"
灰度没有自动回滚就是半成品------人不可能 7×24 小时盯着看板。自动回滚设计三条触发链。
8.1 触发条件(建议默认值,按业务调)
| 指标 | 触发阈值 | 观察窗口 |
|---|---|---|
| 任务完成率 | 低于旧版本 3% | 连续 30 分钟 |
| 错误率(5xx/超时) | 超过 2% | 连续 10 分钟 |
| P95 延迟 | 超过旧版本 1.5 倍 | 连续 30 分钟 |
| 单任务成本 | 超过旧版本 1.3 倍 | 连续 2 小时 |
| 评测通过率 | 低于 90% | 单次评测即触发 |
8.2 回滚动作要"分步"而不是"一刀切"
多 Agent 回滚有两个层次:
- 软回滚(首选):把流量从新版本切回旧版本(金丝雀用户全部切回、流量比例归零、开关关闭)。用户会话可能中断,但服务不宕;
- 硬回滚(兜底):整条链路切回蓝环境 + 重建会话上下文。代价大,只在软回滚解决不了时用(比如新版本把知识库写脏了)。
回滚后必须复盘 :回滚只是止血。回滚后要拉全链路 trace,用评测体系下钻定位根因(哪个 Agent、哪个策略、哪个模型),修完再走一轮"影子 → 金丝雀"流程。同一个变更不能带着未定位的 bug 反复灰度------每次都炸在同一个坑里,说明你的评测集和影子模式有盲区,要先补盲区再灰度。
8.3 回滚脚本示例
#!/bin/bash
# rollback.sh - 一键回滚:把流量全部切回旧版本
# 用法: bash rollback.sh "回滚原因"
echo "=== $(date) 回滚: $1 ===" >> /var/log/canary_rollback.log
# 1. 金丝雀白名单清空(所有用户走旧版本)
python3 update_canary.py --clear-whitelist
# 2. 流量比例归零
python3 update_route.py --gray-ratio 0
# 3. 关闭本次变更的特性开关
python3 update_flag.py --off "new_strategy_v2"
# 4. 通知
curl -s -X POST "$ALERT_WEBHOOK" -d "{\"text\":\"⚠️ 多Agent自动回滚: $1\"}"
echo "=== 回滚完成 ==="
回滚脚本要有幂等性 (重复执行无副作用)、有日志 (谁触发、何时、什么原因)、有演练(每季度演练一次,验证脚本真的能切)。
九、灰度决策矩阵:什么变更用什么灰度
不是所有变更都值得走完整灰度流程。矩阵如下:
| 变更类型 | 影响范围 | 推荐灰度方式 | 说明 |
|---|---|---|---|
| 子 Agent prompt 微调 | 局部 | 功能开关 + 金丝雀 5% | 影响小,快速验证 |
| 编排策略调整 | 全局 | 影子 3 天 → 金丝雀逐档 | 影响所有任务,最谨慎 |
| 模型版本升级 | 全局 | 影子 5 天 → A/B 对照 → 金丝雀 | 必须新旧对照看成本+质量 |
| 新工具/插件接入 | 局部 | 功能开关 + 影子 | 先看工具调用正确性 |
| 知识库更新 | 全局 | 金丝雀 20% + 评测 | 关注检索相关性与幻觉率 |
| 基础设施变更(服务器/网关) | 全局 | 蓝绿 | 无状态,蓝绿最合适 |
判断原则:影响面大(编排、模型)→ 走完整流程;影响面小(单 Agent 微调)→ 轻量灰度;无状态变更(基础设施)→ 蓝绿;有状态变更(会话、知识库)→ 影子 + 金丝雀慢档。
十、实战案例:客服系统一次 R1 模型升级的完整灰度
把以上全部串起来,看一个完整案例。背景:多 Agent 客服系统(意图识别 → 订单查询 → 售后处理 → 质检),线上 DeepSeek-R1 旧版本模型,准备升级到新版本模型,同时调整编排策略(新增"多轮追问"分支)。
第 1 天-第 3 天:影子模式。 生产流量复制 20% 到影子环境(新模型 + 新策略),脱敏后运行。3 天后对比:新版本任务完成率 94.2%(旧 93.8%),但单任务成本 +38%------新模型调用工具更频繁。结论:策略有问题,模型没问题。只灰度策略到影子继续观察。
第 4 天-第 6 天:策略修正后再影子。 给编排者 prompt 加"仅在信息不足时调用工具"约束,影子环境重跑。成本差从 +38% 降到 +6%,完成率 94.5%。通过。
第 7 天:金丝雀 5%。 5% 用户走新模型 + 新策略,其余旧版本。指标:完成率 +0.6%,P95 延迟持平,成本 +5%(在预算内)。评测抽检通过。
第 9 天:升档 20%。 出现异常:"连续追问"场景下新版本有 1.2% 的任务出现上下文丢失(用户在第五轮追问时,编排者把前四轮摘要丢了)。这是影子模式没覆盖到的(影子只跑了单轮任务占比高的流量)。立即暂停升档,金丝雀用户切回 5%,拉 trace 定位:多轮追问分支的摘要生成逻辑有 bug。修复 + 补评测集(新增长会话用例)。
第 12 天:重新灰度。 修复后的版本重新走影子(2 天)→ 金丝雀 5%→20%→50%(每档 2 天,全绿)。
第 18 天:全量切换,蓝环境保留。 绿环境承接 100% 流量,蓝环境保留 7 天后销毁。
复盘要点 :这次灰度唯一的"惊险"是 20% 档的上下文丢失------如果不是先暂停升档而是硬着头皮升 50%,影响面会大得多。灰度节奏的价值就在这:小步快跑,每档都留足观察期,把风险控制在最小范围。
十一、踩坑清单与 FAQ
11.1 踩坑 6 条
- 哈希分流 key 选错:用随机数分流,同一会话新旧模型混用,上下文行为错乱,用户看到"客服前言不搭后语"。分流 key 必须包含稳定标识(用户/会话 ID)。
- 影子模式没脱敏:真实用户数据进了评测环境,违反合规。影子流量必须先脱敏再入环境。
- 只盯质量不盯成本:新模型完成率更高但成本涨 40%,全量后账单爆炸。模型灰度必须质量 + 成本双指标对照。
- 一起灰度模型和策略:出问题分不清是模型还是策略的锅。模型、策略必须分开灰度、分开回滚。
- 金丝雀指标无防抖:单日抖动就告警,天天误报,最后没人看告警。关键指标要"连续 N 小时超阈值"才触发。
- 回滚脚本没演练:真出事时发现回滚脚本跑不通(权限问题、依赖缺失、旧版本端点已下线)。回滚路径要定期演练。
11.2 FAQ 6 问
Q1:灰度期间新旧版本的会话状态怎么兼容?
会话状态存共享存储(Redis/数据库),蓝绿只切换计算层,状态层共用。灰度用户切回旧版本时,会话上下文从共享存储读取,不会失忆。前提是状态 schema 要兼容------变更涉及状态结构时,要先做状态迁移或双写。
Q2:影子模式会不会拖垮线上?
影子流量是异步复制的,不阻塞主链路;影子环境独立部署(用 Flexus 低配实例即可),和线上物理隔离。注意影子环境要限流,别让影子请求打爆模型 API 配额。
Q3:金丝雀要跑多久才能全量?
没有固定天数,看指标:三组指标(业务/性能/成本)连续 3 天稳定不劣化,且覆盖完整业务周期(工作日+周末),就可以逐档升到 100%。快则一周,慢则一个月,别为了赶进度压缩观察期。
Q4:特性开关怎么管?开关多了会不会失控?
开关要"少而明确":一次发布只开一个新开关,开关生命周期管理(上线后及时清理废弃开关)。开关配置走配置中心,记录每次变更(谁、何时、开了什么),出问题能查到"最后一个开关是谁动的"。
Q5:评测集、影子、金丝雀三者什么关系?
三道防线递进:评测集管"已知场景不回归"(离线、快、全覆盖),影子管"真实流量长尾暴露"(在线、零风险、异步),金丝雀管"真实用户最终验证"(在线、小流量、有风险但可控)。变更越大,三道防线越要全走。
Q6:多 Agent 灰度能全自动吗?
可以做到"半自动":评测 + 指标看板 + 升档判定自动化,但"升档决策"建议保留人工确认------多 Agent 系统链路长,指标波动有滞后性,全自动升档可能踩进"指标还没反映出来就放大了"的坑。自动回滚可以全自动(保命优先),自动升档留人工。
十二、总结
这一期把"多 Agent 系统怎么安全变更"讲透了:
- 为什么难:级联失败放大、会话状态跨 Agent 分布、策略与模型耦合------不能像单 Agent 那样一把梭;
- 四维控制:流量(用户/会话/任务三级)、功能(特性开关)、模型(新旧端点对照)、策略(独立灰度),每个维度独立可调、独立可回滚;
- 三道防线:影子模式(零风险暴露长尾)→ 金丝雀(小流量真实验证)→ 蓝绿(全量切换可秒回);
- 自动回滚:错误率、延迟、成本、评测分四条触发链,软回滚优先、硬回滚兜底,回滚后必须复盘补盲区;
- Dify 落地:环境隔离、应用版本管理、轻量模型路由、自动化灰度看板,在 Flexus + MaaS 多端点上完整跑通。
如果只能带走一句话:多 Agent 系统上线变更,永远别"一把梭"------先影子观察,再金丝雀小流量,逐档放大,随时可回滚。评测决定"能不能上",灰度决定"怎么上",两者缺一不可。
至此,本系列完成了从模型接入、知识库、Agent 构建、工具扩展、策略升级、可观测性、评测守护、插件治理、成本治理、多 Agent 评测,到灰度发布的完整闭环。下一期我们聊聊多 Agent 系统的故障演练与混沌工程------当链路越来越长,怎么主动制造故障,验证系统真的扛得住。
DeepSeek 实战指南系列:
Dify 实战系列: