diff options
| author | Chia <Chia@93.nz> | 2026-08-04 19:58:52 +1200 |
|---|---|---|
| committer | Chia <Chia@93.nz> | 2026-08-04 20:43:23 +1200 |
| commit | 5b651488b081b65fda8a323f228e139adb79a35d (patch) | |
| tree | 08baf40efb8fe103b32721cd991ff712323e3173 /docs/architecture.md | |
Build AI gateway control plane and admin UI
Diffstat (limited to '')
| -rw-r--r-- | docs/architecture.md | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..640a37d --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,68 @@ +# 架构说明 + +## 设计目标 + +第一阶段只做高性能、可横向扩容的数据面,并提前固定未来计费、权限和控制面的接口位置。代理核心不在请求热路径同步访问数据库,也不把供应商差异扩散到对外 API 层。 + +```mermaid +flowchart LR + C["客户 SDK"] --> E["OpenAI / Anthropic 入口"] + E --> A["Authenticator + Scope"] + A --> R["Model Catalog + Router"] + R --> P["共享连接池 + Provider Adapter"] + P --> U1["上游 A"] + P --> U2["上游 B"] + P --> U3["后备上游"] + E -. "非阻塞" .-> M["Usage Event Sink"] + E -.-> O["Metrics + Structured Logs"] + M --> L["未来:持久计费账本"] + D["PostgreSQL 控制面"] -. "事实数据" .-> S["Redis generation / PubSub"] + S -. "变更广播" .-> A + D -. "启动与轮询快照" .-> A + D -. "模型和路由快照" .-> R +``` + +## 热路径 + +1. 入口生成不可预测的请求 ID,并通过 Bearer 或 `x-api-key` 解析客户身份。 +2. 身份包含 `key_id`、`tenant_id`、`project_id` 和 scopes;当前是静态实现,代理只依赖 `Authenticator` 接口。 +3. 请求体在配置上限内读取一次,以提取公开模型名并支持故障转移时重放。 +4. Router 按协议过滤路由,先按优先级分组,再在同级内按权重选择首选上游。 +5. Provider Adapter 重写上游模型名和凭证,使用进程级共享 Transport 发送请求。 +6. 上游返回成功头后即锁定路由。SSE 使用固定缓冲区复制并逐块 flush,不等待完整响应。 +7. 请求结束后发布 UsageEvent;发布操作有界、非阻塞,当前消费者输出结构化日志。 + +## 已固定的扩展边界 + +| 边界 | 当前实现 | 下一阶段替换 | +| --- | --- | --- | +| 客户身份 | PostgreSQL 快照、内存 SHA-256 索引 | 管理员 RBAC、撤销审计、Redis/Lua 配额 | +| 权限 | `Principal.Scopes` 中的 `inference` | RBAC/ABAC、模型 allowlist、IP 与预算策略 | +| 模型目录 | PostgreSQL 快照 + 可选 Redis generation 广播 + PG 轮询兜底 | 版本化控制面、热更新、灰度发布 | +| 路由 | priority + weighted selection + failover | 健康评分、延迟 EWMA、成本/质量策略、熔断 | +| 计量 | UsageEvent 异步日志 | 持久消息流、幂等消费、不可变用量账本 | +| 计费 | 未执行扣费 | 价格版本、预授权/额度、结算、退款与对账 | +| 限流 | 仅上游 429 故障转移 | Redis/Lua 或边缘 token bucket、租户并发额度 | +| 协议 | 同协议透传 | 规范化 IR + OpenAI/Anthropic/Google 双向转换 | + +## 计费数据原则 + +真实计费不能直接依赖请求日志。建议下一阶段建立不可变 `usage_ledger`,以 `request_id + attempt` 做幂等键,并同时记录:公开模型、实际上游、价格表版本、输入/输出/cache token、币种、上游成本、客户价格、状态和冲正关系。 + +流式请求的 usage 可能只在最后事件出现。当前 observer 会在线解析 OpenAI/Anthropic SSE 中的 usage;如果上游不返回 usage,事件中的 token 为零。接入商业扣费前,应为每种上游建立有测试的 usage normalizer,并使用上游账单进行日对账。 + +## 扩容方式 + +- 进程无状态,可以在 L4/L7 负载均衡器后横向扩容。 +- HTTP server 不设置 WriteTimeout,避免杀死长时间流;上游只限制响应头等待时间,客户端取消会终止上游请求。 +- 连接池按进程共享,默认保留 4096 个空闲连接、单 host 1024 个,可按实例并发和上游限制调整。 +- 请求体默认最多 16 MiB,响应仅保留最多 64 KiB 用于非流式 usage 提取;正文直接传输。 +- 计量队列有界,慢消费者不会拖住推理请求。正式计费时不能仅靠“丢弃并打指标”,需要本地 WAL 或高可用消息系统。 + +## 建议的后续顺序 + +1. 把管理 bootstrap token 替换为管理员账户、RBAC、审计事件,并与公网推理监听端口隔离。 +2. 增加价格表和账本:tenant、project、api_key、provider_credential、model、route、price_book。 +3. 持久 UsageEvent 和幂等账本,然后再实现余额预授权、扣费和退款。 +4. 主动健康检查、熔断、延迟 EWMA 和按成本路由。 +5. 规范化中间表示,实现可靠的跨协议转换与 Responses/Embeddings 等更多端点。 |
