
1. 为什么要在隔离内网里折腾 AI Agent先把场景说清楚。所谓隔离内网就是那种物理上跟公网断开、或者只允许极少数白名单流量出入的办公网、生产网、涉密研发网。这类环境里你没法直接pip install openai没法调云端大模型 API甚至连 GitHub 都拉不下来。但偏偏这类环境里的需求一点都不少代码仓库检索、日志分析、工单自动分类、内部知识库问答、批量文档处理这些活儿用 AI Agent 来干效率提升是肉眼可见的。我前后在三个不同规模的内网环境里落地过 AI Agent从几十人的小团队到上千人的研发中心都趟过。最大的感受是内网 AI Agent 的难点从来不是模型本身而是工程化这三个字。公网上你随便找个框架跑个 demo 就能发朋友圈内网里你要考虑的是模型怎么进去、依赖怎么装、Agent 怎么跟内部系统对接、并发上来之后怎么不崩、出了问题怎么排查。这一整套东西才是真正卡住绝大多数人的地方。这篇内容适合三类人看一是被派了在内网搞个 AI 助手任务但不知道从哪下手的工程师二是已经跑通了 demo 但一上量就各种报错的开发者三是想系统了解 AI Agent 工程化落地全流程的技术负责人。我会把 MCP、Skills、并发扛压、内网部署这些热搜词背后的东西用我自己踩过的坑串起来讲一遍。不吹概念只讲能直接抄作业的东西。2. 内网 AI Agent 的整体架构设计思路2.1 先想清楚内网 Agent 和公网 Agent 的本质差异很多人第一次做内网 Agent习惯性地把公网那套架构照搬进来结果处处碰壁。根子上是因为两者的约束条件完全不同。公网 Agent 的典型架构是你的程序 → 调用云端大模型 API → 模型侧完成推理 → 返回结果。你的机器基本就是个传话筒算力、模型、工具生态全在云上。而内网 Agent 必须把这一整条链路全部搬到本地模型要本地部署推理要本地算力工具调用要本地实现连依赖包都得提前离线准备好。这个差异直接决定了三件事。第一模型选型不能贪大。公网上你可以随便调千亿参数模型内网里你得看手头有什么卡。一张 24G 显存的消费级卡跑个 7B 到 14B 的量化模型是比较现实的如果只有 CPU那基本只能上 3B 以下的小模型或者用蒸馏版本。第二工具生态要自己搭。公网 Agent 可以直接调各种现成插件内网里你得自己写工具函数、自己定义协议。第三网络通信要重新设计。公网 Agent 走 HTTP 调 API 天经地义内网里如果 Agent 和模型不在同一台机器上你得考虑内网服务发现、端口规划、防火墙策略。我一般建议的架构分层是这样的最底层是模型推理层用 vLLM 或者 Ollama 这类推理框架把模型跑起来对外暴露一个兼容 OpenAI 格式的接口中间是Agent 编排层负责 prompt 管理、工具调用、多轮对话状态维护最上面是业务接入层对接内网的具体系统比如 GitLab、Jira、内部 Wiki。这三层之间用内网 HTTP 或者 gRPC 通信全部走内网地址不碰公网。2.2 模型怎么进内网离线搬运的几种实操路径这是内网落地的第一道坎也是最多人卡住的地方。模型文件动辄几个 G 到几十个 G内网又没法直接下载怎么办我实测下来最稳的方案是外网下载 介质摆渡。具体操作是在一台能上外网的机器上用huggingface-cli download或者modelscope把模型权重、tokenizer、配置文件全部拉下来打包成一个压缩包。然后通过合规的介质移动硬盘、内部文件摆渡系统拷进内网。这里有个细节很多人会忽略模型目录结构必须完整包括config.json、tokenizer.json、tokenizer_config.json、special_tokens_map.json以及所有的.safetensors分片文件少一个都加载不起来。如果你用的是 GGUF 格式的量化模型比如通过 Ollama 部署那就更简单单个文件拷进去就行。但要注意量化等级的选择Q4_K_M 是性价比最高的档位Q5 以上质量更好但显存占用明显上升Q3 以下质量下降比较厉害除非显存实在紧张否则不建议。提示搬运前务必核对模型的 SHA256 校验值内网环境里文件损坏是排查起来最痛苦的问题之一一个字节的差异可能导致模型加载时报出完全看不懂的错误。还有一种情况是内网有私有镜像仓库。这种情况下可以把推理框架比如 vLLM打成 Docker 镜像在外网构建好之后推到私有仓库内网直接拉取。模型文件则通过挂载卷的方式提供。这种方式适合规模化的团队一次搭建好之后后续部署新模型就是改改配置的事。2.3 MCP 协议在内网场景下的价值与取舍MCPModel Context Protocol这两年被提得很多它的核心价值是给模型和外部工具之间定了一套标准化的通信协议。公网生态里 MCP 已经有不少现成的 server 可以用但在内网里MCP 的意义要重新评估。我的判断是内网里 MCP 值得用但不要为了用而用。它的真正价值在于解耦。假设你的 Agent 需要访问内网的 GitLab、Jira、数据库三个系统如果每个都硬编码在 Agent 代码里那后续任何一个系统接口变了你都得改 Agent 主体逻辑。而用 MCP 的话每个系统对应一个 MCP serverAgent 只跟 MCP 协议打交道系统接口变了只改对应的 server 就行。内网里搭 MCP server 有个坑要注意MCP 默认的通信方式有 stdio 和 SSE 两种。stdio 方式适合 Agent 和 server 在同一台机器上简单直接SSE 方式适合跨机器但内网里 SSE 的长连接容易被防火墙或者负载均衡掐断。我一般建议内网优先用 stdio如果必须跨机器就用 HTTP 短连接轮询的方式自己封装一层别硬上 SSE。另外MCP server 本身也是要写代码的内网里没有现成的 npm 包或者 pip 包可以随便装所以依赖要提前在外网准备好打成离线包带进去。这一点在规划阶段就要考虑到别等到写代码的时候才发现装不上依赖。3. Skills 机制让 Agent 真正会干活的关键3.1 Skills 到底是什么为什么它比单纯的工具调用更强Skills 这个概念最近很火但很多人理解得比较浅以为就是给 Agent 加几个函数。实际上 Skills 的本质是把领域知识和操作流程封装成可复用的能力单元。举个具体的例子。你要让 Agent 帮你分析内网的一台服务器为什么 CPU 飙高。如果只是工具调用你给 Agent 一个执行 shell 命令的工具它可能会瞎跑一堆命令效率很低。但如果你封装一个服务器性能诊断的 Skill里面预置了诊断流程先看top找高占用进程再看该进程的线程状态再查对应的日志最后给出结论。这个 Skill 里既有工具调用也有流程编排还有领域经验。Agent 拿到这个 Skill就相当于一个新手拿到了老师傅的诊断手册。在内网环境里Skills 的价值被进一步放大。因为内网的业务系统往往有很强的特殊性公网模型根本不知道你们内部的工单系统长什么样、代码规范是什么、审批流程怎么走。这些知识只能通过 Skills 注入进去。3.2 内网 Skills 的设计原则原子化、可组合、可测试我设计内网 Skills 的时候遵循三个原则。原子化是指每个 Skill 只干一件事粒度要小。比如查询工单状态是一个 Skill修改工单优先级是另一个 Skill不要把一堆操作塞进一个 Skill 里。这样做的好处是复用性强组合灵活。可组合是指 Skill 之间可以互相调用。比如生成周报这个 Skill内部可以调用查询本周工单、统计代码提交、汇总会议记录三个子 Skill。这种组合关系用配置文件描述不要硬编码在代码里方便后续调整。可测试是指每个 Skill 都要能单独测试。内网环境调试困难如果 Skill 只能整体跑起来才能验证那排查问题会非常痛苦。我的做法是给每个 Skill 写一个简单的测试入口输入固定的参数看输出是否符合预期。下面是一个 Skill 定义的简化示例用 YAML 描述name: query_ticket_status description: 根据工单ID查询内网工单系统的当前状态 parameters: - name: ticket_id type: string required: true description: 工单编号格式为 TK-数字 implementation: type: http method: GET url: http://internal-jira/api/ticket/{ticket_id} headers: Authorization: Bearer ${INTERNAL_TOKEN} response_mapping: status: $.fields.status.name assignee: $.fields.assignee.displayName updated: $.fields.updated这种声明式的写法有个好处非开发人员也能看懂改起来不用动代码。内网里经常出现的情况是业务方想调整某个 Skill 的行为但开发排期很紧如果 Skill 是配置化的业务方自己就能改。3.3 Skills 的加载与调度内网里的性能考量Skills 多了之后怎么让 Agent 快速找到该用哪个 Skill是个工程问题。公网上很多框架用的是把所有 Skill 的描述塞进 prompt让模型自己选这在 Skill 数量少的时候没问题但内网里如果 Skill 有几十上百个prompt 会变得极长推理速度直线下降。我的做法是两级检索。第一级用关键词或者向量检索从所有 Skill 里粗筛出 Top 10 候选第二级把这 10 个 Skill 的详细描述塞进 prompt让模型做最终选择。这样既保证了准确率又控制了 prompt 长度。向量检索在内网里需要本地部署一个 embedding 模型用个小模型就行比如 bge-small 这类几百兆的大小CPU 也能跑。把所有 Skill 的描述预先向量化存起来查询的时候算一下相似度。这套东西搭一次后续加 Skill 就是往索引里加一条记录的事。注意Skill 的描述文本质量直接决定检索准确率。描述要写清楚这个 Skill 干什么、什么时候用、输入输出是什么别写得太抽象。我见过有人把 Skill 描述写成处理数据这种描述检索出来全是噪声。4. 并发扛压内网 Agent 最容易翻车的地方4.1 内网 Agent 的并发瓶颈到底在哪公网 Agent 谈并发瓶颈通常在 API 限流或者网络延迟。内网 Agent 的瓶颈完全不一样我总结下来主要是三个模型推理的显存瓶颈、Agent 编排层的状态管理、以及工具调用的阻塞。模型推理这块一张卡同时能处理多少请求取决于模型大小、量化等级、上下文长度和推理框架的调度策略。以 7B 模型 Q4 量化、4K 上下文为例一张 24G 卡用 vLLM 部署并发 8 到 16 路是比较舒服的区间再往上延迟会明显上升。这个数字不是拍脑袋来的是实测出来的并发 8 的时候首 token 延迟大概 300ms并发 16 的时候涨到 800ms 左右并发 32 的时候直接飙到 2 秒以上用户体验就很差了。Agent 编排层的状态管理是很多人忽略的坑。Agent 处理一个请求往往要经过多轮思考-调用工具-再思考这个过程中会话状态要一直保持。如果编排层是无状态的每个请求都重新加载上下文那并发一上来内存直接爆。我的做法是用 Redis 或者内存数据库存会话状态设置合理的过期时间请求之间共享状态存储。工具调用的阻塞是最隐蔽的。假设你的 Agent 调了一个内网接口这个接口响应要 5 秒那这 5 秒里 Agent 的线程就被占住了。并发一高线程池瞬间打满。解决办法是把所有工具调用改成异步的用asyncio或者线程池管理别让一个慢接口拖垮整个 Agent。4.2 实测有效的并发优化手段先说模型层。如果显存允许开启连续批处理continuous batching是提升吞吐最有效的手段。vLLM 默认就支持Ollama 新版本也支持了。它的原理是把多个请求的动态 batch 拼在一起推理GPU 利用率能从 30% 提到 70% 以上。开启方式很简单vLLM 启动时加--enable-chunked-prefill参数就行。再说编排层。请求队列 限流是必须的。我一般用信号量控制同时进行的 Agent 会话数超过阈值的请求进队列等待而不是直接拒绝。队列长度也要设上限防止内存无限增长。具体参数怎么定我的经验公式是队列长度 并发数 × 3这样既能吸收突发流量又不会积压太多导致超时。工具调用层超时和重试必须配好。内网接口不稳定是常态一个接口超时 30 秒不返回如果不设超时Agent 就卡死在那了。我的配置是普通查询接口超时 5 秒重试 2 次写操作接口超时 10 秒不自动重试避免重复写入。重试要加退避别一失败就立刻重试那样会把下游打垮。下面是一个用 Python asyncio 做并发控制的简化示例import asyncio from asyncio import Semaphore class AgentPool: def __init__(self, max_concurrent8, queue_size24): self.semaphore Semaphore(max_concurrent) self.queue asyncio.Queue(maxsizequeue_size) async def handle_request(self, request): if self.queue.full(): return {error: 系统繁忙请稍后重试} await self.queue.put(request) async with self.semaphore: await self.queue.get() return await self._process(request) async def _process(self, request): # 实际的 Agent 处理逻辑 ...这段代码的核心是信号量控制并发数队列控制积压量。实测下来8 并发 24 队列的配置在 7B 模型上能稳定支撑 50 人左右的小团队日常使用。4.3 压测怎么做内网环境下的土办法内网里没有公网那些现成的压测服务得自己想办法。我一般用locust或者自己写个脚本模拟多个用户同时发请求。关键是压测数据要真实别用你好这种简单请求要用实际业务里最复杂的那些 query因为复杂 query 的 token 数多推理时间长才是真正的压力来源。压测的时候重点看三个指标P95 延迟、错误率、GPU 利用率。P95 延迟反映大多数用户的体验错误率反映系统稳定性GPU 利用率反映资源是否浪费。我的经验是P95 延迟控制在 3 秒以内、错误率低于 1%、GPU 利用率在 60% 到 80% 之间是比较健康的状态。压测过程中如果发现 GPU 利用率很低但延迟很高那瓶颈多半在编排层或者工具调用层要去查是不是有同步阻塞。如果 GPU 利用率打满但延迟还能接受那说明模型层是瓶颈考虑加卡或者换更小的模型。5. 内网部署的完整实操流程5.1 环境准备从裸机到可运行假设你拿到了一台内网服务器配置是 32 核 CPU、128G 内存、一张 24G 显存的卡操作系统是 Ubuntu 22.04。从零开始搭一个能跑的 AI Agent 环境步骤是这样的。第一步装基础依赖。内网没法apt update所以要提前在外网把需要的 deb 包下载好用dpkg -i离线安装。核心依赖包括Python 3.10 以上、CUDA 驱动和 toolkit、Docker如果用容器化部署的话。CUDA 版本要和推理框架匹配vLLM 0.4 以上版本一般要求 CUDA 12.1 以上。第二步准备 Python 环境。用 conda 或者 venv 建一个独立环境然后把推理框架和 Agent 框架的离线 wheel 包拷进来装。这里有个技巧在外网用pip download把所有依赖下载到一个目录注意要指定平台和 Python 版本比如pip download vllm --platform manylinux2014_x86_64 --python-version 310 --only-binary:all:这样下下来的包才能在内网直接用。第三步部署模型。把模型文件放到指定目录用 vLLM 启动服务python -m vllm.entrypoints.openai.api_server \ --model /data/models/qwen2-7b-instruct \ --served-model-name qwen2-7b \ --tensor-parallel-size 1 \ --max-model-len 8192 \ --gpu-memory-utilization 0.9 \ --port 8000参数说明tensor-parallel-size是张量并行数单卡就填 1max-model-len是最大上下文长度根据显存调整24G 卡跑 7B 模型 8K 上下文比较稳gpu-memory-utilization是显存占用比例0.9 表示用 90% 的显存留一点给系统。第四步验证模型服务。用 curl 测一下curl http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -d {model: qwen2-7b, messages: [{role: user, content: 你好}]}能正常返回就说明模型层通了。5.2 Agent 编排层的搭建与配置模型服务通了之后接下来搭 Agent 编排层。我一般用 FastAPI 做服务框架因为它轻量、异步支持好、内网部署简单。核心代码结构是这样的一个agent.py负责 Agent 的主逻辑一个skills/目录放所有 Skill 的实现一个config.yaml放配置。Agent 主逻辑要做的事包括接收请求、加载会话历史、检索相关 Skill、构造 prompt、调用模型、解析模型输出、执行工具调用、返回结果。这里有个关键设计prompt 模板要可配置。内网里不同业务场景需要的 prompt 差别很大硬编码在代码里改起来麻烦。我一般把 prompt 模板放在配置文件里用 Jinja2 渲染改 prompt 不用重启服务。工具调用的解析是另一个重点。模型输出的工具调用格式可能不规范要做容错。我的做法是用正则先提取提取失败就尝试 JSON 解析再失败就让模型重新生成。这个重试逻辑要设上限最多重试 2 次避免死循环。5.3 与内网业务系统的对接Agent 要真正干活必须能访问内网的各种系统。对接方式取决于系统的开放程度。如果系统有 REST API那最简单直接写个 HTTP 客户端调用就行。注意内网 API 的认证方式常见的有 token、cookie、mTLS 几种。token 方式最普遍把 token 放在配置文件里注意权限控制别用管理员账号。如果系统只有数据库访问权限那就直连数据库查询。这里要特别注意只读权限Agent 绝对不能有写权限否则模型一个幻觉就可能把数据改了。我一般给 Agent 配一个只读账号只能 SELECT不能 INSERT/UPDATE/DELETE。如果系统啥接口都没有只能通过命令行操作那就用 subprocess 调用。这种方式最脆弱因为命令行输出格式可能变解析容易出错。我的建议是尽量推动业务方提供 API实在不行再用命令行并且要做好输出解析的容错。提示所有对接外部系统的 Skill都要加详细的日志。内网排查问题全靠日志日志里要记录请求参数、响应内容、耗时、错误信息。日志级别用 INFO 就行别用 DEBUG否则日志量太大。6. 常见问题与排查技巧实录6.1 模型加载失败类问题问题一模型加载时报 out of memory。这是最常见的。原因通常是显存不够或者gpu-memory-utilization设得太高。解决办法先降低max-model-len从 8192 降到 4096 试试还不行就换更小的量化等级从 Q5 换到 Q4再不行就换更小的模型。问题二模型加载时报 config.json not found。这是模型文件不完整。检查模型目录下是否有config.json、tokenizer.json等文件对比外网下载时的文件列表缺啥补啥。问题三模型能加载但推理输出乱码。这通常是 tokenizer 不匹配或者模型文件损坏。先核对 SHA256再检查 tokenizer 配置。6.2 并发相关问题的排查问题一并发一上来就报 connection refused。这是模型服务的连接数打满了。vLLM 默认的连接数有限启动时加--max-num-seqs参数调大比如设成 64。问题二并发时延迟忽高忽低。这是批处理调度的问题。检查是否开启了连续批处理如果开了还这样可能是请求的 token 长度差异太大长请求把短请求堵住了。解决办法是给请求按长度分队列短请求优先处理。问题三Agent 处理到一半卡住不动。这多半是工具调用阻塞了。检查工具调用的超时设置看是不是某个接口没返回。用py-spy这类工具 dump 一下线程栈能快速定位卡在哪。6.3 内网特有的坑坑一DNS 解析慢。内网 DNS 服务器如果配置不当每次请求解析域名都要几百毫秒。解决办法是在/etc/hosts里把常用的内网域名写死绕过 DNS。坑二防火墙静默丢包。内网防火墙有时候不返回 RST直接丢包导致连接一直挂着直到超时。这种问题最难查因为从应用层看就是卡住。排查方法是抓包看请求发出去了但没响应那就是被防火墙拦了。坑三时间不同步。内网机器如果时间不同步会导致 token 过期、日志时间错乱等问题。部署前先确认 NTP 服务正常所有机器时间一致。下面整理一个常见问题速查表现象可能原因排查方法解决手段模型加载 OOM显存不足看 nvidia-smi降上下文/降量化/换小模型推理输出乱码tokenizer 不匹配核对模型文件重新拷贝完整模型并发连接拒绝连接数打满看服务日志调大 max-num-seqs延迟忽高忽低批处理调度问题看请求长度分布按长度分队列Agent 卡住工具调用阻塞py-spy dump 线程栈加超时/改异步DNS 解析慢DNS 配置问题测解析耗时写 hosts连接挂起防火墙丢包抓包分析调整防火墙策略6.4 几个我踩过的坑和独家技巧技巧一模型预热。服务启动后先发几个请求把模型跑热让 CUDA kernel 编译好、显存分配好这样正式请求进来时延迟会低很多。我一般写个预热脚本启动后自动跑 10 个请求。技巧二日志分级。内网排查问题全靠日志但日志太多又影响性能。我的做法是正常请求只记 INFO 级别记录请求 ID、耗时、结果状态异常请求记 ERROR 级别记录完整上下文。这样既能排查问题又不会日志爆炸。技巧三灰度上线。内网 Agent 上线别一次性全量先找几个愿意尝鲜的同事试用收集反馈迭代几轮再推广。我见过太多一上线就被吐槽然后项目黄了的案例。技巧四留后门。这里说的后门不是安全后门是降级开关。Agent 如果出问题要能一键切回原来的工作方式。比如 Agent 挂了用户还能通过原来的工单系统提需求。这个降级开关在项目初期就要设计好别等出事了才想。7. 关于内网 Agent 工程化的一些个人体会做内网 AI Agent 这几年我最大的体会是技术选型要保守工程实现要扎实别追新。公网上那些花里胡哨的框架和技巧内网里大部分用不上或者用起来成本极高。反而是那些最基础的东西——稳定的模型服务、清晰的架构分层、完善的日志监控、合理的并发控制——才是决定项目成败的关键。另一个体会是内网 Agent 的迭代速度天然比公网慢。公网上你今天发现个新框架明天就能试内网里你发现个新东西光是把依赖搬进去就要好几天。所以内网项目的规划要做得更长远选型的时候多考虑这个东西半年后还维护吗、社区活跃吗、离线部署方便吗。最后说个具体的如果你现在正准备在内网搞 AI Agent我的建议是先跑通最小闭环。别一上来就想着做多牛的功能先把模型能跑起来、Agent 能调通一个工具、用户能问一个问题得到回答这条链路走通。这条链路走通了后面加功能、优化性能都是在这个基础上迭代。链路没走通想再多都是空中楼阁。至于后续扩展我个人的方向是把 Skills 做得更细、更贴合业务同时把并发能力再往上提一提。内网里用户量虽然不大但大家对响应速度的要求一点不比公网低。这块还有不少优化空间等有新进展再跟大家分享。