智能体面试准备(八十九):智能体生产环境持续交付与版本治理工程------Agent CI/CD、版本化与 Eval-Gated 发布
引言
本文是智能体系列第 87 篇。前面 B72 讲了上线交付与运维护航(发布门禁、灰度、SLO、On-call、回滚),那是"怎么把东西稳稳推上线并扛住"。但 Agent 这种系统有个本质难题:它不是一段确定性代码,而是"提示词 + 工具 + 模型 + 记忆 + 编排策略"的组合,任何一项改一点,行为就漂移。传统的软件 CI/CD 直接套用会翻车------你没法靠"编译通过 + 单测绿"就放心发布一个 Agent。
本文把 Agent 的持续交付当成一门独立工程讲:哪些东西必须版本化、怎么对"非确定性系统"做回归测试、Eval-Gated 发布门禁怎么设计、版本 Registry 与回滚怎么做。这是 Agent 平台/工程岗面试的高频深水区,也和你在做的 4MRAG 容器化交付(B55)直接呼应。
Agent 持续交付流水线
==================================================
变更来源 (4类artifact)
prompt / tools / model / orchestration
│
▼
[ 版本化 & 注册 ] ── Agent Registry(不可变版本)
│
▼
[ 离线 Eval 门禁 ] ── 黄金集 + 轨迹评测 + 回归
│ pass?
▼
[ 分级发布 ] ── 影子 → 灰度 → 全量
│
▼
[ 线上监控+自动回滚 ] ── 指标劣化即回退
一、Agent 为什么不能用普通 CI/CD
普通服务发布看"代码编译过 + 单测过 + 接口契约不变"。Agent 的发布对象里只有代码是确定性的,其余都是行为层:
| 变更项 | 确定性 | 传统 CI 能管吗 | Agent CD 需要 |
|---|---|---|---|
| 业务代码/工具函数 | 高 | 能(单测) | 单测 + 契约测试 |
| Prompt / 系统指令 | 低 | 不能 | 版本化 + 评测回归 |
| 模型版本(换 7B→13B) | 中 | 不能 | 离线 Eval 对比 |
| 编排/路由策略 | 低 | 不能 | 行为回归 + 影子 |
| 记忆/知识库快照 | 中 | 不能 | 数据版本 + 影响评估 |
核心差异:Agent 的"正确性"没有编译期保证,只能靠评测(Eval)在行为层验证。所以 Agent CI/CD 的心脏不是构建,是评测门禁。
二、版本化:四类 Artifact 都要不可变版本
Agent 的每一次可发布单元,应是 (prompt_v, tools_v, model_v, orch_v) 的不可变组合版本,登记进 Agent Registry:
python
# Agent 版本清单(声明式,进 Registry)
agent_manifest = {
"agent_id": "4mrag-retrieval",
"version": "v1.7.3", # 组合版本,不可变
"prompt_ref": "prompts/retrieval@a3f9c2",
"tools": ["ragflow_search@0.4", "rerank@1.2", "calc@0.1"],
"model": {"chat": "qwen3.8-max", "vision": "qwen3.8-max"},
"orchestration": "react@2.1",
"memory_snapshot": "kb_2026q3@sha256:...",
"eval_report": "eval/v1.7.3.json", # 绑定发布时的评测结果
"created_by": "ci-bot",
}
工程要点:① 用内容寻址(hash)引用每个子件,保证可复现;② 组合版本一旦发布不可变,回滚就是切回旧 version,绝不在线上原地改 prompt。
三、Eval-Gated 发布门禁
发布前必须过离线评测门禁,否则不开闸。门禁通常三层:
- 黄金集回归(Golden Set):一批固定高质量样例,新版本得分不得低于基线(如准确率跌 >2% 即拦截)。
- 轨迹评测(Trajectory Eval):不只看最终答案,看工具调用序列、决策路径是否合理(见 B65)。
- 对抗/越狱回归:已知 bad case 集合,新版本不能"旧病复发"。
python
# Eval-Gated 发布门禁(简化)
def eval_gate(candidate: str, baseline: str, golden, threshold=0.02):
cur = run_eval(candidate, golden) # {accuracy, tool_f1, safe_rate}
base = run_eval(baseline, golden)
report = {"cand": cur, "base": base, "diff": sub(cur, base)}
# 主指标劣化超阈值 -> 拦截
if base["accuracy"] - cur["accuracy"] > threshold:
report["gate"] = "BLOCK: accuracy regression"
return False, report
# 安全率不能低于基线
if cur["safe_rate"] < base["safe_rate"]:
report["gate"] = "BLOCK: safety regression"
return False, report
report["gate"] = "PASS"
return True, report
关键:门禁是自动且强制的,CI 不通过任何人工"跳过"按钮(或跳过需双人审批+留痕)。否则门禁形同虚设。
四、分级发布:影子 → 灰度 → 全量
Agent 行为不确定,必须渐进发布:
| 阶段 | 流量 | 目的 | 观察指标 |
|---|---|---|---|
| 影子(Shadow) | 0 真实影响 | 新版本跑真实流量但不回流给用户 | 轨迹差异、延迟、异常率 |
| 灰度(Canary) | 1%~10% | 小流量验证真实效果 | 满意度、工具成功率、成本 |
| 全量 | 100% | 正式接管 | SLO、ROI |
python
# 灰度路由(按租户/用户分桶)
def canary_route(user, agent_v_map):
bucket = hash(user.id) % 100
if bucket < 10: # 10% 灰度
return agent_v_map["candidate"]
return agent_v_map["baseline"] # 其余走稳定版
注意 Agent 的灰度比普通服务难:它有状态与副作用(写数据库、发邮件)。灰度环境必须隔离副作用(沙箱/影子写),否则灰度流量污染真实数据。
五、线上监控与自动回滚
发布后靠线上指标兜底,劣化自动回退:
- 触发信号:满意度下降、工具调用失败率升、成本超预算、安全拦截率异常。
- 回滚动作:切回 Registry 中上一稳定 version(秒级,因为版本不可变)。
- 回滚保护:回滚本身也要记录,避免来回抖动(回滚后冷却期)。
python
# 自动回滚(基于滑动窗口指标)
class AutoRollback:
def __init__(self, registry, window=300):
self.reg, self.win = registry, window
def tick(self, metrics, current_v):
if metrics.satisfaction_5m() < self.reg.baseline_sat - 0.05:
prev = self.reg.prev_stable(current_v)
self.reg.switch(current_v, prev) # 切回稳定版
log_rollback(from_v=current_v, to_v=prev, reason="sat_drop")
六、常见坑与对策
| 现象 | 根因 | 对策 |
|---|---|---|
| 发布后行为"看起来没变"但用户投诉 | 只测最终答案,没测轨迹 | 加轨迹评测 + 影子对比 |
| 回滚后问题依旧 | 根因在共享工具/知识库,非 Agent 本身 | 工具/KB 也要版本化 + 影响评估 |
| 灰度污染真实数据 | 灰度 Agent 有真实副作用 | 副作用沙箱化 / 影子写 |
| 门禁总被"跳过" | 跳过太容易 | 强制自动 + 双人审批留痕 |
| 版本爆炸难追溯 | 子件没内容寻址 | 全量 hash 引用 + 不可变组合版 |
| 评测集过时 | golden 不更新 | golden 集随 badcase 持续回流 |
面试速答
- Agent 为什么不能套普通 CI/CD?因为发布对象里 prompt/模型/编排都是非确定性行为层,编译+单测保证不了正确性,只能靠 Eval 在行为层验证。
- Agent 要版本化哪些东西?四类 artifact:prompt、tools、model、orchestration(加 memory 快照),组合成不可变版本进 Registry,回滚即切版本。
- Eval-Gated 门禁看什么?三层:黄金集回归(主指标不劣化)、轨迹评测(工具调用/决策路径)、对抗回归(旧 badcase 不复发);门禁必须自动强制。
- Agent 灰度为什么比普通服务难?它有状态和副作用(写库/发消息),灰度流量会污染真实数据,所以副作用必须沙箱化或影子写。
高频追问清单
- 当 prompt 和模型同时变更,怎么归因是哪一个是回归根因?
- 评测集(golden)本身有偏差,门禁会不会"奖励错误"?如何防?
- Agent 有长周期记忆,灰度版本读到的记忆和稳定版不一致怎么办?
- 多智能体系统(B58)整体怎么版本化?子 Agent 各自版本如何约束兼容?
- 回滚后用户会话上下文还在旧版,要不要一并回滚会话?
- 评测成本很高(跑大模型打分),如何把门禁成本控制住?
- 私有化交付(B55)下,客户环境没有 CI,怎么把 Eval 门禁下沉?
- Agent 的"行为契约"能像 HTTP 契约测试那样形式化吗?难点在哪?