Skip to content

[codex] add aggregate relay provider rotation#428

Open
kokotao wants to merge 3 commits into
BigPizzaV3:mainfrom
kokotao:codex/aggregate-relay-provider
Open

[codex] add aggregate relay provider rotation#428
kokotao wants to merge 3 commits into
BigPizzaV3:mainfrom
kokotao:codex/aggregate-relay-provider

Conversation

@kokotao
Copy link
Copy Markdown
Contributor

@kokotao kokotao commented May 30, 2026

Summary

  • Add aggregate relay provider settings, persistence, and active-provider handling.
  • Add frontend creation/editing flow for aggregate suppliers with member selection, strategy configuration, and validation messaging.
  • Route protocol proxy requests through aggregate rotation with failover, conversation, request, and weighted strategies, plus tests and implementation plan docs.

Validation

  • git diff --check && git diff --cached --check && cargo fmt --check
  • cargo test --workspace
  • npm run check && npm run vite:build in apps/codex-plus-manager
  • cargo clippy --workspace --all-targets --all-features exits 0; repository still has existing clippy warnings.

Notes

  • Release packaging was not run locally.
  • Untracked DeepSeek planning document is intentionally not included in this PR.

@BigPizzaV3
Copy link
Copy Markdown
Owner

怎么轮换的

@kokotao
Copy link
Copy Markdown
Contributor Author

kokotao commented May 30, 2026

这里的“轮换”是在本地协议代理层做的,不是在保存配置时把某个供应商一次性写死。

整体流程是:

  1. 用户在供应商配置页创建一个聚合供应商,relayMode = aggregate
  2. 聚合供应商只保存:
    • strategy
    • members[].relayId
    • members[].weight
  3. 切换到聚合供应商时,apply_relay_injection 不会把某个真实上游直接写进 Codex 配置,而是写一个本地 proxy provider。
  4. Codex 后续请求先打到本地 127.0.0.1:57321
  5. 本地代理在每次请求进入时,再根据当前策略动态选择一个成员供应商,把请求转发到该成员的真实 base_url + api_key
  6. 如果当前成员失败,并且后面还有候选成员,同一个请求里会继续 fallback 到下一个成员,不需要等下一次请求。
QQ_1780147767514 1780147677718

目前支持 4 种策略:

failover

默认固定使用当前成员。
只有请求失败或返回非 2xx 时,才推进到下一个成员。
适合主备场景。
conversationRoundRobin

按 conversation_id 分配成员。
某个对话第一次进入时分到一个成员,后续同一个对话会一直固定到这个成员。
适合希望同一会话上下文稳定落在同一上游的场景。
requestRoundRobin

每次请求都按顺序轮换。
例如 A -> B -> C -> A。
不区分对话。
weightedRoundRobin

按权重展开调度表。
例如 A=1、B=2、C=1,那么实际顺序是 A -> B -> B -> C,然后循环。
权重大意味着在轮转序列里出现次数更多。
补充几点实现细节:

聚合成员必须引用已有的普通 API 供应商,不能嵌套引用另一个聚合供应商。
成员必须有完整的 Base URL 和 API Key,否则选择阶段会直接报错,不会静默跳过。
/models 探测走的是 select_relay_for_probe,只查看当前应该使用哪个成员,不会推进 request round robin 的游标,避免“打开模型列表”影响真实请求轮换。
策略或成员列表变化后,内部 selector 会重建,不会继续沿用旧状态。
失败 fallback 是“同一个请求内”的,不是这次失败了等下一次请求再切。
相关实现位置:

轮转选择器:crates/codex-plus-core/src/relay_rotation.rs
请求代理与 fallback:crates/codex-plus-core/src/protocol_proxy.rs
聚合供应商切换到本地 proxy:apps/codex-plus-manager/src-tauri/src/commands.rs
配置模型与持久化:crates/codex-plus-core/src/settings.rs

流程图如下:

flowchart TD
    A["用户选择聚合供应商"] --> B["apply_relay_injection 写入本地 proxy provider"]
    B --> C["Codex 请求进入本地协议代理"]
    C --> D["select_relay_for_request 根据 strategy 选成员"]
    D --> E["转发到选中的成员供应商"]
    E --> F{"请求是否成功(2xx)?"}
    F -- "是" --> G["返回结果给 Codex"]
    F -- "否" --> H{"是否还有 fallback 成员?"}
    H -- "有" --> I["切到下一个成员继续尝试"]
    I --> E
    H -- "没有" --> J["返回错误: 未找到可用的聚合供应商成员"]

Loading

@BigPizzaV3
Copy link
Copy Markdown
Owner

太强了,稍等我看一下

@BigPizzaV3
Copy link
Copy Markdown
Owner

请解决一下冲突🙏

@kokotao kokotao force-pushed the codex/aggregate-relay-provider branch from 01a9c82 to 22b9ae0 Compare June 1, 2026 14:55
@kokotao kokotao force-pushed the codex/aggregate-relay-provider branch from 22b9ae0 to a60a653 Compare June 1, 2026 15:24
@kokotao
Copy link
Copy Markdown
Contributor Author

kokotao commented Jun 1, 2026

解决了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants