ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

隔离内网AI Agent工程化落地:MCP工具调用与审批机制实践

隔离内网AI Agent工程化落地:MCP工具调用与审批机制实践 1. 项目缘起与整体设计思路1.1 为什么要在隔离内网里折腾 AI Agent先说清楚这个项目的背景。我所在的团队负责一套内部业务系统的智能化改造这套系统跑在完全隔离的内网环境里——没有外网出口没有公网依赖所有软件包、模型文件、依赖库都得靠离线方式导入。在这种环境下搞 AI Agent跟在公网上随手调个 API 完全是两码事。公网环境下搭 Agent你随便 pip install 一个框架调一下云端大模型接口半小时就能跑通一个 demo。但隔离内网里这条路直接堵死模型得本地部署工具链得离线打包连 MCP Server 的依赖都得提前把 wheel 包下好再拷进去。更麻烦的是内网系统往往涉及审批流程、权限管控、数据不出域这些硬约束Agent 不能像公网那样先跑起来再说每一步都得考虑合规和可审计。这个项目要解决的核心问题就三个第一让 AI Agent 在内网里能真正跑起来不是玩具 demo是能对接真实业务系统的工程化落地第二通过 MCP Tools 和 Skills 机制让 Agent 具备调用内网系统能力的手段同时保证调用过程可控可追溯第三设计一套审批机制让 Agent 的关键操作必须经过人工确认避免自动化带来的风险失控。适合谁来参考这份经验如果你正在做企业内部 AI 应用落地尤其是金融、政务、军工、大型制造业这类对数据隔离有硬性要求的场景这篇内容应该能帮你少踩不少坑。如果你只是想在公网环境玩 Agent那这篇的很多约束对你可能过于严苛但里面关于 MCP 协议设计、Skills 组织方式、审批流实现的思路依然有参考价值。1.2 整体架构选型为什么是这套组合架构设计上我最终确定的方案是本地大模型推理 MCP 协议做工具调用层 Skills 做能力封装 审批网关做操作拦截。这套组合不是拍脑袋定的每一层都有明确的取舍理由。先说模型层。内网环境没法调云端 API只能本地部署。我试过几种方案直接用 Ollama 跑量化模型用 vLLM 做推理服务还有用 llama.cpp 做轻量部署。最后选的是 vLLM 量化模型的路子原因是内网服务器有 GPU 资源vLLM 的吞吐和并发处理能力明显优于 Ollama而且支持 OpenAI 兼容的 API 格式这样上层 Agent 框架的适配成本最低。模型选的是 7B 到 14B 级别的指令微调模型再大的模型内网 GPU 扛不住再小的模型工具调用能力太差7B 到 14B 是效果和资源的平衡点。工具调用层选 MCP 协议这是整个项目最关键的技术决策。MCP 全称 Model Context Protocol本质是一套标准化的模型怎么调用外部工具的协议。为什么不用传统的 Function Calling 自己手写因为 MCP 把工具发现、参数描述、调用结果返回这套流程标准化了Agent 框架和工具实现解耦后续加新工具只需要注册一个新的 MCP Server不用改 Agent 核心代码。在内网环境里这种解耦特别重要——业务系统经常变工具接口跟着变如果每次都要改 Agent 主逻辑维护成本会爆炸。Skills 这一层是我自己加的封装。MCP 解决的是工具怎么被调用但没解决什么场景下该调用哪些工具、按什么顺序调用。Skills 就是把一组相关的 MCP 工具调用、提示词模板、后处理逻辑打包成一个可复用的能力单元。比如查询员工考勤并生成报表这个 Skill内部可能调用了三个 MCP 工具加上一段固定的提示词和结果格式化逻辑。这样 Agent 面对复杂任务时不用从零开始规划工具调用链直接匹配已有 Skill 就行。审批网关是最后一道闸。所有涉及写操作、敏感数据读取、跨系统调用的 Agent 动作都必须经过审批网关。网关的实现思路是Agent 发起操作请求 → 网关拦截 → 根据预设规则判断是否需要人工审批 → 需要则推送到审批界面等待确认 → 确认后放行执行。这套机制保证了 Agent 再智能也不能绕过人的最终控制权。1.3 内网环境下的特殊约束与应对隔离内网带来的约束比想象中多。我列几个最要命的依赖离线化。所有 Python 包、模型文件、MCP Server 的可执行文件都得提前在外网环境打包好通过合规的摆渡方式导入内网。这里有个坑很多包在安装时会动态下载依赖内网直接装会失败。我的做法是用pip download把所有依赖下全包括间接依赖然后在内网用pip install --no-index --find-links离线安装。模型文件同理提前下好权重内网直接加载本地路径。网络隔离导致的调试困难。公网环境调试 Agent日志、追踪、可视化工具一大堆。内网里这些工具往往连不上只能靠本地日志文件和命令行输出。我的应对是在 Agent 框架里内置详细的本地日志模块每个工具调用、每次模型推理、每个审批决策都落盘到本地文件调试时直接看日志。另外准备了一套离线版的追踪工具把调用链数据导出成 HTML 文件在内网浏览器里打开查看。安全审计要求。内网系统通常有严格的审计要求Agent 的每个操作都得留痕。MCP 协议本身支持调用日志但不够细。我在 MCP Server 层加了一层审计中间件记录调用时间、调用方、参数、返回值、审批状态统一写入审计数据库。这样出了问题能追溯到具体哪次调用、哪个审批环节。版本管理复杂。内网没法用公网的包管理服务所有依赖版本得手动维护。我建了一个内网的私有包仓库用简单的文件服务器加索引文件实现所有离线包统一管理Agent 部署时从私有仓库拉取。这样版本一致性有保障不会出现这台机器能跑那台跑不了的问题。2. 核心细节解析与实操要点2.1 MCP Tools 的设计与内网适配MCP Tools 是整个 Agent 能力的基石。在内网环境里设计 MCP Tools跟公网有几个关键差异。第一个差异是工具发现机制。公网 MCP 通常支持动态发现Agent 启动时自动扫描可用的 MCP Server。内网环境里我改成静态注册加白名单机制。所有可用的 MCP Server 在配置文件里显式声明Agent 启动时只加载白名单里的 Server。这样做的好处是安全可控——不会出现某个未授权的工具被意外调用。配置文件大概长这样mcp_servers: - name: hr_system command: /opt/mcp/hr_server args: [--config, /etc/mcp/hr_config.json] allowed_tools: - query_employee - query_attendance - submit_leave_request - name: finance_system command: /opt/mcp/finance_server args: [--config, /etc/mcp/finance_config.json] allowed_tools: - query_budget - submit_expense第二个差异是参数校验的严格程度。公网环境里工具参数校验可以宽松一点出错了重试就行。内网环境里一次错误的写操作可能造成真实业务数据污染所以参数校验必须前置且严格。我在每个 MCP Tool 的实现里都加了参数 schema 校验类型不对、范围超限、格式不符的直接拒绝不进入业务逻辑。比如提交请假申请的工具日期格式必须是YYYY-MM-DD请假天数必须是正整数且不超过 30申请人 ID 必须在员工表里存在这些校验在工具入口就做完。第三个差异是超时和重试策略。内网系统响应速度参差不齐有些老系统查询一次要好几秒。MCP Tool 的超时设置不能太短但也不能无限等。我的经验值是查询类工具超时设 30 秒写操作类工具超时设 60 秒重试次数统一设为 0——内网环境里重试写操作风险太大宁可失败让 Agent 重新规划也不要自动重试造成重复提交。注意MCP Tool 的命名要遵循动词_名词的格式比如query_employee、submit_leave_request。这样 Agent 在规划工具调用时能通过名字快速理解工具用途减少误调用。我试过用纯名词命名Agent 经常搞混查询和提交操作。2.2 Skills 的组织方式与复用策略Skills 是我在这个项目里花心思最多的地方。MCP Tools 是原子能力Skills 是组合能力。一个好的 Skills 设计能让 Agent 处理复杂任务的成功率大幅提升。Skills 的组织我参考了软件工程里高内聚低耦合的原则。每个 Skill 是一个独立的目录包含四个部分manifest.yaml描述文件、prompt.md提示词模板、workflow.yaml工具调用流程、postprocess.py后处理脚本。目录结构大概是这样skills/ attendance_report/ manifest.yaml prompt.md workflow.yaml postprocess.py leave_approval/ manifest.yaml prompt.md workflow.yaml postprocess.pymanifest.yaml定义 Skill 的元信息名称、描述、触发关键词、依赖的 MCP Tools、输入输出 schema。这个文件是 Agent 匹配 Skill 的依据。我特别强调触发关键词的设计——不能太宽泛否则 Agent 会误匹配也不能太窄否则该匹配的时候匹配不上。比如生成考勤报表这个 Skill触发关键词设成[考勤, 报表, 出勤统计, 打卡记录]覆盖了常见的表达方式。workflow.yaml定义工具调用的流程。这里我用的是简单的顺序加条件分支没有上复杂的 DAG。原因是内网环境里Agent 的规划能力受模型能力限制太复杂的流程它执行不了。顺序加条件分支已经能覆盖 80% 的场景。一个典型的 workflow 长这样steps: - name: get_employee_list tool: hr_system.query_employee params: department: {{input.department}} output: employees - name: get_attendance tool: hr_system.query_attendance params: employee_ids: {{employees.ids}} month: {{input.month}} output: attendance_data - name: format_report action: postprocess script: postprocess.py input: attendance_data output: final_reportpostprocess.py做结果的后处理。模型直接输出的结果往往格式不规范需要脚本做清洗、格式化、校验。比如考勤报表模型可能输出一堆自然语言描述后处理脚本把它转成结构化的表格数据再生成 Excel 文件。Skills 的复用策略上我坚持一个 Skill 只做一件事。刚开始我试图做一个HR 全能助手的大 Skill结果提示词太长、流程太复杂Agent 执行成功率很低。后来拆成考勤报表请假申请员工查询三个独立 Skill每个都简单清晰成功率立马上来了。这跟写代码是一个道理函数要小职责要单一。2.3 审批机制的设计与实现细节审批机制是内网 Agent 落地的安全底线。设计这套机制时我遵循一个原则Agent 可以自主决策但关键动作必须有人确认。什么算关键动作我定义了三类第一类是写操作包括提交申请、修改数据、发送通知第二类是敏感数据读取包括薪资、绩效、个人信息第三类是跨系统调用比如从 HR 系统读数据写到财务系统。这三类动作Agent 发起后都会触发审批流程。审批机制的实现分四层规则层。定义哪些工具调用需要审批。规则配置在 YAML 文件里支持按工具名、按参数、按调用方匹配。比如approval_rules: - tool: hr_system.submit_leave_request require_approval: true approvers: [hr_manager] - tool: finance_system.query_budget require_approval: false - tool: finance_system.submit_expense require_approval: true approvers: [finance_manager, dept_head] condition: amount 5000拦截层。Agent 发起工具调用时先经过审批网关。网关根据规则判断是否需要审批。不需要的直接放行需要的挂起请求生成审批单。审批层。审批单推送到审批界面审批人看到的是Agent 的原始意图、要调用的工具、参数详情、预期影响。审批人可以批准、拒绝、或者修改参数后批准。这里有个细节审批界面必须展示 Agent 的推理过程也就是它为什么发起这个调用。这样审批人才能判断这个操作是否合理。执行层。审批通过后网关放行调用执行结果返回给 Agent。审批拒绝的话Agent 收到拒绝原因重新规划。所有审批记录写入审计日志。实操心得审批超时怎么处理我设的是 30 分钟超时超时后自动拒绝Agent 收到审批超时的反馈。不要设自动批准内网环境里自动批准等于没有审批。另外审批人不在线的情况很常见我加了一个代理审批机制主审批人超时未处理自动转给备用审批人。2.4 内网部署的依赖管理与离线打包内网部署最烦的就是依赖管理。我踩过的坑包括pip 装包时偷偷下载依赖失败、模型文件路径不对、MCP Server 缺少系统库、Python 版本不匹配。这些坑踩多了总结出一套离线打包的标准流程。第一步在外网环境准备一个干净的虚拟环境Python 版本跟内网目标机器保持一致。用pip download下载所有依赖pip download -r requirements.txt -d ./offline_packages --platform manylinux2014_x86_64 --python-version 310 --only-binary:all:这里--platform和--python-version必须跟内网机器匹配否则下载的 wheel 包装不上。如果有些包没有预编译 wheel得用--no-binary下载源码包在内网编译但内网编译又需要编译工具链很麻烦。我的经验是尽量找有 wheel 的版本实在没有再考虑源码编译。第二步模型文件单独打包。模型权重文件通常几个 GB 到几十 GB用tar分卷压缩摆渡到内网后合并解压。模型加载路径在配置文件里写绝对路径不要用相对路径避免工作目录变化导致加载失败。第三步MCP Server 的可执行文件打包。如果 MCP Server 是 Python 写的用 PyInstaller 打包成单文件可执行程序这样内网不需要 Python 环境也能跑。如果是 Go 或 Rust 写的直接编译成静态链接的二进制文件。我试过用 Rust 写 MCP Server编译出来的二进制文件只有几 MB依赖全静态链接内网部署特别省心。第四步写一个部署脚本在内网一键完成环境检查、依赖安装、配置生成、服务启动。脚本里加上详细的日志输出哪一步失败了一眼能看出来。3. 实操过程与核心环节实现3.1 本地模型服务的搭建与调优本地模型服务是整个 Agent 的大脑搭不好后面全白搭。我用 vLLM 做推理服务部署流程如下。首先确认内网服务器的 GPU 资源。我这边是两张 24G 显存的卡跑 14B 的量化模型INT4 量化刚好显存占用大概 18G留了余量给并发请求。如果显存更小就得降到 7B 模型或者用更激进的量化INT8 转 INT4。vLLM 的启动命令python -m vllm.entrypoints.openai.api_server \ --model /opt/models/qwen-14b-int4 \ --served-model-name local-agent-model \ --host 0.0.0.0 \ --port 8000 \ --max-model-len 8192 \ --gpu-memory-utilization 0.85 \ --tensor-parallel-size 2参数说明--max-model-len设 8192因为 Agent 的提示词加工具描述加对话历史很容易超过 4096设太小会截断。--gpu-memory-utilization设 0.85留 15% 给系统和其他进程设太高容易 OOM。--tensor-parallel-size设 2两张卡并行推理吞吐能翻倍。模型选型上我对比过几个开源模型。7B 级别的模型工具调用能力普遍偏弱经常把工具名搞错或者参数格式不对。14B 级别的模型明显好很多工具调用的准确率能到 85% 以上。再大的模型内网 GPU 扛不住而且推理速度太慢Agent 响应时间会很长。所以 14B 是当前硬件条件下的最优解。调优方面我调过几个关键参数。temperature设 0.1Agent 场景不需要创造性要的是稳定和准确。top_p设 0.9max_tokens设 2048够 Agent 输出工具调用请求和简短推理过程。另外开了--enable-prefix-caching因为 Agent 的提示词前缀系统提示加工具描述是固定的前缀缓存能显著降低重复计算提升响应速度。注意模型服务启动后一定要用curl测一下 OpenAI 兼容接口是否正常。我遇到过 vLLM 启动成功但接口返回格式不对的情况原因是模型 chat template 配置有问题。测试命令curl http://localhost:8000/v1/chat/completions -H Content-Type: application/json -d {model:local-agent-model,messages:[{role:user,content:你好}]}。3.2 MCP Server 的开发与注册流程MCP Server 是 Agent 调用内网系统的桥梁。我以 HR 系统的 MCP Server 为例讲一下开发流程。MCP Server 的核心是定义工具。每个工具包括名称、描述、参数 schema、执行函数。我用 Python 的mcp库来开发代码结构大概是这样from mcp.server import Server from mcp.types import Tool, TextContent import json server Server(hr_system) server.list_tools() async def list_tools(): return [ Tool( namequery_employee, description根据部门或员工ID查询员工基本信息, inputSchema{ type: object, properties: { department: {type: string, description: 部门名称}, employee_id: {type: string, description: 员工ID} } } ), Tool( namesubmit_leave_request, description提交请假申请, inputSchema{ type: object, properties: { employee_id: {type: string}, start_date: {type: string, format: date}, end_date: {type: string, format: date}, reason: {type: string} }, required: [employee_id, start_date, end_date] } ) ] server.call_tool() async def call_tool(name: str, arguments: dict): if name query_employee: result query_employee_from_db(arguments) return [TextContent(typetext, textjson.dumps(result, ensure_asciiFalse))] elif name submit_leave_request: result submit_leave_to_hr(arguments) return [TextContent(typetext, textjson.dumps(result, ensure_asciiFalse))]工具描述description的写法很关键。Agent 靠这个描述来判断什么时候该调用这个工具。描述要写清楚这个工具做什么、什么场景下用、参数是什么意思。我试过写得太简略Agent 经常该调用的时候不调用或者调用了不该调用的工具。后来把描述写详细加上使用场景说明准确率明显提升。MCP Server 开发完后注册到 Agent 框架的配置文件里。注册信息包括Server 名称、启动命令、参数、允许的工具列表。Agent 启动时会拉起所有注册的 MCP Server通过 stdio 或 SSE 跟它们通信。内网环境里我推荐用 stdio 通信方式比 SSE 简单可靠不需要额外开端口。MCP Server 作为子进程被 Agent 拉起通过标准输入输出交换 JSON-RPC 消息。这种方式在内网里特别合适没有网络配置的麻烦。3.3 Skills 的编写与调试实录写 Skill 是个迭代过程第一版往往不好用得反复调。我以考勤报表Skill 为例讲一下编写和调试的过程。第一版 Skill 的提示词写得很简单根据用户提供的部门和月份查询考勤数据并生成报表。 结果 Agent 执行时经常漏掉步骤比如只查了员工列表没查考勤或者查了考勤没生成报表。原因是提示词没有明确告诉 Agent 要按什么顺序执行。第二版提示词改成了分步骤的指令你是一个考勤报表生成助手。请按以下步骤执行 1. 调用 query_employee 工具根据用户提供的部门查询员工列表。 2. 从员工列表中提取所有员工ID。 3. 调用 query_attendance 工具传入员工ID列表和月份查询考勤数据。 4. 调用 postprocess 脚本将考勤数据格式化为报表。 5. 返回报表文件路径和摘要信息。 注意如果某一步失败停止执行并返回错误信息。这样改完后Agent 的执行成功率从 40% 提升到了 80%。但还是有 20% 的失败率主要原因是 Agent 在提取员工ID时出错有时候把员工姓名当成了ID。第三版在 workflow 里加了显式的数据传递steps: - name: get_employee_list tool: hr_system.query_employee params: department: {{input.department}} output: employees output_extract: $.data[*].employee_idoutput_extract用 JSONPath 从工具返回结果里提取员工ID列表不依赖模型自己解析。这样数据传递就可靠了成功率到了 95% 以上。调试 Skill 时我用的方法是把 Agent 的完整执行日志打出来看它在每一步的输入输出。日志里能看到 Agent 的推理过程、工具调用参数、工具返回结果、后处理脚本的输入输出。哪一步出问题一目了然。内网环境里没有可视化调试工具看日志是最靠谱的办法。实操心得Skill 的提示词里工具名要写准确跟 MCP Server 里注册的名称完全一致。我踩过坑提示词里写的是query_employees复数实际注册的是query_employee单数Agent 调用时找不到工具直接报错。这种低级错误排查起来很费时间写的时候仔细点。3.4 审批网关的部署与联调审批网关的部署分两部分网关服务本身和审批界面。网关服务我用 FastAPI 写核心逻辑是拦截 MCP 工具调用请求根据规则判断是否需要审批。需要审批的请求生成审批单写入数据库同时返回一个待审批状态给 Agent。Agent 收到这个状态后会暂停当前任务等待审批结果。审批界面用简单的 Web 页面实现从数据库读审批单展示给审批人。审批人操作后更新审批单状态网关轮询到状态变化放行或拒绝对应的工具调用。联调时遇到几个问题。第一个问题是 Agent 等待审批时的超时处理。Agent 框架默认的工具调用超时是 30 秒但审批可能要几分钟。我的解决方法是审批类工具调用单独设置超时设成 30 分钟跟审批超时保持一致。第二个问题是审批通过后Agent 怎么恢复执行。我的做法是网关在审批通过后把工具调用结果写入一个临时存储Agent 轮询这个存储获取结果。这种方式比回调简单内网环境里更可靠。审批规则的配置要支持热更新。业务规则经常变不能每次改规则都重启网关。我用的是配置文件加文件监听的方式配置文件变化时自动重新加载规则。这样运维人员改规则不用找开发直接改配置文件就行。4. 常见问题与排查技巧实录4.1 模型工具调用失败的排查思路模型工具调用失败是最常见的问题表现是 Agent 该调用工具时不调用或者调用了错误的工具或者参数格式不对。排查思路我总结成一张表问题表现可能原因排查方法解决方法该调用工具时不调用工具描述不清晰检查工具 description 是否说明了使用场景补充使用场景说明加示例调用了错误的工具工具名称或描述相似对比相似工具的 description差异化描述明确区分场景参数格式不对参数 schema 不明确检查 inputSchema 的格式定义补充 format、enum 等约束工具名拼写错误模型幻觉查看 Agent 日志中的调用请求在提示词里明确工具名列表调用参数缺失模型没理解必填项检查 required 字段在描述里强调必填参数我遇到最多的是工具描述不清晰导致的误调用。比如有两个工具一个叫query_employee查员工一个叫query_attendance查考勤描述都写得很简单Agent 经常搞混。后来把描述改成query_employee根据部门或员工ID查询员工的基本信息包括姓名、工号、部门、职位。适用于需要获取员工身份信息的场景。query_attendance根据员工ID和月份查询考勤记录包括打卡时间、出勤天数、请假记录。适用于需要统计考勤的场景。 这样改完后误调用率大幅下降。另一个常见问题是模型能力不足。7B 模型在工具调用上的表现确实不如 14B。如果硬件允许尽量上更大的模型。如果硬件受限可以通过 few-shot 示例来弥补——在提示词里给几个工具调用的正确示例模型会模仿这些示例的格式。4.2 内网依赖缺失的应急处理内网部署时依赖缺失是家常便饭。我遇到过的情况包括Python 包版本不匹配、系统库缺失、模型文件损坏、配置文件路径错误。应急处理的流程是第一步看错误日志。Python 的报错信息通常很明确缺哪个包、哪个版本日志里都有。系统库缺失的话报错信息可能是error while loading shared libraries: libxxx.so这种就得找对应的系统库包。第二步确认缺失的依赖能否从内网私有仓库获取。我建了一个内网文件服务器存放所有离线包。如果私有仓库里有直接安装。如果没有就得走摆渡流程从外网导入。第三步摆渡导入。摆渡流程有合规要求不能随便拷。我的做法是在外网环境把依赖打包生成校验和通过合规渠道提交摆渡申请审批通过后导入内网。导入后先校验文件完整性再安装。第四步验证。安装完后跑一个简单的测试脚本确认依赖能正常导入和使用。不要等到 Agent 跑起来才发现问题那样排查成本更高。注意内网环境里Python 包的依赖关系特别容易出问题。A 包依赖 B 包的 1.0 版本C 包依赖 B 包的 2.0 版本两个版本不兼容。我的经验是尽量用虚拟环境隔离每个 MCP Server 用独立的虚拟环境避免依赖冲突。另外requirements.txt 里锁定版本号不要用这种模糊版本内网环境里版本一致性比灵活性重要。4.3 审批流程卡顿的优化经验审批流程卡顿是影响 Agent 效率的主要因素。Agent 发起一个需要审批的操作如果审批人半天不处理整个任务就卡住了。我优化过几轮总结了几条经验。第一审批分级。不是所有操作都需要同等审批。我把审批分成三级普通操作如查询类自动通过重要操作如提交申请需要直属领导审批关键操作如大额支出需要多级审批。分级后大部分操作不需要人工介入审批压力大幅降低。第二审批人智能路由。根据操作类型和内容自动路由到对应的审批人。比如请假申请路由到 HR报销申请路由到财务。不要所有审批都推给同一个人那样那个人会成为瓶颈。第三审批超时自动升级。主审批人超时未处理自动升级到上级审批人。我设的是 15 分钟超时升级30 分钟超时自动拒绝。这样既给了审批人处理时间又不会无限等待。第四批量审批。对于同类型的多个审批请求支持批量处理。比如 Agent 一次性提交了 10 个员工的请假申请审批人可以一次性批准所有不用一个个点。优化后审批流程的平均处理时间从 20 分钟降到了 5 分钟以内Agent 的任务完成效率明显提升。4.4 并发场景下的稳定性问题Agent 扛并发是个容易被忽视的问题。单用户使用的时候一切正常多用户同时用的时候各种问题就出来了。第一个问题是模型服务的并发瓶颈。vLLM 虽然支持并发但并发数超过一定阈值后响应时间会急剧上升。我实测下来两张 24G 卡跑 14B 模型并发数超过 8 之后响应时间从 2 秒涨到 10 秒以上。解决方法是加请求队列超过并发上限的请求排队等待而不是直接打满模型服务。第二个问题是 MCP Server 的并发安全。多个 Agent 同时调用同一个 MCP Server如果 Server 内部有共享状态比如数据库连接、缓存可能出现竞态条件。我的做法是MCP Server 设计成无状态的每次调用独立处理不依赖共享状态。数据库连接用连接池每个请求独立获取连接。第三个问题是审批网关的并发处理。多个审批请求同时到达网关要能正确处理。我用的是异步处理加数据库事务保证审批单的创建和状态更新是原子的。另外加了限流防止恶意或异常的审批请求洪水。第四个问题是日志写入的并发。Agent 的日志量很大多用户并发时日志写入可能成为瓶颈。我用的是异步日志加缓冲日志先写内存缓冲再批量落盘。这样对主流程的影响最小。实操心得并发测试一定要做。我是在内网环境用 Locust 做压测模拟 20 个用户同时发起 Agent 任务。压测暴露了很多单用户测试发现不了的问题比如连接池耗尽、日志文件锁冲突、审批单 ID 重复。这些问题不压测根本发现不了上线后就是事故。5. 工具选型与版本管理5.1 核心工具链的选型对比这个项目涉及的工具链比较多我列一下选型对比和最终选择工具类别候选方案最终选择选择理由模型推理Ollama / vLLM / llama.cppvLLM并发能力强OpenAI 兼容接口社区活跃Agent 框架LangChain / 自研 / Spring AI自研轻量框架内网环境需要深度定制现成框架太重MCP 实现官方 Python SDK / 自研官方 Python SDK协议标准兼容性好减少自研成本审批网关FastAPI / Flask / DjangoFastAPI异步支持好性能高代码简洁日志logging / loguruloguru配置简单异步支持好格式灵活配置管理YAML / JSON / TOMLYAML可读性好支持注释适合人工编辑Agent 框架我最终选择自研这个决策值得展开说。LangChain 功能很全但在内网环境里太重了——依赖多、抽象层多、调试困难。我需要的是一个轻量的、可控的框架核心功能就是加载 MCP 工具、匹配 Skill、调用模型、处理审批。这些功能自己写也就几百行代码比用 LangChain 再改源码省事。Spring AI 也考虑过但内网环境里 Java 生态的依赖管理更麻烦放弃了。5.2 版本锁定与升级策略内网环境的版本管理我的原则是锁定版本谨慎升级。所有依赖的版本号都写死在配置文件里不用范围版本。升级要走完整的测试流程不能直接在生产环境升。版本锁定用requirements.txt加pip freeze实现。在外网环境装好所有依赖后pip freeze requirements_lock.txt内网按这个文件安装。这样保证内外网环境一致。升级策略上我分三级补丁版本升级如 1.0.1 到 1.0.2可以直接升风险低小版本升级如 1.0 到 1.1需要测试大版本升级如 1.x 到 2.x需要完整回归测试。升级前先在测试环境验证确认没问题再上生产。模型文件的版本管理也类似。每个模型文件记录版本号、量化方式、来源升级模型时保留旧版本方便回滚。我遇到过新模型效果不如旧模型的情况有旧版本在回滚很快。6. 实际落地中的经验与建议6.1 从 Demo 到生产的距离在内网环境里Agent 从 Demo 到生产距离比想象中远。Demo 阶段只需要跑通一个场景生产阶段要考虑稳定性、并发、安全、审计、运维。我踩过的坑包括Demo 里硬编码的配置在生产环境不适用、Demo 里没处理的异常在生产环境频繁出现、Demo 里没考虑的并发在生产环境导致数据错乱。我的建议是Demo 阶段就要按生产标准来设计至少把配置外置、异常处理、日志记录这三件事做好。配置外置让环境切换不用改代码异常处理让问题可追溯日志记录让排查有依据。这三件事做好了从 Demo 到生产的过渡会平滑很多。6.2 团队协作与知识沉淀内网 Agent 项目通常不是一个人能搞定的需要模型、后端、业务、运维多方协作。协作中的最大问题是信息不对称——做模型的不懂业务做业务的不懂模型能力边界。我的做法是建立一份共享的知识库记录模型能力边界、工具接口文档、Skill 使用说明、常见问题排查。知识库用 Markdown 写放在内网 Git 仓库里所有人可读可写。另外定期做技术分享让各方了解彼此的工作。知识沉淀上我特别强调踩坑记录。每个坑怎么踩的、怎么排查的、怎么解决的都记下来。这些记录比官方文档有价值得多因为它们是针对内网环境的真实经验。6.3 后续可扩展的方向这个项目目前跑通了核心流程后续还有不少可扩展的方向。一是增加更多 Skill覆盖更多业务场景。二是优化模型尝试用 LoRA 微调提升工具调用准确率。三是完善审批机制加入更细粒度的权限控制。四是做 Agent 的可观测性把调用链、性能指标、错误率可视化。内网环境里做这些扩展核心约束还是依赖导入和合规审批。每加一个新组件都要走一遍离线打包和摆渡流程。所以扩展的时候要克制不要什么都往上加保持架构简洁维护成本才可控。我个人在实际操作中的体会是内网 Agent 项目技术难度不是最大的最大的挑战是环境约束和合规要求。技术方案可以有很多选择但环境约束是硬性的必须在这个框架内找最优解。把约束理解清楚方案自然就出来了。另外审批机制虽然增加了操作步骤但它是内网 Agent 能落地的前提没有审批机制业务方根本不敢让 Agent 碰真实系统。这一点想通了设计审批流程的时候就不会觉得是负担而是把它当成产品的一部分来打磨。
返回列表