开篇:为什么需要 tsm-hub
在大模型应用开发中,我遇到了一个普遍的痛点:各家 Provider 的接口格式不统一、限流策略各异,调用方需要为每个模型写一套适配代码。更麻烦的是,当某个模型出现故障或服务不可用时,调用方需要手动切换配置,运维成本很高。
以我自己的项目为例:多个 AI 应用(开发环境、内容生成、自动化服务等)都需要调用 LLM,每个项目都要维护一套 Provider 配置,接入了多家付费模型商但无法统一调度。某个 Provider 出现故障或限流,另一家还能正常服务,但调用方不知道,只能干等着。更麻烦的是,不同任务适合不同的模型,但调用方很难根据任务类型自动选择最合适的模型。
除了模型路由,还有一个更核心的问题:AI 能力的组织方式。每个项目都在重复实现工具调用循环、技能包管理、MCP 服务接入,但这些能力本质上是可以共享的。调用方携带自己的能力声明,网关根据实际使用情况进行统计,管理员可以选择是否将其纳入共享能力池——这才是 tsm-hub 最有辨识度的地方。
为了解决这些问题,我构建了 tsm-hub(GitHub 仓库)——一个集 LLM 网关、能力池平台、快路径引擎、运行时环境、可观测性于一体的统一 LLM 接入与能力平台。它的核心思路是:对外只暴露自己签发的 sk-tr-… Key,调用方像用 OpenAI 一样调用,平台在后端自动完成智能路由、能力注入、快路径加速、运行时隔离和全链路观测。
三个核心卖点:
- Model Gateway:多 Provider / 多模型 / 统一协议,智能路由与自动 failover
- Capability Pool:Tools / MCPs / Skills 的发现、统计与纳入,一次接入全网共享
- Fastpath:确定性请求绕过 LLM,直接本地计算回答
其他能力(Runtime、Sandbox、Memory、Observability、Streaming)作为能力补充,在后续章节详细介绍。
核心能力矩阵
tsm-hub 已经形成了完整的功能矩阵,覆盖从接入到运行的全链路:
| 能力域 | 核心功能 |
|---|---|
| 统一入口 | OpenAI 兼容 API,调用方只需换 Key、换 base_url、换 model 别名 |
| 智能路由 | 可配置的多维度智能调度策略(smart),支持 cost_first / stability_first / task_aware / balanced 四种模式,各维度权重可单独调整;也支持显式路由表,自定义 failover / weighted 等策略;支持通过 config.json、环境变量或 .env 文件配置 |
| 多协议适配 | 已支持 13 种上游协议(OpenAI 兼容、Anthropic、Azure OpenAI、Google Gemini、AWS Bedrock、AWS SageMaker、Cohere、Mistral、Hugging Face、Replicate、Together AI、Fireworks AI、Groq),统一的 Provider 适配器接口 |
| 能力池 | 内置 Tools(通用工具)、MCPs(Model Context Protocol 服务)、Skills(技能包)三层能力体系,支持发现、统计与择优录用 |
| 快路径引擎 | Fastpath 可选加速(算术、统计、单位换算等确定性查询直接回答)、Codegen 代码生成 fastpath |
| 运行时环境 | Sandbox(Docker 隔离的代码执行环境)、Memory(SQLite 持久化的对话记忆与用户偏好存储) |
| 可观测性 | 用量统计、Provider 健康监控、按天趋势、成本归因 |
| 隐私合规 | TLS 传输加密、CORS 白名单、启动安全自检、审计日志 |
关键设计决策与架构收益
在实现 tsm-hub 的过程中,有几个关键的设计决策不仅解决了当下的问题,更重要的是建立了可扩展的架构思维,为后续开发带来了长期收益。
决策一:自制 Token Key 统一鉴权
设计思维:对外只签发 sk-tr- 开头的自制 Key,服务端只存哈希(明文只在创建时返回一次)。每个 Key 可以独立配置允许使用的模型列表、配额限制(总 Token、总成本、每日 Token、RPM)、技能注入模式(不注入 / 技能清单 / 全部技能 / 指定技能)、Agent 开关(是否经过网关内置 Agent 工具循环)。
这样调用方不需要知道上游 Provider 的真实 Key,网关统一管理,也方便后续回收和权限控制。
架构收益:
- 权限细粒度控制:每个 Key 可以独立配置模型范围、配额、技能注入模式,满足不同调用方的需求
- 密钥安全:服务端只存哈希,即使数据库泄露也无法获取明文 Key;明文只在创建时返回一次,降低泄露风险
- 统一回收:某个调用方不再需要时,只需禁用对应的 Key,不需要修改上游 Provider 的配置
- 可追溯:每个请求都关联到具体的 Key,用量统计、成本归因、审计日志都可以按 Key 维度聚合
决策二:可配置的多维度智能调度 + 显式路由表
设计思维:接入多家模型商后,不同场景对路由策略的需求是不同的:有的场景成本敏感,有的场景可靠性优先,有的场景需要平衡质量和速度。因此智能路由不应该是写死的单一策略,而应该是可配置的多维度评分系统,让用户根据自己的业务需求选择合适的策略模式和权重。
默认采用 smart 智能调度策略,对于没有显式路由表的模型,网关自动扫描所有支持该模型的 Provider,综合评估多个维度后智能选择最优上游,无需为每个模型手动配置路由。
四种策略模式(settings.smart.strategy_mode 可配置):
| 模式 | 成本权重 | 稳定性权重 | 延迟权重 | 适用场景 |
|---|---|---|---|---|
cost_first |
100 | 40 | 30 | 成本敏感场景,免费/低价优先 |
stability_first |
30 | 100 | 50 | 生产服务,可靠性优先,成功率高的 Provider 优先 |
task_aware |
50 | 80 | 70 | 混合负载,平衡质量与速度 |
balanced |
60 | 70 | 70 | 通用场景,各维度均衡 |
各维度权重也可以通过 settings.smart.cost_weight / stability_weight / latency_weight 单独覆盖(0 表示用策略默认值)。支持通过 config.json、环境变量(TSM_HUB_SMART_*)或 .env 文件配置。
smart 策略的调度算法综合考虑多个维度:
- 成本维度:免费模型加分 + 单价档位加分(可配置
free_bonus/price_tiers) - 稳定性维度:历史成功率
(requests - errors) / requests× 100,连续失败惩罚;新 provider 给 70 分鼓励探索 - 延迟维度:EWMA 延迟,100ms 以内 100 分,1000ms 以上 0 分;无数据给 60 分
- 健康过滤:自动过滤 429 限流、5xx 错误、高延迟等不健康的 Provider,故障节点自动摘除
- 能力匹配:带 tools 的请求优先选择支持 tool_calls 的模型,长文本请求优先选择支持长上下文的模型
- 通用惩罚:半开候选扣分,429 限流期间大幅降权(-1000)
调度算法对多个维度进行加权综合评分,网关按得分从高到低排序,优先选择得分最高的健康 Provider。如果第一个失败,自动 failover 到下一个,实现多家模型商之间的无缝切换。
同时,用户也可以自由配置显式路由表,为特定模型或路由别名(如 chat、fast、code、reason)定义一组上游 target,选择 failover(严格优先级故障转移)、weighted(加权负载均衡)或 smart(在 target 范围内应用智能调度)等策略。
请求进来时,网关按以下步骤决策:① 匹配显式路由表(如有)→ ② 应用对应策略 → ③ 健康检查过滤 → ④ 能力匹配过滤 → ⑤ 按配置的策略模式和权重综合评分排序 → ⑥ 选择最终 Provider → ⑦ 失败自动 failover。
架构收益:
- 灵活可配置:四种策略模式 + 各维度权重可单独调整,适配不同业务场景;支持 config.json / 环境变量 / .env 三种配置方式
- 稳定性优先可选:选择
stability_first模式时,优先选择近期成功率高的 Provider,故障节点自动摘除,服务质量有保障 - 任务-模型匹配:通过显式路由表为不同任务类型(普通对话、代码生成、深度推理等)配置不同的模型池,各尽其用
- 多活容灾:接入多家模型商,某家出现故障或限流时自动切换到其他家,调用方完全无感知
- 零配置上手:新模型不需要手动配置路由,smart 策略自动扫描所有 Provider 并智能选择
- 质量保证:健康状态和能力匹配是硬过滤条件,不健康或不匹配的 Provider 直接排除
决策三:能力池三层架构 + 发现统计机制
设计思维:将通用能力抽象为三层:
- Tools:轻量级通用工具(get_time、calc、fetch_url、read_file、remember、recall、execute_code 等),网关内置执行,无需外部依赖
- MCPs:Model Context Protocol 服务,通过 stdio 或 HTTP 连接外部工具服务(如文件系统 fs、代码编辑 serena、记忆 memory、思考 think 等),工具名支持
server__tool、server:tool、server/tool三种格式 - Skills:技能包,通过 git submodule 加载(如 demo-lab 服务器巡检、weekly-investment 投资周报等),支持技能清单注入和
skill-run调用
三层能力都支持"发现—统计—择优录用"机制:网关记录调用方在请求中声明的外部能力,按命名约定自动分类(普通工具名→Tools、skill: 前缀→Skills、MCP 风格→MCPs),统计调用次数和使用方数量,在管理后台展示候选列表。管理员可以根据实际需求择优录用,录用时选择实现方式(仅记录标记 / HTTP 调用 / MCP 工具 / 内置实现)。
这个机制的核心价值在于发现和统计——让管理员看到调用方实际在使用什么能力,避免重复造轮子;晋升需要人工审核和配置,不是完全自动化的。对于遵循命名约定的能力识别准确率较高,第三方框架可能需要额外适配。
架构收益:
- 一次接入,全网共享:Tools/MCPs/Skills 只需在网关配置一次,所有通过网关的项目都可以使用
- 能力可见性:自动发现和统计调用方声明的外部能力,让管理员看到实际使用情况,避免重复造轮子
- 渐进式积累:通过"发现—统计—择优录用"机制,能力池可以持续积累调用方的最佳实践
- 灵活的录用方式:录用时可以选择仅记录、HTTP 调用、MCP 工具、内置实现等多种方式,适配不同能力的实际情况
- 解耦调用方与能力实现:调用方只需要声明工具名,不需要知道能力的具体实现方式(内置/MCP/HTTP),网关自动代理
决策四:Fastpath 快路径(可选加速)
设计思维:对于明确的算术、统计、单位换算、日期计算、进制转换、字数统计等确定性查询,网关可以直接在本地计算回答,不调用上游 LLM,从而节省额度并降低延迟。Fastpath 是可配置的加速选项,用户可以根据业务场景选择开启或关闭。
为了降低误匹配风险(比如文章写作请求中的章节编号被当成算术题),设计了三层防护机制:任务型关键词黑名单、全局长度限制、查询型关键词白名单。三层防护的设计原则是"宁漏勿错"——对于不确定的请求,保守地转发给 LLM 处理,宁可多消耗一点额度,也不返回错误的计算结果。
架构收益:
- 低延迟:命中时无需调用上游 LLM,本地直接计算,响应从秒级降至毫秒级
- 节省调用:确定性查询直接本地执行,不消耗 LLM 调用额度
- 安全可控:三层防护 + "宁漏勿错"原则,不确定的请求直接回退到 LLM
- 可选开启:用户可以根据业务场景选择开启或关闭,对于开放式对话或内容生成场景建议谨慎使用
决策五:统一抽象层——多协议流式响应的解耦设计
面对 13 种上游协议各不相同的流式响应格式,采用统一抽象层的设计思维:把"上游格式解析"和"下游格式输出"彻底解耦。每个 Provider 适配器只需实现 StreamChunk 接口,把上游原始 chunk 转换为统一内部表示,再由统一 SSE 编码器负责输出。新增协议只需实现一个适配器文件(通常几百行),输出格式调整只需修改统一编码器,13 种协议自动生效。
决策六:容错识别——MCP 工具名多格式的优雅降级
MCP 生态中工具命名格式不统一(server__tool、server:tool、server/tool 等),采用容错识别设计:按优先级尝试多种分隔符,提取 server 名后校验过滤误匹配,识别成功的按 server 聚合,识别失败的优雅降级到普通 Tools。这样能力发现机制可以自动适配新出现的 MCP 框架命名格式,不需要为每个框架写专门的识别逻辑。
决策七:不可变数据——配置热加载的无锁并发安全
管理后台运行时修改配置需要立即生效,同时有大量请求正在使用旧配置。采用不可变数据 + 原子替换设计:配置对象加载后不可变,修改时创建全新配置对象,通过 atomic.Value 原子替换全局指针。读操作完全无锁,写操作只有原子开销,每个请求生命周期内使用同一份配置,不会出现半新半旧的不一致状态。
典型场景与调用示例
场景一:多项目统一接入,额度集中管理
多个 AI 应用(开发环境、内容生成、自动化服务等)不再各自维护 Provider 配置,而是统一通过 tsm-hub 调用 LLM。网关集中管理多家付费模型商的额度,为不同任务自动选择最合适的模型,优先选择近期成功率高的 Provider,某家模型商出现故障或限流时自动切换到其他家,调用方完全无感知。运维人员只需在管理后台维护 Provider 和 Key,不需要逐个项目修改配置。
场景二:能力复用平台,一次接入全网共享
Tools、MCPs、Skills 三层能力池一次接入,所有通过网关的项目都可以共享使用。例如:文件系统 MCP 服务只需在网关配置一次,所有项目都能通过 fs__read_file 等工具调用;服务器巡检技能包只需加载一次,所有项目都能通过 skill-run 调用。网关还会自动发现和统计调用方声明的外部能力,在管理后台展示候选列表,管理员可以根据实际需求择优录用,避免重复造轮子。
场景三:故障自动转移,服务高可用
当某个上游 Provider 出现故障(429 限流、500 错误、网络超时)时,网关自动 failover 到路由表中的下一个健康 Provider,调用方不需要做任何处理。健康检查机制定期探测各模型的可用性,出现问题自动标记为降级状态,路由时自动跳过。对于关键业务,还可以配置跨 Provider 的多活路由,确保即使某家服务商完全不可用,服务也能正常运行。
调用示例一:内置 Tools 自动执行(客户端不传 tools)
客户端发送普通对话请求,不传 tools 字段,网关自动启用内置 Agent,附加工具池并在服务端执行工具调用循环:
// 客户端请求
{
"model": "chat",
"messages": [{"role": "user", "content": "帮我算一下 123 * 456 等于多少,然后获取当前时间"}]
}
// 网关内部处理流程
// 1. 自动附加工具池(get_time、calc、fetch_url、read_file、remember 等)
// 2. 调用上游 LLM,模型决定调用 calc 工具
// 3. 网关在本地执行 calc(123 * 456) = 56088
// 4. 把工具结果返回给 LLM,模型决定调用 get_time 工具
// 5. 网关在本地执行 get_time() = "当前时间"
// 6. 把工具结果返回给 LLM,模型生成最终回答
整个过程中,算术计算和时间获取都由网关本地执行,不消耗额外的 LLM 调用,延迟从几秒降到几十毫秒。
调用示例二:MCP 工具调用(通过网关代理)
客户端通过网关调用已接入的 MCP 服务,工具名采用 server__tool 格式:
// 客户端请求
{
"model": "chat",
"messages": [{"role": "user", "content": "读取项目根目录下的 README.md 文件"}],
"tools": [
{
"type": "function",
"function": {
"name": "fs__read_file",
"description": "Read a file from the filesystem",
"parameters": {"type": "object", "properties": {"path": {"type": "string"}}}
}
}
]
}
// 网关内部处理流程
// 1. 识别工具名 fs__read_file,提取 server=fs, tool=read_file
// 2. 查找已配置的 fs MCP 服务(stdio 传输,已常驻连接)
// 3. 通过 MCP 协议调用 fs 服务的 read_file 工具,参数 path="README.md"
// 4. MCP 服务执行文件读取,返回文件内容
// 5. 网关把工具结果返回给上游 LLM
// 6. LLM 基于文件内容生成最终回答
客户端不需要知道 MCP 服务的具体连接方式(stdio/HTTP),只需要按 server__tool 格式声明工具名,网关自动代理调用。
技术实现与源码导航
完整源码已开源在 GitHub,欢迎 Star 和提交 Issue。
在具体实现上,选择了 Go + Angular 的技术栈:
后端(Go):
- 标准库
net/http实现 HTTP 服务,无外部 Web 框架依赖 sqlite存储 Provider 健康状态、记忆、审计日志- JSON 配置文件(
data/config.json)存储 Provider、路由、Key 等配置 - 插件式架构:Provider 适配器、Fastpath 匹配器、Agent 工具都可以独立扩展
- 编译为单个二进制,部署简单
前端(Angular):
- 管理后台覆盖 Provider 管理、路由配置、Key 签发、模型目录、额度查询、用量统计、可观测性、Tools/MCPs/Skills 管理、Sandbox/Memory 管理等全部功能
- 组件按
ts/、html/、css/分目录组织,模板与逻辑分离 - 响应式设计,支持桌面端使用
源码导航:
| 文件/目录 | 说明 |
|---|---|
cmd/server/main.go |
服务入口,加载配置、初始化各模块、启动 HTTP 服务 |
internal/proxy/proxy.go |
代理核心,请求鉴权、路由选择、failover、用量记录 |
internal/proxy/adapter/ |
上游协议适配器层,13 种协议,统一接口 + 流式转换 |
internal/router/router.go |
路由选择算法,支持 smart / failover / weighted 三种策略 |
internal/store/ |
配置存储与热加载,SQLite 记忆与健康状态持久化 |
internal/proxy/fastpath.go |
Fastpath 快路径匹配器(算术、统计、单位换算等) |
internal/proxy/agent.go |
网关内置 Agent,工具调用循环与多轮推理 |
internal/proxy/codegen.go |
Codegen 代码生成 fastpath |
internal/api/ |
Admin API(Key 管理、能力管理、模型目录、路由配置等) |
internal/skills/ |
Skills 技能包加载与注入(git submodule 管理) |
internal/mcp/ |
MCP 服务连接与工具代理(stdio/HTTP 传输、工具调用转发) |
internal/sandbox/ |
Docker 沙箱管理(容器生命周期、资源限制、安全隔离) |
web/src/app/ |
Angular 前端,管理后台全部页面(按 ts/html/css 分目录组织) |
部署与运维
Docker 容器化部署
tsm-hub 提供完整的 Docker 容器化部署方案,采用多阶段构建,镜像仅包含 Go 二进制和运行时依赖,体积小、启动快。
快速启动:
make docker-up # 自动构建前端 + 镜像,后台启动容器
启动后访问 http://localhost:9070 即可进入管理台。
Makefile 运维命令:
| 命令 | 说明 |
|---|---|
make docker-build |
构建 Docker 镜像(自动先构建前端) |
make docker-up |
构建并启动容器(后台运行,挂载 ./data) |
make docker-down |
停止并删除容器(保留 ./data 数据) |
make docker-stop |
停止容器(不删除,可恢复) |
make docker-start |
启动已停止的容器 |
make docker-restart |
重启容器 |
make docker-logs |
跟踪容器日志 |
make docker-status |
查看容器状态 + 健康检查 |
数据持久化
容器通过卷挂载 ./data:/data 持久化所有数据,包括配置文件、用量日志、会话记忆、审计日志等。容器删除和重建不会丢失数据,只需保持 ./data 目录完整。
配置方式
支持四种配置方式,优先级从高到低:
- 命令行 flag:如
-addr :9070、-admin-token xxx - 系统环境变量:如
TSM_HUB_ADDR=:9070 - .env 文件:项目根目录的
.env文件(docker compose 自动加载) - config.json:挂载的
./data/config.json配置文件
智能路由策略可通过环境变量配置:
TSM_HUB_SMART_STRATEGY=stability_first # cost_first / stability_first / task_aware / balanced
TSM_HUB_SMART_COST_WEIGHT=40
TSM_HUB_SMART_STABILITY_WEIGHT=100
TSM_HUB_SMART_LATENCY_WEIGHT=60
健康检查与高可用
- 健康检查端点:
GET /healthz,返回所有 provider 健康状态、请求数、运行时间 - docker compose healthcheck:每 30s 自动检查,异常时自动标记
- 配置热加载:
config.json变更后自动热重载(fsnotify),无需重启容器 - 故障自动转移:某 provider 故障或限流时,自动 failover 到其他健康 provider
安全设计
- 容器以非 root 用户运行,遵循最小权限原则
- Admin Token 建议通过环境变量注入,不写入配置文件
- 生产环境建议启用 TLS 或前置反向代理(Nginx / Caddy)
- 所有管理操作自动记录审计日志,可追溯
tsm-hub 和普通的 LLM 代理(如 one-api、new-api)有什么区别?
tsm-hub 不仅做路由和鉴权,还内置了能力池(Tools/MCPs/Skills)、Fastpath 快路径、Codegen、Sandbox 沙箱、Memory 记忆等网关侧能力。调用方不需要自己实现工具调用循环、不需要自己管理技能包、不需要自己处理算术等确定性问题,网关全部搞定。同时支持 13 种上游协议适配器,不局限于 OpenAI 兼容协议。
多模型池是如何统一管理和路由的?
每个 Provider 配置自己的 API Key 和模型列表,网关定期探测各模型的健康状态和成功率。采用可配置的多维度智能调度策略(smart),支持 cost_first / stability_first / task_aware / balanced 四种模式,各维度权重可单独调整。对于没有显式路由表的模型,网关自动扫描所有支持该模型的 Provider,按配置的策略模式综合评分后智能选择最优上游。用户也可以自由配置显式路由表,为特定模型或路由别名定义一组 target 和优先级,选择 failover 或 weighted 等自定义策略。同时支持带 tools 的请求自动过滤不支持 tool_calls 的模型。配置方式支持 config.json、环境变量(TSM_HUB_SMART_*)或 .env 文件。
调用方如何使用网关的 Tools/MCPs/Skills 能力?外部能力如何发现和录用?
有两种使用方式:一是调用方不传 tools,网关自动启用内置 Agent,附加工具池并在服务端执行工具调用循环;二是调用方通过 skill-run 等工具显式调用技能。对于有自己 Agent 流水线的客户端,可以在 Key 配置中关闭网关 Agent,直接透传到上游模型。
网关会自动发现和统计调用方声明的外部能力,按命名约定分类(普通工具名→Tools、skill: 前缀→Skills、MCP 风格→MCPs),展示调用次数和使用方数量,管理员可以根据实际需求择优录用。录用时选择实现方式(仅记录标记 / HTTP 调用 / MCP 工具 / 内置实现),其中 MCP 工具可能需要手动配置连接参数。这个机制的核心价值在于能力的发现和统计,晋升需要人工审核和配置。
Fastpath 快路径会不会误匹配正常的对话请求?
Fastpath 快路径是可选的加速功能,适用于明确的算术、统计、单位换算等确定性查询。为了降低误匹配风险,设计了三层防护机制:任务型关键词黑名单、全局长度限制、查询型关键词白名单。三层防护的设计原则是”宁漏勿错”——对于不确定的请求,保守地转发给 LLM 处理。Fastpath 命中时延迟从几秒降到几毫秒,且不消耗 LLM 额度;用户可以根据业务场景选择开启或关闭。
新增一个上游 Provider 或能力需要做多少工作?tsm-hub 适合生产环境吗?
新增 Provider 方面,如果是 OpenAI 兼容协议,只需要在配置文件中添加 Provider 条目(name、base_url、api_key、models),无需改代码。如果是非 OpenAI 兼容协议(如 Gemini、Bedrock),需要实现一个 Provider 适配器,通常几百行代码即可。新增能力方面,外部 Tools/MCPs/Skills 可以通过发现机制自动录入,管理员择优录用即可。
生产环境方面,tsm-hub 目前已用于实际项目,并持续迭代,核心功能经过实际验证:自制 Key 鉴权与配额管理、多 Provider 智能路由与自动 failover、全链路用量统计与成本核算、TLS 传输加密与 CORS 安全控制、完整的审计日志与操作追溯。编译为单个二进制文件,部署和运维简单,适合中小团队快速搭建统一的 LLM 接入与能力平台。架构设计上预留了扩展空间,可根据业务增长逐步演进到多实例部署。
发表回复