内网离线环境的大模型底座升级与镜像分发落地

日期:2026-08-10

一、项目背景

这个项目的环境比较特殊:客户单位的机房是物理隔离的,跟外网之间连网线都没有,数据进出全靠专人拿移动介质摆渡,还要走审批。机房里跑着一套私有化的 AI 底座,支撑内部的文档问答、公文辅助写作和几个审核类应用。

隔离环境本身不新鲜,难受的是升级。他们前一次升级底座版本的过程大概是这样:运维在外网环境把新版本的容器镜像、依赖包、模型权重打包,压出来接近四百 G,刻到移动硬盘上,走完介质审批带进机房,插上拷贝,拷贝两个多小时,然后 docker load,再一个一个改配置、重启服务。整个升级窗口批的是两小时,实际上从拷贝开始算就超了。那次是拖到凌晨四点才收工,中间还因为一个依赖版本对不上回滚了一次。

运维主管跟我说,他们现在的策略是能不升级就不升级,上一个版本用了十四个月,明知道有性能优化也不敢动。这就形成了恶性循环:越不敢升级,版本跨度越大,下次升级风险越高。

我们要解决的就是这个循环。

二、落地场景

方案没有黑科技,核心是把"一次性大搬运"拆成"可增量、可验证、可回退"的小步骤。

离线制品仓与依赖固化。在外网侧建了一个制品仓,所有依赖(Python 包、系统库、模型权重、镜像层)在这里统一下载、校验、固化版本,产出一份带哈希的清单。内网侧对称建一个只读的制品仓,摆渡进去的只有增量。这一步的关键是把"随机下载"变成"清单驱动",不允许构建过程临时联网拉东西。

增量镜像分层分发。镜像重新做了分层设计:基础系统层、CUDA 与驱动依赖层、推理框架层、业务代码层、模型权重单独走。前面三层变化极少,业务代码层小,模型权重最大但也不是每次都换。这样一次常规升级要摆渡的量从几百 G 降到几 G 甚至几百 M。内网侧用一个轻量镜像仓做分发,各节点从这里拉,不再是每台机器单独拷。

灰度升级与快速回滚。内网机房有多个推理节点,升级按节点分批:先升一个节点,摘流验证,通过后放百分之十流量观察,再逐批推。旧版本的容器不删,保留在本地,回滚就是把流量切回去加重启旧容器,目标是三分钟内完成。

升级前后一致性校验。这块是客户最在意的。升级完成后自动跑一套校验:环境层面比对依赖清单哈希,服务层面跑健康检查和接口冒烟,效果层面跑一套固定的两百条问答基准,把答案跟基线版本做相似度比对,偏差超阈值就告警。

三、关键技术挑战与解决思路

无外网环境下的依赖解析。 听起来简单,实际最折磨人。Python 生态里一个包的依赖树能拉出上百个包,还有平台相关的二进制轮子。我们最早的做法是在外网机器上 pip download,结果带进内网安装时报缺依赖,因为下载机器的 Python 小版本和目标环境差了一位。后来改成在一台跟内网完全一致的"镜像机"上做构建,操作系统、内核、驱动、Python 版本全部对齐,构建产物直接封装成镜像层,不在内网做任何 pip 安装。这个改动之后,因依赖问题导致的升级失败降到零。有点笨,但隔离环境里笨办法最可靠。

大镜像分发的耗时。 模型权重是大头,一个几十 G 的权重文件在内网千兆环境下分发到八个节点,串行拷贝要几个小时。我们做了两件事:权重从镜像里剥出来,放共享存储,节点挂载而不是各存一份;确实需要分发的部分改成 P2P,节点之间互相传,第一个节点从仓库拉,后面的节点从已有节点拉。八节点的分发时间从三个多小时压到不到二十分钟。

版本漂移与环境差异。 隔离环境跑久了,各节点难免被人手工改过东西,某台机器上多装了个包、某台的配置文件被临时改过。升级时这些差异就变成随机故障。我们加了一个升级前的环境体检,比对每个节点的依赖哈希、内核参数、驱动版本、关键配置文件,跟基线不一致的先列出来让运维确认。第一次跑体检就查出三台机器有手工改动痕迹,其中一台的显存参数被人调过,一直没人知道。

