AI 基建
0%
第十一部分 · 实践与运营 · 第 89 章

部署生命周期

作者Changkun Ou
阅读时长约 9 分钟

一个训练好、并且已经能对外吐出 token 的模型(第 31 章),仍然不是一个被运维起来的系统。还需要一套机制决定哪个版本在线上、把流量迁到新版本上而不至于让整个用户群承担风险、在行为发生漂移时察觉到、并在出错时把改动撤回。生产中的 AI 运维因此要把部署生命周期当成一门独立学问:可部署的产物是一个捆绑包,候选版本进入生产靠统计意义上的提升流水线,而回滚必须把模型、提示、检索索引、工具与护栏配置一起恢复。

2026-06-21T23:29:38.331874 image/svg+xml Matplotlib v3.11.0, https://matplotlib.org/ 0 1 2 3 4 5 发布阶段 0.0 0.2 0.4 0.6 0.8 用户可见风险 一次性部署 金丝雀放量
图 89.1. 部署生命周期中发布风险的示意图。相比一次性大爆炸发布,金丝雀渐进能把用户可见风险限制住。理想化曲线,非实测。

把机器学习放到生产里跑了十年,反复学到的一课是:模型只是其中很小的一块。2015 年那篇给问题命名的论文说得很直白:一个真实的机器学习系统里,只有极小一部分是学习代码,其余都是配置、数据管道、服务基础设施,以及让这一切保持可信的监控 (Sculley et al. 2015)。部署生命周期就是运维这一圈外围质量的地方。本书此前只在训练时和服务时搭起过这套外围,部署生命周期补上的是它运行时的另一半。

产物不是模型

第一个误区,是以为被部署的东西是一组权重。在现代技术栈里,产出一个行为的单位是一个捆绑包,就像容器镜像把代码连同它的运行环境一起打包,只不过这里打包的是一个模型行为:模型版本、系统提示、解码参数、模型被允许调用的工具 schema、它读取的检索索引(第 44 章),以及围绕它的护栏配置。其中任何一项变了,可观察到的行为都可能变得和换权重一样大。在同一个 checkpoint 上换一份新的系统提示,就是一次新的部署,而一旦把它当成一次单纯的文本编辑,一处悄无声息的提示改动就会在一周后变成一次无人能归因的回归。

所以登记表(registry)必须给捆绑包做版本,而不是给 checkpoint 做版本。运维上的规则是:每一个能移动输出的元素都被钉住、被一起记录,而一次部署用单一标识符指向一个不可变的捆绑包。这就是 ML Test Score 评分体系背后的纪律,它给一个系统打分,不看它的准确率,而看它的数据、模型与基础设施是否被测试、是否可复现到足以让一个没参与搭建的人也能跑起来 (Breck et al. 2017)。一项对从业者的访谈研究从一线得出了同样的结论:那些能保持清醒的团队,是把数据与配置的版本管理看得和代码版本一样认真的团队;而没这么做的团队,把时间都花在追查没人能归因的改动上 (Shankar et al. 2022)。

cluster_B 一个部署捆绑包(不可变 id) W 模型版本 / 权重 S 线上行为 W->S P 系统提示 P->S D 解码参数 D->S T 工具 schema T->S R 检索索引版本 R->S G 护栏配置 G->S
图 89.2. 可部署的产物是一个捆绑包,而非一个 checkpoint。登记表钉住每一个能移动输出的元素,并用一个不可变 id 指向整体,于是行为变化总能归因到一次有名有姓的部署。

提升流水线

产物定义清楚之后,问题就变成:一个候选捆绑包如何取代当前在线版本。答案是一条逐级扩大暴露面的流水线,而它之所以要分阶段,是因为每一阶段都能抓住上一阶段抓不住的失败。

第一道关口是离线的。一个候选版本在基准测试套件(第 47 章)上跑,并带着 第 48 章 的不确定性纪律来读;对智能体而言,还要在 第 52 章 的轨迹评测、第 50 章 的评审准则,以及 第 53 章 的运营策略上跑。这道关口便宜,而且完全在掌控之内,它能在任何用户看到之前抓住明显的回归。它的弱点是:它衡量的是早就知道该去测的那个世界,而生产则是尚未预料到的那个世界。

