
1. 为什么要在隔离内网里折腾 AI Agent先把场景说清楚。所谓“隔离内网”就是那种物理上跟公网断开、或者只允许极少数白名单出口的环境常见于金融、制造、能源、医疗这类对数据外流极度敏感的行业。你在这种环境里想跑一个 AI Agent第一反应通常是模型怎么进来依赖怎么装工具怎么调外部 API 一个都连不上Agent 不就成了一个只会聊天的空壳我前后在三个不同规模的内网环境里落地过 Agent 工程从最初级的“单机跑个本地模型加几个脚本”到后来带 MCP 工具链、带 Skills 编排、带并发调度的完整中台踩的坑基本能写一本小册子。这篇就把这套东西完整拆开讲核心围绕四件事模型与运行时怎么在内网落地、MCP 协议怎么在无外网条件下跑通、Skills 体系怎么设计和分发、以及并发和工程化怎么扛住真实业务量。适合谁看如果你是被派去内网做 AI 落地的工程师、架构师或者你手上有一台只能内网访问的服务器想把它变成一个能干活的 Agent 平台这篇基本可以当施工图用。如果你只是好奇 AI Agent 是什么也能看懂因为我会尽量用生活化的类比把每个概念讲透。先给一个整体判断内网 Agent 工程的难点从来不是模型本身而是“依赖闭环”和“工具编排”。公网环境下你pip install一下就完事的东西在内网可能要手动搬十几个包、处理三层依赖冲突。而 MCP 和 Skills 这两个概念恰恰是解决“工具怎么标准化接入”和“能力怎么模块化复用”的关键所以它们在内网场景里的价值比公网还大。2. 内网 Agent 的整体架构设计与选型思路2.1 三层架构模型层、编排层、工具层我在内网里用的架构基本固定成三层这个分层不是拍脑袋定的是被现实逼出来的。模型层负责推理内网里通常有两种选择一是本地部署开源模型二是内网已有的推理服务很多公司会有自己的模型网关。我一般优先复用已有推理服务因为显存和运维成本摆在那重复部署没意义。如果确实要自己部署量化后的 7B 到 32B 模型是主流选择具体看任务复杂度。编排层是 Agent 的大脑负责意图理解、任务拆解、工具调用决策、多轮状态管理。这一层我用过 LangChain、LangGraph也用过更轻量的自研状态机。内网环境下我越来越倾向于轻量自研 成熟框架混合因为框架的很多能力依赖外部服务在内网里反而是负担。工具层就是 Agent 的手脚MCP 协议主要作用在这一层。它把数据库查询、文件操作、内部 API 调用、代码执行等能力标准化成统一的工具接口Agent 通过协议去调用不用为每个工具写一套适配代码。提示三层之间一定要有清晰的边界。我见过太多项目把工具调用逻辑写进编排层结果换一个工具就要改核心代码维护成本爆炸。2.2 为什么选 MCP 而不是自己写工具适配MCP 全称 Model Context Protocol你可以把它理解成“AI 和工具之间的 USB 接口标准”。在它出现之前每个 Agent 框架调工具的方式都不一样你为 LangChain 写的工具换到另一个框架就得重写。MCP 把这个事情标准化了工具方按协议暴露能力Agent 方按协议调用双方解耦。在内网里这个价值被放大了。因为内网工具往往是一次性开发、长期使用如果每换一个 Agent 框架就要重写一遍工具人力根本扛不住。用 MCP 之后工具服务独立部署Agent 只认协议不认实现框架升级、模型替换都不影响工具层。有人会问 MCP 到底是软件协议还是硬件协议。明确说MCP 是软件层的通信协议通常基于 JSON-RPC 走 stdio 或 HTTP/SSE 传输跟硬件没关系。你在内网里部署只要保证 Agent 进程和 MCP Server 进程之间网络可达就行stdio 模式甚至连网络都不需要同机进程通信即可。2.3 Skills 体系的定位把“会做某件事”封装成可复用单元Skills 这个词最近很热但很多人没搞清它和 MCP 的区别。我的理解是MCP 解决“能不能调用工具”Skills 解决“会不会用工具完成一件事”。举个例子查数据库是一个 MCP 工具但“根据用户问题生成 SQL、执行、格式化结果、异常重试”这一整套流程就是一个 Skill。Skill 里可以编排多个 MCP 工具也可以包含提示词模板、参数校验、后处理逻辑。在内网里Skills 的最大好处是能力沉淀和分发。一个团队把常用能力做成 Skill 库新项目直接引用不用从零开始。而且 Skill 通常是纯配置或轻代码内网分发成本低不像模型文件动辄几个 G。3. 内网环境下的依赖闭环与模型落地实操3.1 离线依赖包的搬运与安装这是内网工程的第一道坎。公网机器上pip download把所有依赖下下来打包拷进内网然后pip install --no-index --find-links./packages。听起来简单实操全是坑。第一个坑是平台差异。你在 Mac 上下载的包拷到 Linux 服务器上装不了因为 wheel 文件带平台标签。正确做法是在跟目标环境同架构同 Python 版本的机器上下载或者用--platform参数指定。我一般直接在内网找一台能临时联网的机器如果有的话做中转没有的话就在本地起一个和目标一致的 Docker 容器来下载。第二个坑是依赖冲突。Agent 框架的依赖树非常深LangChain 一个包能拖出几十个间接依赖版本还互相打架。我的做法是先在一个干净虚拟环境里装好用pip freeze导出精确版本再按这个清单下载。千万别用pip download不带版本约束下下来的东西装的时候能让你怀疑人生。# 在联网机器上用干净虚拟环境导出精确依赖 python -m venv clean_env source clean_env/bin/activate pip install -r requirements.txt pip freeze locked_requirements.txt # 按锁定版本下载所有包 pip download -r locked_requirements.txt -d ./offline_packages \ --platform manylinux2014_x86_64 \ --python-version 310 \ --only-binary:all:注意--only-binary:all:能强制只下 wheel避免下到源码包在内网编译时缺编译器。但有些包没有 wheel这时候就得单独处理提前在内网装好编译工具链。3.2 本地模型的部署与量化选择如果内网要自己部署模型显存是硬约束。我整理了一个经验对照表基于常见的开源模型模型规模量化方式显存占用适用场景7BFP16约 14GB简单问答、分类7BINT8约 8GB通用对话7BINT4约 5GB资源紧张场景32BINT4约 20GB复杂推理、代码70BINT4约 40GB高复杂度任务选型逻辑很简单先看任务复杂度再看显存。如果 Agent 主要做工具调用和简单决策7B INT4 完全够用别浪费显存。如果要做复杂代码生成或多步推理32B 起步。部署工具我推荐用 vLLM 或 Ollama。vLLM 吞吐高、支持并发适合做服务Ollama 部署简单适合快速验证。内网里 vLLM 的依赖比较重装之前先把 CUDA 版本对齐不然编译能卡你一整天。3.3 模型服务的接口封装内网模型部署好之后一定要封一层统一的 OpenAI 兼容接口。为什么因为 Agent 框架基本都支持 OpenAI 格式的 API你封成这个格式框架就能直接对接不用改代码。vLLM 自带这个能力Ollama 也有兼容层自己部署的话用 FastAPI 写一个转发层也就几十行。# 简单的模型服务封装示例 from fastapi import FastAPI from pydantic import BaseModel import httpx app FastAPI() class ChatRequest(BaseModel): model: str messages: list temperature: float 0.7 app.post(/v1/chat/completions) async def chat(req: ChatRequest): async with httpx.AsyncClient() as client: resp await client.post( http://localhost:8000/generate, json{prompt: req.messages[-1][content]}, timeout60.0 ) return {choices: [{message: {content: resp.json()[text]}}]}这层封装还有个好处统一做限流和日志。内网模型资源有限不加限流很容易被并发打爆。4. MCP 工具链在内网的部署与打通4.1 MCP Server 的两种传输模式选择MCP 支持 stdio 和 HTTP/SSE 两种传输。内网里怎么选取决于你的部署形态。stdio 模式适合 Agent 和工具在同一台机器上的场景。Agent 进程直接拉起 MCP Server 子进程通过标准输入输出通信。优点是零网络配置、延迟极低、天然隔离缺点是工具和 Agent 绑死没法跨机复用。HTTP/SSE 模式适合工具独立部署、多 Agent 共享的场景。MCP Server 起一个 HTTP 服务Agent 通过网络调用。优点是解耦、可复用、好扩展缺点是要处理网络和鉴权。我的建议是开发验证阶段用 stdio生产环境用 HTTP。内网里 HTTP 模式还能配合内网的服务发现和负载均衡工具服务挂了也不影响 Agent 主进程。4.2 内网 MCP 工具服务的开发要点写一个内网 MCP Server核心是把内部能力暴露成标准工具。以数据库查询工具为例关键点有三个第一参数校验要严。内网工具往往直接操作生产数据参数不校验就是灾难。SQL 注入、越权访问这些在 Agent 场景里更容易发生因为调用方是模型它可能生成任何东西。第二返回结果要裁剪。模型上下文有限你返回一个几万行的查询结果直接把上下文撑爆。我的做法是默认限制返回条数超过就截断并提示需要全量的话让 Agent 显式请求。第三错误信息要友好。模型看不懂堆栈你要把异常转成自然语言描述它才能决定下一步怎么做。# MCP 工具定义示例伪代码结构 mcp_tool(namequery_database, description执行只读SQL查询) def query_database(sql: str, limit: int 100): # 1. 校验只允许 SELECT if not sql.strip().upper().startswith(SELECT): return {error: 仅支持只读查询} # 2. 校验禁止危险关键字 forbidden [DROP, DELETE, UPDATE, INSERT, ALTER] if any(kw in sql.upper() for kw in forbidden): return {error: 包含禁止操作} # 3. 执行并限制返回 result db.execute(sql, limitlimit) return {rows: result, truncated: len(result) limit}4.3 工具注册与发现机制内网里工具多了之后怎么让 Agent 知道有哪些工具可用我一般维护一个工具注册表MCP Server 启动时向注册中心上报自己的能力清单Agent 启动时拉取清单并生成工具描述注入到提示词里。这个注册表可以很简单一个内网可访问的 JSON 文件或者一个轻量服务就行。关键是工具描述要写清楚因为模型是根据描述来决定调不调、怎么调的。描述写得好Agent 的工具调用准确率能提升一大截。实操心得工具描述里一定要包含“什么时候用”和“什么时候不用”。我见过太多工具因为描述模糊模型在不该调的时候乱调白白浪费 token 和时间。5. Skills 体系的设计、编排与内网分发5.1 Skill 的粒度设计别太大也别太小Skill 粒度是个经验活。太粗一个 Skill 干十件事复用性差太细一个 Skill 就调一个工具那还不如直接用 MCP。我的经验法则是一个 Skill 对应一个完整的业务动作。比如“生成周报”是一个 Skill它内部可能调用查数据库、查日志、调模型总结三个工具但对使用者来说就是一个动作。再比如“代码审查”是一个 Skill内部包含读文件、静态分析、模型评审、生成报告。判断粒度是否合适有个简单标准如果这个 Skill 的描述能用一句话说清“它帮你完成什么”粒度就对了。5.2 Skill 的组成结构一个完整的 Skill 我一般拆成四部分元信息名称、描述、适用场景、输入输出定义提示词模板指导模型如何完成这个任务工具编排需要调用哪些 MCP 工具调用顺序和条件后处理逻辑结果格式化、校验、异常处理这四部分里提示词模板是灵魂。同样的工具提示词写得好坏效果差好几倍。我写提示词的经验是把模型当成一个聪明但没背景知识的新人该交代的背景、该给的示例、该说的边界一样都不能少。5.3 内网 Skill 库的分发方案内网分发 Skill 有个天然优势Skill 基本都是文本体积小用 Git 内网仓库就能管。我的做法是建一个内网 Git 仓库专门放 Skill每个 Skill 一个目录包含配置文件、提示词、测试用例。Agent 启动时从仓库拉取 Skill 清单按需加载。更新 Skill 只需要 push 到仓库Agent 下次启动就能拿到新版。如果要做热更新可以加一个版本检查机制定期拉取。# Skill 配置示例 name: weekly_report description: 根据数据库和日志生成周报 version: 1.2.0 inputs: - name: week type: string description: 周次如 2026-W20 tools: - query_database - query_logs - summarize_text prompt_template: | 你是一个周报生成助手。根据以下数据生成结构化周报 数据库指标{db_metrics} 日志摘要{log_summary} 要求分点陈述突出异常和趋势。注意Skill 版本管理很重要。生产环境一定要锁定版本别让 Agent 自动拉最新不然某天 Skill 一改线上行为全变了排查起来要命。5.4 Skill 与 MCP 的协作关系很多人把 Skill 和 MCP 混为一谈其实它们是互补的。MCP 是“能力接口”Skill 是“能力用法”。一个 MCP 工具可以被多个 Skill 复用一个 Skill 也可以调用多个 MCP 工具。在内网里我通常让 MCP 层保持稳定尽量少改Skill 层保持灵活快速迭代。这样底层工具不动上层能力可以随业务快速调整工程上最稳。6. 并发调度与工程化落地6.1 Agent 并发模型的选择“AI Agent 怎么扛并发”是个高频问题。内网里并发压力通常来自两方面一是多用户同时用二是单个任务内部并行调多个工具。对于多用户并发核心是模型推理的并发能力。vLLM 这类框架支持连续批处理能显著提升吞吐。如果用的是单实例 Ollama并发能力很有限得靠排队或者多实例。对于任务内并行用异步 IO 就能解决。Agent 调多个工具时用asyncio.gather并发发起等所有结果回来再汇总。这样比串行调用快好几倍。import asyncio async def run_agent_task(task): # 并行调用多个工具 results await asyncio.gather( call_tool(query_database, task.sql), call_tool(query_logs, task.time_range), call_tool(search_docs, task.keyword), return_exceptionsTrue ) # 处理结果异常降级 valid [r for r in results if not isinstance(r, Exception)] return await summarize(valid)6.2 限流、降级与超时控制内网资源有限不限流就是等着雪崩。我的做法是在模型服务和工具服务前面都加一层限流用令牌桶或者信号量控制并发数。降级策略也要提前设计。模型服务挂了怎么办工具超时怎么办我的经验是核心路径必须有降级方案。比如模型不可用时返回缓存结果或者提示用户稍后重试工具超时时返回部分结果并标注哪些没拿到。超时控制尤其重要。Agent 调工具如果不设超时一个慢查询能把整个任务卡死。我一般给每个工具设 10 到 30 秒超时模型推理设 60 到 120 秒整体任务设一个总超时。6.3 日志、追踪与可观测性内网 Agent 出问题最难排查因为你看不到外部调用全靠日志。我的做法是给每个任务生成一个 trace_id从用户请求到模型调用到工具执行全链路打日志用 trace_id 串起来。日志内容要包含输入、输出、耗时、调用了哪些工具、每个工具的返回摘要、异常信息。这样出问题时拿 trace_id 一搜整个执行链路清清楚楚。实操心得日志里千万别打完整的大模型输入输出体积太大。我一般只打摘要和哈希需要详情时再按需开启 debug 模式。6.4 内网 Agent 中台的演进路径如果你要做的不只是一个 Agent而是一个中台那要考虑的更多。我的演进路径建议是第一阶段单 Agent 跑通验证核心链路。第二阶段抽离工具层和 Skill 层形成可复用资产。第三阶段加多 Agent 协作和任务调度。第四阶段做统一入口、权限、监控、计费。每一步都别跳。我见过太多项目一上来就做中台结果基础链路都没跑通最后烂尾。先把一个场景做深做透再谈平台化。7. 常见问题与排查技巧实录7.1 内网部署高频问题速查表问题现象可能原因排查方向解决方案依赖装不上平台不匹配/缺编译工具检查 wheel 标签同平台下载或装工具链模型加载 OOM显存不足/量化不当看显存占用换更小量化或更小模型MCP 工具调不通传输模式配置错检查 stdio/HTTP 配置对齐 Agent 和 Server 配置Agent 不调工具工具描述不清看提示词里的工具描述补充使用场景说明并发上不去模型单实例瓶颈压测模型服务多实例或换 vLLM任务卡死工具无超时检查超时配置给每个工具设超时结果不稳定提示词太随意看 Skill 提示词加示例和边界约束7.2 几个我踩过的深坑坑一stdio 模式下 MCP Server 日志污染通信。stdio 模式靠标准输出传数据如果你的 Server 往 stdout 打日志协议直接乱掉。解决办法是日志全部走 stderr或者写文件。坑二模型上下文被工具返回撑爆。一个查询返回几千行模型直接懵了。解决办法是工具层强制限制返回大小超出的部分做摘要或者分页。坑三Skill 版本漂移导致线上行为突变。某次更新了一个 Skill 的提示词结果线上 Agent 行为全变了。解决办法是生产环境锁定 Skill 版本更新走灰度。坑四并发下模型输出串台。多请求共用一个模型实例时如果没做好请求隔离输出可能串。解决办法是用支持并发的推理框架别自己写简陋的并发封装。7.3 性能调优的几个实用技巧模型层面开启连续批处理能显著提升吞吐vLLM 默认就开。调整 max_tokens也能省不少时间很多任务不需要生成那么长。工具层面缓存高频查询结果。内网数据变化通常不快缓存几分钟能省大量重复查询。合并小请求多个小工具调用能合并就合并减少往返开销。编排层面能并行就并行。前面说的asyncio.gather是基本操作。提前终止也很重要如果某个工具返回了决定性结果后面的工具就不用调了。8. 一些关于内网 Agent 的个人体会做内网 Agent 工程这几年我最大的体会是别被新概念带着跑先把基础链路跑通。MCP、Skills 这些概念很好但它们是手段不是目的。目的是让 Agent 在内网里真正能干活。另一个体会是工具描述和提示词的质量决定了 Agent 的上限。模型能力再强你工具描述写得含糊它也调不对。我花在打磨提示词和工具描述上的时间比写代码还多。还有一点内网环境反而逼着你把工程做扎实。公网环境下很多问题可以用现成服务绕过内网里绕不过去只能自己解决。这个过程虽然痛苦但做出来的东西更可控、更稳定。最后分享一个小技巧内网 Agent 上线前一定要做离线评测集。准备一批典型任务和预期结果每次改动后跑一遍看准确率和耗时变化。没有评测集你根本不知道改动是变好还是变坏。这个习惯帮我避免了好几次线上事故。