# sub2api-cn-relay-manager 方案文档 日期:2026-05-12 ## 1. 背景 宿主 `sub2api` 是一个第三方开源系统,用户较多,迭代很快,且每周都会发布新版本。 当前目标不是修改宿主源码,也不是等待宿主内置原生插件运行时,而是建立一个完全独立交付的外部伴生项目,让任意一台已部署的 `sub2api` 都能通过安装该项目和导入模型包,快速具备国产模型 OpenAI 兼容中转能力。 ## 2. 目标 本方案必须满足以下业务目标: 1. 独立交付,不修改宿主 `sub2api` 源码 2. 可跨机器复用,在任意一台兼容版本的 `sub2api` 上重复安装 3. 可一键导入多个国产模型 key 4. 导入后让普通用户继续通过 `sub2api` 标准 API 使用国产模型 5. 尽量热生效,不依赖宿主重编译 6. 能主动发现“内容未真正生效”“生效后漂移”“部分账号失效” ## 3. 核心结论 在“不改宿主代码”的前提下,不能把该能力定义为“宿主原生插件”。 正确做法是: - 把这套能力定义为一个独立的外部伴生控制面项目 - 把国产模型接入定义为可安装的 `model_pack` - 由控制面调用宿主已有管理 API 自动创建 `group / channel / account / plan` - 由控制面维护安装状态、导入批次、探测结果和对账结果 因此,业务上它表现得像“独立安装插件”,但技术上它是“外部伴生安装器 + 模型资源包”。 ## 3.1 宿主零改动硬约束 为了确保方案始终满足“绝不改宿主代码”,补充以下硬约束: 1. 不修改宿主源码 2. 不 fork 宿主并运行自定义二进制 3. 不直接写宿主数据库 4. 不向宿主容器或宿主目录写入运行时代码或配置补丁 5. 不依赖宿主未公开的动态加载、初始化钩子或内部运行时对象 6. 只通过宿主现有 HTTP 管理 API 和宿主公开标准 API 工作 这意味着本方案的本质是: - 技术上:宿主外部自动化编排 - 业务上:像独立插件一样交付和安装 ## 3.2 审核后的最终结论 经过对宿主现有能力复核后,可以确认: - 该方案可以在零宿主代码改动前提下完成国产模型中转能力增加 - 该方案不能伪装成宿主原生插件中心 - 该方案必须把“访问闭环”和“对账闭环”都纳入首版 ## 4. 为什么这条路线成立 虽然宿主没有原生插件运行时,但它已有足够的管理 API: - 创建 group:`POST /api/v1/admin/groups` - 创建 account:`POST /api/v1/admin/accounts` - 批量创建 account:`POST /api/v1/admin/accounts/batch` - 测试 account:`POST /api/v1/admin/accounts/:id/test` - 查询 account 模型:`GET /api/v1/admin/accounts/:id/models` - 创建 channel:`POST /api/v1/admin/channels` - 创建 plan:`POST /api/v1/admin/plans` 这意味着控制面完全可以把 `sub2api` 当作一个可编排宿主,而不需要侵入其源码。 但这里有一个经过审核后必须写明的宿主约束: - 宿主标准 API 网关要求请求最终落到“已分组 API key”或“有效 subscription” - 仅仅创建 `group / channel / account / plan`,还不足以保证普通用户已经可以调用国产模型 因此,本方案不能只做资源创建,还必须补齐用户访问闭环。 ## 5. 总体架构 整体拆成两个发布物: ### 5.1 控制面 / 安装器 项目名: `sub2api-cn-relay-manager` 职责: - 连接宿主 `sub2api` - 安装 `model_pack` - 预检宿主版本与 API 能力 - 一键导入多个 key - 通过宿主管理 API 创建和维护资源 - 做 smoke test - 做持续对账 - 对外展示“可用 / 降级 / 漂移 / 失败”状态 ### 5.2 模型包 项目内置样例: `packs/openai-cn-pack/` 职责: - 提供 provider 定义 - 提供默认 group / channel / plan / account 模板 - 提供 model mapping 和 smoke test model - 提供导入策略和校验约束 模型包不携带宿主执行逻辑。 ## 6. 运行时组件 控制面内部建议拆成以下模块: ### 6.1 Host Adapter 宿主适配器,只负责把控制面操作翻译成 `sub2api` admin API 调用。 接口建议: - `GetHostVersion()` - `ProbeCapabilities()` - `CreateGroup()` - `CreateChannel()` - `CreatePlan()` - `CreateAccount()` - `BatchCreateAccounts()` - `TestAccount()` - `GetAccountModels()` - `AssignSubscription()` - `CheckAccessPath()` - `DeleteGroup()` - `DeleteChannel()` - `DeletePlan()` - `DeleteAccount()` - `ListManagedResources()` ### 6.2 Pack Runtime 负责读取和校验 `model_pack`: - `pack.json` - `providers/*.json` - `checksums.txt` ### 6.3 Provision Engine 负责把一个 provider + 一批 key 变成宿主真实资源: - 创建 group - 创建 channel - 创建 plan - 创建 account - 绑定 group / model mapping / pricing - 调用测试接口验证账号 ### 6.4 Reconciler 负责持续对账,主动发现: - 资源是否还存在 - key 是否仍可用 - 模型是否仍可列出 - 测试是否通过 - 宿主资源是否被人工改坏 ### 6.5 State Store 负责维护控制面自己的状态,因为宿主不知道“插件”概念。 ## 7. 模型包结构 建议结构: ```text openai-cn-pack/ pack.json providers/ deepseek.json kimi.json qwen.json glm.json minimax.json checksums.txt docs/ ``` ## 8. 模型包协议 ### 8.1 pack.json ```json { "pack_id": "openai-cn-pack", "version": "1.0.0", "vendor": "YourTeam", "target_host": "sub2api", "min_host_version": "0.1.126", "max_host_version": "0.2.x", "providers_dir": "providers", "checksum_file": "checksums.txt" } ``` ### 8.2 provider 定义 每个 provider 文件至少包含: - `provider_id` - `display_name` - `base_url` - `platform` - `account_type` - `default_models` - `smoke_test_model` - `group_template` - `channel_template` - `plan_template` - `import` 示例字段: ```json { "provider_id": "deepseek", "display_name": "DeepSeek OpenAI Compatible", "base_url": "https://api.deepseek.com", "platform": "openai", "account_type": "api", "default_models": ["deepseek-chat", "deepseek-reasoner"], "smoke_test_model": "deepseek-chat", "group_template": { "name": "DeepSeek 默认分组", "subscription_type": "subscription", "rate_multiplier": 1.0 }, "channel_template": { "name": "DeepSeek 默认渠道", "billing_model_source": "channel_mapped", "restrict_models": true, "model_mapping": { "deepseek-chat": "deepseek-chat", "deepseek-reasoner": "deepseek-reasoner" } }, "plan_template": { "name": "DeepSeek 默认套餐", "price": 19.9, "validity_days": 30, "for_sale": true }, "import": { "supports_multi_key": true, "supports_strict": true, "supports_partial": true } } ``` ## 9. 一键导入流程 ### 9.1 安装模型包 1. 上传 `openai-cn-pack.zip` 2. 控制面解压并校验 3. 读取 `pack.json` 4. 校验宿主版本兼容 5. 执行宿主 API 能力探测 6. 注册 provider 定义到控制面状态库 ### 9.2 导入多个 key 1. 管理员选择 provider 2. 粘贴多个 key 或上传 `txt / csv` 3. 选择导入模式: - `strict` - `partial` 4. 运行预检 5. 创建或复用 group 6. 创建或复用 channel 7. 创建或复用 plan 8. 批量创建 accounts 9. 逐个运行账号测试 10. 汇总结果并写入批次记录 ### 9.3 普通用户使用 导入完成后,普通用户继续使用宿主标准 API: - `/v1/chat/completions` - `/v1/responses` - 宿主已支持的其他 OpenAI 标准接口 控制面不接管用户流量,只负责把宿主配置成“可中转国产模型”。 ### 9.4 用户访问闭环 这是方案审核后新增的强制章节。 宿主网关不是只要存在上游 account 就能调用。 实际还需要满足以下至少一条: 1. 用户持有的 API key 已绑定到目标 group 2. 用户在目标 group 上拥有有效 subscription 否则,普通用户即使拿到宿主标准 API 地址,也不能真正使用国产模型。 因此控制面必须明确支持两种访问模式: #### 模式 A:Subscription 模式 适用场景: - SaaS 运营 - 后台给用户开通套餐 - 管理员按用户分配访问能力 控制面职责: - 创建 subscription 类型 group - 创建默认可售或可分配 plan - 调用宿主订阅分配接口,把 group 分配给目标用户 #### 模式 B:User Self-Service API Key 模式 适用场景: - 用户已经登录宿主后台 - 用户自己创建 API key - 用户自己把 key 绑定到控制面准备好的 group 控制面职责: - 负责准备好 group / channel / account / plan - 确保目标 group 对用户可见、可分配、可购买或可授权 #### 首版限制 在零宿主代码改动前提下,控制面不能把“管理员代用户签发最终 API key”作为首版硬依赖。 因此首版应优先保证: - subscription 模式闭环可用 - user self-service API key 模式可用 ## 10. 导入模式 ### 10.1 strict - 任一 key 创建失败或测试失败 - 整个批次回滚 - 适合正式生产导入 ### 10.2 partial - 成功的保留 - 失败的单独记录 - 适合大批量导入 ### 10.3 导入完成判定 经过审核,单纯“资源创建成功”不再视为导入完成。 导入完成至少需要满足: 1. 目标 group 存在 2. 目标 channel 存在并已绑定 group 3. 目标 plan 存在,若当前访问模式依赖 plan 4. 至少一个 account 创建成功 5. 至少一个 account smoke test 或模型探测通过 6. 至少一种用户访问模式已经被验证可用 不满足上述条件时,只能标记为: - `degraded` - `failed` ## 11. 数据模型 控制面至少需要以下表: ### 11.1 hosts - 宿主实例信息 - base_url - 宿主版本 - 最近能力探测结果 ### 11.2 packs - 模型包版本 - checksum - 安装时间 ### 11.3 providers - provider 元信息 - pack 归属 ### 11.4 provider_installs - 某台宿主安装了哪些 provider - 当前状态 ### 11.5 import_batches - 一次导入批次 - provider - 模式 - 请求条数 - 成功条数 - 失败条数 ### 11.6 managed_resources - 宿主侧 group/channel/plan/account 映射 - 宿主资源 ID - 控制面资源键 ### 11.7 reconcile_runs - 每次对账执行结果 ### 11.8 probe_results - 账号测试与模型探测结果 ## 12. 状态机 ### 12.1 provider 安装状态 - `discovered` - `validated` - `installed` - `active` - `degraded` - `drifted` - `failed` - `disabled` ### 12.2 导入批次状态 - `pending` - `running` - `succeeded` - `partially_succeeded` - `rolled_back` - `failed` ## 13. 热生效与重启建议 在本方案下,大多数操作应视为热生效: - 创建 group - 创建 channel - 创建 plan - 创建 account - 更新 model mapping - 导入多个 key 因为这些动作都是通过宿主已有 admin API 写入运行时资源。 因此默认策略是: - 成功写入宿主并通过测试 = 热生效 - 如果出现宿主缓存、运行时异常、版本兼容问题,控制面只给出 `restart_recommended` - 控制面可选支持宿主重启适配器,但不作为首版必需能力 审核补充: - `restart_recommended` 只是运维建议,不应成为主成功路径 - 只要核心能力依赖“必须重启宿主后才能导入成功”,就视为不满足首版目标 - 因此首版所有核心链路必须默认按热生效设计 ## 14. 主动发现未生效 控制面必须周期性对账,而不是只看“导入成功”。 检查项至少包括: 1. 记录中的 group 是否还存在 2. channel 是否还存在 3. plan 是否还存在 4. account 是否还存在 5. account 测试是否通过 6. account 模型列表是否仍可读取 7. provider 的关键模型是否能通过一次标准测试请求 8. 控制面记录与宿主实际资源是否一致 9. 至少一种用户访问模式仍然成立 对于第 9 条,控制面至少要检查一种访问路径: - subscription 模式下:目标用户对该 group 是否仍有有效 subscription - user self-service API key 模式下:是否存在已绑定目标 group 的有效用户 API key 样本 只要任一项不一致,就应标记: - `degraded` - `drifted` - `failed` ## 15. 外部 API 设计 控制面对外至少提供: ### 15.1 宿主管理 - `POST /api/hosts` - `GET /api/hosts` - `POST /api/hosts/:id/probe` ### 15.2 模型包管理 - `POST /api/packs/install` - `GET /api/packs` - `GET /api/packs/:id/providers` ### 15.3 provider 导入 - `POST /api/providers/:provider_id/preview-import` - `POST /api/providers/:provider_id/import` - `GET /api/providers/:provider_id/import-batches` - `POST /api/import-batches/:id/rollback` ### 15.4 访问闭环管理 - `POST /api/providers/:provider_id/access/preview` - `POST /api/providers/:provider_id/access/assign-subscriptions` - `GET /api/providers/:provider_id/access/status` 说明: - 首版优先支持 subscription 访问闭环 - 不把“管理员代用户创建最终 API key”作为首版必需能力 ### 15.5 对账与探测 - `POST /api/providers/:provider_id/reconcile` - `GET /api/providers/:provider_id/status` - `GET /api/providers/:provider_id/resources` ## 16. 首版 CLI 建议首版同时提供 CLI,降低自动化接入门槛: ```bash cnrelay host add --base-url https://your-sub2api --admin-token xxx cnrelay pack install ./openai-cn-pack.zip cnrelay provider import deepseek --keys-file deepseek.txt --mode partial --smoke-test cnrelay provider status deepseek cnrelay reconcile run ``` ## 17. 与宿主升级的兼容策略 由于宿主 `sub2api` 每周发布新版本,控制面必须内置兼容矩阵: 1. 安装前先探测宿主版本 2. 再跑一组能力探针: - groups create/list - accounts create/test/models - channels create/list - plans create/list - subscriptions assign/list - 至少一种用户访问闭环探测 3. 任何一项不满足,即阻断安装或阻断导入 4. 对宿主版本维护 `supported / warning / unsupported` 这样可以避免宿主快速迭代导致导入流程静默失效。 ## 18. MVP 范围 首版只支持: - 一个宿主适配器:`sub2api` - 一种包类型:`openai-cn-pack` - 5 个 provider 模板以内 - 多 key 导入 - strict / partial 两种模式 - account 测试与模型探测 - subscription 访问闭环 - 对账与漂移发现 首版不做: - 多宿主类型 - 在线插件市场 - 远程代码执行 - 宿主内嵌 UI - 宿主数据库直写 - 管理员代用户签发最终 API key ## 19. 验收标准 满足以下标准即视为方案落地成功: 1. 任意一台兼容版本的 `sub2api`,只通过控制面和模型包即可接入至少一个国产模型 provider 2. 支持一次导入多个 key,并得到逐 key 成功/失败结果 3. 导入成功后,至少一种用户访问模式已经被控制面验证可用 4. 普通用户继续通过 `sub2api` 标准 API 成功调用目标模型 5. 控制面可检测删除、失效、模型缺失、测试失败、访问闭环断裂等漂移 6. 宿主升级后,控制面能在导入前给出兼容性结论,而不是静默失败 ## 20. 下一步 建议下一步直接进入实现计划拆解,顺序如下: 1. 定义控制面状态库 schema 2. 实现 `sub2api` 宿主适配器 3. 实现 `model_pack` schema 校验器 4. 实现 provider 导入引擎 5. 实现对账器 6. 再补 CLI 和最小 Web UI