summaryrefslogtreecommitdiff
path: root/docs/architecture.md
diff options
context:
space:
mode:
authorChia <Chia@93.nz>2026-08-05 00:26:25 +1200
committerChia <Chia@93.nz>2026-08-05 00:33:31 +1200
commit1a3d7f9a8a181df48f0e911cbe17a3fad3ab9ac9 (patch)
tree8c92e1e7326fc67ed077a0a878697f1be14b43da /docs/architecture.md
parent5b651488b081b65fda8a323f228e139adb79a35d (diff)
add some scriptsmain
Diffstat (limited to 'docs/architecture.md')
-rw-r--r--docs/architecture.md56
1 files changed, 35 insertions, 21 deletions
diff --git a/docs/architecture.md b/docs/architecture.md
index 640a37d..e522dd5 100644
--- a/docs/architecture.md
+++ b/docs/architecture.md
@@ -2,20 +2,24 @@
## 设计目标
-第一阶段只做高性能、可横向扩容的数据面,并提前固定未来计费、权限和控制面的接口位置。代理核心不在请求热路径同步访问数据库,也不把供应商差异扩散到对外 API 层。
+网关保持轻量且可横向扩容,并把计费、权限和控制面边界固定下来。路由和鉴权只读内存快照;启用预付计费时,请求热路径会执行余额冻结与结算事务,以财务正确性优先。
```mermaid
flowchart LR
C["客户 SDK"] --> E["OpenAI / Anthropic 入口"]
E --> A["Authenticator + Scope"]
- A --> R["Model Catalog + Router"]
+ A --> Q["Redis/local limits"]
+ Q --> B["Balance + monthly quota"]
+ B --> R["Model Catalog + Router"]
R --> P["共享连接池 + Provider Adapter"]
P --> U1["上游 A"]
P --> U2["上游 B"]
P --> U3["后备上游"]
- E -. "非阻塞" .-> M["Usage Event Sink"]
+ P --> M["Usage settlement"]
E -.-> O["Metrics + Structured Logs"]
- M --> L["未来:持久计费账本"]
+ M --> L["PostgreSQL usage + ledger"]
+ S1["Stripe Checkout"] --> W["Signed Webhook"]
+ W --> L
D["PostgreSQL 控制面"] -. "事实数据" .-> S["Redis generation / PubSub"]
S -. "变更广播" .-> A
D -. "启动与轮询快照" .-> A
@@ -25,29 +29,33 @@ flowchart LR
## 热路径
1. 入口生成不可预测的请求 ID,并通过 Bearer 或 `x-api-key` 解析客户身份。
-2. 身份包含 `key_id`、`tenant_id`、`project_id` 和 scopes;当前是静态实现,代理只依赖 `Authenticator` 接口。
+2. 身份包含 `key_id`、`tenant_id`、`project_id` 和 scopes;控制面模式使用 PostgreSQL 摘要快照,代理只依赖 `Authenticator` 接口。
3. 请求体在配置上限内读取一次,以提取公开模型名并支持故障转移时重放。
-4. Router 按协议过滤路由,先按优先级分组,再在同级内按权重选择首选上游。
-5. Provider Adapter 重写上游模型名和凭证,使用进程级共享 Transport 发送请求。
-6. 上游返回成功头后即锁定路由。SSE 使用固定缓冲区复制并逐块 flush,不等待完整响应。
-7. 请求结束后发布 UsageEvent;发布操作有界、非阻塞,当前消费者输出结构化日志。
+4. 项目策略从 PG 热更新快照读取。Redis Lua 原子占用 RPM、估算 TPM 和并发额度;Redis 不可用时退回本机窗口。
+5. Router 按协议过滤路由,先按优先级分组,再在同级内按权重选择首选上游。
+6. 计费开启时,请求进入上游前在 PostgreSQL 原子检查月度消费、冻结保守估算额度;余额不足返回 402,月度额度耗尽返回 429。
+7. Provider Adapter 重写上游模型名和凭证,使用进程级共享 Transport 发送请求。上游返回成功头后即锁定路由;SSE 逐块 flush。
+8. 请求结束后释放并发 lease,并用 `request_id` 幂等持久化 UsageEvent、更新月度汇总、按实际 token 结算;结构化日志仅是异步副本。
## 已固定的扩展边界
| 边界 | 当前实现 | 下一阶段替换 |
| --- | --- | --- |
-| 客户身份 | PostgreSQL 快照、内存 SHA-256 索引 | 管理员 RBAC、撤销审计、Redis/Lua 配额 |
-| 权限 | `Principal.Scopes` 中的 `inference` | RBAC/ABAC、模型 allowlist、IP 与预算策略 |
+| 客户身份 | PostgreSQL 快照、内存 SHA-256 索引 | SSO/OIDC、SCIM、模型 allowlist |
+| 控制台权限 | 平台/租户令牌、六角色 RBAC、租户 SQL scope、审计日志 | SSO、细粒度自定义角色、审批流 |
+| 权限 | `Principal.Scopes` 中的 `inference` + 控制台 RBAC | ABAC、IP 与模型策略 |
| 模型目录 | PostgreSQL 快照 + 可选 Redis generation 广播 + PG 轮询兜底 | 版本化控制面、热更新、灰度发布 |
| 路由 | priority + weighted selection + failover | 健康评分、延迟 EWMA、成本/质量策略、熔断 |
-| 计量 | UsageEvent 异步日志 | 持久消息流、幂等消费、不可变用量账本 |
-| 计费 | 未执行扣费 | 价格版本、预授权/额度、结算、退款与对账 |
-| 限流 | 仅上游 429 故障转移 | Redis/Lua 或边缘 token bucket、租户并发额度 |
+| 计量 | PostgreSQL UsageEvent + 月度汇总 + 异步日志副本 | 分区表、持久消息流、供应商账单对账 |
+| 计费 | 预付余额、冻结/结算、不可变流水、Stripe Checkout | 价格版本、退款/争议、信用额度、Metronome 企业合同 |
+| 限流 | Redis Lua 全局 RPM/估算 TPM/并发,故障时本机降级;PG 月度消费配额 | 滑动窗口、层级策略、边缘 token bucket |
| 协议 | 同协议透传 | 规范化 IR + OpenAI/Anthropic/Google 双向转换 |
## 计费数据原则
-真实计费不能直接依赖请求日志。建议下一阶段建立不可变 `usage_ledger`,以 `request_id + attempt` 做幂等键,并同时记录:公开模型、实际上游、价格表版本、输入/输出/cache token、币种、上游成本、客户价格、状态和冲正关系。
+真实计费不依赖请求日志。当前以 `request_id` 作为 reservation、usage 和扣费幂等键,价格快照随冻结记录保存,账本流水不可变。余额使用百万分之一币种单位,所有变更在锁定 tenant wallet 的 PostgreSQL 事务中完成。
+
+Stripe 充值使用 Checkout Session:本地先创建 top-up order,Stripe 请求使用 order ID 作为幂等键;Webhook 验证签名后再次核对 event ID、order ID、session ID、金额和币种。浏览器成功跳转不具有入账权威性。
流式请求的 usage 可能只在最后事件出现。当前 observer 会在线解析 OpenAI/Anthropic SSE 中的 usage;如果上游不返回 usage,事件中的 token 为零。接入商业扣费前,应为每种上游建立有测试的 usage normalizer,并使用上游账单进行日对账。
@@ -57,12 +65,18 @@ flowchart LR
- HTTP server 不设置 WriteTimeout,避免杀死长时间流;上游只限制响应头等待时间,客户端取消会终止上游请求。
- 连接池按进程共享,默认保留 4096 个空闲连接、单 host 1024 个,可按实例并发和上游限制调整。
- 请求体默认最多 16 MiB,响应仅保留最多 64 KiB 用于非流式 usage 提取;正文直接传输。
-- 计量队列有界,慢消费者不会拖住推理请求。正式计费时不能仅靠“丢弃并打指标”,需要本地 WAL 或高可用消息系统。
+- 余额冻结和结算当前各需要一次 PostgreSQL 事务,以正确性优先。高吞吐阶段可把计费拆成独立服务并做账户分片,但不能用最终一致缓存替代权威账本事务。
+
+## 管理面安全
+
+bootstrap token 只映射为 `platform_admin`,用于首次签发控制台令牌和故障恢复。控制台令牌使用高熵随机值,数据库仅保存 SHA-256 摘要;平台角色没有 `tenant_id`,租户角色必须绑定一个 tenant。所有管理 API 在 handler 执行前校验 permission,租户过滤在 SQL 查询或资源所有权检查中完成,前端隐藏菜单不承担安全职责。
+
+每个通过认证的管理请求都写入 `audit_logs`,包含 actor、角色、tenant、action、状态码、请求 ID、IP 和 User-Agent。审计写入失败不会回滚已成功的资源事务,但会输出结构化告警。
## 建议的后续顺序
-1. 把管理 bootstrap token 替换为管理员账户、RBAC、审计事件,并与公网推理监听端口隔离。
-2. 增加价格表和账本:tenant、project、api_key、provider_credential、model、route、price_book。
-3. 持久 UsageEvent 和幂等账本,然后再实现余额预授权、扣费和退款。
-4. 主动健康检查、熔断、延迟 EWMA 和按成本路由。
-5. 规范化中间表示,实现可靠的跨协议转换与 Responses/Embeddings 等更多端点。
+1. 将管理监听端口与公网推理端口分离,并接入 OIDC/SSO、MFA 与短期会话。
+2. 增加价格版本、退款/冲正、Stripe dispute 处理和供应商日账单对账。
+3. 为不返回 usage 的上游增加可靠 token 计算器,并监控 `uncollected_micros`。
+4. 把 UsageEvent 做时间分区和归档,增加 CSV 导出与对账作业。
+5. 主动健康检查、熔断、延迟 EWMA 和按成本路由。