
干了好几年私有化交付的AI工程我有个特别深的感触真正劝退人的往往不是模型效果而是环境。尤其是隔离内网——没有外网、没有现成的包管理器连pip install都变成要提前规划好的大事。偏偏这类需求在政企、金融、能源、医疗行业里最普遍客户对数据出域零容忍模型必须本地化部署Agent框架、依赖、镜像全都要离线搬运。这篇文章就围绕隔离内网下的AI Agent工程实战展开把我从零搭建、踩坑、调优的过程完整复盘一遍顺便把Agent怎么扛并发这个老大难问题讲透。适合准备做私有化交付、信创适配、内网落地的同学参考也适合那些刚接触Agent工程化、想搞清楚本地模型和LangGraph这类框架到底怎么配合的读者。1. 隔离内网AI Agent先分清楚隔的是什么1.1 隔离内网与常规联网环境的五大差异隔离内网这词听起来简单实际干起来才明白它跟普通上线环境完全不是一回事。我参与过的内网项目大致分两种一种是非涉密的业务内网允许访问企业内部服务但不允许直接访问公网另一种是真正物理隔离的网络机房、终端、服务器全都不和外网任何设备有连接。不管哪种对AI Agent工程的影响都集中在下面五点。第一模型获取渠道被切断了。常规做法是从Hugging Face这类模型托管平台直接拉权重内网环境里这条路走不通必须在有网环境把权重准备好、校验好哈希再通过内部审批流程拷入内网。第二Python依赖、Conda包、Docker镜像全都没有公共源可用只能建立内部源或者做离线包整体搬运。第三GPU驱动、CUDA、NCCL这类底层组件版本固定想升级非常困难很多内网机器还停留在老驱动对新的推理框架支持很差。第四外网API调用基本别想模型必须本地跑一些依赖百度、阿里、OpenAI接口的服务全部要替换成内网自建模块。第五也是最容易被忽略的内网安全策略严Agent要调数据库、调工单系统、收发消息每一个工具接口都要提前报备权限动态执行代码这种功能在很多合规环境下会被直接砍掉。1.2 离线优先是这类项目的第一设计原则我见过太多团队一上来就规划Agent的Prompt、Tool调用、多Agent协作结果到内网现场才发现跑不起来原因全是环境层面的。我的经验是隔离内网项目必须倒过来设计先确定哪些东西能离线准备再谈Agent业务逻辑。离线的范围包括模型权重、推理框架安装包、Agent框架依赖、基础镜像、embedding模型、向量库程序、前端静态资源甚至中文字体。建议在项目启动第一天就建一个离线物料清单表格把每项物料、版本、大小、来源、校验方式全部记下来。这个清单就是整个项目的生命线。模型权重尤其要盯紧同一个模型的不同精度FP16、INT8、INT4占用的显存差别巨大必须根据内网服务器的GPU型号提前定好。如果是多台机器分发还需要考虑局域网内的包分发方式而不是每台机器都去配一套离线环境。2. 架构选型模型、推理框架、Agent编排怎么搭配2.1 分层架构是隔离内网项目的保命设计隔离内网AI Agent的架构我建议严格分层每一层之间用标准的内部接口隔开。最底层是模型层也就是本地化部署的开源大模型比如Qwen2.5系列、DeepSeek-R1蒸馏版、Llama 3.1系列再往上是推理服务层负责把模型跑起来并提供OpenAI兼容的API中间是Agent编排层也就是LangGraph、Spring AI这类框架负责规划、调用工具、管理状态再往上是一个工具与集成层对接内网数据库、工单系统、知识库、消息中间件最上面是应用接入层通常用FastAPI这类Web框架做统一入口给前端或业务系统调用。为什么一定要分层因为在隔离内网里每一层的容错率都很低一旦耦合在一起出了故障根本定位不到源头。分层之后模型推理服务可以单独扩容Agent编排可以单独升级工具层可以独立做权限管控。我自己常用一套很直白的比喻模型层是发动机推理层是变速箱Agent编排层是司机工具集成层是车辆上的各种执行机构接入层是方向盘和仪表盘。每层各司其职出现问题就能直接说是发动机抖动还是司机判断错了。2.2 主流Agent框架横向对比LangGraph、Spring AI、低代码平台隔离内网环境里Agent框架的选择比联网环境更敏感因为要综合考虑语言生态、离线安装难度、现有团队技术栈、后期运维成本。我横向对比过三种主流路线第一种是LangGraph基于Python适合复杂状态流编排社区活跃多Agent协作和人工审批节点都支持得很好配合LangChain的生态组件能省不少事第二种是Spring AIJava生态的Agent框架非常适合那种后台就是Spring Boot老系统的企业可以无缝接进现有服务但Agent编排能力比LangGraph弱一些复杂图结构表达起来比较吃力第三种是扣子这类低代码平台企业内部如果有私有化版本业务人员也能搭出简单Agent但灵活性和深度定制能力有限真正复杂的工程化落地还是得靠代码。以我个人的工程实战经验想快速验证业务价值、又希望后续能灵活演进选LangGraph FastAPI是最稳妥的这个组合在隔离内网里部署简单、资料多、遇到问题能找到人问。如果团队全是Java背景选Spring AI也没错但要做好Agent状态管理相对简陋的心理准备。低代码平台可以作为业务部门自助搭建的工具不适合作为核心Agent系统的主承载。3. 离线安装与依赖搬运先断网再干活3.1 Python依赖的完整离线迁移流程隔离内网里跑Agent最基础也最磨人的就是装环境。很多同学习惯在联网机器上直接pip install到了内网就傻眼。正确的做法是在一台与目标内网操作系统、CPU架构、Python版本一致的中转机上先把依赖全部下载成wheel包再搬运进内网安装。具体步骤大概是这样的先在外网开发环境用pip download把项目需要的全部依赖包下载到本地目录命令是pip download -r requirements.txt -d ./wheelhouse这里有个关键参数--platform manylinux2014_x86_64它指定目标平台的兼容性标签。如果是内网是ARM架构的机器就得改成aarch64这一步千万不能省否则搬进去会报not a supported wheel on this platform。下载完后检查wheelhouse里是否有.tar.gz源码包——这类包在内网编译需要编译器工具链很容易踩坑。要尽量锁定依赖版本避免传递依赖在下载时被意外解析出不同版本。内网安装的时候用pip install --no-index --find-links./wheelhouse -r requirements.txt强制从本地目录安装不带任何联网动作。对于Conda环境可以用conda pack把整个环境打包成压缩包内网解压后直接激活这种方式对复杂环境尤其好用但要注意目标机的glibc版本兼容性。建议把整个wheelhouse目录连同requirements.txt、Python解释器安装包一起放到离线物料清单里并记录每一层的安装顺序。3.2 模型、Docker镜像与系统依赖的离线导入Python依赖只是第一关模型和Docker镜像才是重头戏。模型文件动辄十几GB我习惯用huggingface-cli download在有网环境把指定模型完整下载到本地同时生成SHA256校验文件。搬运进内网后先做哈希校验再解压防止拷贝过程中的文件损坏。如果内网用Ollama部署可以把下载好的GGUF格式模型写进Modelfile用ollama create导入成内网私有模型这个流程我复用过很多次非常可靠。Docker镜像离线导入是另一个高频场景。外网机器上docker pull好需要的镜像然后docker save -o image.tar导出内网里用docker load -i image.tar导入。如果内网有自建的Harbor镜像仓库可以直接把镜像推送到内网Harbor每台节点从内网仓库拉取这种方式在多机部署时效率最高。这里有个容易踩的坑内网机器如果无法访问公网docker pull默认仓库地址必须改成内网Harbor地址或者提前把daemon.json的registry-mirrors配置清掉否则每个拉取操作都要等超时。系统级依赖也不要忽略比如libgomp、OpenBLAS、openssl这些往往不是pip包能解决的。建议在离线物料清单里单独列一行标注需要操作系统的离线RPM或DEB包并在中转机上用yumdownloader或apt download提前下载。我在一个项目里就吃过亏内网机器缺libgomp.so.1跑任何需要多线程的推理都会崩溃排查了半天才定位到是这个系统库缺失。4. 核心实现FastAPI LangGraph 搭建知识库问答Agent4.1 Agent状态图设计与小试牛刀示例架构定好后最关键的落地环节就是Agent本身的实现。我用的是经典的知识库问答Agent场景因为它在隔离内网里需求最普遍也最能体现Agent和普通接口问答的区别——它需要根据问题决定是否检索、检索什么、要不要调用别的工具而不是每次固定走同一条链路。LangGraph所有编排逻辑都建立在一个显式的状态图上。我定义了一个包含用户问题、检索结果、工具输出、最终答案的状态对象然后建立四个核心节点路由节点负责判断问题意图决定走直接回答还是知识库检索或工具调用检索节点负责从向量库中召回相似段落生成节点负责把检索结果和对话历史拼进Prompt交给模型生成答案工具节点负责实际执行内网数据接口。代码骨架大概长这样from typing import TypedDict, Literal from langgraph.graph import StateGraph, END class AgentState(TypedDict): query: str intent: str contexts: list[str] tool_result: str answer: str def route_node(state: AgentState) - AgentState: # 这里用本地模型做意图分类或者用规则匹配 state[intent] retrieve # 简化示意 return state def retrieve_node(state: AgentState) - AgentState: # 查内网向量库召回top-k段落 state[contexts] search_kb(state[query], top_k4) return state def generate_node(state: AgentState) - AgentState: # 拼接上下文与历史调用本地推理服务 state[answer] llm_generate(state[query], state[contexts]) return state graph StateGraph(AgentState) graph.add_node(route, route_node) graph.add_node(retrieve, retrieve_node) graph.add_node(generate, generate_node) graph.add_edge(route, retrieve) graph.add_edge(retrieve, generate) graph.add_edge(generate, END)这套图的好处是状态流转一目了然而且每个节点都是独立函数特别方便在隔离内网环境里做单节点调试。先把图跑通再逐步加上条件分支。4.2 工具调用、人工审批与内网数据接入知识库问答只是Agent的第一步真正体现干活能力的是工具调用。我在内网项目里接过的工具包括查业务数据库、读监控平台指标、创建运维工单、发送企业微信/钉钉消息、调内部API。LangChain的工具机制让我用装饰器或者pydantic类定义工具入参格式Agent判断需要用到哪个工具时先生成结构化参数再调对应函数。工具调用在隔离内网里有两个很容易出问题的地方。第一个是工具的入参和返回结果必须极其规范模型一旦生成不匹配的参数工具就会报错所以我会给每个工具写严格的pydantic模型凡是校验失败就返回明确错误信息让Agent有机会重新生成参数。第二个是权限问题内网系统的安全要求普遍高我强烈建议给工具调用加人工审批节点凡是写操作比如发消息、改配置、建工单都要先暂停流程等人工确认后继续。LangGraph里可以用interrupt机制实现这个效果线上系统的安全和效率冲突时安全永远优先。4.3 流式输出与网关封装浏览器端向FastAPI发起对话请求后如果等Agent图全跑完再返回结果用户会盯着空白页面好几秒甚至十几秒体验很差。我在实际项目里统一用SSEServer-Sent Events接口做流式输出FastAPI收到请求后后端把Agent每个节点的执行进度、最终答案逐段推送给前端。FastAPI端核心处理逻辑大概是这样调用LangGraph图的stream方法遍历执行事件把事件里的文本增量封装成SSE格式通过StreamingResponse返回。前端只需要用EventSource或者fetch的流式读取就能逐句渲染。这里有个细节工具调用的过程信息也可以推送出来用户能看到正在检索知识库正在调用运维工单接口这些进度提示即使模型回答变慢了用户的感知也会好很多。网关封装则解决的是统一鉴权、限流和审计问题。我给Agent服务包了一层FastAPI网关所有请求先经过API Key校验然后按用户维度做频控最后把会话ID、请求参数、Agent轨迹、最终结果全部写入审计日志。隔离内网虽然不对外开放但内部审计要求一样严格这一步千万别省。5. 隔离内网里AI Agent怎么扛并发5.1 先找准瓶颈LLM推理与工具调用链网上关于AI Agent怎么扛并发的讨论非常多但很多都忽略了一个根本前提并发瓶颈到底在哪。我拆开看Agent的完整处理链路发现主要瓶颈有两个。第一个是模型推理LLM生成是计算密集型的GPU显存和算力决定了同一时刻能跑多少个请求这是最硬的瓶颈第二个是工具调用与外部系统交互内网数据库、接口服务的连接数和响应速度也会拖慢整体吞吐。尤其是隔离内网里的Agent每个请求通常要经历规划-检索-生成-工具调用-总结多个步骤整体链路过长任何一个环节出现慢请求都会积压。我拿一个简单问答Agent压过测并发20个请求时模型推理服务先开始排队首token延迟从500毫秒一路涨到4秒以上工具调用节点的数据库连接池也打到上限。这个现象说明单纯增加Agent应用副本治标不治本必须从模型服务和整体链路分别优化。5.2 实战并发方案异步队列多副本三管齐下我落地过的并发方案可以总结为三件事推理服务独立化、请求队列削峰、Agent应用多副本。模型推理服务独立是第一步。我在内网里用vLLM跑本地模型它对并发请求支持得比裸HuggingFace pipeline好太多关键是启用了continuous batching多个请求可以在同一个批次内动态调度。启动参数里有两个最值得调--max-num-seqs控制并发生成的最大序列数通常设为128到256--gpu-memory-utilization控制显存利用率我一般设0.9。vLLM提供了OpenAI兼容的APILangChain/LangGraph可以直接通过ChatOpenAI类接入。第二步是处理瞬时流量。Agent任务里大量请求是非实时的报表、批处理类工作我会把这类任务切进队列异步执行用Celery或者简单的Redis队列都行。前端提交任务后立刻返回任务IDAgent工作节点从队列拉取任务慢慢跑做完再把结果回写到业务库。这样尖峰流量被削平模型推理服务不至于被打爆。第三步是Agent应用本身的多副本。因为Agent层是纯计算编排不持有太多状态可以相对容易地水平扩展前面挂Nginx做负载均衡。这里要特别提醒LangGraph的State如果本地内存保留多副本会导致会话状态不一致。生产环境要把Agent运行状态维持放到Redis里保证同一个会话的请求能被路由到同一个副本处理。5.3 压测验证与调优指标并发方案做完了不能靠感觉验收我会用k6写压测脚本模拟并发用户不断发Agent请求重点盯三个指标吞吐量每秒完成请求数、TTFT首token延迟、错误率。压测目标一般参照客户的用户规模和业务容忍度比如要求50并发下TTFT小于2秒请求成功率大于99%。实际压测过程经常能暴露很多问题。有一次我发现并发上升到30的时候错误率突然飙升查了半天发现是工具调用节点连内网数据库的连接池没有配置上限排队的请求全在超时边缘。改完连接池大小、加上数据库查询超时时间错误率立刻降了下来。所以压测不是走形式它是并发问题排查的最好手段。每次调完参数必须回归同一套压测脚本对比数据搬进内网之后更要压测因为内网机器性能和网络带宽往往比外网测试环境更差。6. 常见故障排查与避坑实录6.1 模型启动崩溃与显存不足隔离内网项目里模型起不来是故障率最高的问题。我自己遇到过的典型场景是模型已加载成功但一处理长上下文就OOM崩溃。原因通常是最大序列长度设置太大预留的KV Cache激增。排查时先看GPU显存使用曲线再逐步往下调--max-model-len比如从32K降到16K问题往往就解决了。另一类炸在推理框架兼容性。内网机器GPU驱动版本老vLLM的最新版可能根本装不上。技巧是把vLLM这类与CUDA版本绑定很紧的框架选择与内网驱动匹配的版本并让它依赖的nvidia相关库全部离线打包。如果内网GPU特别老比如Tesla P4、T4、V100用Ollama或者llama.cpp更省心它们对驱动要求宽松CPU也能勉强跑小模型就是并发能力有限适合小规模验证。6.2 Agent行为异常与安全边界问题用户问了不在知识库范围内的问题Agent会一本正经地编答案这在知识库场景特别致命。我的处理方案是双保险检索节点对召回的top-k结果的相似度分数设一个阈值低于阈值直接返回知识库无相关内容生成节点在Prompt里明确要求只能基于给定上下文回答如果上下文为空必须明确拒绝。内网场景对事实准确性要求比互联网闲聊高得多宁可答不上来不能瞎编。安全边界是另一个容易漏掉的地方。为了防止Agent乱调工具我给工具执行节点做了三件事第一工具列表白名单化只有显式注册过的函数才能被调用第二工具函数内部做参数校验防止注入或越权第三所有工具调用动作记录审计日志包括模型生成的原始参数和实际执行的结果。有一次测试时Agent把数据库查询条件拼错了查出了目标表之外的数据幸好是测试环境白名单和参数校验拦住了大部分问题。这里我强烈建议凡是涉及生产数据的写操作必须要人工审批节点兜底。6.3 中文检索效果差与embedding模型选型内网知识库很多是中文文档embedding模型选不对召回效果会严重拉胯。我测试过通用英文embedding模型处理中文内容检索出来的上下文经常前言不搭后语。实战下来BGE-M3、bge-reranker这类中英双语模型在中文场景里的效果很稳。embedding模型也是小型神经网络同样需要离线部署它一般可以单独封装成一个服务为向量检索提供文本转向量能力。政务服务里如果涉及敏感词过滤可以在检索前先做一层文本清洗。分段策略对召回的影响极大我按章节标题正文段落切分每个chunk控制在300到500字并让相邻chunk重叠20%左右确保语义跨段时不会被切碎。再加一个rerank环节从粗召回的20个段落里重新排序取前4个作为上下文实测答案准确率有明显提升。7. 一个完整的内网交付案例复盘去年我做了一个金融企业内网的运维知识助手Agent可以算是一个很典型的小而全案例我把过程完整复盘一下。需求很简单一线运维人员在处理故障时希望用自然语言问答的方式快速查到内部运维手册、历史故障记录和监控系统数据所有数据绝不能离开内网。前半程主要是物料准备。客户提供了一台双路CPU加两张RTX 4090的服务器显存总共48G。我选定Qwen2.5-14B-Instruct的主模型INT8量化后占用显存大约16G同时部署BGE-M3作为embedding模型剩余显存留给了KV Cache。模型和所有依赖包在一台联网中转机上整理好做完整SHA256校验后通过内部流程拷贝进内网这个过程花了两天。中间核心是数据与框架的落地。客户有几千份PDF运维手册我用离线文档解析链路把正文抽取出来清洗后切分成chunk用BGE-M3转成向量写入本地向量库。实战中我选了Milvus单机模式它部署相对简单在隔离内网里跑得很稳。Agent层用LangGraph搭了路由-检索-生成的图并额外接入了两个工具监控平台的指标查询API和工单创建系统其中工单创建必须经过人工审批。后半程是并发与稳定性调优。客户预期最多30个运维人员同时使用我把vLLM的--max-num-seqs设成了128应用层2个副本Redis存储会话状态。压测数据是35并发时TTFT平均1.2秒成功率99.6%达到了客户预期。上线后又调了一周主要是修复某些专业术语在向量检索里召回不准的问题加了三轮rerank和同义词扩充后知识库命中率从82%提到了93%。这个案例最让我感慨的不是技术而是交付节奏。隔离内网项目调试窗口少出一次现场机会很难得所以我强烈建议在联网环境搭一套一模一样的影子环境先把流程全部跑通再一键切换到内网。影子环境和内网环境的差异越小现场故障越少。8. 给准备入坑的工程师几句实在话按我个人经验隔离内网AI Agent项目的成败从来不是被模型强不强决定的而是被一堆不起眼的工程细节决定的。模型效果不好还有个回旋余地离线包缺一个、模型输出乱码、会话状态对不上号这些问题在现场解决起来的代价远超想象。所以给准备入坑的工程师几个具体建议第一永远先做离线物料清单把每一项依赖、模型、镜像、系统库都记录在案这是你在内网现场最大的底气第二所有Agent编排逻辑先在联网影子环境跑透再交付到隔离网络第三内网环境尽量选成熟稳定的版本最新版本看起来香但离线依赖、驱动兼容问题会把你折腾得没脾气。最后分享一个我自己一直在用的小技巧把整个离线安装过程写成幂等脚本包括wheelhouse的生成、模型的哈希校验、Docker镜像的导入、服务的启动参数检查全部脚本化固化到内部工具库里。下一次换一个内网项目时这些脚本就是最宝贵的资产。隔离内网下的AI Agent工程实战说到底拼的不是炫酷的技术而是把这些细节做到位、把风险提前想清楚的能力。