去年末我们接了一个在隔离内网里交付 AI Agent 项目的活儿。机房物理断网业务数据不能出域但客户要求智能体必须能对话、能查内部系统、能写总结。一开始团队里有人认为内网跑 Agent无非是把模型文件拷进去、装个环境、起个服务不就行了结果真正动手才发现隔离内网不是没有网而是整个技术栈的获取方式、依赖管理方式、工具调用方式、故障排查方式全部变了。这篇就围绕隔离内网下 AI Agent 工程实战这个主题把我们踩过的坑、筛选出能复用的方案以及一套从架构到部署的落地框架完整写出来。内容覆盖模型私有化选型、离线环境构建、技能层工具接入、知识库搭建、并发改造、运维监控与模型迭代适合正在做私有化 Agent 交付、对数据安全要求较高的读者参考。1. 隔离内网部署AI Agent核心矛盾从智能转向了交付1.1 为什么内网环境会把Agent项目拖入地狱模式先说结论隔离内网下做 Agent技术难度本身不高真正折磨人的是依赖管理和环境一致性。外网环境里装一个 Python 包可能就是一条 pip install 命令缺什么补什么但在隔离内网里没有公网源、没有镜像源、没有预编译 wheel 缓存你面对的只有一台干净的服务器和一块装有安装包的移动硬盘。更要命的是 Agent 系统的依赖是多层叠加的底层有 PyTorch、Transformers 这类重型框架中层有 LangChain、LangGraph 这类编排框架上层还有向量库客户端、HTTP 服务框架、任务队列、OCR 识别库等等。任何一个包版本不对或者某个传递依赖缺失整个链路都跑不起来。我们在交付时碰到过一次特别典型的状况开发机上是 Python 3.11 LangChain 0.1.x内网服务器是 Python 3.9 旧版 NumPy结果 Embedding 模型加载后做向量检索时数组广播直接报错排查了两天才定位到是依赖版本组合问题。所以在隔离内网里做 Agent第一优先级不是模型效果多好而是交付链路多稳。你需要把整个项目当成一个自包含的离线制品来构建而不是把一堆代码扔到内网里再现场解决环境问题。1.2 我最终定下的分层架构我们最终采用的架构是按能力边界分层的每一层都尽量解耦层次职责典型组件模型层提供大模型推理与 Embedding 能力vLLM、SGLang、Ollama、本地 Embedding 模型语义层负责 Agent 的规划、记忆、工具调度LangGraph 状态机、LangChain 工具抽象技能层把内部系统能力封装成工具FastAPI 内置函数、MCP 协议服务、HTTP 调用知识层私有知识库的写入、检索、重排Milvus、Chroma、BM25、本地 Rerank 模型调度层管理多轮任务、队列、并发、流式FastAPI、Celery、Redis Stream、SSE服务层对外提供统一 API 网关、权限校验Nginx、网关服务、统一身份认证运维层日志、监控、模型热更新、备份Prometheus、Grafana、systemd、K8s这套分层不是一开始就想清楚的而是被内网环境的孤岛效应逼出来的。比如在技能层我们要求所有工具调用都必须走统一的协议内网里不能出现开发机上有这个环境变量、内网没有这种隐性依赖在模型层所有模型文件固定在同一个目录结构下便于内网服务器批量拷贝。后面所有章节讲的基本都是在这套分层里逐个击破的实战记录。1.3 模型选型一切从能私有化开始既然要在隔离内网跑第一步必然是模型选型。我们的约束很明确模型必须能私有化部署、必须能用单卡或双卡 GPU 带动、中文效果要过得去。在这个前提下7B 到 14B 规模的开源模型是主力区间。主流选型上有几条路线Qwen 系列是我们在中文场景的首选文档全、生态好、指令遵循能力在同尺寸里算是前排GLM 系列在中文对话上有自己的优势特别是长文本场景如果是纯英文为主的技术文档问答场景Llama 系列也能打。我们最终选了 Qwen2.5-7B-Instruct 作为主对话模型搭配一个刚过 1B 的轻量模型做意图分类和摘要Embedding 走 BAAI/bge-m3 本地部署。有个很关键的细节模型量化一定要提前在开发机上测好。内网 GPU 型号五花八门有些老卡只支持 FP16有些新卡可以跑 INT4/INT8。我们遇到过客户服务器是 V100结果我们带过去的 AWQ 量化模型格式加载不了只能现场现场重新导出。所以无论你倾向 GPTQ、AWQ 还是 GGUF都要先在目标机器同型号的显卡上跑一遍完整加载和推理测试别只在本机验证完就打包。2. 先解决依赖环境的离线问题再谈智能2.1 离线 Python 环境的三种思路我推荐最笨的一种隔离环境下构建 Python 环境传统的有三条路pip download 打包 wheel、全量离线 wheelhouse、容器镜像迁移。我们三路都实际试过。pip download 方案在开发机上用pip download -r requirements.txt -d ./packages下载所有 wheel但有个坑是不少包在 PyPI 上同时提供 sdist 源码包和 wheel 二进包如果下载策略没指定--only-binary:all:会混入一堆需要现场编译的源码包内网没有编译工具链就卡死了。即便打包完整内网服务器系统是 CentOS 7 还是 Ubuntu 22.04Python 是 3.9 还是 3.11glibc 版本差异都会让 wheel 失效。wheelhouse 全量方案提前准备一个包含所有安装包的文件夹然后内网 pip install --no-index --find-links。思路没问题但本质上和第一种一样受限于同架构同系统同 Python 版本。容器镜像迁移法在开发机上用 Docker 构建一个完整镜像这个镜像里已经装好了 Python 环境、所有依赖、甚至代码和模型路径规划都做好了。然后把镜像 save 成 tar 包拷进内网后 docker load。内网服务器只要支持 Docker 运行基本不需要关心宿主机 Python 版本和依赖冲突问题。我们最终选的就是第三种虽然业内调侃容器迁移是最笨的办法但它恰恰是隔离内网交付里故障率最低、复现性最强的方式。第一版我们图省事想用 Python 虚拟环境直接搬运结果内网服务器缺 libgomp.so.1、缺 OpenSSL 1.1一个个补系统依赖补到崩溃。换成容器后宿主机只需要有 NVIDIA 驱动和 container runtime其余全部封装进镜像干净利落。2.2 容器镜像迁移法实操记录具体操作上建议把整个 Agent 项目做成一个 Dockerfile 多阶段构建。第一阶段用 python:3.11-slim 作为基础镜像安装 PyTorch 等重型依赖第二阶段拷贝项目代码安装 requirements第三阶段设置启动命令。注意几个工程细节第一基础镜像不要用带 CUDA 的大镜像因为内网服务器的 GPU 驱动版本未知镜像里带 CUDA 很容易和宿主机驱动起冲突。建议基础镜像用纯 CPU 版本然后在运行时通过--gpus all和宿主机驱动配合。PyTorch 在 Docker 里加载 CUDA靠的是宿主机 NVIDIA 驱动 容器内 CUDA 运行库这个组合我们测下来最稳。第二在开发机上提前把模型文件放在镜像外部的独立目录避免把几十 GB 的模型打进容器镜像。这样做的好处是模型更新只需要替换外部目录不用重新构建整个镜像坏处是镜像内代码要写清楚模型路径的配置统一从环境变量读取。第三整个镜像 build 完成后用docker save agent-image:latest | gzip agent-image.tar.gz压缩。在隔离内网里用zcat agent-image.tar.gz | docker load导入。压缩率大概能到 30%-50%一个 6GB 的镜像压缩后可能只有 2-3GBU 盘就能带走。2.3 模型文件的离线加载隐藏的坑很多模型文件在内网加载和在线环境下最大的区别就是 HuggingFace Hub 的行为。默认情况下Transformers 加载模型时会尝试访问 HF Hub 检查是否有更新即使你已经指定了本地路径某些版本库还是会发起网络请求。解决方式是设置环境变量export HF_HUB_OFFLINE1 export TRANSFORMERS_OFFLINE1这两个变量要写进容器启动脚本否则内网环境下的模型加载会出现卡住几分钟然后超时的诡异现象。我们在第一轮交付时就因为这个浪费了整整半天在线环境从没暴露过这个问题。另一个坑是 transformers 的缓存目录结构。如果你在开发机上用snapshot_download下载过模型缓存目录里会有 blobs 和 snapshots 两套结构。直接把这个缓存目录拷到内网是可以的但路径字段必须保持一致。更稳妥的做法是在开发机上把模型文件整理成标准目录例如models/qwen2.5-7b-instruct/下直接放 config.json、model-00001-of-00004.safetensors 等然后用代码指定本地路径加载不要依赖缓存机制model AutoModelForCausalLM.from_pretrained( /opt/models/qwen2.5-7b-instruct, trust_remote_codeTrue, torch_dtypetorch.float16, device_mapauto )2.4 版本一致性不可复现的构建就是灾难这一点我单独拎出来强调Agent 项目不是一个简单的单体脚本是多个库之间深度耦合的系统工程。LangChain 0.1 时代和 0.2/0.3 时代的 API 变化巨大Flow 概念的引入、工具调用的参数格式、回调机制都改过Pydantic 从 V1 迁移到 V2 时很多 LangChain 组件的模型配置写法也完全不同。我们内部就出过一次事故开发机用 LangChain 0.2 跑通的功能推到内网时结果发现内网镜像里锁的是 0.1.17工具调用的参数是从arguments字段解析的两边格式对不上Agent 一步工具都没调用成功。所以必须在项目仓库里同时锁定三个层级的版本Python 版本、核心依赖库版本、以及所有组件的传递依赖版本。具体要求用pip freeze requirements-lock.txt生成完整的锁文件不能只写langchain0.1这样的宽松约束镜像内统一使用同一个虚拟环境路径环境变量里不要出现多个 Python 版本混淆记录基础镜像的 tag包括python:3.11-slimsha256:xxx这种不可变引用别用 floating tag。如果团队里有多个人协作建议所有依赖变更都必须走重新构建镜像 - 完整回归测试 - 导出交付镜像这个流程别让开发机上的临时性调整悄悄流到交付物里。3. 技能层改造把工具调用搬到内网3.1 外网时代的工具调用在内网基本失效Agent 的核心能力之一是工具调用。外网环境下大家的 Agent 动辄接上几十个 API天气查询、新闻聚合、网页检索、代码仓库操作等等。但在隔离内网场景下这些外部工具全部失效。你面对的是一堆内部系统OA 审批接口、运维工单系统、数据库查询平台、内部Wiki、资产管理系统甚至还有一堆老掉牙的 CGI 接口全是非标准协议、非标准认证。这就带来一个原则性调整内网 Agent 的工具集不是能接什么就接什么而是必须接客户真正需要的、且权限边界清晰的系统。我们交付时第一个版本把 Agent 描述成万能办公助手结果客户试用时提出一堆帮我查下今天的天气这种根本没法支持的需求。后来学乖了工具列表完全围绕客户的实际业务流来设计比如提交运维工单查询业务报表数据检索内部知识库生成周报摘要。Agent 的能力边界和客户预期对齐了项目验收才顺利。3.2 用MCP协议统一工具接入工具接入的协议我们建议直接用 MCPModel Context Protocol。虽然它最初是为了解决模型与外部工具的标准通信问题但在内网环境下它带来的标准接入层价值更大——不同内部系统可以各自封装成一个 MCP ServerAgent 主程序只负责和多个 MCP Server 通信内部系统怎么改都不影响 Agent 主体。我们在内网技能层做了这么一套设计Agent 主服务通过 MCP client 连接本地 MCP Server每个内部系统一个独立 MCP Server 进程互相隔离MCP Server 内部完成认证、参数校验、调用内部 API、返回结构化结果所有工具通过 MCP 暴露的能力都经过统一审计日志记录。实际实现一个内网工具的 MCP Server核心代码并不复杂。下面是一个从内部工单系统查询状态的简单示例用 Python 实现from mcp.server.fastmcp import FastMCP mcp FastMCP(ticket-tool) mcp.tool() def query_ticket(ticket_id: str) - str: 查询内部工单状态返回工单进度摘要 # 这里调用内部工单系统 HTTP API并做鉴权 response internal_ticket_api.query(ticket_id) if response.code ! 0: return f查询失败: {response.msg} return f工单 {ticket_id} 当前状态: {response.data.state}处理人: {response.data.assignee} if __name__ __main__: mcp.run(transportstdio)Agent 主服务侧用 LangChain 的 MCP 适配器把工具加载进来注册进 Agent 的工具列表from langchain_mcp_adapters.tools import load_mcp_tools from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client server_params StdioServerParameters( commandpython, args[mcp_servers/ticket_tool.py], env{INTERNAL_API_KEY: os.environ[INTERNAL_API_KEY]} ) async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: tools await load_mcp_tools(session) # 将 tools 注入 Agent executor / graph这个方案有一个非常大的好处MCP Server 和 Agent 主服务是进程隔离的某个工具进程崩溃了重启这个 Server 就行不会拖垮整个 Agent 服务。我们在后期迭代中新接入一个内部系统只需要新写一个 MCP Server 文件路径下注册启用即可不再修改 Agent 主体代码。3.3 工具设计守则内网工具设计绝大多数坑都出在参数设计太粗或返回内容过大上。总结三条守则第一工具的粒度要原子。不要把处理工单全流程做进一个工具里而是拆分成查询工单指派处理人更新状态添加备注四个独立工具。模型的工具选择能力受限于 prompt 中工具描述的清晰程度工具描述要写明什么时候用它、输入是什么、输出结构是什么描述越具体模型选错的概率越低。第二工具的返回内容必须是给模型看的结构化摘要不是原始 API 的完整报文。我们遇到过一版实现直接返回 JSON 原始大字段模型读了几千个 token 才能找到关键信息多轮对话越聊越慢。后来每个工具都做了一次返回裁剪只保留状态、关键字段、摘要文本Token 消耗直降 70%。第三工具内部必须做超时和异常兜底。内网 API 一样有变慢、宕机的可能。所有工具调用都要设置超时时间内部系统一般 5 秒足够超时后返回系统暂时不可用请稍后重试不能让一次工具调用卡死整个 Agent 对话。4. 知识库私有化向量、分块与召回4.1 Embedding模型选型与维度坑企业内部的 Agent 落地大概率逃不开知识库问答。隔离内网场景下在线 Embedding API 不可用必须本地部署向量模型。我们实测下来BAAI/bge-m3 是一个很稳的选择中文效果不错、支持 8192 长度、同时支持稠密向量和稀疏向量两种检索模式在纯中文企业文档场景下比同规模的通用模型表现更好。但这里有一个必须提前规避的坑向量维度不匹配问题。bge-m3 默认输出的向量维度是 1024 维。如果你的现有代码是从 OpenAI Embedding API 迁移过来的它默认输出 1536 维两者完全不是一套东西。如果你的知识库之前已经用在线 API 向量化好了切到本地模型后必须全量重新向量化否则检索出来的相似度毫无意义。在工程上我们建议在代码里做成一个 Embedding 服务抽象层所有向量化请求统一走这个服务后续想替换模型只需要改一处配置即可。类似这样class LocalEmbeddingService: def __init__(self, model_name: str BAAI/bge-m3): self.model SentenceTransformer(model_name, devicecuda) def embed_documents(self, texts: list[str]) - list[list[float]]: return self.model.encode(texts, normalize_embeddingsTrue).tolist() def embed_query(self, query: str) - list[float]: return self.model.encode([query], normalize_embeddingsTrue).tolist()4.2 混合检索是内网知识库的底线方案只做向量检索在内网知识库场景下很容易出现语义相似但答案错误的情况。企业文档里存在大量专有名词、编号、型号比如WCS-2200 型传感器向量模型对这类精确标识的召回能力远不如关键词检索。所以我们采用了混合检索向量检索 BM25 关键词检索并行执行再做结果融合。具体实现不复杂。向量检索用 Milvus 或 ChromaBM25 可以用 Elasticsearch但隔离内网里没必要为一个关键词检索专门部署 ES直接用 Python 的 rank_bm25 库把文档切好分块后内存构建索引就行几十万篇文档以内性能完全够用。然后融合阶段给向量检索和关键词检索各自设置权重推荐从 0.6/0.4 起步根据实际测试效果调整。另外强烈建议在知识库链路上加一层 Rerank。普通向量检索的 Top 20 结果里混着不少噪声直接全量丢给大模型会拉低回答质量。我们用本地部署的 bge-reranker-v2-m3 对候选结果重排取 Top 4-5 给模型。这个额外的重排步骤对回答准确率提升非常明显特别是知识库文档之间存在较多相似内容的场景。4.3 分块策略与召回质量知识库的召回效果一半取决于分块策略。我们踩过的分块坑详细说一下。第一种常见做法是按固定字符数切块比如每 500 字切一块再加 50 字重叠。这个做法简单但很可能把一张表格拆得七零八落或者把一个完整概念切断成两半导致召回的内容语义不完整。第二种是语义分块根据文档标题和段落边界进行切分。对 Markdown 或带结构的文档按标题层级切分效果很好。对 PDF可以先做版面分析按标题、段落、表格分区域切块。适当的做法是优先保留文档结构按标题层级把每个章节作为单独的检索单元长章节内部再用固定窗口做二次切分保证单块长度在 300-500 字之间避免单块过大。同时要控制单块召回的上下文完整度。文档中经常出现如上表所示该模块的接口定义如下这类依赖前文的表达如果切块过于碎片化模型拿到的片段就是一堆指代词无法生成有效的回答。我们最终采用了两级分块策略粗分块按章节细分块按段落向量化时用细块但召回结果返回时带上所属章节的完整上下文模型理解效果会改善一个档次。4.4 RAG的克制使用内网知识库项目接多了会发现一个共同问题客户对 RAG 的期望过高总觉得有了知识库模型就能成为公司万事通。实际上的经验是能不用 RAG 就让模型直接回答的尽量直接回答必须用 RAG 的一定要做好检索失败兜底。检索失败的表现很典型用户的问法跟知识库文档里的表述差别很大向量检索和关键词检索都召不回有效内容。这种情况下如果 Agent 强行编造一篇答案企业场景是无法接受的。我们的做法是在 RAG 链路里加一道召回置信度判断检索出的最高相关分数低于阈值时Agent 明确回复我在内部知识库中没有找到相关内容请换个说法或联系文档负责人更新资料。这个 不知道就说不知道 的行为在很多客户眼里反而是 AI 项目专业度的加分项。5. 并发Agent 扛压的不传之秘5.1 单路调用很好看并发一来全垮网上总有人搜ai agent 怎么扛并发这类问题说明这是个项目交付的普遍痛点。单路对话演示时一切正常用户数一上来内存暴涨、响应超时、GPU 排队每一步都可能崩。Ant Agent 的请求链路比普通 Web 接口长得多。一个对话请求进来可能要经过鉴权 - 路由 - Agent 规划 - 多次模型推理 - 多次工具调用 - 多轮检索 - 生成回复整个过程几十秒甚至几分钟期间还伴随多次上下文拼接。这和普通接口秒回的模式完全不同并发模型也完全不一样。我们在内网交付时第一版用的是同步 FastAPI 直接处理所有请求结果 5 个并发用户就把系统拖垮了。后来做了一整套异步化改造才稳定下来。5.2 异步化改造入口快、重活下沉核心思路是长耗时的 Agent 任务不要占着 HTTP worker 不放而是把请求压进任务队列立刻返回一个任务 ID前端通过轮询或 SSE 获取进度和结果。实操上我们用了 Redis Stream 做消息队列也可以用 RabbitMQ。FastAPI 只负责接收请求、校验参数、把任务塞入队列然后返回queue.add( agent_tasks, {task_id: task_id, session_id: session_id, query: query} ) return {task_id: task_id, status: queued}另一边独立的 Worker 进程消费队列任务执行完整的 Agent 编排逻辑。Worker 的数量配置很有讲究和 GPU 显存、模型并发度强相关。我们最初配了 2 个 Worker每个 Worker 串行处理任务但模型推理是单实例并发两个 Worker 同时请求模型反而会互相抢占显存后来调整成 1 个 Worker 模型服务内部并发反而更稳。流式输出方面用 SSEServer-Sent Events实现比较合适。Worker 在执行过程中通过 Redis Pub/Sub 推送给 FastAPI 网关网关再通过 SSE 把 token 逐步推给前端。这样用户端的体验是流式打字效果不必等待整个任务跑完才看到第一个字。5.3 模型服务的并发度配置模型推理层用什么框架直接影响并发上限。我们对比过 vLLM 和原生 TransformersTransformers 的 generate 方法在每个并发请求下都要独立加载模型上下文和 KV Cache很容易 OOMvLLM 通过 PagedAttention 和连续批处理在相同显存下能支撑的并发数高得多。推荐在内网部署场景直接用 vLLM 做模型服务或者用 SGLang。以 Qwen2.5-7B-Instruct 为例单张 24GB 显存的显卡上vLLM 开启连续批处理实测可以同时服务 8-16 个并发请求具体取决于最大生成长度和请求频率。配置如下vllm serve /opt/models/qwen2.5-7b-instruct \ --served-model-name local-agent-model \ --max-model-len 8192 \ --gpu-memory-utilization 0.85 \ --max-num-seqs 16 \ --enable-auto-tool-choice注意其中的--max-num-seqs它代表最多同时处理的序列数。设得太高显存不够会 OOM设得太低并发能力上不去。建议内网交付时先用测试脚本压一把找到稳定值再写入参数配置。这里提一个额外的坑Agent 场景下每个用户的上下文长度差异巨大有的用户一个问题很短有的用户五轮对话后上下文超过 4000 token。vLLM 的--max-model-len设置如果太大单个请求占用的 KV Cachekey-value缓存用于解码历史上下文就多可用并发量随之降低。合理做法是限制最大模型长度在 8192 或 4096长对话及时截断摘要而不是无限放宽长度。5.4 幂等、重试与熔断伴随着异步化而来的是任务重复执行的风险。比如 Redis 队列消息被重复消费、网络超时导致 Worker 执行了两次、用户在前端点了两下发送产生了两个任务。在 Agent 场景里最怕的是重复提交工单重复扣款这类不可逆操作。所以凡是涉及写操作的工具都必须设计成幂等工单编号重复提交时直接返回已存在的结果不做二次创建数据库更新操作带上操作来源标记避免重复执行覆盖掉新数据。另外任务重试必须有上限。我们给 Worker 包装了一层重试逻辑单个任务最多重试 2 次超过次数就进入失败队列并通知管理员人工处理。还在 Agent 主链路上加了熔断逻辑如果模型服务连续返回 5 次错误直接把对应下游服务熔断 30 秒避免雪崩。6. 部署、监控与持续迭代6.1 部署方式systemd还是K8s隔离内网场景的部署方式我们的经验是要看客户运维团队的水平。如果客户只有一两个运维没有专职容器平台上 K8s 反而是灾难出了问题没人会排查、升级流程复杂、遇到故障求助无门。这种客户我们优先用 Docker Compose systemd 的方式交付。计划大概是这样的宿主机装 Dockerdocker-compose.yml 里编排模型服务、Agent 主服务、Worker、Redis、向量库这几个容器。systemd 只负责 docker-compose 的启停和开机自启。日志走 Docker 的 json-file driver统一收进一个日志目录方便巡检。如果客户已经有成熟的 K8s 集群那就按标准做法走模型服务作为 StatefulSet有状态应用需要挂载模型目录Agent 主服务作为 DeploymentRedis 和向量库用已有集群资源或单独部署。不管哪种方式都要坚持一个原则模型文件和镜像分离这样迭代时不用把几十 GB 模型重新拷贝一遍。6.2 三类必须盯的指标内网系统出了问题最大的痛点是没有外网查资料和复现困难。因此监控指标必须提前铺好而不是出了问题再去补。我把监控分成三层三类指标必须齐全第一模型服务指标请求次数、错误率、单 token 生成延迟、平均生成长度、GPU 显存占用率、GPU 利用率。这些指标通过 vLLM 暴露的 Prometheus metrics 直接采集Grafana 出面板。GPU 利用率低于 20% 说明并发上不去高于 90% 说明可能需要限流或扩容。第二Agent 链路指标任务队列长度、任务平均耗时、工具调用成功率、检索召回率、上下文 token 消耗分布。这类指标我们是在业务代码里手动埋点的每个任务在关键环节打点最后统一输出一条结构化日志。第三业务侧指标用户提问数、有效回复率、超时率、用户反馈的答非所问比例。这个可能有人觉得做和不做区别不大但我们实测下来这一层是向客户汇报项目效果时最有力度的数据也是后续优化模型 prompt 和工具描述的依据。6.3 模型升级的灰度与回滚模型不是交付完就完事了每过一两周客户就可能提出新需求比如你们能不能让模型更了解我们公司简称或者回答风格能不能更简洁。为了应对这类需求模型更新流程必须灰度化。我们的做法是模型服务启动两个实例一个挂载旧模型一个挂载新模型通过路由规则把 10% 的流量切到新模型上跑一两天重点看错误率和用户反馈。在隔离内网环境里拉齐两个实例也不难关键是模型目录独立、版本号打清楚。确认没问题后再逐步提升新模型流量比例直到全量切换。另外每个 Agent 会话记录里要带上模型版本号。客户如果反馈今天下午回答风格变了你能迅速定位到是不是模型切换导致的快速回滚到上一版。这里没有全局统一的绝对标准核心原则是所有变更可回滚、有记录、有对比才敢在隔离内网里持续迭代。我在这个项目里最深的体会是隔离内网并没有让 AI Agent 的智能降低它只是逼着你把工程化细节做扎实。曾经在公网环境里被隐藏掉的问题——依赖冲突、网络超时、缓存失效、工具调用不稳定——在内网里全部暴露无遗。但也正因为如此一旦把离线镜像、MCP 工具层、混合检索、异步队列这一整套框架搭好这套 Agent 系统会变得异常稳定因为它的每一步都不依赖外部环境不受网络波动影响。至于后续扩展方向我们正在尝试把更多内部系统以 MCP Server 的形式接入进来同时把长对话的上下文管理往里做深。内网 Agent 的想象空间不在于联网能力,而在于把企业内部的数据流转、业务逻辑真正沉淀成可被模型调用的能力。希望这篇实战记录能给正在隔离内网里挣扎的团队一些参考。