于是候选版本接下来去见真实流量,却不影响任何人。在影子(shadow)或镜像(mirror)模式下,线上请求被复制一份给候选版本,候选的输出被记录、被打分,而只有当前版本的输出会返回给用户。影子模式以零用户风险揭示评测集与线上输入之间的分布差距,它的主要代价是让两个模型并跑一段时间的算力。

候选版本通过影子阶段之后,真正的暴露才开始。金丝雀(canary)把一小部分百分比的线上流量导给候选版本,盯住在线指标:延迟、错误率、拒答率,以及产品能测的任何任务成功代理量,然后只在这些指标稳住时才把百分比往上调。在小爆炸半径上放量、在扩大之前先盯住真实信号,这套纪律是 Google 生产手册里最老的一条思想,早在机器学习之前就有了 (Beyer et al. 2016)。蓝绿(blue-green)是同一个思想的另一种形态:两套完整环境、瞬时切换,代价是同时跑两支机队。这条流水线画在 图 89.3

C 候选捆绑包 O 离线评测闸 C->O SH 影子 / 镜像流量 O->SH 通过 RB 回滚 / 暂停 O->RB 失败 CA 金丝雀从 1% 放到 100% SH->CA 指标稳住 SH->RB 差距过大 F 全量上线 CA->F 指标稳住 CA->RB 回归
图 89.3. 把提升看作逐级扩大的暴露面。每一阶段抓住上一阶段抓不住的东西:离线闸抓住已知回归,影子流量以零用户风险抓住评测到生产的分布差距,金丝雀放量在全量铺开前在小爆炸半径上抓住线上失败。任一阶段的指标不达标都会折回到回滚。
下层约束

服务是从一个分布里采样的,所以同一个输入跑两次并不会返回同样的字节(第 31 章)。这个完全活在推断层里的事实,规定了两层之上发布流程的形态:无法靠把候选版本的输出和在任版本逐字相比来提升它,因为哪怕什么都没改,它们也会不一样。提升只能是统计意义上的。要比较的是某个打分指标在大量请求上的分布,问的是候选版本是否在显著性上更差,而不是某一条输出是否变了。这正是为什么 第 52 章 的评测框架会悄悄变成发布闸门:决定一次部署能否上线的,和决定一个智能体好不好的,是同一套机器,而一个没有可信框架的团队,也就没有可信的方式去做提升。

当脚下的地面在移动

一次部署在它上线那天是好的,并不会一直好下去,因为它服务的世界一直在动。有两种漂移要紧,而且它们朝相反的方向失败。

输入漂移是常见的那种:用户发来什么的分布逐周偏移,一个新用例出现了,一次产品发布改变了在提问的人是谁,于是上个月把评测刷到满分的候选版本,如今在回答它从没见过的问题。应对办法是让回归套件从生产本身长出来。一条线上系统处理得很糟的轨迹,被用户反馈或在线评审抓到后,被提升进离线套件,于是下一个候选版本就会在它上面被打分。因此这套套件永远没有完工的一天,它是系统已经犯过的每一种错误留下的累积记录,而把这个回路当作基础设施来运维的,是关于生产数据引擎的那一章(第 92 章)。

行为漂移是构建在并非自己托管的模型之上时特有的那种。当产品调用一个第三方端点(第 73 章),提供商可以在一个稳定的名字下把模型升级掉,而自以为已经钉住的捆绑包,在自己这边没有任何一次部署的情况下就移动了。上个季度验证过的输出,这个季度是由一个不同的模型产出的,而自己的变更日志里没有任何一条记下这件事。主要的应对手段,是趁提供商给出明确日期时钉住对应的模型版本,并对线上端点持续跑一支固定输入的金丝雀,让一次悄无声息的升级表现为一个看得见的指标偏移,而不是一张解释不了的工单。

事件响应,以及必不可少的那次回滚

这些流程都假定改动能被撤回,而对一个模型系统来说,这个撤回不像对代码那么直接。回滚权重很容易,只要上一个捆绑包在登记表里仍然可寻址,而这正是给捆绑包而非给 checkpoint 做版本的全部回报。回滚一个从提示与检索的交互里冒出来的行为,则只有在提示与索引版本被钉在同一个捆绑包里时才容易,这就是为什么登记表的纪律不是记账,而是恢复的前提。运维上的最低标准是:上一个良好的捆绑包永远只差一次路由改动,且金丝雀的在线指标接到了告警,于是一次回归在抵达所有人之前、而不是之后,触发一次回滚。

