news 2026/9/10 22:23:13

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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/9router

9Router 是一个基于 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-sse+src/sse),状态写入db.json,用量写入usage.jsonlog.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 下:

  • 兼容 API:src/app/api/v1/*src/app/api/v1beta/*
  • 管理/配置 API:src/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.js):

  • src/app/api/v1/chat/completions/route.js:OpenAI Chat Completions;
  • src/app/api/v1/messages/route.js:Claude Messages;
  • src/app/api/v1/responses/route.js:OpenAI Responses API;
  • src/app/api/v1/models/route.jssrc/app/api/v1beta/models/route.jssrc/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*)、OAuth(src/app/api/oauth/*)、密钥/别名/Combo/定价(src/app/api/keys*src/app/api/models/aliassrc/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.jsopen-sse/services/model.js
  • 账户回退逻辑:open-sse/services/accountFallback.js
  • 翻译注册表:open-sse/translator/index.js
  • 流转换:open-sse/utils/stream.jsopen-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.jssrc/app/api/auth/login/route.js
  • API Key 生成与校验:src/shared/utils/apiKey.js
  • 提供商密钥持久化在 providerConnections 条目中;
  • 上游代理支持:通过环境代理变量(见 open-sse/utils/proxyFetch.js)。

5) 云端同步

  • 调度器初始化:src/lib/initCloudSync.jssrc/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),完整链路为:

  1. 客户端 POST 到/v1/chat/completions,rewrite 落到src/app/api/v1/chat/completions/route.js
  2. 路由调用 src/sse/handlers/chat.js 的handleChat(request)
  3. handleChat解析/解析模型字符串(getModelInfo/getComboModels)——如果是 Combo 名称则进入handleComboChat/handleFusionChat逐模型迭代;
  4. 通过getProviderCredentials(provider)选择账户与令牌;
  5. 进入open-sse/handlers/chatCore.jshandleChatCore(body, modelInfo, credentials)
  6. 核心内部:检测源格式 → 翻译为目标格式 → 调用executor.execute(provider, transformedBody)发起上游请求;
  7. 收到 SSE/JSON 响应后,按需处理 401/403(refreshCredentials()刷新后重试);
  8. 把上游流翻译/归一化为客户端格式,SSE 分块或 JSON 返回;
  9. 用量提取并持久化到 usageDb。

从源码看,open-sse/handlers/chatCore.js 中格式决策的优先级是:sourceFormatOverride(如 "openai-responses")→detectFormat(body)检测源格式 →getModelTargetFormat(alias, model)取目标格式 → 对多端点提供商用resolveTransport(provider, sourceFormat)选择零翻译的原生通道。同时核心会做一系列"净化"工作:能力裁剪(stripUnsupportedModalities移除模型不支持的图片/音频)、远程图片预取(prefetchRemoteImages)、thinking 配置归一化、工具去重(dedupeTools,Claude 客户端下消除内建工具与等价 MCP 工具的重复)。

一个值得注意的实现细节是native passthrough 通道:当检测到客户端工具与提供商属于同一生态(如 Claude Code → Claude)时,跳过全部翻译,仅替换 model 与 Bearer,实现无损直通(见 open-sse/handlers/chatCore.js)。

令牌节省器(Token Saver)管线

在最终 dispatch 之前,chatCore 会依次应用一组可选的令牌节省器(每个都可用请求头X-Token-Saver: off整体关闭,见TOKEN_SAVER_HEADER):

  • RTK:压缩 tool_result 内容(compressMessages);
  • Headroom:可选的外部代理压缩,代理不可用时 fail-open 不阻塞请求,并检测"幻影节省"(outbound JSON 缩小不足 5% 时告警);
  • Caveman / Ponytail:注入简洁风格或"懒惰资深工程师"风格 system prompt(rtk/caveman.jsrtk/ponytail.js);
  • PXPIPE:针对 Claude 格式请求压缩大图片上下文,作为 dispatch 前的最后一环。

这些能力均位于open-sse/rtk/目录,体现了网关在"省 token"上的纵深设计。

Combo 模型序列 + 账户回退:永不因单点失败中断

回退决策流程

对应 docs/ARCHITECTURE.md 的流程图,逻辑如下:

  1. 请求携带的模型字符串如果是 Combo 名,则加载该 Combo 的模型序列(string[] models),否则走单模型路径;
  2. 逐个尝试模型:解析 provider/model → 选择账户凭据;
  3. 无凭据则返回 provider unavailable;
  4. 执行失败时判断是否属于"可回退错误"(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 与 fusion

src/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)的接入流程为:

  1. 面板 UI 发起GET /api/oauth/[provider]/[action](authorize 或 device-code 流);
  2. OAuth 路由在提供商鉴权服务器创建授权/设备流,返回 auth URL 或设备码载荷;
  3. UI 随后POST exchange或轮询,完成令牌交换;
  4. 成功后createProviderConnection(oauth data)写入 localDb;
  5. 面板调用POST /api/providers/[id]/test验证凭据(可触发一次刷新),更新状态/令牌/错误信息。

流量中的令牌刷新则在 open-sse/handlers/chatCore.js 内通过 executor 的refreshCredentials()完成:401/403 时先刷新再重试,无需用户介入。

云端同步生命周期(启用 / 同步 / 禁用)

对应 docs/ARCHITECTURE.md 的时序图:

  • enable:UI 提交POST /api/sync/cloud(action=enable)→ 设置cloudEnabled=true、确保 API Key 存在 →POST /sync/{machineId}上传 providers/aliases/combos/keys →GET /{machineId}/v1/verify校验 → 返回启用状态;
  • sync:拉取远端数据,将更新的本地令牌/状态写回 DB;
  • disablecloudEnabled=falseDELETE /sync/{machineId},必要时把ANTHROPIC_BASE_URL切回本地。

启用后由CloudSyncScheduler周期触发同步(src/shared/services/cloudSyncScheduler.js)。

数据模型与存储映射

对应 docs/ARCHITECTURE.md 的 ER 图,核心实体包括:

  • SETTINGScloudEnabledstickyRoundRobinLimitrequireLoginpassword_hash
  • PROVIDER_CONNECTIONidproviderauthTypenamepriorityisActiveapiKeyaccessTokenrefreshTokenexpiresAttestStatuslastErrorrateLimitedUntilproviderSpecificData(JSON);
  • PROVIDER_NODE:自定义兼容节点的idtypenameprefixapiTypebaseUrl
  • MODEL_ALIASaliastargetModel
  • COMBOidnamemodels(字符串数组);
  • API_KEYidnamekeymachineIdisActive
  • USAGE_ENTRYprovidermodelprompt_tokenscompletion_tokensconnectionIdtimestamp

物理存储文件:

  • 主状态:${DATA_DIR}/db.json(或~/.9router/db.json);
  • 用量统计:~/.9router/usage.json
  • 请求日志行:~/.9router/log.txt
  • 可选的翻译/请求调试会话:<repo>/logs/...(需开启ENABLE_REQUEST_LOGS=true)。

从实现看,当前主状态库已迁移到 SQLite 层(src/lib/localDb.js 仅为兼容 shim,重导出 src/lib/db/index.js),package.jsonbetter-sqlite3放在 optionalDependencies(无构建工具的环境回退到sql.js),这是部署健壮性的一个细节。

部署拓扑

对应 docs/ARCHITECTURE.md 的拓扑图:开发者主机上的 CLI 工具与浏览器面板都指向 9Router 运行时(Next.js 服务,PORT=20128),SSE 核心与 executors 负责上游调用,主库db.json与用量库usage.json/log.txt就近持久化,外部只依赖 AI 提供商与可选的云端同步服务。注意 package.json 中dev/start默认端口为 20127,文档验证清单使用PORT=20128,部署时以实际环境变量为准。

模块映射(决策关键)

路由与 API 模块

  • src/app/api/v1/*src/app/api/v1beta/*:兼容 API;
  • src/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/*:用量与日志 API;
  • src/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)覆盖antigravitygemini-cligithubkirocodexcursor,此外还包含azureiflowqodervertexqwenopencodegrok-cligrok-webperplexity-webollama-localcommandcodexiaomi-tokenplanmimo-freecodebuddy-cn/intltraezedwindsurfdevin-cli等,并提供了便捷别名(cu→cursor、gcli/gb→grok-cli、mmf→mimo-free)。其余所有提供商(含兼容节点)统一走open-sse/executors/default.js,通过getExecutor(provider)惰性实例化并缓存。

格式翻译覆盖

检测的源格式(detectFormat/detectFormatByEndpoint依据请求载荷形态判定):openaiopenai-responsesclaudegemini。目标格式: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.js;
  • usage.json中的按请求用量聚合;
  • log.txt中的文本请求状态日志;
  • ENABLE_REQUEST_LOGS=truelogs/下的深度请求/翻译日志;
  • 面板用量端点/api/usage/*供 UI 消费。

安全敏感边界

  • JWT_SECRET:面板会话 Cookie 的签名/校验;
  • INITIAL_PASSWORD:初始密码回退值(默认123456,真实部署必须修改);
  • API_KEY_SECRET:本地 API Key 格式的 HMAC 密钥;
  • 提供商密钥(API Key/令牌)持久化在本地 DB,应在文件系统层面保护;
  • 云端同步端点依赖 API Key 鉴权 + machineId 语义。

环境变量与运行时矩阵

代码中实际使用的环境变量:

类别变量
应用/鉴权JWT_SECRETINITIAL_PASSWORD
存储DATA_DIR
安全哈希API_KEY_SECRETMACHINE_ID_SALT
日志ENABLE_REQUEST_LOGS
同步/云端 URLNEXT_PUBLIC_BASE_URLNEXT_PUBLIC_CLOUD_URL
出站代理HTTP_PROXYHTTPS_PROXYALL_PROXYNO_PROXY及小写变体
平台/运行时辅助APPDATANODE_ENVPORTHOSTNAME

已知架构注意事项

  1. usageDb当前存于~/.9router,不遵循DATA_DIR
  2. /api/v1/route.js返回静态模型列表,并非/v1/models的主要模型来源;
  3. 请求日志开启后会写完整请求头/体,logs/目录应按敏感数据对待;
  4. 云端行为依赖正确的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(当PORT=20128时)。完整的架构演进与历史变更可进一步查阅 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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 22:21:11

DAB变换器控制策略对比:PI与MPC在Simulink中的实现

1. 项目概述&#xff1a;DAB变换器的控制策略对比 在电力电子领域&#xff0c;双有源全桥(DAB)变换器因其功率密度高、电气隔离性好等优势&#xff0c;已成为中高功率DC/DC转换的首选拓扑。这次我们通过Simulink搭建仿真平台&#xff0c;对比传统PI控制与模型预测控制(MPC)在单…

作者头像 李华
网站建设 2026/9/10 22:19:10

在 agno 中使用 N1N 模型:OpenAI 兼容集成实战指南

在 agno 中使用 N1N 模型&#xff1a;OpenAI 兼容集成实战指南 【免费下载链接】agno Build, run, and manage agent platforms. 项目地址: https://gitcode.com/GitHub_Trending/ag/agno 导读 本文以 agno 仓库中 cookbook/90_models/n1n 的 cookbook 示例为核心&…

作者头像 李华
网站建设 2026/9/10 22:17:59

AI+Three.js快速开发3D网页游戏实战

1. 项目概述&#xff1a;AI辅助快速开发3D网页游戏这个项目展示了如何利用现代AI工具与传统Web 3D技术结合&#xff0c;在极短时间内完成一个完整的3D太空射击游戏开发。核心在于通过Cursor&#xff08;智能代码编辑器&#xff09;与Grok/Claude等AI助手的协同&#xff0c;配合…

作者头像 李华