AI API 多路复用调度转发网关 —— 严格优先级 · 渠道级熔断 · P2C 选路 · 自动回切
MuxAPI 是一个轻量的 AI API 中转调度网关。它把客户端请求按「分组 → 上游池」转发到多个上游中转平台,提供严格优先级调度、渠道级熔断、标准 P2C 选路、故障自动回切、跨协议翻译与 per-upstream 代理出口,并自带一个 Vue3 管理后台。
主流中转方案常见三个痛点:
- 优先级不严格:加权随机,做不到「A 活着就必走 A」;
- 不回切:高优先级上游恢复后不主动切回;
- 故障发现被动:靠请求失败才感知,恢复也被动。
MuxAPI 针对这三点设计:严格优先级、主动探测发现故障与恢复、上游恢复后自动回切。熔断按上游渠道统一管理,模型差异只记录为短期能力缓存。
- 多上游聚合:全局上游池 + 分组隔离,每个分组是独立调度池,拥有自己的上游成员与接入密钥
- 严格优先级:优先级数字越小越优先,绝不掺低优先级层
- 标准 P2C:同优先级层内按权重独立抽取 2 次,比较渠道 TTFT EWMA 与当前并发
- 渠道级熔断:不同模型的连接、鉴权、限流和上游错误共同计入同一渠道状态
- 模型能力缓存:明确的模型不存在只短期排除该模型与渠道组合,不影响渠道健康
- 统一探测:探测读取完整响应;流式响应必须出现完成事件,连续成功两次才恢复渠道
- per-upstream 代理出口:每个上游可单独配代理(
http/socks5),轻松接入墙外上游 - 协议翻译:按渠道配置使用内置转换关系连接 OpenAI Chat、OpenAI Responses、Claude Messages 与 Codex Responses;透传模式保持原请求不变
- 模型清单汇总:
/v1/models实时汇总分组内各上游模型并集,带缓存 - 接入密钥:客户端用接入密钥访问,按密钥路由到对应分组的上游池
- 监控看板:按上游主标签分区展示「渠道 + 模型」卡片,保留成功率、延迟与 24h 趋势;异常模型优先显示
- Webhook 告警:熔断状态翻转时推送 Webhook,带去抖防刷屏
- 请求审计:记录完整渠道尝试链、TTFT、总耗时、Token、流量、SSE 完成事件、上游 Request ID 与结构化错误来源,默认保留 7 天
- 请求分析:按时间、渠道、模型、结果、错误与请求 ID 筛选;区分直接成功、切换后成功和流中断,提供范围统计、按需详情及标准页码分页(默认每页 20 条)
- 上游计费采集:按渠道适配
sub2api/newapi,采集余额、计费分组与倍率;分组可设倍率上限,超限渠道自动退出调度 - 费用比对:以本地 LiteLLM 价目独立估算用量成本,与上游自报原价、实际扣费双轨核对,可选 1 小时 / 24 小时 / 7 天窗口
- Web 管理后台:分组、上游、密钥、监控、请求记录、运行时设置一站式管理;上游支持一个主标签和多个普通标签,以及搜索、组合筛选、分页、批量启停和批量打标签
比对分两条独立轨道,避免把「价目表不一致」误报成「上游多收」:
| 轨道 | 比较对象 | 告警含义 |
|---|---|---|
| 价目核对 | 本地 LiteLLM 估算 vs 上游自报原价 | 上游挂牌价明显高于公共行情(余额按虚标价扣) |
| 计费核对 | 实际扣费 vs 上游自报原价 × 倍率 | 上游没按自己声明的倍率计费 |
计费核对优先取上游自报原价作基准 —— 用上游自己的挂牌价算,结论不受本地价目表漂移影响。上游不提供原价时(如 newapi)降级用本地估算,界面会标注「基准:本地价目表(降级)」,此时结论可信度较低。
比对窗口默认 24 小时:单个采集间隔(10 分钟)样本量太小、噪声最大,且结论会被下一轮采集覆盖。窗口内倍率有调整只做标注,不再放弃比对。计费快照保留 30 天,每个上游保底留最近两条。
本地估算的用量口径:计入 success 与 partial(响应已提交后流中断,上游仍已生成并计费),canceled 默认不计入(上游断连后是否照收各家不同)。流在 usage 事件前断掉的尝试记为「用量不完整」,比对会标注而非按缺失的 token 定价。每次尝试的渠道协议随审计一起快照,事后改协议不会改变历史用量的缓存 token 口径。
五层解耦,策略可生长:
| 层 | 职责 |
|---|---|
| 接入层 Ingress | HTTP 入口、鉴权、客户端协议识别、模型清单汇总 |
| 调度层 Scheduler | 按分组选上游:严格优先级 → 同层 P2C 延迟感知选路 |
| 健康层 Health | 渠道级熔断器 + 模型能力缓存 + Webhook 告警 |
| 转发层 Forward | 按候选渠道翻译请求与响应、首事件前换源、渠道尝试链 |
| 监控层 Monitor | 唯一主动探测源:双写看板统计与路由熔断器 |
回切原理:每个请求都重新筛选健康上游并取最高优先级层。高优先级上游一旦被健康层探测判定恢复,下个请求立即重新被选中——failback 自然发生,无需额外逻辑。
流式切换边界:透传渠道以首个响应字节为界;翻译渠道以首个有效客户端事件为界。边界前发生连接错误、失败状态、翻译错误或超时,会排除当前渠道并尝试下一优先级。已经向客户端发送内容后不再换源,防止响应重复。
前端通过 Go embed 内嵌进二进制,构建顺序:先 build 前端,再 build 后端。
# 1. 构建前端(产物 web/dist 会被内嵌进后端二进制)
cd web && npm install && npm run build && cd ..
# 2. 构建后端(单文件,已含前端 + 管理后台)
go build -o muxapi ./cmd/muxapi
# 3. 运行(可选:复制 .env.example 为 .env 修改端口/token 等)
cp .env.example .env
./muxapi默认监听 :8080,启动前必须配置 PostgreSQL 连接串。浏览器打开 http://<地址>:<端口> 即管理后台,「设置」页会显示客户端接入地址。
应用启动时会按文件名顺序自动执行 database/migrations/ 中尚未应用的 PostgreSQL 迁移,并记录到 schema_migrations。
从旧 SQLite 数据库迁移配置:
export MUXAPI_DATABASE_URL='postgres://muxapi:password@127.0.0.1:5432/muxapi?sslmode=disable'
go run ./cmd/migrate-sqlite -source ./muxapi.db迁移工具会复制分组、渠道、成员关系、接入密钥、监控项与运行时设置;请求历史不迁移。
web/dist不存在时go build会因 embed 报错,务必先构建前端。开发模式(前端热更新):cd web && npm run dev。
Go 主程序与 PostgreSQL 驱动均无需 cgo;SQLite 驱动仅供旧数据迁移和单元测试:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o muxapi-linux-amd64 ./cmd/muxapi产出静态链接二进制,丢到目标机直接运行。
启动级配置通过环境变量,也可复制 .env.example 为 .env 写入(真实环境变量优先于 .env):
| 变量 | 默认 | 说明 |
|---|---|---|
MUXAPI_ADDR |
:8080 |
监听地址 |
MUXAPI_DATABASE_URL |
(必填) | PostgreSQL 连接串,建议连接本机加密隧道或私网地址 |
MUXAPI_TOKEN |
(空) | 管理后台鉴权 token,留空则后台无鉴权,切勿对外暴露 |
MUXAPI_FAIL_THRESHOLD |
3 |
连续失败多少次熔断 |
MUXAPI_COOLDOWN |
30s |
熔断冷却时长 |
MUXAPI_MAX_RETRIES |
3 |
单次下游请求最多尝试的上游数 |
探测参数已全部下放到各监控项(探测周期、端点、消息内容、max_tokens、是否流式逐项可配),不再用全局环境变量。
以下为运行时设置,在管理后台「设置」页配置(存库、即时生效):
| 设置 | 默认 | 说明 |
|---|---|---|
request_retention_days |
7 |
请求记录保留天数,每 10 分钟分批删除过期请求与尝试链 |
alert_webhook |
(空) | 熔断翻转告警 Webhook URL,留空关闭 |
alert_debounce |
60s |
告警去抖窗口,同键窗口内最多发一次 |
first_response_timeout_ms |
120000 |
上游首个响应或流中连续无数据的超时;每收到字节都会重新计时,超时后切换渠道或结束卡住的流,并立即熔断该渠道 |
| 端点 | 协议 |
|---|---|
POST /v1/chat/completions |
OpenAI |
POST /v1/responses |
OpenAI Responses(兼容 Codex CLI 等) |
POST /v1/messages |
Claude |
GET /v1/models |
汇总分组内各上游模型清单(OpenAI 兼容) |
GET /healthz |
健康检查 |
GET /admin/logs |
请求记录偏移量/游标分页与筛选 |
GET /admin/logs/stats |
当前筛选范围的成功率、延迟与 Token 统计 |
GET /admin/logs/options |
请求记录筛选项 |
GET /admin/logs/{id} |
单次请求及完整渠道尝试链 |
/admin/* |
管理 API(供后台调用) |
客户端用接入密钥访问(请求头 Authorization: Bearer <access-key> 或 x-api-key),MuxAPI 据此路由到对应分组的上游池并按渠道协议转发。
每个上游可在管理后台选择协议:
| 值 | 上游端点 |
|---|---|
passthrough |
保留客户端路径和协议,兼容现有渠道 |
openai |
/v1/chat/completions |
openai-response |
/v1/responses 标准协议 |
claude |
/v1/messages |
codex |
/v1/responses Codex 协议 |
协议转换使用本地固定的 CLIProxyAPI 翻译 SDK(源码快照 09da52ad,Go 依赖标识 v7.2.80),源码及 MIT 许可证位于 third_party/cliproxyapi/。渠道切换时始终从客户端原始请求重新翻译;协议不兼容不会计入渠道熔断。
- 后端:Go(标准库
net/http)+ PostgreSQL(pgx) - 前端:Vue 3 + Vite + Chart.js
- 生产环境务必设置
MUXAPI_TOKEN,否则管理后台无鉴权。 - PostgreSQL 连接应使用 TLS、私网或 SSH 隧道,禁止将应用账号直接暴露到公网。
- 数据库连接串、接入密钥和上游凭证不得提交到代码仓库。