ARTICLE DETAIL

资讯详情

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

统一网关tsm-hub:整合LLM、Tools、MCP与Skills的AI集成实践

统一网关tsm-hub:整合LLM、Tools、MCP与Skills的AI集成实践 1. 为什么需要统一网关从工具链碎片化说起最近把项目里的AI集成方式彻底重构了一遍起因很直接当时代码仓库里同时跑着三套完全独立的调用逻辑——一套直接调OpenAI兼容接口一套通过Function Calling走自研工具函数还有一套是接MCP Server的外部工具查询。每次加新能力都要改动不同位置的配置密钥散落在环境变量、配置文件、甚至前端静态资源里。团队里新同学接手时问得最多的一个问题就是我们到底有几个入口在连大模型后来决定做一个统一网关也就是tsm-hub这个名字的由来。它的定位很朴素把所有与大模型相关的调用动作包括LLM请求、Tools工具调用、MCP协议对接、Skills技能装载全部收拢到一个服务里。对外暴露一个统一的入口对内统一管理路由、鉴权、限流、缓存和日志。这篇文章不聊太多概念重点讲清楚这个网关解决了什么问题、内部是怎么设计的、以及我在实际搭建和接入过程中的真实经验。如果你是做AI应用开发、正在被多模型切换和工具管理折磨的工程师或者刚接触MCP和Skills概念想找一个整体视角这篇文章应该能帮上忙。我不会假设你已经掌握所有术语每个关键概念都会从使用场景角度解释一遍然后再落到工程实现上。2. 四个核心对象的边界划定LLM、Tools、MCP、Skills在动手设计网关之前必须先把四个核心对象的边界想清楚。这看起来像概念科普实际上直接决定网关的数据模型长什么样。2.1 LLM模型的统一接入网关里的LLM指的不是某个具体模型而是一类可配置的模型接入资源。比如DeepSeek、通义千问、本地部署的Qwen、或者兼容OpenAI协议的自建服务在网关里都应该被抽象成同一个东西一个具有模型名、Base URL、API Key、温度等参数、支持文本补全或对话补全的端点。这里有一个常见误区很多人把模型和供应商绑死换模型就要改代码。网关的做法是把模型接入变成一条配置记录。我用一个统一的Provider接口屏蔽各家差异OpenAI格式的请求进来之后网关负责做协议转换转发到对应的上游。对于不支持原生Function Calling的模型网关还要在请求层做工具描述信息的注入和返回结果的解析。这个设计最大的好处是切换模型零代码。之前某国产模型服务不稳定我只需要在网关配置里把该模型的权重切换一下上层应用毫无感知。2.2 Tools网关内部的可调用能力Tools在网关里指的是你自己实现的一批可被模型调用的函数。它们通常以JSON Schema描述入参和出参模型根据对话上下文决定是否调用、以什么参数调用。网关收到模型发来的Tool调用请求后执行对应的处理函数再把结果回传给模型继续生成。举一个实际例子我在网关里注册了一个查询今日汇率的Tool它的入参Schema是目标币种函数内部去调用一个公开的汇率API。模型在对话中判断用户想要汇率信息时就会以JSON格式发起调用{target_currency: USD}。网关匹配到对应的Tool处理器执行后返回结果模型再基于这个结果组织语言回复用户。Tools的注册需要做到热更新。我的实现是一个Python字典作为注册表key是工具名value是执行函数的引用和Schema描述通过装饰器注册。网关启动时扫描一个tools目录下的所有模块自动完成注册。新增工具只需把文件丢进目录不用改主程序。2.3 MCP外部能力的标准化收割MCP是Model Context Protocol的缩写它做的事情是把外部数据源和工具服务标准化成一个协议。通俗理解MCP是AI世界的USB接口任何遵循该协议的Server都可以被任意支持该协议的Client直接插拔使用。我在网关里加入MCP兼容层的主要原因是社区里已经存在大量现成的MCP Server。比如文件系统操作、数据库查询、浏览器自动化、蓝湖设计稿信息读取等等。这些都是别人封装好的能力如果每一个都要自己重新实现一遍Tools工作量巨大且维护成本高。网关对接MCP Server的方式有两种一种是HTTP形式Server本身是一个服务端链路通过URL和鉴权信息连接另一种是本地进程形式Client通过标准输入输出与Server通信。我在这两种方式上都做了支持。HTTP方式适合远程共享的MCP能力本地进程方式适合安全和隐私要求更高的场景——数据完全不出本机。这里必须提醒一点MCP协议还在快速演进不同Server对工具描述、参数校验的严谨程度差异很大。如果你打算在网关里聚合多个MCP Server一定要设一层异常隔离。我见过一个MCP Server返回了非UTF-8编码的内容直接把整个进程的日志输出干崩。隔离层的作用就是任何一个外部能力出问题都不能拖垮网关主链路。2.4 Skills可复用的指令技能包Skills这个词在AI应用里有两层含义。第一层是Claude Code或OpenCode里那种可安装的技能包通常包含一组指令、示例和辅助脚本指导模型在特定场景下如何表现。第二层是更广义的技能定义一个特定任务的完整处理策略。在tsm-hub网关里我把Skills设计成一组不可直接调用、但会影响模型行为的配置资源。它和Tools最大的区别是Tools是模型可以主动发起调用的函数Skills是模型在接收用户请求时需要遵循的上下文策略。举个例子一个代码审查Skills包包含审查规则清单、常见问题模式、输出格式模板。当用户在对话中提到帮我审查代码时网关会把这个Skills包的内容注入到系统提示词中让模型按照预设框架执行。这个机制本质上是在不修改模型权重的情况下通过上下文的策略注入来定制模型行为。Skills的管理要考虑优先级和冲突问题。我设计了一个简单的权重体系每个Skills包有一个名称、一个触发条件列表、一组内容片段。网关在组装请求时遍历所有匹配用户输入关键词的Skills包按权重排序拼接。如果两个Skills包对同一个问题给出了冲突的策略权重高的生效。3. 网关内部架构接入层、注册层、执行层如何各司其职统一网关不是把所有代码堆在一个服务里而是把功能清晰分层。我把tsm-hub拆成三个核心层次再加一个辅助的配置管理层。3.1 接入层统一对外接口接入层是所有请求进网关的入口。我对外只暴露两类端点一类是 /v1/chat/completions完全兼容OpenAI的请求格式方便任何已经适配过OpenAI SDK的应用无痛切换另一类是 /v1/tools/execute用于手动触发工具调用或调试。这一层做的事情包括请求格式校验、API密钥校验、基础限流、请求日志记录。日志非常重要——统一网关的一个核心价值是审计。每次请求用了哪个模型、调了哪些工具、耗时多少、消耗了多少Token都必须有迹可循。我用结构化日志输出到JSON文件方便后续接入日志分析系统。3.2 注册层一切资源的元数据中心注册层是整个网关的大脑。它维护了几个核心存储表第一是模型配置表。记录每个模型端点的名称、供应商、Base URL、加密后的API Key、支持的参数范围、当前是否启用、权重等。我在这一层做了探活机制定期向每个端点发送一个极小的请求判断其可用性。某个供应商的端点连续失败三次后自动摘除路由权重。第二是工具注册表。包含Tools和MCP Server暴露的工具。每个工具的元数据统一归一化成一个结构工具名、描述、入参Schema、调用目标类型本地函数还是MCP Server、超时时间、是否需要人工审批。统一归一化是网关的另一个关键点——上层应用完全不需要关心这个工具到底是本地实现的还是远端MCP提供的。第三是Skills注册表。记录技能包的名称、版本、触发条件、内容片段、适用模型列表。有些Skills包只适用于特定参数风格的模型注册表里的适配规则可以精确控制注入行为。3.3 执行层请求编排与工具调度执行层是真正干活的地方。一次典型的请求处理流程是这样的用户请求进入之后接入层做鉴权和校验然后交给执行层。执行层先根据请求内容结合注册层里的Skills匹配规则组装出系统提示词。然后调用配置好的LLM端点把修好的Prompt发给模型。模型如果返回了工具调用请求执行层就按工具注册表找到对应的执行器调用本地函数或MCP Server把结果拼回到对话上下文中再次请求模型继续生成。这个过程可能循环多次直到模型认为信息已足够、给出最终回复。这里有一个必须重视的问题循环次数必须有上限。某些模糊的用户意图可能导致模型反复调用工具消耗大量Token和外部API配额。我设定了一个最大工具循环次数默认配置为5次超过后强制让模型基于已有信息作答。这个参数可以按应用场景调整比如写代码场景可以放宽到8次简单的知识问答场景控制在3次以内。执行层里还需要一个工具结果缓存。对于天气查询、汇率查询这类实时性要求不高的工具在短时间窗口内直接复用之前的结果能显著降低外部API的调用频率和整体延迟。我用一个带过期时间的缓存字典来实现默认TTL是60秒可以在工具注册表里单独指定。4. 密钥与鉴权绕不过去的安全设计热词里有人问使用LLM时如何防止密钥等鉴权信息泄露这个问题我在做网关时体会特别深。没有统一网关之前团队里每个应用都得自己保存一份模型供应商的API Key。有人把Key写在代码注释里有人把Key放在前端环境的配置文件中有人直接把Key提交到Git仓库里等发现时已经没法追溯泄露范围了。4.1 密钥分层存储与最小暴露tsm-hub里我把密钥全部集中到一个加密配置文件中内存里只保留解密后的值进程退出后即消失。文件本身用环境变量里的主密钥进行AES-GCM加密。这样即使配置文件被泄露没有主密钥的人也读不出任何有效内容。所有下游应用通过网关调用模型时只需要持有网关自己的API Key不需要也不应该知道上游供应商的密钥。这个密钥有自己的有效期可以在网关中独立轮换。一旦某个下游应用出现问题可以单独撤销它的访问权限而不影响其他应用。4.2 下游应用的独立密钥管理给每个接入应用分配独立的API Key是我强烈建议的做法。这样做有几个直接好处一是可以按Key粒度做限流和配额控制二是密钥泄露时可以精准吊销三是在日志中可以通过Key定位是哪个应用在调什么服务方便异常行为分析。密钥生成时我会同时设置一个备注字段记录该Key归属什么项目、对接人是谁、申请日期。这个备注在排查问题时非常有用。有一次团队里一个后台任务疯狂触发工具调用我通过日志中的Key信息立刻定位到了具体的消费者服务。4.3 网关自身的防护细节网关作为统一入口本身会成为攻击者的重点目标因此必须做好几层防护。一是传输层所有与网关的通信必须走HTTPS不接受任何明文HTTP请求。在本地开发环境用自签名证书也要走TLS。二是请求体大小限制和超时控制。LLM的上下文长度有限过大的请求体既浪费资源也容易被恶意利用。我设置的请求体上限是1MB超过直接返回413。三是对上游模型端点的出站请求也要做保护。有些供应商的SDK会把密钥放在请求头的Authorization字段里网关需要确保这个流量只走可信通道。如果供应商提供了专用的VPC终端或内网域名要优先使用避免密钥在公网链路上传输。四是日志脱敏。网关日志里不能出现完整的API Key、Token、用户隐私内容。我在日志输出前加了一层脱敏处理器对所有符合密钥格式的字符串自动替换为掩码形式。模型的输入输出内容默认不打印只有在明确开启调试模式时才输出到单独的文件并且加了访问权限控制。5. 实操从零接入一个MCP Server和一个Skills包讲了这么多设计来两个实际接入的例子。我选一个相对复杂、一个是相对常见的场景尽量把操作过程中的关键判断也讲清楚。5.1 接入一个HTTP形式的MCP Server假设我们要接入一个提供设计稿信息的MCP Server类似蓝湖MCP的场景。这类Server通常提供一个Base URL和对应的鉴权Token。第一步在网关的MCP配置区新增一条记录。需要填写的字段包括连接名称、服务器类型HTTP或STDIO、Base URL、鉴权请求头模板、工具列表刷新策略。我建议把工具列表刷新策略设置为按需刷新也就是每次请求工具列表时先查本地的缓存如果超过5分钟才真的向Server发起一次工具列表请求。第二步验证工具发现机制。HTTP形式的MCP Server一般实现了一个工具列表端点网关通过这个端点拿到它支持的工具清单。这里经常遇到的问题是对工具Schema的解析失败。不同MCP Server对JSON Schema的实现略有差异有的会在Schema里塞入注释字段有的会缺少必填项的约束。网关在解析时必须足够宽容——解析失败时跳过该工具而不是整个Server崩溃。第三步测试实际调用。拿根据设计稿ID获取切图信息这个工具做例子。在管理接口里手动构造一次调用请求tools/execute入参是设计稿ID。网关会记录完整的调用耗时和返回结果。我把手动测试工具做成了一个独立页面或命令行子命令因为在自动集成模式下排查问题会比较别扭。第四步把该MCP Server的可用工具注册到网关的全局工具命名空间。这里要注意命名冲突处理。我的做法是为每个MCP连接设置一个命名空间前缀格式是{连接名称}_{工具名}。这样即使两个MCP Server暴露了同名的工具也不会冲突。5.2 创建并装载一个Skills包Skills包的开发更像是写文档加示例的过程。我以一个图片生成辅助技能包为例它的作用是当用户请求生成图片时指导模型如何正确调用图片生成工具。第一步定义Skills包的元信息。包括名称、版本号、作者、描述、适用模型列表。我用YAML格式维护元信息头部正文用Markdown编写指令。第二步编写触发条件和指令内容。触发条件我定义为一组关键词列表图片生成、画一张图、制作海报、生成形象照等。指令内容包括必须确认图片的用途和风格偏好后再生图调用生图工具前先检查参数是否完整生成完图片后要主动向用户说明生成参数方便二次调整。这些指令会在用户请求命中关键词时注入系统提示词。第三步把Skills包文件放到网关的skills目录下。网关启动时会递归扫描这个目录发现新的Skills包自动安装。这里我设计了一个版本控制的细节Skills包的目录名包含版本号同一技能允许多版本共存。配置里指向哪个版本网关就装载哪个版本的指令内容。第四步验证注入效果。在调试模式下网关的日志会输出最终发送给模型的系统提示词内容你可以看到该Skills包的指令语句是否在正确的位置、是否与其他Skills包的指令产生冲突。5.3 从Demo到可用的几个经验这些实操做完后你可能会发现一些和看起来能用之间的差距我把踩过的坑先说几个。第一个坑是MCP工具的鉴权方式五花八门。有的Server用Header里的Authorization Bearer有的用自定义的Header字段还有的要在请求体里塞Token。网关对接MCP时鉴权信息模板必须做活也就是支持动态关联到该连接配置的密钥变量。我最初用硬编码换一个Server就得改代码完全不可持续。第二个坑是Skills包的指令内容和模型基座有关。同一个系统提示词在指令遵循能力强的模型上效果显著在弱一点的模型上可能被忽略或误解。所以在Skills包的适用模型列表中明确标注哪个模型的哪个版本设置是合理的。比如一个包含复杂规则约束的Skills包标注了只适用于新版模型老版本模型会自动跳过装载。第三个坑是工具循环中的上下文长度膨胀。每调用一次工具返回结果拼接到对话里多轮下来Prompt会变得非常长。有些工具的返回结果是结构化的长文本比如完整的数据库表结构或项目文件清单堆进上下文会挤占宝贵的窗口空间。我的解决办法是给工具结果设置截断策略默认只保留前2000个字符超长部分在末尾加一行结果已截断共N条记录如需完整内容请指定查询范围。模型看到这个提示后一般会主动要求更精确的查询而不是盲目把全部内容塞进上下文。6. 真实部署中的踩坑记录与排查思路网关这种中间层服务问题往往不是单个组件的问题而是组件间配合的问题。下面几个是我在部署和运行过程中真实遇到的每一个的完整排查链路都值得复盘。6.1 案例一模型返回的Tool调用参数格式漂移现象某天开始同一个应用频繁报出工具入参解析失败的错误。网关日志显示模型的Tool调用返回内容里参数JSON突然从标准JSON变成了含有Markdown代码块包裹的文本。代码块的起始符是json结束符是这种文本直接JSON.parse必然失败。排查链路先确认是不是某个特定模型的问题。翻看日志发现这个应用最近切换到了一个新接入的模型端点。再往前查该模型是通过一个中间代理服务接入的代理服务对模型返回流做了格式化处理把Tool调用结果包装到了代码块里。根因中间代理的提示词设置让模型习惯性地用代码块包裹JSON输出而网关在解析时没有做这个容错处理。解决思路在网关的工具调用解析层加一个预处理如果检测到内容被代码块包裹剥掉代码块标记再解析如果JSON解析失败尝试用宽松模式提取内容中合法的JSON片段。这两层容错是防御性的干净的标准JSON请求不受影响但能显著提升对接各种模型的成功率。6.2 案例二本地进程MCP Server的退出导致僵尸进程堆积现象系统运行几天后服务器上出现大量垃圾进程CPU占用攀升。排查链路先top命令看进程状态发现一堆残留的子进程。这些子进程的名称指向一个通过STDIO方式接入的本地MCP Server。该Server设计为从标准输入读取指令、在标准输出返回结果但它在处理完一个请求后内部发生了状态异常进程没有退出也没有响应新的请求。网关判断请求超时后没有主动杀掉子进程于是这个Server就一直挂在那里。根因网关对于STDIO类型的MCP连接在启动时会拉起子进程但在进程无响应时只标记超时没有实现自动重启和强制清理的逻辑。解决思路在进程中增加一个资源管理器维护所有STDIO子进程的句柄和健康状态。每次请求前检查进程是否存活如果进程存在但连续三次请求无响应则强制结束该子进程并重新拉起一个新的实例。服务初始化时重新建立STDIO通道。经过这个修复后类似问题在后续一段时间里没有再发生。6.3 案例三网关自身的默认超时设置导致下游应用连锁失败现象一次上游大模型服务的响应速度整体变慢网关里大量请求堆积。但这些请求最终超时失败后下游应用却没有收到明确的错误信息。下游应用按自己的超时逻辑再次重试结果又打进来一批请求整个系统进入了雪崩状态。排查链路先看网关的请求入口日志发现长耗时请求非常多。再看网关调用上游的客户端超时配置是30秒。但下游应用连接网关的等待超时是20秒也就是说下游在20秒时已经断开等待但网关还在继续处理30秒时才返回错误。此时返回的错误报文因为连接半开下游根本收不到。下游应用等不到响应就认为是网络问题开始重试。根因上下游超时时间没有形成正确的递减梯度。正确的设计是下游连接网关的超时时间要小于网关连接上游模型的超时时间并且网关在等待上游结果时要向客户端发送标准的超时响应尽早释放下游连接。解决思路调整超时体系客户端连接超时10秒网关收到请求后15秒内必须发起对上游模型的调用响应超时放宽到60秒但网关通过异步等待的方式让客户端可以在10秒内就收到一个任务已接收的确认真正的结果通过单独的结果查询接口获取。如果是同步调用场景则把下游连接超时设为15秒确保在网关内部30秒超时之前下游可以收到明确的错误报文。超时参数明确后再配合网关的限流模块在全链路压力偏高时优先拒绝新请求而不是无限堆积。7. 自己的几点体会搭完这个统一网关之后我对中间层这个概念的体会深了很多。中间层如果只做转发价值非常有限真正的价值在于把下游的复杂性拦截在网关内部让上游应用面对一个简单、稳定的接口。为了做到这一点网关里必须承载超出很多人预期的复杂度协议转换、密钥管理、工具注册、超时治理、容错恢复、日志审计。每一样单独看都不是特别高深的技术但组合在一起需要非常细致的工程积累。一点小建议如果你也要搭类似的网关不要一开始就追求功能全面。先把最基本的模型接入、工具调用、密钥集中管理这三件事做好跑通一个真实场景再逐步引入MCP和Skills。这样每一步都有可验证的成果排查问题时也不会因为因素太多而无从下手。还有一个细节网络上关于MCP和Skills的教程越来越多但很多都停留在单一工具的接入演示。不同工具之间的能力冗余、命名冲突、调用成本才是网关层面更需要关注的东西。这些内容没有现成教程能覆盖只能在自己动手接入过程中积累。希望这篇关于tsm-hub网关设计的拆解能给你提供一个整体的框架参考帮你在自己的AI应用集成中少走一段弯路。
返回列表