一个很常见的场景是这样的:机房里摆着几台高配机器,网线一根没插,模型在里面跑得好好的,但当你问“它现在跑的是不是上周评审通过的那一版权重”时,没人能立刻答上来。权重从哪台机器拷进来的、依赖有没有漏装、评估集是不是同一份、推理服务的参数有没有被人手动改过,全靠一张手写的交接记录。这就是气隙环境下的 AI 部署最真实的样子——机器能跑,但过程不可证明。
气隙(air gap)这个词听起来很硬核,实际上它带来的麻烦远比“断网”复杂。断网只是起点,真正难的是:你怎么把几百 GB 的东西搬进去,怎么证明搬进去的东西一个字节都没变,怎么在没有在线反馈的情况下判断效果好不好,怎么在不能随时升级的前提下做长期维护。离线 AI 部署的工程量,八成以上都花在这四件事上,而不是花在模型本身。
这篇文章想讨论的就是这四件事。它不聊宏大叙事,只聊一个工程团队把 AI 能力放进隔离环境时,到底要准备什么、按什么顺序做、哪些坑几乎一定会踩。
1. 先把“气隙”还原成一个工程约束,很多困惑会自动消失
1.1 气隙切断的不是网络,而是反馈通路
大部分人对隔离环境的第一个误解,是把它理解成“网速为零的内网”。按这个理解去做方案,你会得到一堆看起来很合理、落地就崩的设计。
真正的差异在于反馈。在线环境里,你改一个参数,几秒钟就能看到输出变化;模型效果不好,换一个版本重跑一遍就行;依赖装不上,搜索引擎里三分钟就有答案。这套“尝试—观察—修正”的循环几乎是免费的,所以大多数人的开发习惯建立在这个前提上:先跑起来,出问题再调。
气隙环境把这个循环的成本抬高了两个数量级。想换一版权重,你得走一遍导入流程;想加一个 Python 包,你得回到联网侧重新打包、重新校验、重新摆渡;想看一条报错,日志可能只写在本机磁盘上,你得想办法把文件拿出来。于是“先跑起来再调”这套习惯直接失效,因为每一次调整都要付出可见的成本。
这就是为什么很多团队把在线方案平移到内网时,第一周就卡住。不是技术不行,是工作方式不匹配。在线环境下 tolerable 的随意性,在隔离环境里会变成实打实的返工。
我在实践中总结出一个判断:在气隙环境里,方案的好坏不取决于它跑得多快,而取决于它“可被证明”的程度。 你能不能证明这个权重是评审过的那一版,能不能证明这个容器镜像没有被替换,能不能证明这次输出是由这套参数产生的。证明不了,这套系统在合规视角下就等于不存在。
1.2 为什么在线方案平移进内网,第一周通常就会崩
具体崩在哪里,几乎有固定顺序。
第一崩是依赖。联网时 pip install 一条命令解决的事,在离线环境里会变成几十个 wheel 包的依赖树。你没意识到 torch 会拖进来一堆 nvidia-* 的 CUDA 运行库,也没意识到某个包只有源码分发、需要在目标机上现场编译,而目标机的 gcc 版本不匹配。这类问题不解决,连“Hello World”都跑不出来。
第二崩是模型格式。不同推理框架对权重的组织方式不一样,有的要求合并后的单文件,有的要求分片加索引,有的对量化格式有额外要求。你在联网侧用一个框架验证通过,搬到内网换成另一个框架,权重可能直接加载失败,而且报错信息往往非常含糊。
第三崩是评估。在线时你可以随时抽几条真实请求看看效果,离线时你手上只有一份静态的评估集。如果这份评估集是随手攒的,跑出来的分数既不能横向比较,也不能纵向追踪,最后没人敢拿它做决策。
第四崩是运维。服务起来了,但没有健康检查、没有结构化日志、没有资源监控。某天推理服务 OOM 挂掉,你只能看到“容器退出了”,连是哪次请求把显存打满的都查不到。
这四崩有个共同点:它们都不是模型问题,全是工程配套问题。所以真正该先做的,不是选模型,而是把配套的打包、校验、评估、观测四条链路先立起来。
注意:不要用“先让模型跑起来,其他以后再说”的思路推进隔离环境项目。在没有快速反馈的前提下,“以后”往往意味着两周后重新做一遍。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 一个离线 AI 栈到底要搬哪些东西进去
2.1 从权重到运行时:最小可运行集合
把“AI 能力”搬进隔离环境,很多人第一反应是搬模型文件。模型文件确实是核心,但它只是最小集合里的一项。
一个能对外提供服务的离线推理栈,通常包含五层内容:
| 层级 | 具体内容 | 常见遗漏点 |
|---|---|---|
| 模型权重 | 主权重分片、索引文件、tokenizer 配置、生成配置 | tokenizer 的额外词表文件、chat template 配置 |
| 推理运行时 | 推理框架本体、CUDA/cuDNN 等加速库、Python 运行时 | CUDA 小版本与驱动版本的匹配关系 |
| 服务层 | API 服务、反向代理、进程守护、健康检查脚本 | 进程守护的日志轮转配置 |
| 依赖与工具 | Python 依赖树、系统包、诊断工具 | 诊断工具(如 nvidia-smi、py-spy)常常被忘掉 |
| 配套资产 | 评估集、基线输出、配置模板、部署脚本 | 基线输出——没有它就无法判断新版本是否退化 |
第五层的“基线输出”最容易被跳过,但它决定了你后面能不能做版本比较。做法很朴素:用固定评估集、固定参数、固定随机种子跑一遍,把原始输出原样存下来,连同当时的模型哈希、运行时版本、参数配置一起归档。以后每换一版,跑同一份输入,做逐条 diff。没有基线,所谓“新版本效果更好”就是一句无法验证的话。
关于模型格式,有个经验判断:优先选择推理框架官方支持、且能在纯离线条件下加载的格式。 有些格式依赖在线下载配置或校验,离线环境会直接失败。落地前先在联网侧的干净机器上模拟一遍断网加载,这个验证成本很低,能省掉大量返工。
2.2 真正的麻烦在依赖供应链
模型文件再大,它也是“静态的、可哈希的、搬一次就不动了”。依赖不一样,依赖是有树的,而且树的形状随环境变化。
离线装依赖的标准做法是“在联网侧把 wheel 全部下载好,在内网侧从本地目录安装”。命令本身很简单:
bash复制# 在联网侧,按目标环境的 Python 版本和平台下载全部依赖
pip download -r requirements.txt \
-d ./wheels \
--platform manylinux2014_x86_64 \
--python-version 311 \
--only-binary=:all:
但这里有几个必须注意的点,踩过的人都知道疼。
第一,--platform 和 --python-version 必须和目标机完全一致,不是和打包机一致。如果打包机是较新的系统、目标机是较老的发行版,glibc 版本差异会让 wheel 装上了也跑不起来。
第二,--only-binary=:all: 是个好东西,它强制所有依赖都以 wheel 形式下载。如果某个包只有源码包,这条命令会直接报错,让你提前发现问题,而不是等到内网才发现需要现场编译。真遇到必须源码编译的包,就得在联网侧按目标平台预先构建好 wheel。
第三,系统级依赖(apt 包、系统库)不在 pip 的管理范围内。CUDA 驱动、libGL、字体库这类东西,要么提前做成离线包仓库,要么在镜像里固化掉。我更推荐把它们全部固化进容器镜像,这样内网侧只需要处理“导入镜像”这一个动作,变量最少。
镜像的搬运与校验:
bash复制# 联网侧:保存镜像并生成校验值
docker save -o inference-runtime-1.4.2.tar inference-runtime:1.4.2
sha256sum inference-runtime-1.4.2.tar > inference-runtime-1.4.2.tar.sha256
# 内网侧:先校验,再导入
sha256sum -c inference-runtime-1.4.2.tar.sha256
docker load -i inference-runtime-1.4.2.tar
顺序很重要:永远先校验再使用。 校验失败就直接中止,不要抱“可能只是文件尾截断了”的侥幸心理。
2.3 数据不出域,评估集反而要更早准备
离线环境里最尴尬的局面,是模型上线了,但没人说得清它到底行不行。
在线场景下,这件事有天然的兜底:真实流量会告诉你答案。离线场景下,如果业务方不允许把真实数据拿出来标注,你就只能靠内部构建的评估集。而评估集的质量,直接决定了后续所有版本决策的可信度。
构建评估集时,我一般按三个维度分层:
- 能力覆盖:把业务里实际会用到的那几类任务拆开,每类都要有样本。别只测通用问答,那和真实用途可能差得很远。
- 难度分层:简单、中等、困难各占一部分。如果全是简单样本,所有版本都能拿高分,区分度为零;如果全是困难样本,分数低到没有参考价值。
- 边界样本:空输入、超长输入、多语言混排、含特殊格式的内容、明显不该回答的问题。这类样本最能暴露工程问题(而不是模型能力问题)。
规模上不用追求大。每个任务类别几十到一两百条,只要标注质量稳定、判定标准统一,就足够做版本比较了。关键不是数量,是同一份评估集、同一套判定规则、长期不变。任何一次调整评估集,都必须同时重跑旧版本作为对照,否则历史分数就断了。
还有一点常被忽略:判定标准要写下来。什么叫“回答正确”、什么叫“部分正确”、容不容忍表述差异,这些必须在跑评估之前定好。否则两个人看同一份输出会给出不同结论,评估结果就成了主观意见的集合。
注意:评估集本身也是敏感资产,进入隔离环境的路径要和权重走同一套校验流程。评估集被悄悄改过,比模型被改过更难发现。
3. 从联网侧到内网侧:一条可复现的搬运流程
3.1 联网侧:先做清单,再做构建
离线部署最常见的失败模式,是“搬了十次,每次漏一样东西”。解决办法不是更仔细,而是把清单变成产物。
我建议在联网侧维护一份机器可读的清单文件,描述这次交付包含什么:
json复制{
"release": "offline-ai-2024-06-r3",
"model": {
"name": "internal-instruct",
"path": "/models/internal-instruct",
"files": ["config.json", "tokenizer.json", "model-00001-of-00004.safetensors"],
"sha256_manifest": "model.sha256"
},
"runtime": {
"image": "inference-runtime:1.4.2",
"image_tar_sha256": "…"
},
"assets": {
"eval_set": "eval/v3/eval_set.jsonl",
"baseline": "eval/v3/baseline_outputs.jsonl"
},
"params": {
"max_model_len": 8192,
"gpu_memory_utilization": 0.85,
"max_num_seqs": 16
}
}
清单的价值在于,它把“这次交付了什么”从人的记忆变成了可 diff 的文件。下一次交付,直接对比两份清单,就能看出模型换了没有、参数改了没有、评估集是不是同一版。
配套的哈希清单生成方式:
bash复制# 为模型目录生成逐文件哈希
find /models/internal-instruct -type f -print0 \
| sort -z \
| xargs -0 sha256sum > model.sha256
这里 sort 不能省。find 的输出顺序在不同文件系统上不保证一致,不排序的话两次生成的清单会有无意义的差异,做对比时会淹没真正的变化。
还有一个建议:在联网侧跑通一次完整流程,然后用断网方式重跑。 具体做法是临时切断这台机器的外网访问,从头执行安装和启动脚本。任何隐藏的在线依赖都会在这一步暴露出来——包括某些库启动时偷偷拉取配置、某些框架检查更新版本号。
3.2 摆渡环节:哈希、签名、双人复核
摆渡是整个流程里风险最集中的一段。文件离开受控环境再进入另一个环境,中间发生了什么,技术上无法完全保证,只能靠流程约束。
我认为最低限度的三件事是:哈希校验、来源签名、双人复核。
哈希校验解决“文件有没有变”,这是基础。用 sha256sum -c 在进入内网后、使用前执行,失败即中止。注意校验要在目标机本地做,不能只在摆渡介质上做——介质本身也可能有问题。
来源签名解决“这份文件是不是我们发的”。在联网侧用私钥对清单文件签名,在内网侧用预置的公钥验签。这样即便有人替换了文件并重新生成了哈希,签名也对不上。对多数团队来说这一步可能显得重,但只要交付物会被长期保存、多次复用,签名带来的确定性就值回成本。
双人复核解决“人有没有看错”。规则很简单:导入操作由一人执行,另一人对照清单逐项确认,两人都在记录上留下标识。这不是不信任,而是把单人失误的概率降下来。
这三件事听起来都是流程,不做技术。但在气隙环境里,流程就是技术的一部分。你没法靠实时监控发现问题,只能靠事前约定和事后可查。
注意:摆渡介质的清理和登记同样重要。介质里残留的旧版本文件,很容易在下次导入时被误当作新版本使用。
3.3 内网侧:安装、启动和最小验证
东西进来了,接下来是按固定顺序验证。顺序错了会很浪费时间:先起服务再查依赖,出问题时你分不清是依赖问题还是配置问题。
我一般按这个顺序走:
- 校验全部文件。哈希、签名、文件数量,一项都不能跳。
- 验证运行时可用。导入镜像,跑一条最简单的命令,确认 CUDA、驱动、Python 运行时都对得上。
- 验证模型可加载。不启动服务,先用框架自带的加载方式把权重读进来,确认能加载、能前向一次。
- 启动推理服务。用保守参数,
max_num_seqs给一个小值。 - 跑冒烟测试。固定几条输入,确认输出格式、字段、编码都正确。
- 跑完整评估集。和基线做 diff,看有没有明显退化。
- 接入上游。最后才让业务方接进来。
第 3 步最容易被跳过,但它能省下最多时间。很多“服务起不来”的问题,本质是权重加载失败,只是被服务框架的报错掩盖了。单独验证一次加载,能立刻把问题范围缩小一半。
一个推理服务的启动示例(参数按实际环境调整):
bash复制python -m vllm.entrypoints.openai.api_server \
--model /models/internal-instruct \
--served-model-name internal-chat \
--tensor-parallel-size 2 \
--max-model-len 8192 \
--gpu-memory-utilization 0.85 \
--max-num-seqs 16 \
--host 0.0.0.0 \
--port 8000
冒烟测试用两条命令就够:
bash复制# 确认服务起来了
curl -s http://127.0.0.1:8000/v1/models
# 确认能正常推理
curl -s http://127.0.0.1:8000/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{"model":"internal-chat","messages":[{"role":"user","content":"用一句话说明什么是气隙环境"}],"max_tokens":64}'
第二条命令的返回里,除了内容本身,还要看几个字段:finish_reason 是不是正常结束、usage 里的 token 数是否合理、有没有异常截断。这些细节比“有没有返回文字”更能反映服务状态。
3.4 从单机验证到小规模服务化
单机能跑通,距离能对外服务还有一段路。这段路上需要补的东西,基本都是“出问题之后能不能查”的能力。
最小的一套服务化改造包括:进程守护(崩了自动拉起)、健康检查接口(让上游能感知状态)、结构化日志(每次请求记一条,带请求标识、耗时、token 数、状态)、资源监控(显存占用、队列长度、请求并发)。
其中结构化日志在隔离环境里的价值被严重低估。在线环境里服务挂了,你可以临时加日志再发一版;离线环境里,加一条日志意味着走一遍完整的导入流程。所以日志在第一次部署时就该设计到位,宁可多记。
日志内容我建议至少包含:请求时间、请求标识、输入 token 数、输出 token 数、总耗时、首 token 延迟、结束原因、错误码。不要记录完整的输入原文——那是另一个层面的数据风险,需要单独评估。
还有一个容易忘的点:日志轮转。离线机器磁盘写满导致的故障,排查起来非常费劲,因为表现是“服务莫名其妙不响应”,而不是一条明确的报错。给日志目录设个上限,是最便宜的保险。
4. 把推理服务跑稳:参数要一起算,不能逐个调
4.1 显存、上下文长度和并发是同一个方程
在线环境调参数,习惯是“先跑起来,慢了再调大”。离线环境没有这个余地,因为一次参数调整的成本远高于在线,而且参数之间互相制约。
最核心的三者关系是:显存占用 ≈ 模型权重 + KV 缓存。模型权重基本是固定的(量化方式定了就不变),KV 缓存则随上下文长度和并发数线性增长。
几个常被误解的点:
gpu_memory_utilization不是“用得越多越好”。设到 0.95,框架预分配的缓存会挤占其他进程空间,系统层面一出问题就是 OOM。0.8 到 0.88 是更稳的区间。max_model_len设得越大,单条请求可能占用的 KV 缓存越多。如果实际业务输入只有几百 token,把它设成模型上限,等于给并发能力上了一道无形的锁。max_num_seqs是并发上限,不是性能开关。设太大,多个长请求同时进来会直接把缓存打满;设太小,吞吐上不去。它是需要根据实际输入长度分布来定的参数。
我一般这样估算初始值:先确定业务的有效输入长度上限(比如 95 分位是 2000 token),把 max_model_len 设成它的 2 倍左右留余量;然后按显存余额反推能容纳几个并发,把 max_num_seqs 设在估算值的七成。这个七成不是保守,是给长尾请求留空间——平均值永远低估峰值。
| 参数 | 常见误设 | 更稳的做法 | 影响 |
|---|---|---|---|
max_model_len |
直接设成模型上限 | 按业务输入 95 分位的 2 倍设定 | 决定单请求 KV 缓存上限 |
gpu_memory_utilization |
0.95 追求极致 | 0.80–0.88 | 过高会引发系统级 OOM |
max_num_seqs |
按理论并发设满 | 理论值的 70% 左右 | 过高会导致长请求互相挤占 |
tensor-parallel-size |
随便设 | 必须等于实际参与计算的 GPU 数 | 不匹配会直接启动失败 |
调参的正确顺序是:固定输入长度分布 → 定 max_model_len → 算缓存余量 → 定并发 → 压测验证。 反过来先调并发,会发现怎么调都不稳定,因为上限根本不在并发这一侧。
4.2 离线环境更需要结构化的运行记录
隔离环境里没有实时监控大盘,也没有随手可查的调用链。你能依赖的只有落盘的东西。
所以我建议在第一次部署时就把三份记录立起来:运行日志、版本台账、变更记录。
运行日志是技术层面的,前面说过。版本台账记的是“当前环境里有什么”:模型版本、运行时镜像版本、依赖清单版本、配置版本。变更记录记的是“谁在什么时候改了什么、为什么改”。后两份听起来像行政工作,但它们是隔离环境里唯一能回答“为什么现在是这样”的材料。
举个具体的例子。某次评估发现新版本在某一类问题上表现变差。如果没有版本台账,你得花半天确认这次到底换了什么;如果有台账,一对比就知道这次只换了权重、运行时没动,那问题范围立刻缩到模型本身。台账省下的不是记录时间,是排查时间。
版本台账最简单的实现就是一个文本文件,随每次交付更新,和清单文件放在一起:
text复制2024-05-12 offline-ai-2024-05-r1
权重 internal-instruct-v1 | 镜像 1.4.2 | 评估集 v3
变更:首次部署
2024-06-03 offline-ai-2024-06-r3
权重 internal-instruct-v2 | 镜像 1.4.2 | 评估集 v3
变更:权重升级,评估集与参数未变,基线已对比
这份文件的价值随时间增长。半年后回看,你会庆幸当初写了。
5. 故障排查:先分层,再定位
5.1 一条固定的排查顺序
隔离环境里排查问题,最大的障碍不是找不到原因,而是范围太大。在线环境你可以一边改一边试,离线环境每次尝试都有成本,所以必须先把范围缩小。
我用的顺序是从外到内、从静态到动态:
- 先确认现象类型:起不来、起来了不响应、响应但结果异常、响应但很慢。四类现象的排查路径完全不同。
- 再确认文件层:哈希对不对、文件数量对不对、关键配置文件在不在。这一步最便宜,应该最先做。
- 再看运行时层:驱动版本、CUDA 版本、框架版本三者是否匹配。版本不匹配的报错往往很隐晦。
- 再看加载层:能不能单独把权重加载进来。这一步能把“模型问题”和“服务问题”分开。
- 再看参数层:显存相关参数是否超出可用资源、并发设置是否与实际输入长度冲突。
- 最后看工具边界:这个框架版本对这类权重格式是否支持、有没有已知限制。
这个顺序的意义在于,每一步都能把可能性砍掉一半,而不是靠猜测跳来跳去。
5.2 六类高频故障的现象与验证方式
下面这张表是我在不同环境里反复见到的六类问题。现象描述尽量写成你能直接对照的形式。
| 现象 | 常见原因 | 快速验证方式 |
|---|---|---|
| 服务启动即退出,日志只有一行 | 权重路径写错,或目录结构不符合框架预期 | 列出目录,对照框架文档确认文件层级 |
| 启动时报 CUDA 相关错误 | 驱动版本与容器内 CUDA 版本不匹配 | 宿主机跑 nvidia-smi,容器内跑框架版本查询,两者对照 |
| 启动成功但请求超时 | 模型加载尚未完成,或端口被占用 | 看启动日志是否走完加载流程,用 ss -lntp 查端口 |
| 短请求正常,长请求必失败 | KV 缓存不足,max_model_len 超过实际余量 |
逐步减少输入长度,找到失败阈值 |
| 输出乱码或明显截断 | tokenizer 配置缺失,或 chat template 未生效 | 用最小输入测试,检查返回的 token 计数与结束原因 |
| 服务运行数小时后变慢 | 日志/缓存占满磁盘,或长请求堆积 | 查磁盘占用、查进程内存、看队列长度 |
表格只能覆盖共性。真正排查时,还有一个更根本的原则值得单独说:永远先怀疑输入,再怀疑环境,最后才怀疑模型。
这条原则听起来反直觉,因为大家本能地觉得“模型那么大,肯定容易出问题”。实际上模型权重是最稳定的东西——它一旦被校验过就不变。变化的是输入格式、环境变量、路径、编码、权限。我见过太多次“模型效果突然变差”,最后发现是上游传过来的文本编码变了,或者某条请求的 system 字段被误删。
6. 长期运维:更新节奏和适用边界
6.1 离线更新应该走“窄带”节奏
在线环境的更新习惯是高频小步:一周一个小版本,有问题立刻回滚。气隙环境没法这么干,每一次更新都是一次完整的搬运流程,成本高、风险集中。
所以离线更新更适合“窄带”节奏:更新频率低,但每次更新范围小、变更明确。
具体来说,把更新拆成三个独立轨道:
- 权重轨道:模型版本变化。频率最低,影响最大,必须配完整评估。
- 运行时轨道:框架、驱动、加速库变化。频率中等,风险在兼容性,需要单独验证。
- 配置轨道:参数、提示模板、接入方式变化。频率最高,但可以随时回退。
三条轨道分开走,好处是每次变更的影响面可控。如果一次交付里同时换了权重和运行时,效果变差了,你没法判断是哪一项造成的。分开之后,评估结果可以直接归因。
回滚能力也要在设计时就留好。最省事的做法是新旧版本共存:磁盘上同时保留两版权重和两个镜像标签,切换通过配置项完成,不做覆盖安装。这样回滚是一次配置变更,不是一次搬运流程。
6.2 什么情况下气隙方案并不划算
写到这里,需要说清楚边界。气隙不是万能方案,有些场景强行上它,投入产出比会很难看。
| 场景特征 | 是否适合气隙方案 | 原因 |
|---|---|---|
| 数据出域零容忍,且有明确合规要求 | 适合 | 隔离是硬性前提,工程成本是必要投入 |
| 模型需要频繁迭代,一周一版 | 不太适合 | 搬运成本会吃掉迭代速度,除非能压缩导入流程 |
| 依赖大量第三方在线服务或实时数据源 | 不适合 | 离线环境无法维持数据新鲜度 |
| 团队没有专职运维,只有兼职开发 | 需要谨慎 | 隔离环境的运维负担明显高于在线环境 |
| 只需验证概念、短期试用 | 不适合 | 前期搭建成本远高于收益 |
| 输入数据规模小、可脱敏后出域 | 通常没必要 | 脱敏方案的成本往往更低 |
我用“通常”“需要谨慎”这类词,是因为边界不是绝对的。有些团队通过把导入流程做得很轻——比如把清单、校验、部署全部脚本化,把一次导入压缩到半天——就能让原本“不太适合”的场景变得可行。关键变量不是场景本身,而是导入流程的成熟度。
还有一个容易被低估的成本:人员。隔离环境里的问题,往往需要能同时理解模型、系统和流程的人。如果团队只有一个人懂这套东西,他一休假,整个环境就处于无人可维护的状态。这不是技术问题,但会实实在在影响可用性。
7. 一份可复用的检查清单,和三个最该先做的事
回到开头那个问题:你能不能证明,现在跑的是你以为的那个模型?
这个问题没法靠“我们很小心”来回答,只能靠流程和产物。下面这份清单是我在不同环境里反复用到的版本,按交付前后分成三段。
交付前(联网侧)
- 模型、依赖、评估集是否都有哈希清单
- 是否在断网状态下完整重跑过一遍安装流程
- 清单文件是否已签名
- 参数配置是否写进了清单,而不是留在某人的命令历史里
- 基线输出是否已生成并归档
导入时(摆渡环节)
- 是否在目标机本地做了哈希校验,且全部通过
- 是否验签成功
- 是否双人对照清单确认
- 摆渡介质是否已登记并清理
导入后(内网侧)
- 运行时是否单独验证可用
- 权重是否单独验证可加载
- 冒烟测试是否通过,返回字段是否正常
- 完整评估是否跑过,与基线的差异是否在预期内
- 版本台账是否已更新
- 日志、磁盘、进程守护是否就位
如果只能先做三件事,我会选这三件:把清单变成产物、把基线输出存下来、把导入流程脚本化。 前两件决定了你能否证明系统状态,第三件决定了这套东西能不能长期跑下去。模型选哪个反而是最容易改的决定,因为模型可以换,流程换起来代价高得多。
所谓“守护”,从来不是把门锁上就完事。门锁上之后,里面每一样东西都得说得清来历、对得上哈希、查得到变更。这件事做扎实了,隔离环境里的 AI 系统才真正处于可控状态;做不扎实,它只是一个恰好能跑起来、但没人敢担保的黑盒。
