隔离内网 + AI Agent 是这两年最容易让人"从兴奋到崩溃"的组合。我做过几个政企类项目,业务环境完全碰不到公网,需求却高度一致:让一线人员用自然语言查数据、跑流程、生成分析报告。听起来就是大模型时代的常规动作,真动起手来才发现,AI Agent 的搭建、开发、部署,在隔离内网里完全是另一套工程打法。你在线环境里的每一个"理所当然"——模型仓库、pip 源、镜像站、外部工具 API——到了内网会全部断掉,剩下的是整套交付链路的重新设计。
先把场景定义清楚:本文说的隔离内网,指业务系统所在网络不能访问公网,数据进出只能靠人工拷贝、审批后的单向摆渡或专门的受限通道。金融、能源、政务、大型集团里有大量这种环境。在这种环境里交付 AI Agent 工程,核心矛盾不在模型选型,而在"从外网准备,到内网落地,再到长期运维"每一环都必须离线闭环。这篇文章把我实际做完几个项目后的经验完整整理一遍,覆盖架构选型、离线交付细节、运行时改造,以及几起真实事故的排查链路,希望能给准备踩这条路的团队一些参考。
1. 隔离内网 Agent 项目的真实形态:链路断点远比模型问题更致命
1.1 五类"理所当然"的断点
在云上开发 Agent 习惯了,你会默认这些东西都是随手可得的。到了隔离内网,它们全部一次性断给你看:
| 资源类别 | 在线环境默认行为 | 隔离内网里的现实 |
|---|---|---|
| 模型权重 | 从模型仓库直接自动下载 | 模型仓库不可达,只能靠摆渡人工搬运 |
| 依赖包 | pip / npm / cargo 在线拉取 | 包索引源不通,所有包要预下载并校验 |
| 容器镜像 | 镜像仓库随便拉 | registry 不可达,镜像只能离线导入 |
| 外部工具 | OpenAI、搜索、天气等 API 随手调 | 全部不可用,Agent 只能调用内网服务 |
| 密钥鉴权 | 在线申请 API Key | 需要对接内网证书体系或统一认证 |
这五类断点叠加以后,Agent 项目就从一个"纯应用开发"直接变成了"应用开发 + 基础设施交付 + 安全合规"三合一。很多团队就是死在这上面:模型文件传到一半发现漏了一个分片,镜像导入以后 docker tag 不一致,依赖包在 Python 3.10 和 3.11 之间打架……每一项单独看都不是大事,但隔离环境里每一件小事都需要重新走审批流程和传输通道,修复成本比在线环境高一个数量级。
1.2 可用性标准被重新定义
在线环境里,Agent 可用性约等于"模型服务是否在线",超时重试就完事了。隔离内网里,可用性必须拆成三层看,这也是我在项目评审会上反复强调的:
- 服务可用:推理服务本身不能挂。内网没有云上那种弹性伸缩,只能用容器健康检查、进程守护、看门狗脚本来解决。我一般会在推理服务旁边放一个监控小脚本,定时检查端口响应和显存占用,异常自动拉起服务并告警。
- 工具可用:Agent 调用的每一条工具链路都要在内网闭环。查库存要走内网库存中台接口,生成报表要走内网报表服务,任何一条工具链路断掉,Agent 表面上还在运行,实际已经在空转了。这个问题在真实项目里特别隐蔽,因为大模型会在工具返回异常时"编"一个看起来合理的回答。
- 资源可用:显存、内存、磁盘都要在时间维度上可控。离线环境最怕日志和临时文件无节制堆积,线上磁盘满了可以秒扩容,内网扩磁盘要提工单、等审批、停机操作,一次下来几个工作日就没了。
1.3 我的标准交付流程
踩过几次坑以后,我把隔离内网 Agent 项目的交付流程固化成了下面这套:
- 在外网开发机上锁定全部依赖版本,生成 requirements.txt、Cargo.lock、Dockerfile,所有版本固化。
- 在外网环境完成镜像构建,导出为 tar 包;用 pip download 之类的命令把依赖包统一拉下来,形成一个完整的传输清单。
- 模型权重走审批通道导入,优先用单文件格式减少搬运件数。
- 内网侧建本地 registry 和本地包源,把传输进来的包逐个导入,用哈希校验确保完整。
- 启动推理服务,在测试区跑完验证三件套(下面第 3 章会细说),确认 Agent 最小闭环能通。
- 接业务工具、接统一鉴权、上线观测。
这套流程里最重要的一条经验是:把验证前置到测试区,而不是上线后验证。隔离环境里改任何东西都要重新走审批和搬运,一次验证成本高得离谱。宁可测试期多花三天,也不要把问题带进生产。
2. 架构选型:推理引擎、Agent 框架与 Rust 二进制的组合判断
2.1 离线推理引擎怎么选
这是最基础也最影响稳定性的选择。我实际对比过这几个主流选项:
| 引擎 | 优势 | 劣势 | 适用判断 |
|---|---|---|---|
| vLLM | 吞吐高、OpenAI 接口兼容、社区生态完整 | 显存要求高、部署相对重 | 生产环境多路并发首选 |
| Ollama | 安装极简、模型管理方便 | 并发吞吐一般、定制受限 | 小团队快速验证、低负载场景 |
| llama.cpp / llama-server | 单文件、轻量、CPU/GPU 都能跑 | 功能少、要自己封装一层服务 | 低配机器、可信可控环境 |
| SGLang / TensorRT-LLM | 推理性能极致 | 学习成本高、对硬件敏感 | 性能调优到极限才考虑 |
我的选择逻辑很简单:先看硬件预算。如果是 A10 / A100 这类卡,直接上 vLLM,接口标准、生态成熟,内网集成最省事。如果是老型号卡,或者驱动版本混乱,果断用 Ollama 或 llama.cpp,因为不用编译 CUDA 环境,部署坑最少。我一次经验教训:在隔离机 Docker 里现场编译 vLLM,编到一半发现缺一个内网没有的系统依赖,卡了整整两天。从那以后我在内网环境的优先级就一句话:能稳定跑起来,永远比跑得漂亮重要。
另外,vLLM 做了 OpenAI 兼容接口是它在内网场景比分发的重要原因。Agent 框架、Django 后端、测试脚本都只需要记住/v1/chat/completions这类的接口规范,后面换引擎也只是切换 base_url 的事,不用改业务代码。
2.2 Agent 框架与主流架构模式
"ai agent 主流架构"这个话题热度一直很高,我把它简化为三种收敛模式:
- 单 Agent 直调:一个编排循环,LLM 负责意图识别和工具选择,最直接,适合场景单一、工具数量在 5 个以内的项目。
- 多 Agent 协作:不同角色 Agent 分头干活,比如一个负责查数、一个负责写报告、一个负责审核,中间有通信机制。适合复杂业务流程,但调试成本指数级上升。
- 工作流编排:把流程画成 DAG,节点是固定的处理逻辑,LLM 只在分支判断或内容生成处介入。这是我在政企项目里最推荐的形式,因为每一步都可控、可回溯、可审计。
框架选型上,我走的路线是"框架 + 自研插件"。Dify、FastGPT 这类开箱即用的平台,整体搬到内网以后自带 Web 界面和知识库管理,非常适合给非技术的业务同事用,第一版验证业务价值很快。LangGraph 则更偏纯代码编排,适合后续深度定制。我自己的经验是:如果审批流程允许,第一版用 Dify 或 FastGPT 快速交付,等业务价值验证清楚了,再逐步替换成 LangGraph 或自研编排。一上来就追求深度定制,在隔离内网项目的交付窗口下是自找麻烦。
2.3 为什么我会把部分能力用 Rust 重写
搜索榜里"基于 Rust 语言 ai agent"一直有人问,我的实践结论是:Rust 在隔离内网里非常好用,但不是用来写整个 Agent,而是用来写工程里的"边角料"。理由有三个:
- 无运行时依赖:Rust 静态链接编译出的二进制,扔到任何 x86_64 Linux 机器上直接跑,不需要预装 Python 环境、JRE 或 Node。内网装一个运行时都要走审批,能少一个依赖就少一个审批项。
- 体积小、启动快:一个工具二进制几十 MB,比起一堆常驻 Python 进程省内存多了。内网服务器配置普遍不高,动不动被超大运行内存吞掉的情况很常见。
- 运行稳定:Agent 的工具执行经常跑很久,Rust 写的工具没有 GC 停顿、没有依赖地狱,不会半夜莫名其妙崩掉。
我实际用 Rust 做过的几类工作包括:日志解析、格式转换这类文本处理工具;摆渡文件的哈希计算与清单核对工具;内网服务端口探测和健康检查小服务;甚至把整套工具执行器重写成 Rust 的异步任务调度器,Python 侧只管 LLM 调用和编排协议,效果非常理想。
但也要泼盆冷水:Rust 开发成本确实高,团队没有相关经验时不要强行上。我的分工标准是,只有"性能敏感、依赖敏感、生命周期长"的工具才用 Rust 重写,Agent 主流程用团队最熟悉的技术栈。工程是团队协作,不是表演技术。
2.4 Django 业务系统的集成路径
很多企业内网的管理系统是 Django 写的。所以"用 ai agent 开发 django"这个热搜,本质上是个伪命题,真正的问题应该是:如何把 Agent 能力接入已有 Django 系统。我常用三种集成路径:
- API 直接接入:Django 后端调用 Agent 服务的 HTTP 接口,适合一次性查询、简单生成任务。
- 任务队列接入:把 Agent 执行交给 Celery / RQ 异步队列,Django 只负责提交任务和查状态。适合耗时较长的分析、报告生成任务。
- 回调式接入:Agent 执行过程中调 Django 提供的回调接口,把进度、状态、审批节点实时回写。适合智能审批、智能客服类交互场景。
实际项目里用得最多的是"任务队列 + 回调"的组合。Django 负责用户会话和权限控制,Agent 侧负责工具执行和状态管理。这里有一条重要原则:Agent 每次调业务接口都要携带具体用户上下文,绝不能让 Agent 用一个超级管理员身份跑所有任务。权限问题在隔离内网里比在线环境敏感得多,后面我会讲到它引发的真实事故。
3. 离线交付细节:镜像、模型、依赖的三重搬运闭环
3.1 镜像构建与瘦身
内网不能直接从镜像仓库拉取,所以必须在能通外网的构建机上先构建再导入。这里有三个经验:
第一,不要在生产机器上构建镜像。在外网开发机或专门的构建机把镜像构建好、打好标签,用 docker save 导出成 tar 包。我会把整个交付物打成一个 tar 包,里面包含镜像、模型、启动脚本、校验和文件,交付审核时直接看清单就行。
第二,镜像必须瘦身。隔离环境的传输带宽极其有限,数据摆渡通道经常是按天排队。一个 2GB 的镜像,在外网是秒钟级的 pull,在内网可能是一整天的传输。我用 Alpine 基础镜像和多阶段构建,把编译工具链全删掉。有一次把一个项目镜像从 4.2GB 瘦到 700MB,传输时间从一整天缩到两小时,这个优化的性价比高得离谱。
第三,检查逻辑写进镜像。在镜像内置一个check.sh,启动时检查模型文件、依赖、配置是否就位,打印关键版本号。隔离环境没有完善的日志链路,一个启动自检脚本能帮你省掉大量排障时间。后面讲到的模型损坏事故,就是靠这个脚本提前拦截的。
3.2 模型权重的搬运与校验
模型文件是整个工程里最重的部分。7B 模型 FP16 接近 15GB,就算量化到 4bit 也有 4-5GB。我的处理习惯:
- 量化模型优先:GGUF 的 Q4_K_M、GPTQ 或 AWQ 量化版都是可选方案。文件小了,显存压力小,传输也快。除非业务对生成质量非常敏感,否则我一般不搬全量 FP16。
- 单文件格式优先:GGUF 一个文件就是完整模型,自带 tokenizer 和配置,搬运和部署都省心。safetensors 是一堆文件,漏一个就得重新走传输流程。
- 哈希校验必须做:摆渡过程中文件损坏非常隐蔽,模型权重坏几个字节,推理结果就会随机错乱,而且服务不报错。我真的遇到过这种事,后面单独讲。
另外,把 LLM 和 Embedding 模型分开管理。Embedding 模型往往只有几百 MB,和向量库配套使用;迁移时先迁 Embedding 和向量库,因为 RAG 检索链路不依赖 LLM 也能测试。这样在正式环境前,先让知识库检索链路提前验证起来。
3.3 依赖包的离线安装
内网里装 Python 依赖,别指望任何在线源。我的标准流程是在外网构建机上先锁版本、再下载,最后到内网离线安装:
# 外网构建机:指定平台和 Python 版本,只下载预编译 wheel pip download -r requirements.txt -d ./wheels/ \ --platform manylinux2014_x86_64 \ --python-version 3.11 \ --only-binary=:all: # 内网环境:无索引离线安装 pip install --no-index --find-links=./wheels/ -r requirements.txt注意--only-binary=:all:的前提是依赖都有预编译 wheel。如果某个包没有 wheel,就得在外网用同一套系统环境先编译好再打包带进去。另一个容易踩的坑是 pip 自身版本:内网 Python 的 pip 太老,遇到新版 wheel 会报"does not support the wheel format"。所以我会把 pip 升级到指定版本,下载好 wheel,一起带进去装。
Node 和 Rust 依赖同理。npm 用npm pack批量打 tgz,内网搭建本地私有 registry;Cargo 用cargo vendor把依赖全部落到本地目录,内网构建时配置.cargo/config.toml指向本地源。
3.4 离线验证三件套
搬运完成后,别急着接业务。先在纯离线环境跑完这三步:
- 启动推理服务,用测试 prompt 确认模型输出正常,重点检查 prompt 模板有没有残留外部标注或不该有的系统提示。
- 跑一遍 Agent 最小闭环:用户问题 → 意图识别 → 工具调用 → 生成回答。所有工具全部用内网假数据回归一遍。
- 用真实业务数据跑一轮端到端测试,检查 RAG 检索相关性、输出格式和响应延迟。
这三步全过,才算"基础设施就绪"。我会把整个过程写成文档,因为隔离环境下外部顾问大概率进不来,值班的人只能照着文档定位问题。文档里要包含:服务列表、端口、日志位置、常见故障处理步骤、重启命令。别觉得这是多余,真出了事故你会感谢当时的自己。
4. 运行时改造:无外网环境下 Agent 的关键机制调整
4.1 工具链的内网闭环与外呼限制
在线环境的 Agent 爱用什么工具就用什么工具,搜索、地图、翻译随便调。隔离内网里全得换。我一般拿到项目第一件事,就是做全量工具盘点,把每个工具分成三类:
- 可替换:比如查天气,换成内网气象数据接口;翻译,用离线翻译模型。
- 可改造:比如知识检索,公网搜索换成内网知识库检索。
- 必须废弃:任何只存在于公网的能力,直接砍掉,不要留幻想。
工具链内网闭环之后还有一个隐形问题:Agent 有时会产生"幻觉式工具调用",以为某个工具存在,实际上根本不通。我用了一个很土但很有效的办法:给每个工具标记一个"内网可达性探针",运行时用一个轻量探针定时检查所有工具服务的健康状态,Agent 编排层拿这份结果做路由决策。这个设计让幻觉调用比例明显下降,因为不可达的工具直接被探针过滤掉了。
4.2 token 概念的两种含义与内网资源规划
"ai agent token是什么意思"这个热搜词,我分两个层面解释,因为内网场景下两个层面都很关键。
第一个层面,token 是模型的分词粒度。一句话会被 tokenizer 切成一串 token 后才能进模型,输出也是一次吐一个 token。中文和英文的切法完全不同,一个汉字大约对应 0.3-0.6 个 token,代码、标点、特殊符号切法更复杂。你不能精确预判一段文本的 token 数,只能用工具估算。在 Agent 场景里,上下文窗口是硬上限,超了要么报错要么被截断,所以我处理长文档时都会先做 token 估算,再决定是全文塞入还是分段摘要。
第二个层面,token 是显存和时间预算。离线内网没有计费概念,但 token 直接占用显存和推理时间:上下文越长,KV cache 越大;生成 token 越多,响应越慢。同样的显卡,并发用户越多,每个用户能分到的上下文越短。所以内网里做 token 规划,本质就是做资源规划。
这里分享一个实测结论:很多模型在无约束时会输出大量思考过程和客套话,在离线场景纯属浪费算力。我们在系统提示词里明确约束"只输出必要内容"之后,一次回答的平均生成 token 从 900 降到 450,响应速度提升了近一倍。如果你的内网性能紧张,先检查这个。
4.3 上下文与记忆的分层策略
隔离内网的业务场景往往涉及大量私有知识,Agent 不能只靠有限的上下文窗口硬扛,必须做分层记忆:
- 短期记忆:当前会话的对话上下文,我限制在 8 轮以内,超出就把旧信息做摘要塞回上下文,原文丢弃。
- 中期记忆:用户或任务的关键状态存到内网 Redis,比如提单号、审批节点、填了一半的表单。Agent 恢复执行时从 Redis 拉回状态。
- 长期记忆:知识库,走 RAG 向量检索。我用内网向量库(Milvus、pgvector 都可以),文档入库前要分块,分块大小和重叠率直接影响检索效果。
但我不会把检索到的所有片段都塞给模型。先由检索层做相关性排序,只取 top-k(一般 4~8 个片段)拼到 prompt 里。有团队把整个知识库片段全塞进上下文,瞬间爆掉窗口,还把推理速度拖到不可用。RAG 不是把知识库全塞给模型,而是帮模型找到最相关的那几段。
4.4 超时、并发与可观测
在线环境里 API 调用失败,重试一下就行。隔离内网里有三个更棘手的问题:
- 推理服务并发配额:vLLM 默认是连续批处理,你发 20 个请求它可能同时处理 20 个,看上去"并发",实际是把显存撑爆、每个请求都在排队。我在 Agent 端做了并发信号量,限制同时进行的 Agent 任务数,同时给推理服务配置好
max_num_seqs和max_num_batched_tokens。两者配合到位,稳定性和吞吐才能平衡。 - 工具调用超时边界:Agent 里每一步工具调用的超时必须小于整体任务超时,否则一个卡住的工具就能拖死整个任务。我给每个工具都配置了超时和重试参数,并做熔断:同一个工具连续报错三次就停用它。不然 Agent 会像复读机一样反复尝试死掉工具,永远结束不了。
- 日志与可观测:内网没有云平台的可观测体系,我会在 Agent 编排层打全量结构化日志,记录请求 ID、意图、工具名、参数、耗时、token 数。这一步是把 Agent 从"玩具"推向"生产系统"的分水岭。排障时第一眼看意图识别和工具调用的耗时占比,问题五分钟内就能圈定范围。
5. 从三次事故看排查链路:模型损坏、同步阻塞、工具僵死
5.1 事故一:模型文件搬运损坏,推理结果随机错乱
第一次部署时,团队觉得模型文件大、传输任务重,就压缩后分片传输,没有做完整性校验。上线第二周开始有用户反馈:并发一高,回答就答非所问。
完整的排查链路是这样走的:
- 查看推理服务日志,发现服务完全没报错,响应时间也正常。
- 怀疑是上下文管理出了问题,检查 prompt 拼接和上下文窗口,没发现异常。
- 在推理服务侧直接发单条请求,用固定 prompt 反复测试,发现错误概率约三分之一,非常随机。
- 这时才怀疑模型文件本身。用 SHA256 校验摆渡进来的分片文件,果然有几个分片哈希对不上。
原因是摆渡通道不稳定,分片文件存在静默损坏,而推理服务加载了损坏的权重以后,照样能跑,只是输出随机错乱。这种故障极其隐蔽,靠日志几乎不可能定位。
教训就一条:文件进入内网必须做全量哈希校验,推理服务启动时必须主动校验模型完整性。后来我把校验动作直接写进了镜像里的check.sh,启动即校验,从根上杜绝同类事故。
5.2 事故二:Django 同步调用 Agent,请求全卡死
这个项目里 Django 是管理平台,用户点"生成分析报告",后端把任务推给 Agent 服务。最初为了省事,我在视图函数里同步调用 Agent 的 API,结果用户一多,Django 的 worker 全部被 Agent 的长耗时请求占住,连最简单的查询都返回不了,网关直接 504。
排查链路:
- 看 Django 日志,发现视图函数里 Agent 调用常常耗时 2-3 分钟。Django 默认同步 worker 是阻塞的,一个长请求占死一个 worker。
- 单独压测 Agent 服务,发现并发性能没问题,瓶颈在调用方式。
- 确定方案:在 Django 和 Agent 之间插入一层异步任务队列,长耗时任务全部异步化。
改造后,Django 的 worker 只负责提交任务和查询状态,真正的执行放到了 Celery / RQ 里。同样的业务量,504 再没出现过。从那以后我定了一条规矩:所有耗时可能超过 10 秒的外部调用,一律异步化,绝不放在请求线程里同步等待。这一条如果早点定,能省很多事。
5.3 事故三:Python 工具进程僵死,Rust 静态二进制接班
有一类 Agent 工具是文本处理,比如解析几万行的日志文件。最初用 Python 写的,单机跑没问题。后来部署到 CPU 受限的容器里,问题来了:处理大文件时内存飙到容器上限,Python 进程被系统重启,Agent 侧拿到的却是"空输出但状态成功",表现成"无响应"而不是"报错"。
排查链路:
- 在压力机上用同样的数据集复现,确认内存到顶后进程被系统杀掉。
- 查代码,发现 Python 的多线程处理受全局解释器锁影响,在受限容器里性能很差,内存还一直涨。
- 决定把文本处理类工具全部改成 Rust 编译的静态二进制,不依赖 Python 运行时,内存占用大幅下降。
- 同时给 Agent 编排层加了异常检测:工具返回空结果但状态为成功,一律按失败处理并触发告警。
这个改造花了大概两周,效果立竿见影:工具执行成功率从 93% 提到 99.5%。现在团队里形成了固定分工——独立工具类模块默认用 Rust 写,Python 只负责 Agent 主流程和业务粘合层。
5.4 隔离内网的安全加固清单
隔离内网不等于绝对安全,内网自身的权限、数据保护和审计要求反而更严格。几个实战要点:
- 用户鉴权不能跳过。Agent 调用的每条业务接口都要带用户上下文,绝不能用统一管理员身份跑所有任务。我之前遇到过项目为了省事用系统账号调用所有工具,结果任何用户都能查敏感数据,直接被合规打回重做。
- 工具执行留审计日志。每一步调用的用户、参数、返回结果全部记录,关键操作(删除、修改、外发)加二次确认。这不仅是合规要求,也是出事之后唯一的取证手段。
- 模型服务只对白名单网段开放。vLLM 和 Ollama 默认不鉴权,一旦被内网其他机器发现,你的模型就是一台免费算力矿机。
- LLM 输出做内容过滤。内网场景里模型会接触到公司内部资料,对外回复前必须过滤敏感信息,防止大模型把不该说的字段拼进回答。
这几条不是可选项,是隔离内网项目的入场券。
做了几个此类项目以后,最深的体会就是:隔离内网 AI Agent 工程表面在部署模型,本质是在解决"依赖固化、镜像搬运、工具极简化、验证前置化"这四件事。如果你接下来也要做类似项目,我第一条建议是:验证前置到底。模型下载、依赖缺包、镜像构建失败、工具卡死,这些问题都能靠提前验证暴露出来。在线环境里验证是开发的一个普通环节,在隔离内网里,验证就是整个项目能不能按期交付的生命线。