第 17 章:部署与运维:灰度、监控与回滚¶

上线不是把版本推上去就算完事,而是要把不确定性关进笼子:你知道怎么灰度、怎么看盘、怎么回滚、怎么复盘。没有回滚能力的发布,本质上就是在赌博。[5][6]
AI 产品的运维比传统软件更凶险:模型微调了一下、提示词改了两个字、检索库更新了一批文档,或者工具定义换了个参数,任何一处变动都可能导致线上的行为分布发生剧烈漂移。你不能只监控错误率(Error Rate),你得监控“质量、成本、风险”这三座大山。把这些指标纳入发布门禁,你才能在持续迭代的同时,不被线上的各种“惊喜”拖垮。[6]
你将收获什么¶
- 一套发布策略:从 1% 流量灰度到全量,什么时候该推进,什么时候必须暂停,什么时候立刻回滚。[5]
- 一份运维观测口径:别光看 CPU/内存,要学会同时盯着 质量/延迟/成本/风险 四条线看。[6]
- 一份救火 Runbook:事故发生时,脑子通常是懵的。你需要一份按表执行的操作手册,而不是现场凭直觉瞎指挥(Runbook 库详见:E-runbooks.md)。[5]
三层思考:运维就是让系统"坏"得慢一点¶
第 1 层:论证链条¶
可控发布的逻辑链条非常硬:
版本化(代码/配置/提示/模型全是版本)→ 灰度策略(先让少数人试毒)→ 观测口径(死死盯着关键指标)→ 告警处置(响了就得动)→ 回滚复盘(快速止损并转化成经验)→ 回归集更新(把坑填上,下次不准再掉进去)
如果你没有版本化,你就解释不了为什么今天变笨了;如果你没有回归集,你就防不住同一个 bug 下个月再来一次。[6]
第 3 层:落地与验收¶
验收这章学没学会,就看三件事: 1. 可追溯:你能明确说出这次发布到底改了哪几个提示词、换了哪个索引切片吗? 2. 可执行:你能在 10 分钟内完成回滚或降级吗? 3. 可复利:每次事故后,你能产出一个复盘文档,并把失败样本塞进自动化回归测试里吗?[6]
关键流程:可控发布闭环¶
不要迷信复杂的流程图,核心逻辑就这几步,缺一步就是裸奔:
1. 版本化打包:代码 + Config + Prompt + Model + Index + Tools = Version Set
2. 小流量灰度:先放 1% 或指定白名单用户(可控样本)
3. 四线观测:盯着 质量 / 延迟 / 成本 / 风险
4. 决策关口:
- 达标 -> 推进扩量
- 波动 -> 暂停分析
- 越界 -> 立即回滚/降级(按表执行,别犹豫)
5. 现场取证:固定证据包(请求样本/日志/指标/版本快照)
6. 复盘闭环:结论 + 行动项 -> 只有更新了回归集,事故才算结束
建议:证据包(Evidence Pack)不要散落在聊天记录里,统一存到 reports/YYYY-MM-DD/<change-id>/。目录结构和字段模板直接抄这里:附录 D:证据包与门禁速查。
版本化:把变化变成“对象”¶
在 AI 系统里,只管理代码版本是远远不够的。你得把下面这些也管起来: - 提示词与输出合同:Prompt 变了,输出格式(Output Contract)可能就变了。 - 检索配置与索引版本(RAG):切片大小(Chunk Size)变了,召回结果就全变了。 - 工具清单与权限边界(Agent):工具参数改了,模型可能就不会用了。 - 模型版本与后训练策略:底模微调过没?用的哪个 Checkpoint?
落地做法(0→1)¶
把非代码资产当成“制品”(Artifact)来管理,别让它们在文件系统里裸奔。
- 大文件:模型权重、向量索引快照,用 Git LFS 或专门的制品库(如 S3 + 版本号目录)存好。
- 数据与索引:用 DVC 或简单的 manifest 文件记录。索引不是随手跑出来的,它是一次发布的产物,必须有 index_version。
- Prompt Hub:把 prompt 集中管理,别散落在代码字符串里。日志里必须打印 prompt_version。
- Version Set:每次发布,输出一个“版本组合 ID”,包含 {code_v, prompt_v, model_v, index_v}。出了问题,先看这个组合 ID 对不对。
输出合同(Output Contract):这不仅是 JSON Schema,更是你和模型之间的契约。字段有哪些?必填项是啥?长度限制多少?允许的枚举值是什么?把它当成 API Schema 来管理,并在代码里做强校验。灰度时,这个合同就是你的法律依据。
特别提醒 RAG:向量索引必须版本化。你不能说“我更新了知识库”,你应该说“我发布了索引 v2025.12.24.01”。这样一旦线上发现检索质量雪崩,你可以像回滚代码一样,瞬间切回 v2025.12.24.00,而不是在线上且战且退,试图修复数据。[6]
灰度发布:别拿全量用户做实验¶
灰度的本质很简单:在真实环境验证假设,但把爆炸半径控制在你赔得起的范围内。[5]