一个最小的提升与回滚控制回路让这个形态变得具体。闸门是一次统计比较,回滚是一次路由改动,不是一次重建。

def promote(candidate, incumbent, traffic, alpha=0.01):
    # 离线闸:候选版本不得在留出套件上出现回归。
    if score(candidate, OFFLINE_SUITE) < score(incumbent, OFFLINE_SUITE):
        return hold(candidate, reason="offline regression")

    # 分阶段扩大暴露面,比较的是分布,而非单条输出。
    for pct in (0, 1, 5, 25, 100):          # pct == 0 即影子:记录,不对外服务
        route(candidate, fraction=pct)
        cand, base = sample_scored_metrics(candidate, incumbent, traffic)
        if worse_with_significance(cand, base, alpha):
            route(incumbent, fraction=100)   # 回滚是一次路由改动
            return hold(candidate, reason=f"regression at {pct}%")
    return live(candidate)
什么仍有争议
  • 钉住一个版本,还是追最新。 钉住一个带日期的模型,换来可复现性和一份稳定的行为契约;追提供商的最新,换来白拿的能力增益,却交出了那份契约。受监管的系统和智能体系统偏向钉住;想要最新能力的消费级功能偏向追新。没有一种设置能两头都赢。
  • 离线评测,还是强制的在线金丝雀。 一派信任一套强离线套件来把守提升,把金丝雀当成走过场;另一派坚持没有哪套离线套件能把线上行为预测得足够好,所以金丝雀才是真正的闸门,而离线数字只是一道筛子。这场分歧其实是在争:任何人的评测集到底有多大代表性。
  • 轨迹回放对线上行为的预测力有多强。 把生产轨迹拿来对候选版本回放,是最便宜的真实性来源,但一个随机的、依赖上下文的智能体,在回放时未必会重现它在线上做过的事,所以回放的预测价值本身就尚无定论。

部署生命周期带来什么

部署生命周期几乎不新增能力;一个模型在被提升之后,恰好和之前一样能干。它提供的是另外两样东西。效率是这套机器的成本:影子和金丝雀意味着同时跑不止一个捆绑包,并为把守每次提升的评测算力买单,而运维上的问题是,给定的风险水平能撑得起多少这样的保险。信任是这条流水线的核心产出。这条流水线之所以存在,是为了让一次对生产行为的改动可归因、可逆、且在影响扩大前被发现,而一个团队如果说不清哪个捆绑包在线上、不靠逐字比对输出就无法提升、或无法用一次路由改动回滚,那它握着的就是一个能干的模型加一个不可信的系统。下一章把信任的问题进一步带入一个输出在构造上就是非确定的系统的可靠性(第 90 章)。

延伸阅读

  • Sculley et al., “Hidden Technical Debt in Machine Learning Systems” (外围质量占大头的论证,以及配置与管道的现实), 2015. papers.nips.cc
    这篇 NeurIPS 2015 论文指出,真实机器学习系统因边界侵蚀、纠缠、隐藏反馈回路和数据依赖等特有反模式而积累大量隐性技术债务。
  • Breck et al., “The ML Test Score: A Rubric for ML Production Readiness and Technical Debt Reduction” (把测试与可复现性作为就绪标准), 2017. research.google
    Breck 等人提出 ML Test Score,一套覆盖数据、模型、基础设施与监控的 28 项可操作测试评分准则,用于量化 ML 系统的生产就绪程度并指导技术债务削减。
  • Shankar et al., “Operationalizing Machine Learning: An Interview Study” (从业者真正在做什么:版本管理、漂移,以及速度与可复现性之间的张力), 2022. arXiv:2209.09125
    对18位机器学习工程师的访谈研究识别出MLOps成功的三个关键变量(速度、验证、版本管理),并记录了在生产环境中部署和维护机器学习流水线的实践与痛点。
  • Beyer, Betsy; Jones, Chris; Petoff, Jennifer; Murphy, Niall Richard. Site Reliability Engineering: How Google Runs Production Systems (金丝雀、错误预算,以及在小爆炸半径上放量). O'Reilly Media, 2016. sre.google
    Google SRE 书籍阐述了大规模生产系统可靠运行所用的原则、实践与组织结构,涵盖服务等级目标(SLO)、值班、事故管理与自动化。

评论

登录后评论