9Router 架构深度解析:本地 AI 路由网关的 API 兼容层、翻译核心与容错回退设计

发布时间:2026/9/10 22:23:19
9Router 架构深度解析:本地 AI 路由网关的 API 兼容层、翻译核心与容错回退设计 9Router 架构深度解析本地 AI 路由网关的 API 兼容层、翻译核心与容错回退设计【免费下载链接】9routerUnlimited FREE AI coding. Connect Claude Code, Codex, Cursor, Cline, Copilot, Antigravity to FREE Claude/GPT/Gemini via 40 providers. Auto-fallback, RTK -40% tokens, never hit limits.项目地址: https://gitcode.com/GitHub_Trending/9r/9router9Router 是一个基于 Next.js 的本地 AI 路由网关与可视化面板对外暴露统一的 OpenAI 兼容端点/v1/*在内部完成上游提供商调度、多格式请求/响应翻译、模型组合与账户级回退、令牌刷新与用量统计。本文以仓库 docs/ARCHITECTURE.md 为骨架结合 src/sse/handlers/chat.js、open-sse/handlers/chatCore.js、open-sse/services/accountFallback.js 等源码完整还原其分层架构、请求生命周期、数据模型与故障韧性设计帮助读者理解一个本地进程如何把 Claude Code / Codex CLI / Cursor 等客户端路由到数十种上游 AI 服务的完整机制。系统定位与核心能力9Router 的运行模型非常清晰Next.js 应用路由同时承载面板管理 API 与兼容 API一个共享的 SSE/路由核心负责提供商执行、翻译、流式转发、回退与用量统计。核心能力包括面向 CLI/工具的 OpenAI 兼容 API 表面/v1/*跨提供商格式的请求/响应翻译模型 Combo 回退多模型序列账户级回退同提供商多账户OAuth 与 API Key 两种提供商连接管理提供商、密钥、别名、Combo、设置、定价的本地持久化用量/成本追踪与请求日志可选的云端同步支撑多设备状态同步。范围边界本仓库涵盖本地网关运行时、面板管理 API、提供商鉴权与令牌刷新、请求翻译与 SSE 流式转发、本地状态与用量持久化、云端同步编排而NEXT_PUBLIC_CLOUD_URL背后的云端服务实现、本地进程之外的提供商控制面以及 Claude CLI、Codex CLI 等外部 CLI 二进制本身均不在本仓库范围内。高层系统上下文从整体数据流看对应 docs/ARCHITECTURE.md 中的 mermaid 图客户端侧Claude Code、Codex CLI、OpenClaw/Droid/Cline/Continue/Roo 等工具以及任意 OpenAI 兼容客户端全部接入/v1/*浏览器面板接入/api/*管理 API。9Router 本地进程/v1/*兼容 API 与/api/*面板 API 汇入 SSE 翻译核心open-ssesrc/sse状态写入db.json用量写入usage.json与log.txt。上游提供商三类——OAuth 类Claude/Codex/Gemini/Qwen/iFlow/GitHub/Kiro/Cursor/Antigravity、API Key 类OpenAI/Anthropic/OpenRouter/GLM/Kimi/MiniMax、兼容节点类OpenAI 兼容 / Anthropic 兼容的自建端点。可选云端通过NEXT_PUBLIC_CLOUD_URL指向的云端同步端点完成多设备同步。这一上下文说明了一个关键设计所有客户端看到的都是单一本地端点所有上游差异都被收敛在翻译核心内部这正是路由网关的核心价值。分层架构从 API 路由到持久化1) API 与路由层Next.js App Routes兼容 API 与管理 API 都实现在 Next.js App Router 下兼容 APIsrc/app/api/v1/*、src/app/api/v1beta/*管理/配置 APIsrc/app/api/*路由重写next.config.mjs中的 rewrites 把/v1/*映射到/api/v1/*。从 next.config.mjs 可以看到完整的重写表除了/v1/:path*外还处理了/v1/v1/:path*防止客户端重复拼接前缀、/codex/:path*与/responses映射到/api/v1/responses、/v1beta/:path*等。这意味着 Codex CLI 等以/responses为根路径的客户端也可以直接指向本网关。关键兼容路由可在src/app/api/v1/下找到对应route.jssrc/app/api/v1/chat/completions/route.jsOpenAI Chat Completionssrc/app/api/v1/messages/route.jsClaude Messagessrc/app/api/v1/responses/route.jsOpenAI Responses APIsrc/app/api/v1/models/route.js与src/app/api/v1beta/models/route.js、src/app/api/v1beta/models/[...path]/route.js模型列表与路径化查询src/app/api/v1/messages/count_tokens/route.js令牌计数。管理域则按领域划分鉴权与设置src/app/api/auth/*、src/app/api/settings/*、提供商与连接src/app/api/providers*、自定义兼容节点src/app/api/provider-nodes*、OAuthsrc/app/api/oauth/*、密钥/别名/Combo/定价src/app/api/keys*、src/app/api/models/alias、src/app/api/combos*、src/app/api/pricing、用量src/app/api/usage/*、同步/云端src/app/api/sync/*、src/app/api/cloud/*、CLI 工具辅助src/app/api/cli-tools/*。2) SSE 翻译核心这是网关的心脏主流程模块入口src/sse/handlers/chat.js核心编排open-sse/handlers/chatCore.js提供商执行适配器open-sse/executors/*格式检测与提供商配置open-sse/services/provider.js模型解析与解析src/sse/services/model.js、open-sse/services/model.js账户回退逻辑open-sse/services/accountFallback.js翻译注册表open-sse/translator/index.js流转换open-sse/utils/stream.js、open-sse/utils/streamHandler.js用量提取与归一化open-sse/utils/usageTracking.js。3) 持久化层主状态库src/lib/localDb.js注意当前它已退化为 shim实际实现重导出自src/lib/db/下的 SQLite 层物理文件为${DATA_DIR}/db.json未设置DATA_DIR时回退到~/.9router/db.json实体包括 providerConnections、providerNodes、modelAliases、combos、apiKeys、settings、pricing用量库src/lib/usageDb.js文件为~/.9router/usage.json、~/.9router/log.txt目前独立于DATA_DIR。4) 鉴权与安全面面板 Cookie 鉴权src/proxy.js、src/app/api/auth/login/route.jsAPI Key 生成与校验src/shared/utils/apiKey.js提供商密钥持久化在 providerConnections 条目中上游代理支持通过环境代理变量见 open-sse/utils/proxyFetch.js。5) 云端同步调度器初始化src/lib/initCloudSync.js、src/shared/services/initializeCloudSync.js周期任务src/shared/services/cloudSyncScheduler.js控制路由src/app/api/sync/cloud/route.js。请求生命周期/v1/chat/completions一次完整往返以POST /v1/chat/completions为例时序图见 docs/ARCHITECTURE.md完整链路为客户端 POST 到/v1/chat/completionsrewrite 落到src/app/api/v1/chat/completions/route.js路由调用 src/sse/handlers/chat.js 的handleChat(request)handleChat解析/解析模型字符串getModelInfo/getComboModels——如果是 Combo 名称则进入handleComboChat/handleFusionChat逐模型迭代通过getProviderCredentials(provider)选择账户与令牌进入open-sse/handlers/chatCore.js的handleChatCore(body, modelInfo, credentials)核心内部检测源格式 → 翻译为目标格式 → 调用executor.execute(provider, transformedBody)发起上游请求收到 SSE/JSON 响应后按需处理 401/403refreshCredentials()刷新后重试把上游流翻译/归一化为客户端格式SSE 分块或 JSON 返回用量提取并持久化到 usageDb。从源码看open-sse/handlers/chatCore.js 中格式决策的优先级是sourceFormatOverride如 openai-responses→detectFormat(body)检测源格式 →getModelTargetFormat(alias, model)取目标格式 → 对多端点提供商用resolveTransport(provider, sourceFormat)选择零翻译的原生通道。同时核心会做一系列净化工作能力裁剪stripUnsupportedModalities移除模型不支持的图片/音频、远程图片预取prefetchRemoteImages、thinking 配置归一化、工具去重dedupeToolsClaude 客户端下消除内建工具与等价 MCP 工具的重复。一个值得注意的实现细节是native passthrough 通道当检测到客户端工具与提供商属于同一生态如 Claude Code → Claude时跳过全部翻译仅替换 model 与 Bearer实现无损直通见 open-sse/handlers/chatCore.js。令牌节省器Token Saver管线在最终 dispatch 之前chatCore 会依次应用一组可选的令牌节省器每个都可用请求头X-Token-Saver: off整体关闭见TOKEN_SAVER_HEADERRTK压缩 tool_result 内容compressMessagesHeadroom可选的外部代理压缩代理不可用时 fail-open 不阻塞请求并检测幻影节省outbound JSON 缩小不足 5% 时告警Caveman / Ponytail注入简洁风格或懒惰资深工程师风格 system promptrtk/caveman.js、rtk/ponytail.jsPXPIPE针对 Claude 格式请求压缩大图片上下文作为 dispatch 前的最后一环。这些能力均位于open-sse/rtk/目录体现了网关在省 token上的纵深设计。Combo 模型序列 账户回退永不因单点失败中断回退决策流程对应 docs/ARCHITECTURE.md 的流程图逻辑如下请求携带的模型字符串如果是 Combo 名则加载该 Combo 的模型序列string[] models否则走单模型路径逐个尝试模型解析 provider/model → 选择账户凭据无凭据则返回 provider unavailable执行失败时判断是否属于可回退错误fallback-eligible不是 → 直接返回错误是 → 给该账户标记不可用冷却cooldown尝试该提供商的下一个账户账户耗尽 → 若处于 Combo 中则尝试下一个模型全部耗尽 → 返回 all unavailable。该决策由 open-sse/services/accountFallback.js 驱动依据状态码 错误消息启发式规则判断。错误分类规则的源码细节open-sse/config/errorConfig.js 定义了精确的规则表ERROR_RULES自上而下匹配文本规则优先于状态码规则规则类型匹配条件冷却/行为文本包含no credentials/improperly formed request2 分钟冷却文本包含request not allowed5 秒冷却文本包含rate limit/too many requests/quota exceeded/capacity/overloaded指数退避状态码401 / 402 / 403 / 4042 分钟冷却状态码429指数退避兜底其他未匹配错误30 秒瞬态冷却指数退避配置BACKOFF_CONFIG { base: 2000, max: 5min, maxLevel: 15 }即 2s → 4s → 8s … 封顶 5 分钟getQuotaCooldown实现见 open-sse/services/accountFallback.js。此外提供商自报的限流冷却如 codex 的resets_at可能长达 5-6 小时会被MAX_RATE_LIMIT_COOLDOWN_MS 30min硬性封顶避免账户长时间不可用。模型锁与账户锁accountFallback 还实现了模型级锁定通过连接记录上的扁平字段modelLock_${model}无模型时使用modelLock___all标记某个账户在指定模型上的冷却状态避免把刚被限流的模型立刻重新路由到同一账户。Combo 策略fallback 与 fusionsrc/sse/handlers/chat.js 显示 Combo 支持两种顶层策略fallback默认按顺序尝试模型序列前一个失败才进入下一个fusion将多个模型的结果做融合输出可选judgeModel裁判模型与fusionTuning调参实现见open-sse/services/combo.js。策略优先级为 Combo 专属配置comboStrategies[modelStr].fallbackStrategy 全局settings.comboStrategy并且支持comboStickyRoundRobinLimit粘性轮询阈值控制同一会话内对某模型的复用倾向。OAuth 接入与令牌刷新生命周期对应 docs/ARCHITECTURE.md 的时序图OAuth 类提供商Claude/Codex/Gemini/Qwen/iFlow/GitHub/Kiro/Cursor/Antigravity的接入流程为面板 UI 发起GET /api/oauth/[provider]/[action]authorize 或 device-code 流OAuth 路由在提供商鉴权服务器创建授权/设备流返回 auth URL 或设备码载荷UI 随后POST exchange或轮询完成令牌交换成功后createProviderConnection(oauth data)写入 localDb面板调用POST /api/providers/[id]/test验证凭据可触发一次刷新更新状态/令牌/错误信息。流量中的令牌刷新则在 open-sse/handlers/chatCore.js 内通过 executor 的refreshCredentials()完成401/403 时先刷新再重试无需用户介入。云端同步生命周期启用 / 同步 / 禁用对应 docs/ARCHITECTURE.md 的时序图enableUI 提交POST /api/sync/cloudactionenable→ 设置cloudEnabledtrue、确保 API Key 存在 →POST /sync/{machineId}上传 providers/aliases/combos/keys →GET /{machineId}/v1/verify校验 → 返回启用状态sync拉取远端数据将更新的本地令牌/状态写回 DBdisablecloudEnabledfalseDELETE /sync/{machineId}必要时把ANTHROPIC_BASE_URL切回本地。启用后由CloudSyncScheduler周期触发同步src/shared/services/cloudSyncScheduler.js。数据模型与存储映射对应 docs/ARCHITECTURE.md 的 ER 图核心实体包括SETTINGScloudEnabled、stickyRoundRobinLimit、requireLogin、password_hashPROVIDER_CONNECTIONid、provider、authType、name、priority、isActive、apiKey、accessToken、refreshToken、expiresAt、testStatus、lastError、rateLimitedUntil、providerSpecificDataJSONPROVIDER_NODE自定义兼容节点的id、type、name、prefix、apiType、baseUrlMODEL_ALIASalias→targetModelCOMBOid、name、models字符串数组API_KEYid、name、key、machineId、isActiveUSAGE_ENTRYprovider、model、prompt_tokens、completion_tokens、connectionId、timestamp。物理存储文件主状态${DATA_DIR}/db.json或~/.9router/db.json用量统计~/.9router/usage.json请求日志行~/.9router/log.txt可选的翻译/请求调试会话repo/logs/...需开启ENABLE_REQUEST_LOGStrue。从实现看当前主状态库已迁移到 SQLite 层src/lib/localDb.js 仅为兼容 shim重导出 src/lib/db/index.jspackage.json中better-sqlite3放在 optionalDependencies无构建工具的环境回退到sql.js这是部署健壮性的一个细节。部署拓扑对应 docs/ARCHITECTURE.md 的拓扑图开发者主机上的 CLI 工具与浏览器面板都指向 9Router 运行时Next.js 服务PORT20128SSE 核心与 executors 负责上游调用主库db.json与用量库usage.json/log.txt就近持久化外部只依赖 AI 提供商与可选的云端同步服务。注意 package.json 中dev/start默认端口为 20127文档验证清单使用PORT20128部署时以实际环境变量为准。模块映射决策关键路由与 API 模块src/app/api/v1/*、src/app/api/v1beta/*兼容 APIsrc/app/api/providers*提供商 CRUD、校验、测试src/app/api/provider-nodes*自定义兼容节点管理src/app/api/oauth/*OAuth/设备码流src/app/api/keys*本地 API Key 生命周期src/app/api/models/alias别名管理src/app/api/combos*回退 Combo 管理src/app/api/pricing成本计算用的定价覆盖src/app/api/usage/*用量与日志 APIsrc/app/api/sync/*src/app/api/cloud/*云端同步与云端辅助src/app/api/cli-tools/*本地 CLI 配置写入/检查。路由与执行核心src/sse/handlers/chat.js请求解析、Combo 处理、账户选择循环open-sse/handlers/chatCore.js翻译、executor 分发、重试/刷新、流建立open-sse/executors/*各提供商的网络与格式行为。翻译注册表与格式转换器open-sse/translator/index.js翻译注册表与编排register(from, to, requestFn, responseFn)注册制各格式模块以副作用导入方式自注册规避循环依赖请求翻译器open-sse/translator/request/*响应翻译器open-sse/translator/response/*格式常量open-sse/translator/formats.js。持久化src/lib/localDb.js持久化配置/状态shim →src/lib/db/src/lib/usageDb.js用量历史与滚动请求日志。提供商执行器覆盖专用 executor见 open-sse/executors/index.js覆盖antigravity、gemini-cli、github、kiro、codex、cursor此外还包含azure、iflow、qoder、vertex、qwen、opencode、grok-cli、grok-web、perplexity-web、ollama-local、commandcode、xiaomi-tokenplan、mimo-free、codebuddy-cn/intl、trae、zed、windsurf、devin-cli等并提供了便捷别名cu→cursor、gcli/gb→grok-cli、mmf→mimo-free。其余所有提供商含兼容节点统一走open-sse/executors/default.js通过getExecutor(provider)惰性实例化并缓存。格式翻译覆盖检测的源格式detectFormat/detectFormatByEndpoint依据请求载荷形态判定openai、openai-responses、claude、gemini。目标格式OpenAI chat/Responses、Claude、Gemini/Gemini-CLI/Antigravity envelope、Kiro、Cursor。翻译对from→to依据源载荷形态与提供商目标格式在运行时动态选择当客户端工具与提供商同生态时走 native passthrough 零翻译直通。失败模式与韧性设计1) 账户/提供商可用性对瞬态/限流/鉴权错误触发账户冷却请求失败前先做账户回退当前模型/提供商路径耗尽时做 Combo 模型回退。2) 令牌过期可刷新提供商在请求前预检并刷新失败重试核心路径中 401/403 在刷新尝试后重试。3) 流安全断线感知的流控制器createStreamController见 open-sse/handlers/chatCore.js翻译流带流结束 flush 与[DONE]处理提供商未返回用量元数据时使用用量估算回退。4) 云端同步降级同步错误会暴露但本地运行不受影响调度器具备可重试逻辑但周期执行默认单次尝试。5) 数据完整性DB 结构迁移/缺失键修复localDb 与 usageDb 的损坏 JSON 重置保护。可观测性与运维信号运行时可见性来源控制台日志src/sse/utils/logger.jsusage.json中的按请求用量聚合log.txt中的文本请求状态日志ENABLE_REQUEST_LOGStrue时logs/下的深度请求/翻译日志面板用量端点/api/usage/*供 UI 消费。安全敏感边界JWT_SECRET面板会话 Cookie 的签名/校验INITIAL_PASSWORD初始密码回退值默认123456真实部署必须修改API_KEY_SECRET本地 API Key 格式的 HMAC 密钥提供商密钥API Key/令牌持久化在本地 DB应在文件系统层面保护云端同步端点依赖 API Key 鉴权 machineId 语义。环境变量与运行时矩阵代码中实际使用的环境变量类别变量应用/鉴权JWT_SECRET、INITIAL_PASSWORD存储DATA_DIR安全哈希API_KEY_SECRET、MACHINE_ID_SALT日志ENABLE_REQUEST_LOGS同步/云端 URLNEXT_PUBLIC_BASE_URL、NEXT_PUBLIC_CLOUD_URL出站代理HTTP_PROXY、HTTPS_PROXY、ALL_PROXY、NO_PROXY及小写变体平台/运行时辅助APPDATA、NODE_ENV、PORT、HOSTNAME已知架构注意事项usageDb当前存于~/.9router不遵循DATA_DIR/api/v1/route.js返回静态模型列表并非/v1/models的主要模型来源请求日志开启后会写完整请求头/体logs/目录应按敏感数据对待云端行为依赖正确的NEXT_PUBLIC_BASE_URL与云端端点可达性。运维验证清单构建与启动命令中的路径按实际仓库位置替换npm run build # 从源码构建 docker build -t 9router . # 构建 Docker 镜像启动后验证curl http://host:20128/api/settings # 面板设置可用 curl http://host:20128/api/v1/models # 兼容模型列表可用CLI 工具的 base URL 应指向http://host:20128/v1当PORT20128时。完整的架构演进与历史变更可进一步查阅 CHANGELOG.md运行方式与容器化部署参考 DOCKER.md。综上9Router 的架构本质是一个兼容面 翻译核心 回退矩阵 本地持久化四层结构对外用最少的兼容端点覆盖最多客户端对内用翻译注册表吸收上游格式差异用账户冷却/模型锁/Combo 序列保证高可用用db.json/usage.json支撑离线可运行的本地优先体验——这是理解其所有功能特性的总纲。【免费下载链接】9routerUnlimited FREE AI coding. Connect Claude Code, Codex, Cursor, Cline, Copilot, Antigravity to FREE Claude/GPT/Gemini via 40 providers. Auto-fallback, RTK -40% tokens, never hit limits.项目地址: https://gitcode.com/GitHub_Trending/9r/9router创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考