灰度策略卡:按表操作,禁止临场发挥¶
| 维度 | 说明 |
|---|---|
| 灰度对象 | 内部员工 / 白名单用户 / 1% 随机租户 |
| 观察窗口 | 至少覆盖一个完整的使用周期(如 24 小时) |
| 通过门槛 | 质量不降、延迟达标、成本可控、风险为零 |
| 暂停条件 | 任一守门指标出现“看不懂的波动” |
| 回滚条件 | 守门指标越过红线(Error Rate, Latency, Cost) |
门槛怎么定?¶
别拍脑袋定个绝对值。用基线(Baseline)加波动范围。 - 基线:取上一个稳定版本过去 7 天的 P50/P95 数据。 - 红线:绝对不能触碰的底线(如:注入攻击成功、敏感数据泄露)。
| 监控线 | 指标 | 通过门槛 (Example) | 暂停阈值 (Example) | 回滚阈值 (Example) |
|---|---|---|---|---|
| 质量 | 采纳率、任务成功率 | ≥ 基线 | < 基线 - 3% | < 基线 - 5% 或 出现严重 Bad Case |
| 延迟 | P95、超时率 | ≤ 基线 + 10% | > 基线 + 15% | > 基线 + 25% 或 超时率翻倍 |
| 成本 | 单次 Token 消耗 | ≤ 基线 + 10% | > 基线 + 15% | > 基线 + 25% 或 预算耗尽速率异常 |
| 风险 | 注入/越权/泄露 | 0 事件 | 命中红队样本 | 任一 越权/泄露/注入 成功即回滚 |
灰度推进手册:推进、暂停、回滚¶
灰度最考验人心态的时候,就是数据“似是而非”的时候。比如延迟涨了一点点,但用户没投诉。这时候千万别开会讨论“这算不算问题”,直接按表执行:信号不确定就暂停,指标越界就回滚,只有证据确凿才能推进。[5][6]
决策表(打印出来贴墙上):
| 信号状态 | 你的动作 | 必须留存的证据 | 资产回写 |
|---|---|---|---|
| 绿灯:指标稳定,业务指标向好 | 推进 (扩量/延长观察) | 当前版本号;关键指标截图;Trace 对比 | 新增正向样本:把这次改进带来的收益固化成测试用例 |
| 黄灯:指标波动,但在历史范围内 | 暂停 (保持流量,查原因) | 分桶对比报告(新旧版本/不同租户);失败日志 | 补充分布样本:把导致波动的特定输入/场景加到回归集 |
| 红灯:错误率/延迟/成本 越界 | 回滚 (切回上一版本) | 触发回滚的告警图;最小复现请求 (Curl) | 事故复发样本:把这个坑写进阻断级测试,严防死守 |
| 黑灯:安全事故 (注入/泄露) | 止损 (强回滚 + 关入口) | 审计日志;攻击链路;影响面清单 | 红线样本:攻击样本入库,以后这就是发布红线 |
监控口径:四线同看¶
AI 产品上线后,如果你只看 HTTP 200/500,那你离死不远了。必须建立四维监控视图:[6]
- 质量线:用户到底爽不爽?(点赞/点踩、采纳率、任务完成度)。
- 延迟线:这玩意儿慢不慢?(P95、首字延迟 TTFT、总生成耗时)。
- 成本线:这玩意儿贵不贵?(Token 消耗速率、GPU 占用、API 账单预估)。
- 风险线:这玩意儿安不安全?(越权调用、敏感词触发、注入尝试)。
风险治理:把 AI 特有风险做成门禁¶
风险控制不是靠人盯着看,而是要自动化阻断。
风险控制卡:
| 风险类型 | 监控指标 | 动作 |
|---|---|---|
| 注入突破 | 注入攻击成功率 | 发现 1 例即回滚 |
| 越权调用 | 未授权的 Tool Call | 立即阻断 + 封禁用户 + 报警 |
| 数据泄露 | PII 匹配命中率 | 超过基线即回滚 + 审计 |
| 幻觉 | 无引用断言比例 | 暂停灰度,补测数据 |
| 过度拒答 | 拒答率飙升 | 调整安全策略,别把正常用户杀误伤了 |
观测性:把“看见”变成默认能力¶
不要等出了事再去加日志。最低要求:打通 Logs (日志)、Metrics (指标)、Traces (链路) 三件套。并且,必须有一个唯一的 ID 把它们串起来。[61]
最小可观测字段合同¶
请把下面这些字段刻在你的代码里,缺一不可:[61]
trace_id: 全链路唯一标识,没有它你根本查不清问题。version_set:{model: "gpt-4", prompt: "v1.2", index: "20251224"},出了事得知道是哪个版本惹的祸。[6]tokens_in/tokens_out: 算钱用的,也是算延迟瓶颈用的。[6]tool_calls: 调了啥工具?耗时多少?成功没?latency_ms: 别只记总耗时,要拆分:排队、检索、首字、生成。
示例:一个能跑的最小观测闭环 (Python)¶
别整那些虚的,先搞定最基本的 trace_id 透传和指标暴露。我们复用 docs/examples/inference/budgeted_gateway.py (假设已存在,或参考下文逻辑)。
怎么验证你的观测闭环是通的?
-
启动网关 (Mock 模式):
bash python3 docs/examples/inference/budgeted_gateway.py --provider mock --port 8787 & PID=$! # 等待服务启动 sleep 2 -
发请求带上 Trace ID: ```bash # 构造 payload python3 -c "import json; print(json.dumps({'user_id': 'u1', 'prompt': '测试回滚', 'budget_ms': 1000}, ensure_ascii=False))" > /tmp/payload.json
发送请求,强制带上 x-trace-id¶
curl -sS -X POST http://127.0.0.1:8787/chat \ -H 'Content-Type: application/json' \ -H 'x-trace-id: canary-test-001' \ --data-binary @/tmp/payload.json > /tmp/response.json
echo "Response:" cat /tmp/response.json ```
-
检查指标:
bash curl -sS http://127.0.0.1:8787/metrics | grep "gateway_requests"预期输出:你应该能看到gateway_requests_total和gateway_requests_latency_seconds有变化。 -
清理:
bash kill $PID rm /tmp/payload.json /tmp/response.json
这个实验告诉你:Trace ID 是你唯一的救命稻草。无论是日志、指标还是报错,只要带上这个 ID,你就能还原现场。[61]
推理服务:从能跑到能运维¶
服务选型不是看谁跑分高,是看谁能运维。
- KServe: 适合已经是 K8s 重度用户的团队,标准化程度高,运维界面统一。[63]
- TGI (Text Generation Inference): Hugging Face 出品,适合想快速把模型跑起来且性能不错的团队,支持流式、支持量化,开箱即用。[49]
- vLLM: 吞吐量大杀器,如果你自己搞推理服务,大概率会用到它作为后端。
选型灵魂拷问: 1. 能 10 分钟回滚吗? 如果回滚需要重新打镜像、推仓库、拉起容器,那就不合格。最好是切配置就能回滚。 2. 能限流吗? 别指望自动扩缩容救你,那是滞后的。必须有配额(Quota)和限流(Rate Limiting)。 3. 多租户隔离了吗? 别把 A 公司的 Prompt 泄露给 B 公司。
告警与处置:先保命,再治病¶
告警响了,优先级如下: 1. 降级:关掉费钱的工具,切断复杂的逻辑,只留核心对话。 2. 限流:把超额的用户踢掉,保住大盘。 3. 回滚:切回上一个版本。 4. 复盘:等火灭了,再慢慢查原因。
模板:事故 Runbook (10 分钟止损版)¶
把这个表格填好,打印出来,贴在屏幕旁边。
| 阶段 | 时间限制 | 动作指令 | 产出物 |
|---|---|---|---|
| 感知 | T+3min | 确认影响谁?挂了多少?核心功能能不能用? | 影响范围通告 |
| 止损 | T+7min | 能降级先降级,不能降级立刻限流,搞不定就回滚。别查 Bug! | 止损操作记录 |
| 取证 | T+10min | 截取告警图,保存失败的 Trace ID,导出当前配置快照。 | 证据包 (Evidence Pack) |
| 定位 | T+N | 拿到证据包,在预发环境复现。 | 最小复现 Payload |
| 根治 | T+24h | 修复 Bug,把 Case 加到回归集,写复盘文档。 | 回归集更新 + 复盘报告 |
常见陷阱¶
- “幽灵发布”:出了事问改了啥,回答“好像改了点 Prompt”。如果你不能精确指向一个 Version Set,你就是在裸奔。[6]
- “无代表性灰度”:灰度只放了内部员工,结果上线被真实用户的长文本把 GPU 显存撑爆了。灰度样本必须包含攻击样本、长文本样本和高成本样本。[6]
- “回滚死循环”:想回滚,发现数据库结构变了,或者索引格式变了,回不去了。永远保留上一个版本的兼容性,或者保留旧版本的全套环境。[5][6]
交付物清单与验收标准¶
- [ ] 灰度策略卡:明确写着通过和回滚的数字门槛。[5]
- [ ] 四线监控面板:Grafana 上必须有 质量/延迟/成本/风险 四个板块。[6]
- [ ] Runbook:必须有一份 10 分钟止损手册。[5]
- [ ] 可观测性证明:任意给一个 Trace ID,能查到它的输入、输出、耗时拆解和版本号。[61]
- [ ] 推理服务方案:明确是用 KServe、TGI 还是托管 API,并有配套的回退路径。[49][63]
下一章¶
运维保的是底线,评测保的是上限。下一章我们将深入构建一套无情的评测机器:离线评测、在线监控、红队演练与持续回归。去这里:18-evaluation.md。
参考¶
详见本书统一参考文献列表:references.md。