Files
codex-proxy-rs/docs/architecture.md
T
2026-07-25 03:26:18 +08:00

11 KiB
Raw Blame History

Codex Proxy RS 架构

本文是仓库唯一架构文档,只描述当前架构。

1. 系统边界

Codex Proxy RS 是单进程、可多副本部署的多 Provider AI 网关:

  • 客户端面提供 OpenAI Responses 兼容的 JSON、SSE、WebSocket 与模型目录协议。
  • 管理面提供 /api/admin/* 和 Vue 静态管理端。
  • 当前 Provider 为 OpenAI 与 xAI;账号 credential 均由所属 Provider 独占解释。
  • OpenAI 行为以重构前正式实现为语义基准;xAI/Grok 行为以 grok2api 验证结果为基准。
  • 两个 Provider 的请求画像都由启动配置提供基线,并通过进程级共享状态向每次新请求发布一致快照。OpenAI CLI、OpenAI Desktop 与 xAI CLI 的官方版本检查会分别原子更新自己负责的版本字段。
  • OpenAI CLI 使用官方 npm 包 @openai/codex,OpenAI Desktop 使用官方 appcast,xAI CLI 使用官方 npm 包 @xai-official/grok。检查失败保留上一份成功画像;检查成功后 OAuth、catalog、quota/billing、inference 与 Dashboard 自动采用最新版本。
  • PostgreSQL 是业务与配置事实的唯一权威存储。
  • Redis 只保存可丢失、可重建或有自然过期时间的协调状态。

Gateway Engine 不识别具体 Provider 协议;Provider 不拥有客户端 admission、跨 Provider 路由或业务重试预算。

2. Workspace 与依赖方向

backend/
├── apps/gateway/               composition root、HTTP server、后台任务
├── crates/gateway-core/        operation、routing、engine、policy、accounting
├── crates/gateway-protocol/    可共享 wire contract 与 canonical event
├── crates/gateway-admin/       管理领域、用例与抽象端口
├── crates/gateway-store/       PostgreSQL、Redis adapter
├── crates/gateway-api/         OpenAI Responses 与 Admin HTTP adapter
├── crates/gateway-host/        host/update/system 能力
├── crates/providers/openai/    OpenAI credential、catalog、transport
├── crates/providers/xai/       xAI/Grok credential、catalog、transport
└── migrations/0001_initial.sql 唯一终态初始迁移

依赖规则:

  • gateway-core 不依赖 HTTP、数据库、Redis 或具体 Provider。
  • gateway-protocol 不依赖其他 workspace crate。
  • Provider crate 之间禁止互相依赖。
  • gateway-api 只面向 Admin/Core/Protocol 抽象,不导入具体 Provider。
  • gateway-store 实现 Admin/Core 端口,但不拥有业务策略。
  • 只有 apps/gateway 组合具体实现。

各 crate 的 architecture 测试强制验证 crate 集合、依赖 DAG、生产源码边界与测试树。

3. 请求执行链

API decode/auth
  -> freeze RuntimeSnapshot
  -> compile RoutePlan
  -> admission
  -> persist model_request
  -> select Provider/account
  -> persist attempt facts in model_request
  -> cross upstream send barrier
  -> canonical stream
  -> persist downstream delivery barrier
  -> terminal observation and accounting

核心不变量:

  1. 每个客户端请求只有一条 model_requests;attempt 明细保存在其 JSON 事实中,不另建 attempt 表。
  2. 任何可能到达上游的调用都必须先有持久请求事实。
  3. not_sent、sent、ambiguous 是不同的上游发送边界;ambiguous 不自动重放。
  4. downstream_committed_at 表示网关已作出不可撤回的交付承诺,从该时刻禁止 retry/fallback;它在实际首字节写出前持久化,不宣称字节已经到达客户端。
  5. Provider 每次 execute 只能选择一个 credential 并准备一个 cold stream,不得隐藏换号或业务 retry。
  6. 下游 commit 前,Core 可按冻结策略处理同一 Provider 内的账号 fallback;禁止跨 Provider fallback。
  7. 本架构不通过隐式连接复用承载业务身份。HTTP client 可安全复用 transport 连接,但账号、credential revision、cookie/session binding 必须显式绑定到本次调用。

4. 路由、fallback 与错误处理

RuntimeSnapshot 冻结 Provider 集合、模型能力、运行时策略和全局 config_revision。一次请求始终使用同一快照,不在执行中拼接新旧配置。

Fallback 只允许在同一 Provider 内更换可用账号,不跨 Provider。

明确的上游认证、封禁、额度或 cooldown 错误会更新对应账号状态,使下一次选择排除该账号;满足重放安全条件且尚未 downstream commit 时,可以换号。传输结果不明确时不得假定请求未到达上游。

重试矩阵属于独立策略,本次终态迁移保持 OpenAI 原正式行为与 xAI 参考行为,不在 Provider transport 内增加额外重试。

5. Continuation

系统只保存已被上游确认的安全外部 ID:model_requests.upstream_response_id,不新增 conversation、transcript、continuation 或 claim 表。

  • store=true:使用 Provider 持久化的 native handle。
  • store=false:opaque replay state 仅存在于活连接内,不落 PostgreSQL。
  • OpenAI continuation 顺序为 native、replay owner、replay any。
  • xAI 使用客户端提交的完整历史作为已验证 continuation 路径。
  • continuation 失败仍受 send barrier、downstream commit 和 Provider kind 边界约束。

6. Provider 与 credential owner

Provider 接收 canonical Operation + ProviderCandidate + AttemptContext,返回携带冻结 metadata 的 canonical cold stream。Registry 使用稳定 ProviderKind 查找实现。

Provider 独占以下职责:

  • credential 文档的编码、解码与校验;
  • OAuth 登录、导入、刷新与轮换;
  • 账号选择所需的 Provider 私有事实;
  • catalog 查询与能力编译;
  • HTTP/WebSocket transport 和错误分类;
  • quota 投影与 Provider 私有观测字段。

credential 更新使用 credential_revision CAS。认证永久失败、封禁、额度耗尽和带截止时间的 cooldown 是账号运行时事实。cooldown 到期后,Core 的有效调度谓词会自然允许账号重新参与选择;Redis cooldown 只是热缓存。成功调用后才可把账号状态重新观测为 ready。

refresh_token_expires_at 不是公共 SQL 列或 Core 权威状态。xAI 可在 provider_credentials_json 内保存它作为 Provider 私有提示;真正失效以 refresh endpoint 返回的永久错误为准。

7. 控制面与 revision

管理写入使用 expected_config_revision 做全局乐观并发控制。会改变调度快照或安全配置的写入,必须在同一 PostgreSQL 事务中:

  • 校验 expected revision;
  • 执行业务 mutation;
  • 推进 runtime_settings.config_revision;
  • 写入脱敏 admin_audit_events。

推进全局 revision 的 mutation 包括 runtime settings、客户端 Key、账号导入/创建/删除、管理员显式启停和管理员 credential rotation。

不推进全局 revision 的运行时观测包括 quota、cooldown、catalog generation、请求统计以及自动 credential refresh;自动 refresh 只推进 credential_revision。提交后 Redis 通知只负责缩短其他副本的收敛延迟,周期性 PostgreSQL 对账才是正确性基础。

8. PostgreSQL 终态

backend/migrations/0001_initial.sql 创建且只创建七张业务表:

表 权威事实
admin_users 管理员身份与密码摘要
admin_audit_events 管理 mutation 审计
client_api_keys 客户端鉴权、限额与授权范围
runtime_settings 全局配置与 config_revision
provider_accounts 账号资料、Provider-owned 明文 credential JSON、revision、quota、cooldown
model_requests 请求、attempt、计费、交付与恢复事实
ops_events 脱敏运行事件

设计规则:

  • 一个事实只存一次;可表达关系使用真实 FK 与支持索引。
  • Provider 差异只进入受 schema/version 校验的 JSONB 边界。
  • credential JSON 以 Provider 自己的 schema 明文保存在 provider_credentials_json;日志、Debug、API 和 audit 不输出其中的 secret,Provider 只在需要发往上游时把值包装为运行时 secret。
  • stale recovery 只把超时 running 请求收敛为 incomplete,不重放业务请求。
  • ops_events 当前逐条同步持久化,occurrence_count=1;OpsFlush 可禁用,不存在隐藏内存聚合权威。
  • retention 只删除已满足保留规则的历史事实,不改变运行中请求。

业务 schema 由唯一初始迁移 0001_initial.sql 定义。

9. Redis 终态

Redis 保存 admission、lease、circuit/cooldown 热状态、OAuth pending flow 与 runtime change 通知。Redis 丢失后必须从 PostgreSQL 或 Provider 事实恢复;恢复完成前需要保护的 acquire 路径 fail closed。

OAuth pending key:

codex-proxy-rs:oauth-pending:v1:{provider_kind}:{flow_fingerprint}
flow_fingerprint = SHA-256(provider_kind || 0x00 || raw_flow_binding)

Hash 字段恰好为:

  • owner_fingerprint
  • expires_at_epoch_seconds
  • provider_payload

create/take 使用 Lua 原子执行。owner mismatch 不删除记录;匹配 owner 的 take 返回 payload 并一次性删除。OpenAI TTL 为 10 分钟,xAI TTL 为 30 分钟。

10. 后台任务与恢复

后台任务由 Provider bundle 和 host bundle 显式贡献,bootstrap 统一启动:

  • RuntimeSnapshot revision 对账与 Redis change wake-up;
  • credential refresh、catalog、quota 等 Provider worker;
  • stale execution recovery;
  • retention 与必要的 Redis 热状态重建;
  • host update/system worker。

worker 不得通过导入 Admin use case 绕过边界,也不得维护第二份业务状态。

11. 测试与验收

  • 生产 src 禁止 #[cfg(test)]、#[path] 和 include! 测试挂载。
  • 测试位于各 package 的 tests/,目录镜像生产模块。
  • Core 规则使用确定性测试;Provider 使用 contract/fixture 测试。
  • FK、CAS、revision、recovery 使用真实 PostgreSQL 测试。
  • admission、lease、cooldown、OAuth pending 使用真实 Redis 测试。
  • 真实账号测试只从仓库外部文件读取,不打印、复制或提交凭证。

真实对话测试是显式 ignored 的生产边界测试,必须依次穿过 Provider 导入/必要刷新、实时 catalog、账号 selector、生产 HTTP/SSE transport、canonical 解码、usage 与 completed 终态。xAI 用例允许 OAuth refresh token 轮换,因此必须额外显式授权:

CODEX_REAL_ACCOUNT_FIXTURE=/outside/cpr-accounts.json \
  cargo test -p provider-openai --test main \
  admin::real_openai_conversation_crosses_production_provider_boundaries \
  -- --ignored --exact

XAI_REAL_ACCOUNT_FIXTURE=/outside/grok-accounts.json \
XAI_ALLOW_DESTRUCTIVE_FIXTURE_REFRESH=1 \
  cargo test -p provider-xai --test main \
  admin::real_xai_conversation_crosses_production_provider_boundaries \
  -- --ignored --exact

终态门禁:

cd backend
cargo fmt --all -- --check
cargo test --workspace --all-targets