资讯中心

LLM/MCP/Skills统一网关实战:将工具与技能收进一个Agent入口

📅 2026/10/27 8:27:18
LLM/MCP/Skills统一网关实战:将工具与技能收进一个Agent入口
这几周我一直在折腾一个东西把 LLM、Tools、MCP、Skills 这四层能力收进同一个网关项目代号就叫 tsm-hub。起因很简单我手里同时有三四个模型 API、两套 MCP server、还有一堆写好的 AI Skills每次接新项目都要重新配一遍连接、鉴权、工具描述实在太烦了。这篇不聊概念堆砌只聊我实际怎么设计这个统一网关、怎么把 MCP 挂上去、怎么让 Skills 真正被模型用起来以及那些文档里没有但踩过才知道的坑。适合正在做 Agent 开发、或者想在团队里统一管理 AI 能力的同学参考。1. 项目背景LLM、Tools、MCP、Skills 为什么需要一张总装图1.1 LLM 侧的碎片化问题先说 LLM。今天的模型市场用一个词形容就是百家争鸣OpenAI 系、Anthropic 系、开源权重系、以及国内各家大厂的中小参数模型每隔一两个月就会冒出来一个号称干翻 GPT的新面孔。问题在于每个模型的 API 格式、上下文窗口、工具调用能力、定价策略都不一样。你在代码里写死一家后面想换模型或者做多云容灾就要把所有调用逻辑重写一遍。我之前在项目里见过最典型的场景某个功能用 Claude 的 function calling 调得好好的老板说换成本地私有化模型结果发现对方只实现了 Chat Completion根本不支持 tools 参数整个 Agent 逻辑直接瘫掉。这种问题不是单一代码能解决的它是接入层的问题——你需要一个统一的地方把模型差异抹平给上层业务一个稳定的工具调用接口这才是 tsm-hub 想解决的第一件事。1.2 Tools 和 MCP 的爆发式增长再说 Tools 和 MCP。2024 年底 Anthropic 开源 MCP 协议之后整个 Agent 生态像是被按下了快进键数据库、浏览器、设计稿、测试平台、甚至 PS 和 Blender 都有人做了 MCP server。市面上的 MCP server 数量增长极快但随之而来的问题是每种 MCP 的传输方式、鉴权方式、工具命名习惯各不相同。有的是 stdio 子进程有的是 SSE 长连接有的是 streamable HTTP还有的用 WebSocket 做全双工。如果你在 Agent 里直接用 SDK 一个个接入那每接一个就要写一段胶水代码项目里会堆满各种连不上超时schema 报错的补丁。MCP 的价值是把工具变成数据一个工具就是一个 JSON Schema 描述模型通过 tools/list 发现能力通过 tools/call 去执行。但工具变成数据的前提是你得有一个统一的数据通道去管理它们。tsm-hub 在这里扮演的角色就是那个把所有 MCP server 收拢进来的网关让上层 Agent 只面对一个入口而不需要知道工具到底跑在哪个进程、哪个端口。1.3 Skills 的兴起与组织难题Skills 是 2025 年最热闹的方向之一Claude Code 带火了技能这个概念之后大家突然发现与其每次把公司知识库、代码规范、Debug 流程写在长长的 system prompt 里不如把它打包成一个带元信息的技能包一个文件夹、一个 SKILL.md、若干参考文件模型在需要的时候自动加载。好处是立竿见影的上下文更干净、知识复用性更高、团队之间能直接复制交流。但 Skills 也有自己的麻烦不同平台的 skills 格式并不完全一样Claude Code 的 skill、OpenCode 的 skill、Codex 的 skill元信息字段和执行逻辑各有差异更麻烦的是一个 Agent 往往需要同时具备多个技能比如前端开发技能 MCP 调试技能 公司规范技能这些技能之间还可能互相依赖。如果靠手工在每次会话里拼 prompt那跟直接在 system prompt 里写 5000 个字没什么区别。所以 Skills 也需要一个统一的注册、调度、注入机制——这也是 tsm-hub 里很核心的一块。1.4 网关的最终定位四个统一想清楚上面三件事之后我给 tsm-hub 定的目标就非常明确它不是一个又来一个框架的框架而是一个轻量的统一网关做四件事——统一模型接入、统一工具注册、统一技能管理、统一调用链路。模型、工具、技能都注册进网关由网关负责路由、鉴权、上下文组装和结果回传。打个比方以前你要自己拿着插线板给每个设备供电现在你要的是一个带总闸的配电箱所有设备都接到配电箱里总闸一拉所有能力就都通了。tsm-hub 就是这个配电箱。它不需要发明新的协议只需要把现有的 MCP、JSON Schema、SKILL.md 这些接口标准焊死在网关内部。2. 整体设计统一网关的架构与选型思考2.1 为什么不做成框架而是做成网关在设计初期我其实犹豫过到底是写一个 Python SDK 让项目引用还是一个可以独立部署的网关服务最后选了网关。原因很现实如果做成 SDK那每个项目都要重新引入依赖、配置环境变量小团队还好一旦有三四个独立服务API 后端、定时任务、运营脚本每个服务的模型调用和工具配置都会变成孤岛维护成本指数上升。网关的好处是一处配置处处使用LLM 的 API Key 存在网关里MCP server 的连接配置存在网关里Skills 的目录也由网关统一扫描。所有下游服务只需要通过 HTTP 或 SDK 打到网关的入口然后等着拿结果就行。服务间不需要关心对方用的是什么模型、挂了多少工具互相之间的职责边界一下子就清晰了。2.2 核心模块划分Connector、Registry、Router、Executor、Skill Storetsm-hub 的内部结构我按职责拆成了五个模块下面逐个说。Connector连接器负责和外部系统建立连接。对外有两种类型一种是 Model Connector封装不同 LLM 供应商的 API把 OpenAI Format 的请求转成各家协议另一种是 MCP Connector负责启动 MCP client、处理 stdio/SSE/HTTP 的传输细节、维护连接生命周期。Registry注册中心所有模型、MCP server、Skill 的元信息都登记在这里。Registry 里记录的不只是有哪些东西还包括健康状态、负载情况、版本号。我让 Registry 支持动态注册和心跳上报这样新增一个 MCP server 不需要重启网关热加载就能生效。Router路由器根据请求里的模型偏好、工具需求、成本策略决定这次调用走哪个模型、把请求转给哪个 MCP server。Router 还负责工具调用的聚合如果用户问帮我查一下数据库里的订单再画个图那 Router 就要把数据库 MCP 和图表 MCP 都列进工具清单让模型自行选择。Executor执行器把模型返回的工具调用指令真正执行掉再把执行结果打包回给模型。Executor 里有超时控制、重试策略、并发限制防止某个工具卡住导致整个请求挂掉。Skill Store技能库专门管理 Skills。启动时扫描技能目录解析每个 SKILL.md 的 frontmatter建立技能索引请求进来后Skill Store 根据会话意图决定激活哪些技能并把技能内容拼进上下文。这五个模块之间只通过内部接口通信互不直接调库。这样做的好处是以后哪怕要把网关改成 Go 或者 Rust 实现每个模块的边界都还在重构不会变成推倒重来。2.3 关键选型协议适配层优先整个设计里我最看重的是协议适配层。今天的模型调用也好工具调用也好本质都在往标准化走模型侧大家在向 OpenAI API 格式收敛工具侧大家在向 MCP 收敛。但收敛需要时间现实世界里全是半标准。比如有的模型虽然宣称支持 OpenAI 格式实际 tools 参数里有几个字段不兼容又比如 MCP server 有的只支持旧版 SSE没有 streamable HTTP 的实现。所以我在 Connector 里专门加了一层适配器每个外部系统进来之后先声明自己支持哪个协议版本然后由适配器转换成网关内部统一的规范格式。这样后续新增一个半标准系统只需要写一个适配器不用动 Router 和 Executor。2.4 同步和异步的统一流式优先模型调用天然是流式的工具调用天然是同步的这两者混在一起容易出问题。我的处理原则是网关对外统一支持流式响应SSE内部用异步任务池去并行执行工具调用。什么意思呢就是当模型返回了三个工具调用请求时网关不会傻等一个执行完再执行下一个而是丢进 Executor 的任务池并行跑等全部完成后统一拼接结果再喂回模型。这个设计在大规模 Agent 场景下非常关键实测能把多次工具调用的总耗时压缩 40% 以上。3. 核心原理拆解MCP、Tool 注册与调用链路3.1 MCP 协议到底在传什么理解 MCP 之前先记住一句话MCP 是工具界的 USB-C。Client 和 Server 之间走的是 JSON-RPC 2.0核心就三个方法——initialize做能力协商tools/list拉取工具清单tools/call执行具体工具。过程有点像面试先握手互相确认我支持什么然后候选人Client看岗位列表tools/list最后投简历干活tools/call。传输层这边stdio 模式适合本地命令行工具网关以子进程方式拉起 MCP server生命周期随网关SSE/streamable HTTP 模式适合远程服务网关通过 HTTP 连接适合部署在独立机器上的工具WebSocket 模式适合需要服务端主动推送的场景。选哪种不是拍脑袋主要看 MCP server 是给本机用还是分布式使用如果 server 和网关在同一台机器、又是内网工具stdio 最省事如果要跨机器跨网络那就走 HTTP/SSE。3.2 Tool 注册的本质是给模型递菜单每一个接入网关的工具最终都会变成一个 JSON Schema 样式的描述包括名称、说明、参数结构。这段描述会随每次请求发送给 LLM模型读完之后在回答时返回一个结构化的工具调用指令。听起来很顺但这里有个很隐蔽的坑工具描述写不好模型就会瞎用或不用。我之前给一个查询接口写的描述是根据用户输入查询相关信息结果模型经常在不需要查询的时候也去调它把上下文搞得一团糟。后来我学到一个实操技巧工具描述要像写外卖菜单一样写清楚适用场景、不适用场景、注意事项。比如查询工具应该写成当用户询问订单金额、订单状态、物流信息时使用本工具当用户问天气、新闻等与订单无关的内容时绝对不要调用本工具。实测这样写之后工具误调率至少下降一半以上。这个细节在 tsm-hub 里我直接写进了注册规范每个工具接入的时候必须带上使用边界字段。3.3 Skills 在网关里的组织方式Skills 在 tsm-hub 里的组织方式我参考了 Claude Code 的规范一个团队技能仓库里放多个技能子目录每个技能至少包含一个 SKILL.md 文件。SKILL.md 的 frontmatter 里有 name、description、适用场景正文里则是具体的操作步骤、代码规范、注意事项。网关读取 SKILL.md 后会先对 description 做语义索引。请求进来时Skill Store 把用户消息和技能描述做匹配只激活相关的技能然后把技能内容插进 system prompt 或上下文后缀里。这样做的好处是就算你装了 50 个技能每次请求也只有两三个相关的技能会被加载Token 消耗不会爆炸。我在一个前端项目里同时注册了React 规范“数据库调试”“MCP 排查”三个技能实测额外消耗只有几百 Token但模型的回答质量提升非常明显尤其代码风格一致性上判若两人。3.4 完整调用链路一个请求从进到出把上面所有设计串起来一个完整的调用链路是这样的用户请求通过 HTTP 打到网关带上模型偏好比如用便宜模型就行。网关解析请求提取有意向的工具范围Skill Store 根据消息内容激活相关技能并把技能内容注入上下文。Router 从 Registry 拉取已注册的模型和工具清单把工具全部转成 LLM 要的 JSON Schema 格式。网关把组装好的 messages tools 发往选定的 LLM。LLM 返回两种结果之一要么是最终文本回答要么是一系列工具调用请求。如果是工具调用Executor 把请求路由到对应的 MCP ConnectorMCP server 执行完返回结构化结果。网关把工具结果拼进对话历史再次发给 LLM。循环执行步骤 5-7直到模型给出最终文本回答网关通过 SSE 把结果流式返回给用户。这个链路里最容易出问题的就是第 6 步工具执行成功了但结果格式不合法或者执行超时都会导致模型在下一步看不懂上下文。所以 Executor 里我加了结果校验层每个 MCP 返回的结果都先做类型检查和长度控制异常结果会在回传给模型之前先被网关拦截并转换为友好提示。别小看这一步它能让整个 Agent 的稳定性上一个台阶。4. 实操从零把 tsm-hub 跑起来4.1 环境准备与配置文件骨架先声明一下tsm-hub 本身的代码还在打磨这里给你的是我目前实践下来最顺的配置思路你可以照着搭自己的版本。环境上我推荐用 Python 3.11 或 Node 20核心依赖就是mcp官方 SDK 和一个 HTTP 框架。整体配置我分三块model.yaml管 LLM 连接mcp.yaml管 MCP server 列表skills.yaml管技能仓库路径。三个文件互相独立网关启动时加载并注册到 Registry。这样无论是加模型、加工具、加技能都只动各自对应的文件不用改代码。# model.yaml models: - name: claude-sonnet provider: anthropic base_url: https://api.anthropic.com api_key_env: ANTHROPIC_API_KEY default_max_tokens: 8192 - name: local-llama provider: openai-compatible base_url: http://localhost:8000/v1 api_key_env: OPENAI_API_KEY # 注意本地模型不一定完整支持 tools需要做能力探测4.2 接入第一个 LLM 供应商配置好 model.yaml 之后网关启动时就会为每个模型创建一个 Connector。这里有个关键点接入的时候一定要做一次能力探测用一个小请求测试这个模型到底支不支持 function calling / tools 参数探测结果写进 Registry。我不止一次遇到配置里写了 tools但由于模型版本或部署方式问题实际请求时工具参数被忽略的情况。有了能力探测Router 在分配请求时就不会把必须用工具的任务派给不支持工具调用的模型。能力探测的代码很简单本质上就是发一个带tools参数的请求看模型返回是否报错。async def probe_tool_support(client): try: resp await client.chat.completions.create( modelmodel_name, messages[{role: user, content: 你好}], tools[{ type: function, function: { name: ping, description: 测试工具是否存在, parameters: {type: object, properties: {}} } }], max_tokens10, ) return True except Exception as e: # 记录具体报错原因通常是 tools 参数不被支持 return False4.3 挂载一个 MCP Serverstdio 和 SSE 两种模式接下来是最有成就感的一步挂 MCP server。我拿两个典型场景演示。第一个是本地文件系统 MCP走 stdio 模式配置里只需要指定启动命令和参数网关启动时会自动拉起子进程。# mcp.yaml mcp_servers: - name: fs-tools transport: stdio command: npx args: [-y, modelcontextprotocol/server-filesystem] env: ALLOWED_DIRS: /workspace/data第二个是一个远程的图表生成 MCP走 SSE 模式。- name: chart-server transport: sse url: https://mcp.chart.example.com/sse headers: Authorization: Bearer ${CHART_API_TOKEN}这里有个经验stdio 模式的 server 在网关进程重启之后一定要做连接回收否则会残留一堆僵尸子进程。我一开始没注意跑了两天发现服务器进程数爆到两百多。后来在网关的 shutdown 钩子里统一调用session.close()并 kill 子进程问题才解决。SSE 模式则要关注心跳机制有些 MCP server 如果长时间没有请求SSE 连接会被中间负载均衡断开需要靠自动重连逻辑保证稳定性。4.4 注册第一个自定义 SkillSkills 这块我建议直接在仓库里建一个skills/目录每个技能一个子目录。以前端开发规范技能为例最终长这样skills/ frontend-dev/ SKILL.md react-best-practices.md project-tree.mdSKILL.md 的 frontmatter 里要写清楚触发条件格式如下--- name: frontend-dev description: 当用户需要编写或修改 React 组件、涉及前端工程化配置时启用帮助其遵循团队代码风格和项目目录结构。 applies_to: - code_generation - code_review ---网关扫描到技能目录之后会把每个技能的名称和 description 建索引。请求进来后Skill Store 做一次简单的关键词 语义匹配选中最相关的 1-3 个技能注入上下文。你也许会有疑问为什么一次只注入 1-3 个因为技能本质是增量知识注入太多会把模型带偏。我之前试过一次注入 10 个技能模型反而开始混淆不同技能里的规则输出质量明显下降。控制数量是技能管理里的一条重要经验。注入技能之后你可以测试一下效果让模型写一个 React 组件如果它输出的代码风格明显符合 SKILL.md 里的规范说明技能加载链路是通的如果没什么变化多半是技能描述写得太模糊模型没匹配上。4.5 端到端验证与调试网关跑起来之后我习惯先用一个极小的命令验证链路比如直接调用带工具的回答。debug 模式开启后网关会把每一步的耗时、Token 消耗、工具调用次数打印出来方便快速定位问题。调试时我常用三个指令/models查看模型健康状态/tools查看已注册工具清单/skills查看技能激活情况。一旦发现工具调用了但模型没反应先看工具清单里有没有这个工具有再挂 debug 看模型返回的原始 JSON——大多数情况下都是模型返回的 tool_call 里有字段解析失败不是网关逻辑错了。5. 常见问题与排查技巧实录5.1 provider rejected the request schema or tool payload这个报错大概率会在接第三四个模型的时候遇到我估计你在网上搜到的大多数答案都只说检查 schema但不告诉你具体查什么。我踩过之后总结出四个排查顺序第一看 JSON Schema 格式是否合法。type是否写全properties是否都带类型声明required里的字段有没有在properties中缺失。这些低级错误在编辑器里不报错但模型服务端是非常较真的。第二工具描述里不能包含非法字符比如未转义的引号、换行符描述别超过服务端的长度上限。第三有些模型服务端不支持additionalProperties: false你把这个字段去掉可能就好了。第四确认发送时tool_calls相关字段没有被网关缓存污染——我遇到过网关对同一个模型连接复用了带旧工具定义的 session导致第二次请求 schema 不一致。这里建议在 Connector 里记录服务端返回的原始报错信息不要吞异常只返回调用失败。原生报错往往直接告诉你是哪一块 schema 出问题能省很多时间。5.2 MCP 握手超时和连接反复断开stdio 模式的常见问题是启动超时MCP server 启动要 10 秒但网关默认只等 5 秒于是握手必然会挂。解决办法是在 Connector 里把 initialize 超时设置为可配置且至少 30 秒起步。SSE 模式的常见问题则是端点路径不对有的 server 是/sse有的是/mcp你直接照抄厂商文档是没用的需要先 curl 一下原始端点试试握手是否返回协议要求的头部和响应体。另外特别提醒MCP server 返回的工具参数一定要做类型收敛。我遇到过某个 Python 写的 server返回数字用 int 但 JSON Schema 里写的是 number模型严格按 schema 解析后直接报类型不匹配错误。网关接入层一定要加一层宽容转换int 和 float 互转、null 转空字符串这些小细节能省掉大量隐性故障。5.3 Skills 不生效三种典型原因技能加载了但模型行为不变九成是三种原因。第一种是 description 写得不行都是帮助用户解决问题这类废话语义匹配召回了也没内容可加载。第二种是技能正文全部是抽象描述没有可执行的 checklist比如写要注重代码质量这种话模型根本不知道具体要做什么。第三种是技能注入位置错了模型根本读不到——我早期把技能内容拼在 assistant 的某条历史消息里而不是 system prompt 附近Claude 这种强指令遵循的模型还勉强可以用但一些开源模型的指令遵循能力弱技能放不对位置就跟没放一样。所以我现在的做法是技能正文必须包含可执行的步骤列表和禁止事项列表放在 system prompt 的末尾作为权威指令。每次加载技能之后网关会在 debug 日志里显示技能 X 已注入预估生效等级让你第一时间知道技能有没有进上下文。5.4 网关自身的稳定性速查表网关是中间层它的稳定性直接决定上层服务的可用性所以有三个参数我建议从一开始就配好全局超时、工具执行并发上限、模型调用失败重试策略。下面是我项目里的实测参数可以直接抄作业配置项推荐值说明模型调用超时60sLLM 流式响应一般 30s 内首包会到MCP 工具执行超时30s超过直接取消避免拖垮整体单请求工具并发3-5避免多个工具抢资源模型失败重试次数2 次每次间隔指数退避不要死磕技能注入数量上限3 个防止上下文被技能淹没工具描述总 Token 限制8000超过会挤占回答空间除了参数还有一个架构层面的建议网关一定要做内存缓存把每次请求的 message 序列和工具定义哈希存起来同样的请求进来直接命中缓存不要再打一遍模型。我做了这个优化之后同参数重复请求的响应时间从 3-4 秒降到了几十毫秒对内部调试和测试帮助巨大。5.5 关于工具调试的一个独家技巧最后分享一个调试 MCP 时非常实用的方法在网关里加一个echo 模式。当某个工具调用出问题时先不让网关执行真实请求而是把模型返回的 tool_call 原样打印出来手动模拟一次tools/call。这样能快速区分问题出在模型端还是工具端。比如数据库 MCP 报连接错误你直接手动拼一个请求去打底层数据库如果手动能通就说明是 MCP server 的鉴权上下文问题不是数据库本身的问题。这个小技巧帮我排查掉至少五六次诡异故障。写在最后的经验做 tsm-hub 最大的收获不是技术方案而是对复杂系统要靠分层这件事的重新理解。模型、工具、技能每一层单独拎出来都不算难但当它们搅在一起的时候如果没有一个职责清晰的网关整个系统很快就会变成一团乱麻。我强烈建议你从最小闭环开始先接一个模型、一个 MCP server、一个技能跑通之后再逐步往上加。网关的价值是在规模效应出现时才真正体现出来的你加的第一百个工具和第几个工具体验应该是一样的这才是一个合格的统一网关该有的样子。

看完文章,想为自己的企业也做一次专业网站诊断?

尧图顾问免费为您评估现有网站,并给出建站/改版建议与报价方案。

免费获取方案