回滚时的数据兼容。 版本一升,向量库的索引格式变了、对话历史表加了字段,这时候回滚就麻烦。我们的处理是:数据层的变更必须向前兼容,新版本只加字段不改语义,加的字段要有默认值;索引格式如果变化,升级时保留旧索引,双写一段时间,确认稳定再删旧的。这条规矩定下来之后,回滚就变成了纯粹的服务层动作,不涉及数据恢复。有一次真回滚了,从决定到恢复正常用了两分四十秒。

案例片段(已脱敏):依赖清单与摆渡增量

``` manifest_v2.4.1.lock (节选)  base-os          sha256:7c1f... 未变 (复用 v2.3.0)  cuda-runtime     sha256:a90b... 未变  infer-framework  sha256:3e44... 变更 (vLLM 版本升级)  app-code         sha256:c812... 变更  model-weights    sha256:f105... 未变 (复用)

本次摆渡包大小:3.7 GB(上一次全量:392 GB) 介质审批单号:MJ-2025-0417   校验:全部 sha256 通过 ```

案例片段(已脱敏):升级后一致性校验报告

[环境校验]  8/8 节点依赖哈希一致 [冒烟测试]  12/12 接口通过(含流式、批量、embedding) [效果基准]  200 条基准问答    答案相似度均值 0.971(阈值 ≥0.95)    低于阈值 3 条:Q-047 / Q-112 / Q-166    人工复核:3 条均为表述差异,事实一致,判定通过 [性能对比]  P95 首字延迟 1.42s -> 1.18s(-16.9%)            吞吐 tokens/s  提升约 21% 结论:允许放量至 100%

四、效果数据

改造完成后,客户已经用新流程做了四次升级,其中一次是跨两个中版本的较大更新。

升级窗口时长从上一次实际用掉的五个多小时(批准两小时,超时)降到平均三十八分钟,最长的一次是那个跨版本更新,用了一小时零六分钟,仍在批准窗口内。运维不用再熬夜了,这一条他们提得最多。

摆渡数据量降幅最明显,常规升级从几百 G 降到个位数 G,介质审批的流程也跟着简化了,因为量小到可以用加密 U 盘走快速通道。四次升级平均摆渡包大小四点二 G。

分发耗时从三个多小时降到二十分钟以内,主要是共享存储加 P2P 的功劳。

回滚成功率是四次里触发过一次,成功,耗时两分四十秒。虽然样本少,但演练做了六次,都在三分钟内完成。

升级失败次数为零。这里的失败指的是升级后服务不可用或效果明显退化,需要计划外处理。相比之前平均每次升级都要处理一到两个意外,改善还是实在的。

顺带的收益是版本节奏,客户从"一年多不敢动"变成了现在每季度跟一次版本,最新的推理框架优化他们也用上了。文中数据为项目复盘口径,已做脱敏。

五、可复用经验总结

隔离环境的升级问题,本质不是技术问题,是流程摩擦太大导致的人不敢动。所以优化的方向不是让单次升级更强大,而是让单次升级更小、更快、更容易撤销。把一次四百 G 的大手术拆成四 G 的小操作,心理门槛下降的效果比技术指标本身还大。

构建环境必须跟目标环境完全一致,这是我们花了最多冤枉时间才认下的一条。在隔离场景里,任何"应该差不多能跑"的侥幸最后都会变成凌晨的故障。宁可多维护一台镜像机。

回滚能力要在数据层就设计好,不能等到出事再想。向前兼容这条规矩看起来限制了开发的自由度,实际上它把回滚从一个高风险操作变成了低风险操作,有了这个底气,灰度才敢往前推。

环境体检建议每个隔离项目都做,成本很低,收益很实在。手工改动在长期运行的封闭环境里几乎必然会发生,早发现比升级时被它绊倒强得多。

还有一块我们做得不够好:模型权重的增量更新。现在权重只要变了就是整个文件替换,几十 G 照样得摆渡。理论上可以做块级差分,我们试过一版,差分计算本身开销不小,收益取决于权重变化的稀疏程度,微调产出的权重差分率能到七成多,全量重训的就没意义了。这块还在权衡,暂时没上生产。