1. 内网环境给 AI Agent 工程带来的真实约束
很多人做 AI Agent 的第一反应是打开公网、拉个 API Key、跑个 LangChain Demo,半小时就能看到模型回复。但一旦场景切换到隔离内网——比如金融交易室、制造业产线控制网、政务专网、医院内网——这套打法会瞬间失效。我在过去两年里参与过三个完全物理隔离环境下的 Agent 落地项目,最深的体会是:内网不是"网速慢一点的公网",而是一套完全不同的工程约束体系。
先把这个约束体系讲清楚,否则后面所有的架构选择都是空中楼阁。
1.1 隔离内网到底"隔"掉了什么
物理隔离意味着目标网络与外部互联网之间没有任何路由可达。这不是防火墙策略层面的阻断,而是物理链路上就不通。由此带来的直接后果有三类:
- 模型权重必须离线交付。你没法调用任何云端推理服务,所有大模型必须以权重文件形式通过合规介质导入,再在内网自建推理服务。开源模型(Qwen、DeepSeek、Llama 系列等)是主流选择,参数量从 7B 到 72B 不等,取决于内网 GPU 资源。
- 依赖包无法在线安装。pip、npm、cargo、maven 全部不可用。所有 Python 包、Node 模块、Rust crate 都要提前在外部环境用相同操作系统和 Python 版本下载好 wheel 包或离线仓库,再整体搬进去。
- 外部工具调用全部失效。搜索、天气、地图、第三方 SaaS API 一律不可达。Agent 能调用的工具,只能是内网已有的系统接口。
这三条约束叠加起来,直接决定了内网 Agent 的工程形态和公网 Demo 完全是两回事。
1.2 为什么"照搬公网方案"必然翻车
我见过最典型的翻车案例,是一个团队把公网跑通的 LangChain + OpenAI 方案直接搬到内网,结果卡在三个地方:
第一,模型能力断崖式下降。公网用的是千亿参数级别的闭源模型,内网只能部署 32B 级别的开源模型,工具调用的准确率从 95% 掉到 70% 左右。原来靠模型"聪明"就能兜住的模糊指令,现在必须靠工程手段补。
第二,工具生态归零。公网 Agent 可以随手调用搜索、代码执行、网页抓取,内网里这些全没了。你得自己把内网系统的接口一个个封装成 Agent 能理解、能调用的工具。
第三,调试链路断裂。公网出问题可以看云端日志、可以临时改 prompt 重试,内网里每一次变更都要走审批、走介质导入,迭代周期从分钟级变成天级。
所以内网 Agent 工程的核心命题不是"怎么让模型更聪明",而是怎么在模型能力受限、工具受限、迭代受限的三重约束下,把系统做到稳定可用。这也是我后面所有章节要展开的主线。
1.3 内网 Agent 的能力边界该划在哪里
在动手之前,必须先回答一个问题:这个 Agent 到底要干什么?我的经验是,内网场景下要主动收缩能力边界,把 Agent 定位成"受控的流程编排器",而不是"自主决策的智能体"。
具体来说,适合内网 Agent 的任务类型包括:多步骤的信息查询与汇总、跨系统的数据搬运与格式转换、基于规则的审批流转、结构化的报告生成。不适合的任务包括:开放式创意生成、需要外部实时信息的判断、高风险的资金操作决策。
提示:能力边界划得越清楚,后面的工具设计、审批机制、测试用例就越有章可循。边界模糊是内网 Agent 项目最大的隐性风险。
2. 内网 Agent 的架构选型:为什么我最终选了 MCP + Skills 组合
架构选型是内网 Agent 项目里最容易走弯路的地方。我前后试过三种方案,最后稳定在 MCP(Model Context Protocol)加 Skills 的组合上。这一章把选型逻辑和踩坑过程完整讲一遍。
2.1 三种候选架构的横向对比
内网环境下,Agent 的工具接入方式主要有三种思路,我把它们的实际表现列成表格:
| 架构方案 | 工具接入方式 | 内网适配性 | 迭代成本 | 主要问题 |
|---|---|---|---|---|
| 硬编码函数调用 | 直接在代码里写 if-else 分发 | 高 | 极高 | 每加一个工具都要改代码、重新走审批 |
| 传统插件框架 | 自定义 JSON Schema 注册 | 中 | 中 | 各家框架协议不统一,迁移困难 |
| MCP + Skills | 标准化协议 + 技能包 | 高 | 低 | 需要前期搭建协议层 |
硬编码方案在工具数量少于 5 个时还能忍,一旦超过 10 个,代码会变成一团乱麻,而且每次新增工具都要重新走一遍内网部署审批,成本高到无法接受。传统插件框架的问题是协议碎片化,换个模型或换个框架就要重写一遍。
MCP 的价值在于它把"工具描述"和"工具实现"解耦了。工具以标准协议暴露自己的能力,Agent 侧只需要理解协议,不需要关心工具内部怎么实现。Skills 则是在 MCP 之上再抽象一层,把一组相关的工具、提示词、执行逻辑打包成一个可复用的技能单元。
2.2 MCP 在内网落地的关键改造点
标准 MCP 假设工具服务可以通过网络发现和连接,但内网里没有服务发现机制,也没有公网 registry。我做的改造主要有三处:
第一,工具注册表本地化。把 MCP Server 的清单文件(manifest)提前生成好,随部署包一起导入内网,Agent 启动时从本地文件加载,而不是去远程拉取。
第二,传输层收敛为 stdio 和本地 HTTP。内网里 SSE、WebSocket 这类长连接在部分网络设备上会被干扰,我最终统一用 stdio 做进程内通信,跨机器的工具服务用本地回环 HTTP,稳定性最好。
第三,工具描述精简。开源模型对长工具描述的理解能力有限,我把每个工具的描述压缩到 100 字以内,参数说明用最直白的语言,实测工具调用准确率能提升 15 个百分点左右。
{ "name": "query_employee_info", "description": "根据工号查询员工基本信息,返回姓名、部门、职级", "parameters": { "type": "object", "properties": { "employee_id": { "type": "string", "description": "员工工号,8位数字" } }, "required": ["employee_id"] } }这个描述看起来简单,但每个字都是反复打磨出来的。"8位数字"这种约束写进去之后,模型传错格式的概率明显下降。
2.3 Skills 分层设计:把复杂流程拆成可测试的单元
Skills 是我在内网项目里最看重的一层抽象。一个 Skill 本质上是一个"带提示词和工具集的子 Agent",它解决一个明确的子问题。比如"生成月度考勤报告"这个 Skill,内部会调用查询考勤数据、计算统计指标、套用报告模板三个工具,并附带一段固定的提示词约束输出格式。
分层设计的好处有三个:
- 可测试。每个 Skill 可以独立写测试用例,输入固定、输出可断言,不依赖整个 Agent 链路跑通。
- 可复用。考勤报告 Skill 里的"数据统计"子逻辑,可以被绩效报告 Skill 直接引用。
- 可审批。内网环境下,新增一个 Skill 的审批粒度比新增一个完整 Agent 小得多,合规部门更容易放行。
我通常把 Skills 分成三层:原子技能层(单个工具调用封装)、组合技能层(多个原子技能编排)、业务技能层(面向具体业务场景的完整流程)。这种分层让整个系统的复杂度可控。
2.4 模型选型:不是越大越好
内网部署模型,很多人第一反应是"上最大的"。但实际项目里,我更多时候选的是中等参数模型。原因很现实:内网 GPU 资源有限,72B 模型跑起来并发上不去,响应延迟高到用户无法接受。
我的选型经验是:先按任务复杂度分档,再按并发需求定参数量。简单工具调用和格式转换用 7B 到 14B 就够,复杂推理和多步规划用 32B 到 72B。实际部署时用路由层做分流,简单任务走小模型,复杂任务走大模型,整体吞吐能提升 2 到 3 倍。
3. 工具封装与审批机制:内网 Agent 的合规生命线
内网 Agent 和公网 Agent 最大的差异,不在技术,而在审批机制。公网 Agent 可以随便调工具,内网 Agent 每调用一个敏感工具,都可能触发合规审查。这一章讲工具封装和审批机制的设计。
3.1 工具分级:把"能调"和"该调"分开
我做的第一件事是把所有工具按风险等级分成三级:
| 风险等级 | 工具类型 | 审批要求 | 示例 |
|---|---|---|---|
| 低风险 | 只读查询 | 无需审批 | 查询员工信息、查询库存 |
| 中风险 | 数据写入 | 记录日志 | 更新工单状态、写入备注 |
| 高风险 | 敏感操作 | 强制人工审批 | 资金划转、权限变更、数据导出 |
分级之后,Agent 在执行高风险工具前必须暂停,把调用意图、参数、预期结果推送给审批人,审批通过才继续。这个机制在内网项目里是刚需,没有它,合规部门根本不会放行。
3.2 审批中断与恢复的实现细节
审批机制的技术难点在于"中断与恢复"。Agent 执行到高风险工具时,需要把当前状态完整保存下来,等审批结果回来后再恢复执行。我用的方案是把 Agent 的执行状态序列化成 JSON,存到内网的持久化存储里,审批通过后用同一个 session_id 恢复。
def execute_with_approval(agent_state, tool_call): if tool_call.risk_level == "high": approval_id = submit_for_approval(tool_call) save_state(agent_state, approval_id) return {"status": "pending", "approval_id": approval_id} else: return tool_call.execute()这里有个坑:状态序列化必须包含完整的对话历史,否则恢复后模型会"失忆",不知道之前聊了什么。我一开始只存了工具调用参数,恢复后模型完全接不上上下文,后来把 messages 数组一起存进去才解决。
3.3 审批超时与并发冲突的处理
内网审批是人工流程,可能几分钟,也可能几小时。我设了三级超时策略:5 分钟内未审批则提醒,30 分钟未审批则降级为"拒绝",2 小时未审批则自动关闭会话。
并发冲突是另一个坑。同一个用户可能同时发起多个 Agent 会话,如果两个会话都要操作同一条数据,就会出现冲突。我的做法是在工具层加乐观锁,操作前检查数据版本号,版本不一致就拒绝执行并提示用户重试。
注意:审批机制一定要在项目早期就设计进去,后期再补会牵动整个架构。我见过一个项目做到一半才想起要加审批,结果工具层、状态层、前端全部返工。
3.4 审计日志:不只是合规要求
审计日志在内网项目里不只是应付检查,它还是排查问题的核心依据。我设计的日志包含四个维度:谁(用户 ID)、什么时候(时间戳)、调了什么(工具名和参数)、结果如何(成功/失败/审批状态)。
日志格式用结构化 JSON,方便后续用 ELK 或类似方案做检索。实测下来,Agent 出问题时,80% 的情况能通过审计日志快速定位到是模型理解错了、工具返回异常、还是审批卡住了。
4. 内网 Agent 的并发扛压与性能调优
"AI Agent 怎么扛并发"是最近被问得最多的问题。内网场景下的并发挑战和公网不太一样:公网拼的是绝对吞吐,内网拼的是在有限资源下稳定支撑业务峰值。这一章讲我的实战调优经验。
4.1 内网并发的真实瓶颈在哪里
很多人以为瓶颈在模型推理,实测下来,内网 Agent 的瓶颈往往在三个地方,按出现频率排序:
- 模型推理排队。GPU 数量有限,多个请求同时到达时会在推理服务前排队。这是最直观的瓶颈。
- 工具调用串行化。内网系统接口往往不支持高并发,Agent 并发调用时会把后端系统打挂。
- 状态存储锁竞争。审批机制引入的状态持久化,在高并发下会出现锁竞争。
我遇到过一个案例:Agent 本身响应很快,但一上并发就超时,排查半天发现是后端工单系统的接口 QPS 上限只有 10,Agent 并发一高就把工单系统打挂了。
4.2 请求队列与优先级调度
解决模型推理排队,我用的方案是引入请求队列加优先级调度。把请求按业务重要性分成 P0、P1、P2 三档,P0 请求优先占用 GPU,P1 次之,P2 在空闲时执行。
import heapq import time class PriorityQueue: def __init__(self): self.queue = [] self.counter = 0 def push(self, priority, request): heapq.heappush(self.queue, (priority, self.counter, request)) self.counter += 1 def pop(self): if self.queue: return heapq.heappop(self.queue)[2] return None这个队列配合一个固定大小的线程池,就能把 GPU 利用率稳定在 80% 以上,同时保证高优先级请求的延迟可控。
4.3 工具调用的限流与熔断
针对后端系统被打挂的问题,我在工具层加了限流和熔断。每个工具配置独立的 QPS 上限,超过就排队或拒绝;连续失败达到阈值就熔断,一段时间内不再调用,避免雪崩。
| 工具类型 | QPS 上限 | 熔断阈值 | 恢复时间 |
|---|---|---|---|
| 查询类 | 50 | 连续 10 次失败 | 30 秒 |
| 写入类 | 10 | 连续 5 次失败 | 60 秒 |
| 敏感类 | 2 | 连续 3 次失败 | 120 秒 |
这套参数不是拍脑袋定的,是根据后端系统的实际承载能力反推出来的。定参数前一定要和后端系统的负责人对齐,否则限流值定高了照样打挂。
4.4 缓存策略:哪些能缓存,哪些绝对不能
内网 Agent 的缓存要非常谨慎。我的原则是:只读的、变化频率低的、非敏感的数据可以缓存,其余一律不缓存。
可以缓存的:组织架构、字典表、配置项。这些数据一天变不了几次,缓存能大幅降低后端压力。
绝对不能缓存的:员工个人信息、资金数据、实时库存。这些数据一旦缓存,轻则显示错误,重则造成合规问题。
缓存失效策略我用的是"主动失效 + 定时刷新"组合:数据变更时主动清缓存,同时每小时全量刷新一次兜底。
5. 内网部署与离线依赖管理的实操细节
内网部署是纯工程活,但坑特别多。这一章把离线依赖管理、模型权重导入、服务编排的实操细节讲透。
5.1 离线依赖包的完整打包流程
打包离线依赖,核心是"在外部环境模拟内网环境"。我的标准流程是:
- 在外部准备一台与内网目标机器操作系统版本、Python 版本、CPU 架构完全一致的机器。
- 用
pip download把所有依赖下载到本地目录,注意要带上--platform和--python-version参数。 - 用
pip install --no-index --find-links在内网机器上离线安装。 - 安装完成后跑一遍完整的 import 测试,确认没有遗漏。
# 外部环境下载依赖 pip download -r requirements.txt -d ./offline_packages \ --platform manylinux2014_x86_64 \ --python-version 310 \ --only-binary=:all: # 内网环境离线安装 pip install --no-index --find-links=./offline_packages -r requirements.txt这里最大的坑是二进制兼容性。有些包在外部机器上能装,搬到内网就报错,原因是 glibc 版本不一致。解决办法是尽量用 manylinux 标准的 wheel 包,避免源码编译。
5.2 模型权重导入与推理服务搭建
模型权重动辄几十 GB,导入内网要走合规介质。我的经验是提前把权重转成推理框架需要的格式(比如 GGUF 或 safetensors),减少内网里的转换步骤。
推理服务我用的是 vLLM 或类似的本地推理框架,配置要点有三个:
- 显存预留。不要把所有显存都分配给模型,留 10% 给 KV Cache 和系统开销。
- 批处理大小。根据显存和并发需求调
max_num_seqs,太大容易 OOM,太小吞吐上不去。 - 量化策略。显存紧张时用 INT8 或 INT4 量化,实测 INT8 量化对工具调用准确率影响很小,INT4 会有明显下降。
5.3 服务编排与健康检查
内网 Agent 通常由多个服务组成:推理服务、工具服务、Agent 编排服务、审批服务、前端。我用 docker-compose 做编排,每个服务配置健康检查,启动顺序用depends_on加condition: service_healthy控制。
健康检查不能只检查端口通不通,要检查服务是否真正可用。比如推理服务的健康检查要发一个真实的推理请求,确认能返回结果,而不是只看进程活着。
提示:内网环境没有镜像仓库,所有 Docker 镜像要提前
docker save成 tar 包导入。镜像里的基础镜像也要一并打包,否则内网拉不到。
5.4 灰度发布与回滚
内网发布不能一次全量,必须灰度。我的做法是保留两套服务实例,新版本先接 10% 流量,观察一段时间没问题再逐步放大。回滚就是把流量切回旧实例,秒级完成。
灰度期间重点观察三个指标:工具调用成功率、审批通过率、平均响应延迟。任何一个指标明显劣化就立即回滚。
6. 内网 Agent 的测试与效果验证
内网 Agent 的测试比公网难得多,因为没法用真实用户流量做 A/B 测试。这一章讲我用的测试方法。
6.1 构建内网专用的测试用例集
测试用例集是内网 Agent 项目的核心资产。我的做法是从真实业务场景出发,构造覆盖各类边界的用例:
- 正常路径:标准输入,期望标准输出。
- 边界输入:空值、超长文本、特殊字符。
- 歧义输入:模型可能理解错的模糊指令。
- 对抗输入:试图绕过审批机制的恶意指令。
每个用例都要有明确的期望结果,能自动断言。我通常维护 200 到 500 个用例,覆盖所有 Skill 和工具。
6.2 工具调用准确率的量化评估
工具调用准确率是内网 Agent 最关键的指标。我的评估方法是:给定一批测试输入,看 Agent 是否调用了正确的工具、传了正确的参数。
| 指标 | 定义 | 目标值 |
|---|---|---|
| 工具选择准确率 | 选对工具的比例 | > 90% |
| 参数填充准确率 | 参数完全正确的比例 | > 85% |
| 端到端成功率 | 完整任务成功的比例 | > 80% |
实测下来,32B 模型在优化过工具描述后,工具选择准确率能到 92% 左右,参数填充准确率 87% 左右。这个水平在内网场景下已经够用。
6.3 人工评审与持续迭代
自动化测试覆盖不了所有情况,尤其是输出质量这类主观指标。我每周会抽样 50 条真实会话做人工评审,重点看模型有没有"一本正经地胡说八道"。
评审发现的问题,分类处理:工具描述问题就改描述,提示词问题就改提示词,模型能力问题就考虑换更大模型或拆解任务。这个迭代循环是内网 Agent 效果持续提升的关键。
7. 我在内网 Agent 项目里踩过的几个深坑
最后分享几个具体的坑,都是真金白银换来的教训。
第一个坑:低估了模型对中文工具描述的理解偏差。早期我用英文写工具描述,模型调用准确率一直上不去。改成中文后,准确率提升了近 20 个百分点。内网场景下用户输入是中文,工具描述也用中文,模型的理解一致性最好。
第二个坑:审批状态和对话状态分离存储。一开始我把审批状态存在审批服务里,对话状态存在 Agent 服务里,结果恢复时两边对不上。后来统一存到一个状态服务里,用同一个 session_id 关联,问题才解决。
第三个坑:忽略了内网时钟同步。内网机器时钟可能不同步,导致审计日志时间戳错乱,排查问题时对不上。后来统一配置了内网 NTP 服务,所有机器时钟对齐。
第四个坑:工具返回结果太长撑爆上下文。内网系统接口经常返回大段 JSON,直接塞给模型会占满上下文窗口。我的做法是在工具层做结果裁剪,只返回模型需要的字段,长结果做摘要。
第五个坑:没有预留模型切换的抽象层。项目初期直接绑定了某个模型,后来要换模型时发现代码里到处是模型特定的调用。后来加了一层模型适配器,切换模型只需要改配置。
这些坑的共同点是:都不是技术难题,而是工程细节。内网 Agent 项目的成败,往往就取决于这些细节有没有提前想到。
8. 给准备做内网 Agent 的团队几条实在建议
如果你正准备启动一个内网 Agent 项目,我的建议是:
先把能力边界划清楚,别一上来就想做"全能助手"。选一个具体的、高频的、规则明确的场景切入,跑通闭环再扩展。
架构上优先考虑 MCP 加 Skills 的组合,前期多花一周搭协议层,后期能省几个月。审批机制一定要在架构设计阶段就纳入,别等合规部门找上门才补。
模型选型别迷信大参数,先按任务复杂度分档,用路由层做分流。工具描述用中文、写短、写具体,这是提升准确率性价比最高的手段。
测试用例集要当成核心资产来维护,它是内网环境下唯一可靠的回归验证手段。审计日志要做结构化,它既是合规要求,也是排查问题的命脉。
内网 Agent 工程没有公网那么多花哨的玩法,拼的是扎实的工程功底和对业务场景的深刻理解。把约束当成设计输入而不是障碍,反而能做出比公网方案更稳定、更可控的系统。