跳转到内容

架构总览

一个接收任意 LLM 协议请求、选出最优账号并转发到上游的代理中间层,用 Rust 从零构建。先建立全局认知,再按模块深入。

统一 LLM 账号、协议转换与代理转发服务——多上游账号统一管理、按模型和协议选择 runtime、请求可审计、账号隔离可控。

承诺 含义 技术体现
协议无关 不绑定任何特定 LLM 提供商协议 Canonical IR + Client/Upstream Adapter
账号隔离可控 User Token 绑定账号组,不能越界访问 SelectionScope + 组过滤 + fail closed
请求可审计 每次转发的完整链路可追溯 request_logs + token_stats + ProxyOutcome
  • 通用工作流平台(不是 n8n / Airflow)
  • 企业 RBAC 中心(不是 Keycloak / Auth0)
  • 任意协议网关(专注 LLM API)
  • 模型推理/训练服务

面试怎么聊:讲清楚“为什么不做成通用网关”——专注 LLM 协议意味着 Canonical IR 的语义层可以做得很薄,但又能精准建模 text/image/tool_call/thinking 等 LLM 特有概念。通用网关做不到这一点。

┌──────────────────────────────────────────────────────────────┐
│ API /v1/* /internal/* /api/* /health │
│ ↓ 客户端请求 │
├──────────────────────────────────────────────────────────────┤
│ Middleware 认证 / CORS / IP 过滤 / 日志 / 限流 │
├──────────────────────────────────────────────────────────────┤
│ Protocol Handler OpenAI Chat / Claude / Gemini / MCP │
│ ↓ 解码为 CanonicalRequest │
├──────────────────────────────────────────────────────────────┤
│ Routing model_mapping + RuntimeRegistry │
│ ↓ resolved_model + RuntimeKind │
├──────────────────────────────────────────────────────────────┤
│ ProxyOrchestrator 账号 scope 解析 → select_lease → 重试 │
├──────────────────────────────────────────────────────────────┤
│ Accounts 统一账号服务、选择、Lease、组隔离 │
├──────────────────────────────────────────────────────────────┤
│ Upstream Runtime ProviderRuntime 执行上游请求 │
├──────────────────────────────────────────────────────────────┤
│ Protocol Adapter encode_request / decode_stream_event │
├──────────────────────────────────────────────────────────────┤
│ Transport HTTP client pool / proxy pool │
├──────────────────────────────────────────────────────────────┤
│ DB PostgreSQL / SQLite │
└──────────────────────────────────────────────────────────────┘
Middleware → Handler → Routing → Orchestrator → Accounts/Selection
→ Upstream Runtime →
Transport → 上游服务

关键约束

  • Handler 不直接选账号;选账号走 Orchestrator → AccountService::select_lease
  • Runtime 不重新扫 DB 选账号;只消费 AccountLease
  • 跨账号重试在 Orchestrator 做,不在 Runtime 做
  • 协议转换集中在 protocol/,不走点对点硬编码
模块 路径 一句话职责
accounts src/accounts 账号域模型、账号选择、租约、组隔离
api src/api HTTP DTO、admin/v1 handler、错误响应
commands src/commands 服务启动、命令式操作 glue
db src/db 唯一持久化层,仅此处 SQL
integrations src/integrations 系统进程、cloudflared、CLI 同步、更新检测
locales src/locales 多语言资源文件
log src/log tracing 初始化、日志桥接、敏感信息脱敏
models src/models 跨层 DTO、配置、token、quota 数据结构
observability src/observability 指标、重试事件和可观测记录
protocol src/protocol 协议转换中心:Canonical IR、Client/Upstream Adapter
proxy src/proxy 反代编排:中间件、handler、Orchestrator
routing src/routing 模型路由、RuntimeRegistry、server lifecycle
upstream src/upstream Provider Runtime、OAuth、quota、transport
utils src/utils 通用 ID、HTTP、crypto、cache、i18n、version

面试怎么聊:15 个模块的拆分不是过度设计——每个模块有明确的“只能做什么”和“不能做什么”。db 是唯一能碰 SQL 的,protocol 是唯一能做协议语义转换的,accounts 是唯一能选账号的。这让代码审查变得机械化。

这是整个系统最核心的设计:任何 LLM 请求都经过统一的数据转换管道

Client Protocol (OpenAI/Claude/Gemini/...)
↓ client adapter 解码
Canonical IR (CanonicalRequest) ← 协议无关的中间表示
↓ routing + account selection
↓ upstream adapter 编码
Upstream Protocol (发送到上游)
Upstream Response/Stream
↓ upstream adapter 解码
CanonicalStreamEvent / CanonicalResponse
↓ StreamCollector 聚合
↓ client adapter 编码
Client Response/SSE

核心设计决策

设计 理由
Canonical IR 不做“超集” 只包含 LLM 最核心的语义:messages、tools、streaming、thinking、images
Client/Upstream 双 Adapter OpenAI→Claude 和 Claude→OpenAI 只写一次,相互独立
requested_model >= resolved_model >= upstream_model 三段模型链,每段变更可追溯
协议选择在 Orchestrator resolve_upstream_protocol() 根据 lease 的 supported_protocols 决定

面试怎么聊:重点讲清楚“为什么需要 Canonical IR”——不是过度抽象,而是消除 O(N x M) 的协议转换爆炸。8 种客户端协议 x 8 种上游 Runtime 如果不通过 IR,需要 64 个点对点转换器。

不属于任何协议 handler,不属于任何 runtime。AccountService::select_lease() 是唯一入口。所有模块依赖这个函数的返回值决定执行策略。

User Token 绑定账号组后:组不存在 → 请求失败;查询失败 → 请求失败;组为空 → 请求失败。不降级到全量账号

未知协议不能静默落到 Antigravity 或兜底 runtime。必须通过 runtime_options_json.protocolsupported_protocols 声明。

requested_modelresolved_modelupstream_model,每段变更可追溯。provider 级别名和 fallback 必须可观测。

不存在 handler 直接 JSON.json → runtime 直接 JSON.json 的路径。必须经过 Canonical IR。

以一次 POST /v1/chat/completions 为例:

1. 请求进入 Axum route (routing/server/ routes)
2. auth_middleware 验证 User Token / admin key
3. ip_filter_middleware 检查 IP 过滤
4. monitor_middleware 注入 trace_id 和时间
5. OpenAI chat handler 解码请求 (protocol/client/openai)
→ CanonicalRequest { requested_model: "gpt-4o-mini" }
6. model_mapping 解析: "gpt-4o-mini" → "gpt-4o-mini"
→ resolved_model, RuntimeKind::OpenAI
7. account_scope::resolve_selection_scope()
User Token 有 group_id → SelectionScope::Group { group_id, account_ids }
8. AccountService::select_lease(Request)
├─ 过滤: enabled/status/proxy_disabled/protocol/runtime/model
├─ 排序: last_used ASC → created_at ASC → id ASC (LRU)
└─ 返回 AccountLease { account_id, credentials, runtime_kind }
9. ProxyOrchestrator::execute_chat(OrchestratorRequest)
- 最多 max_attempts 次
- resolve_upstream_protocol: checks lease.runtime_options.supported_protocols
- RuntimeRegistry::get(RuntimeKind::OpenAI)
- ProviderRuntime::execute_chat(RequestContext, lease, request)
- 失败调用 should_retry (429/5xx/network) → 排除账号 → select_lease 再选
10. ProviderRuntime 执行:
- upstream adapter encode_request(CanonicalRequest) → OpenAI JSON
- transport send → upstream response SSE/JSON
- upstream adapter decode_stream_event → CanonicalStreamEvent
- StreamCollector 聚合
- client adapter encode → OpenAI Chat SSE chunks
11. Orchestrator 记录 ProxyOutcome::Success
12. request_logs 异步写入 DB
13. 客户端收到 SSE/JSON 响应
维度 Account Manager LiteLLM One-API Gateway API
语言 Rust Python Go Go
账号选择 确定性 avai … 轮询/随机 轮询 路由表
协议转换 Canonical IR
账号组隔离 原生 support
OAuth 自动化 统一入口 + loopback
流式协议互转 OpenAI/Claude/Gemini 双向
部署模式 二进制 / Compose / 容器 Docker / pip Docker Docker

面试怎么聊:重点讲“为什么用 Rust”和“为什么自己写 Canonical IR”。Rust 带来的零成本抽象让 IR 转换无 GC 停顿——这对流式 100+ chunks/second 不是一个新 API 门面。

需求 Rust 优势
代理延迟敏感 SSE 流式转发不抖动
高并发连接池 actix/axum + tokio,结构化并发
单二进制部署 cargo build --release
类型安全 编译期捕获账号域/协议匹配错误
模式 场景
SQLite 单机部署、开发环境
PostgreSQL 多实例部署、共享账号池

ABV_DATABASE_URL 环境变量决定数据库选择,设置 Postgres 连接串则使用 Postgres,否则使用 SQLite。非法连接 Postgres 配置直接报错,不静默回退。

Phase 内容 状态
P0 账号模型 + 数据库 + OAuth + 基本代理 Done
P1 Canonical IR + Client/UpstreamAdapter Done
P2 统一账号选择 + 代理编排 Done
P3 流式转换 + 多Client 协议 Done
P4 User Token 隔离 + 账号组 Done
P5 管理 API + 前端 Done
P6 生产部署 + 自动发布 Done