断网也要把大模型跑起来:离线交付缺的不是权重而是四条依赖链

一、离线是依赖清单的照妖镜
据公开报道,有方案把千亿参数级别的模型放进本地乃至断网环境运行,卖点是全栈开源,其背景是硬件成本上涨时部分公司转向本地部署。这里的参数规模、成本走向都不作为本篇的判断依据,本篇只接一个工程问题:真到了隔离网络里,卡住的东西往往不是模型本身。
联网部署有一种虚假的顺利。缺文件就自动下载,版本不对就顺手升一个,算子没有就退回通用实现,这些行为都不报错,于是交付方从来没有被迫回答一个问题:这套东西到底由哪些部件构成。离线环境把答案强制问出来了,它要求所有部件在物理介质上存在,且存在的是被验证过的那一版。所以我们把离线当作依赖清单的照妖镜来做,而不是当作一种特殊的部署技巧;洹拓内部把它列为隔离环境项目的开工前置项。
对我们这类做交付的人来说,离线项目的成败在签合同时就大致定了。要问的不是能不能跑,而是四个链条是否随包交付:模型文件链、运行时链、系统与固件链、验证链。四条里断任何一条,现场都会停在那里等一份没人授权的下载。
二、权重之外必须随包交付的内容
权重只是模型文件的一部分,现场最常缺的恰好是它旁边的东西。下面这张表是我们列随包内容时的固定项,交付方与甲方都要按它清点。
| 类别 | 具体对象 | 离线环境里的典型故障 | 必须一并交付的说明 |
|---|---|---|---|
| 分片与索引文件 | 权重分片、层名映射、索引清单、配置与结构描述 | 分片数量或命名与加载器预期不符,加载半途失败 | 分片顺序、缺失判定方式、能否重排 |
| 分词器与词表 | 词表文件、合并规则、特殊符号码位、模板文件 | 权重能载入但输出乱码或截断异常 | 与模型版本绑定的分词器标识 |
| 推理引擎与算子库 | 引擎主体、后端计算库、图优化与内核集合 | 部分算子无实现,逐层退回慢路径直至超时 | 算子覆盖清单与未覆盖项的行为 |
| 驱动与固件依赖 | 设备驱动、运行时驱动、固件版本、内核兼容范围 | 设备可枚举但不可用,报错发生在很下层 | 经过验证的版本区间,而不是最低版本 |
| 基准输入与期望输出 | 固定输入集、参考输出、容差说明、精度模式标记 | 跑起来了但没人能判断结果是否正确 | 生成该基准时所用的完整软件版本 |
五类里最容易被当作次要项处理的是分词器和基准输出,而这两项一旦缺失,现场连跑得对不对都无法自证。我们的做法是把这五类做成一个不可拆的包,缺一项就视为包不完整,不允许先装能装的部分。
三、更新链:没有网络时补丁怎么进来
离线不等于一次交付结束,反而更考验更新链,因为每一次更新都要走人工通道。设计上有四件事必须在第一次交付时就定下来。
第一是补丁介质与准入方式。谁刻盘、介质如何进入现场、进入前是否做恶意代码扫描,这三问要落成一条流程。介质要单向,现场的东西不能原路带回开发环境,否则隔离的意义会被一次拷贝抹掉。
第二是版本配对表。离线环境里最贵的错误是版本组合未经测试:模型文件、分词器、引擎、驱动、固件这五项两两组合的空间很大,不能靠现场尝试。配对表要写成一行一行的组合,每行标注在哪个硬件形态上验证过、验证人是谁、结论是什么。表里没有的组合,即使理论上兼容,也判定为未通过。
第三是回退点。每次更新前必须留下一套可回退的完整旧版本,包括当时能跑通的那组配置,而不是只保留新包。回退的判定条件要提前写:出现哪几类现象就回退,由谁拍板,回退后原问题如何记录。
第四是签字。离线环境的变更影响的不只是运维,还有依赖输出结果的业主。谁签字才允许更新,要区分开:软件包完整性由交付方签字,验证结论由使用方签字,回退决定由双方共同签字。
四、完整性核对:禁止先跑起来再说
没有在线校验渠道时,完整性只能靠预先约定。三条最低要求。
其一,逐包哈希清单。每个文件都给出哈希值与大小,清单本身也要有签名或者至少有一份独立保存的副本,避免清单和数据同时被替换。现场核对不是抽查,是全量核对,抽查会漏掉刚好被替换掉的那一个。
其二,逐包来源记录。每个包要写明从哪个仓库或者哪个内部构建产出、由哪次构建生成、构建环境是什么。全栈开源的说法降低了来源核对的难度,但降低了不等于省掉了:现场需要能回答这个二进制是谁编译的,否则出了问题只能回退,不能定位。
其三,禁止跳过校验启动。加载器里凡是找不到文件就去下载、校验失败就告警告了继续的默认行为,在离线交付前必须关掉。这两条逻辑在联网环境是便利,在隔离环境会变成现场最难排查的问题,因为它会让系统以半残缺状态运行,并把故障推到很后面。
五、联网掩盖的行为差异与异构移植面
联网环境跑通、离线环境跑不通,通常不是功能问题,而是某些行为在断网后消失了。要在交付文档里把它们列成对照,逐项给替代方案。
| 联网时的隐含行为 | 离线后的表现 | 交付时的处理方式 |
|---|---|---|
| 缺失文件自动下载 | 加载直接失败,报错指向很下层 | 随包补齐并在清单里标明所需全部文件 |
| 依赖与引擎后台更新 | 版本长期不动,与新模型不匹配 | 由更新链统一驱动,禁止单点自行更新 |
| 按需调用外部服务 | 检索、翻译等附属能力静默失效 | 明确降级路径与对用户的提示文案 |
| 时间自动同步 | 证书与日志时间异常,鉴权失败 | 现场提供内部时源并写明同步策略 |
异构算力的移植面是另一条独立的链。同一份权重换一种计算设备,要逐项确认四件事:算子覆盖度,未覆盖的部分是走通用实现还是直接不支持;精度模式,该设备是否支持所需的低精度类型,支持范围与限制是什么;显存与内存带宽约束,决定可运行的上下文长度与并发;量化策略,量化权重的来源、生成方式与精度损失如何验证。这四项没有一项能靠换个设备名跑通来代替结论。
六、四张验收表与它们的字段
验收要拆成四张表,因为它们回答的是四个不同问题,混成一张就会出现装得上就算交付通过这种结果。
| 验收表 | 回答的问题 | 必须列出的字段 | 通过判定 |
|---|---|---|---|
| 装得上 | 环境是否就绪 | 介质与哈希核对结论、逐包来源记录、驱动与固件版本是否落在配对表内、自动下载与跳过校验是否已关闭 | 逐项写明结论与证据位置,不接受一句符合 |
| 跑得对 | 结果是否可信 | 基准输入集全量执行记录、与期望输出的容差判定、分词与模板行为核对、精度模式下的偏差说明 | 需使用方在场并签字,决定后面所有使用的可信度 |
| 跑得动 | 容量边界在哪里 | 目标并发与上下文长度下的响应时间、显存与内存占用水位、越界时的失败形态是排队还是报错 | 只记现场实测到的现象,不写来自宣传口径的数字 |
| 跑得久 | 能不能长期维护 | 连续运行稳定性、缓存与临时目录的增长、日志量与保留策略、回退演练做过几次及其结果 | 至少完成一次真实回退演练 |
四张表都有未通过项时,交付状态只能写部分通过,并把未通过项写清楚归到哪条依赖链上。这条规矩听起来死板,但它换来的是一份能拿去争论的交付记录。离线项目真正的风险从来不是网络不通,而是我们以为自己交付的是模型,实际上交付的是一整套没有清单的软件组合;清单做扎实了,断网只是把难度换了一种形式。