feat: scaffold ai gateway identity and design

This commit is contained in:
2026-05-09 16:01:32 +08:00
parent 6323e70e49
commit 5b20f017eb
18 changed files with 3043 additions and 372 deletions
+707 -159
View File
File diff suppressed because it is too large Load Diff
+78 -23
View File
@@ -1,48 +1,103 @@
# integration-platform 迁移实施计划
## 第 1 周:基础设施
## Phase 0:脚手架与基础契约
- 在 Agent memory 的 `easyai-pgvector` 实例上建立独立数据库 `easyai_ai_gateway` 和 AI Gateway 表,不直接使用 `easyai_memory` 记忆库。正式 EasyAI compose 默认账号为 `easyai` / `easyai2025`
- 完成 JWT / API Key 授权验证
- 完成基准 provider、基准模型库、平台与模型管理 API
- 完成基准定价、平台默认折扣、平台模型覆盖的 schema
- React 控制台接入平台、基准模型、TPM/RPM 限流窗口列表
- 在 Agent memory 的 PostgreSQL 18 `easyai-pgvector` 实例上建立独立数据库 `easyai_ai_gateway` 和 AI Gateway 表,不直接使用 `easyai_memory` 记忆库。正式 EasyAI compose 默认账号为 `easyai` / `easyai2025`
- 完成 Go API、React 前端、Nx/go.work/pnpm monorepo、基础 migration
- 完成本地账号注册登录、可选邀请码、JWT / API Key 授权验证骨架,并将默认身份模式设为 `hybrid`
- 固化兼容路由、任务事件、队列、定价、限流、回调 outbox 的基础设计
- React 前端先具备登录页、首页、模型、用户工作台、管理工作台、API 文档的页面骨架
## 第 2 周:路由行为复刻
## Phase 1:模型库 + 首批生成能力
第一阶段只做可落地的核心闭环:**模型库、大模型对话、文本生图、图像编辑**。Client 只迁移 **OpenAI****Gemini** 两个,暂不迁移视频和其他 provider。
### 1.1 模型库
- 建立 `model_catalog_providers``base_model_catalog``model_pricing_rules` 的首批数据。
- 建立 `gateway_tenants``gateway_users``gateway_user_groups``gateway_tenant_invitations` 和用户组策略,支持独立租户/用户、可选邀请码注册、`server-main` 同步租户/用户、不同用户组的充值折扣、调用折扣和并发/限流策略。
- 建立独立模式本地闭环表:`gateway_api_keys``gateway_wallet_accounts``gateway_wallet_transactions``gateway_recharge_orders`
- 导入 OpenAI、Gemini 的基准 provider、基准模型、能力 schema、默认限流模板。
- 支持全局模型配置:模型类型、上下文、多模态能力、图片输入/输出能力、stream 支持、价格规则。
- 支持平台模型 follow 基准模型、平台折扣、模型级自定义价格和能力覆盖。
- 管理工作台可查看和编辑基准模型、平台模型、定价规则、默认限流。
### 1.2 大模型对话
- 迁移兼容路由:
- `/chat/completions`
- `/v1/chat/completions`
- `/responses` / `/v1/responses` 可先保留契约,按 OpenAI/Gemini Chat 能力逐步补齐。
- 支持同步响应和 stream 响应。
- 支持文本、多模态图片输入的参数归一与能力校验。
- 支持 TPM/RPM/并发限流、失败切换、任务事件、usage / billings 回填。
- 先完成 OpenAI Chat Client 和 Gemini Chat Client 的 contract test。
### 1.3 生图与图像编辑
- 迁移兼容路由:
- `/images/generations`
- `/v1/images/generations`
- `/images/edits`
- `/v1/images/edits`
- 支持 prompt、参考图、mask / edit 输入、尺寸、质量、数量等参数归一。
- 文件输入与结果转存统一调用 `server-main` `/v1/files/upload`
- 支持图像价格预估:分辨率、质量、数量、生成/编辑模式权重。
- 先完成 OpenAI Image Client 和 Gemini Image Client 的 contract test。
### 1.4 第一阶段验收
- 模型库中能维护 OpenAI、Gemini 的基准模型、能力和价格。
- 管理员能配置平台、平台模型、折扣、限流和重试策略。
- 管理员能配置租户、用户、用户组、成员关系、充值折扣、调用折扣、TPM/RPM/并发策略。
- 普通用户能在模型页看到可用 Chat / 生图 / 图像编辑模型。
- API 文档能在线测试 Chat、生图、图像编辑。
- OpenAI 与 Gemini 的 Chat、生图、图像编辑至少各跑通一个端到端用例。
- estimated billing 与真实 billings 使用同一个 effective pricing resolver。
- 测试模式可模拟 Chat、生图、图像编辑的成功、可重试失败、不可重试失败。
- 任务进度写入 `gateway_task_events` 和 callback outbox,失败可重试和 replay。
## Phase 2:路由、队列与稳定性补强
- 从旧代码抽取以下行为测试:
- 同名模型平台权限过滤。
- `assignClientsByModelName` 候选排序。
- `assignClientsByProviderMethod` provider-level 负载均衡。
- estimated billing 使用真实候选集。
- 建立 TPM/RPM/并发限流 fixtures,覆盖预占、释放、失败切换重新计数。
- Go 侧实现 router,并用 fixtures 对齐旧行为。
- 补齐持久化队列、任务租约、heartbeat、重启恢复、attempt 审计。
- 补齐租户、用户和用户组策略解析:`source + externalTenantId` 租户同步、`source + externalUserId` 用户同步、多组命中、优先级、策略合并、任务策略快照。
- 补齐 callback outbox、settlement outbox 的重试、死信和手动 replay。
## 第 3 周:核心 provider
## Phase 3server-main 薄门面与灰度
- 先迁 OpenAI-compatible / Universal
- 再迁生图、生视频主 provider
- 每个 provider 建 contract test
- `server-main` 的 Chat、生图、图像编辑入口内部切到 Gateway HTTP SDK
- 开启 shadow / dry-run,比对旧实现和 Gateway 的候选模型、预估扣费、参数预处理结果
- 前端逐步增加 `VITE_GATEWAY_API_BASE_URL`,灰度切流核心接口
- 观察任务成功率、平均排队时间、限流命中、扣费一致性、回调 outbox 滞留。
## 第 4 周:任务链路
## Phase 4:视频与更多 provider
- 实现队列、任务状态、SSE 进度
- 实现 TPM/RPM 一分钟窗口计数和并发 lease 恢复
- 打通 Chat、生图、生视频端到端
- 生成结算事件,接入 server-main 幂等扣费
- 在 Phase 1 稳定后再迁移生视频、音频、Embedding、音乐、数字人等能力
- 迁移 RunningHub、Jimeng、Vidu、Kling、Hunyuan Video、Suno 等 provider
- 对 app-style provider 补 `assignClientsByProviderMethod``provider + methodName` 队列 key
- 每个 provider 增加 contract test、retry classification test、billing snapshot
## 第 5 周:切流
## Phase 5:清理旧实现
- server-main `OpenaiService` 加 Gateway client。
- 开启 shadow / dry-run 比对
- 前端增加 `VITE_GATEWAY_API_BASE_URL`
- 灰度切流,观察任务成功率、平均排队、扣费一致性。
- 删除或冻结 `server-main` 中重复的 runtime client。
- 保留必要 BFF、用户历史、账单、文件上传能力
- 将旧 `integration-platform` 配置迁移脚本和回滚脚本固化
## 风险控制
- 第一阶段不做视频和大量 provider,避免迁移面过宽。
- 不做 first-match 回退,所有候选选择都要有行为测试。
- API Key 不在 Gateway 落库
- 接入 `server-main` 模式下 API Key 不在 Gateway 落库;独立模式的本地 API Key、余额、充值订单和钱包流水在 Gateway 闭环
- OSS 密钥不进入 Gateway;文件统一调用 server-main 开放上传接口。
- 租户、用户和用户组可由 Gateway 管理或从 server-main 同步;接入模式下充值执行、余额流水仍以 server-main 为事实源。
- 平台凭证和 provider 凭证当前阶段只允许全局管理员配置,不开放租户管理员自助维护。
- 业务前端实时进度仍走现有 WebSocket 网关;Gateway 只负责事件与回调 outbox。
- 平台模型没有自定义价格时必须 follow 基准模型,不能隐式按 0 计费。
- estimated billing 与真实结算必须使用同一个 effective pricing resolver。
- 结算事件必须幂等和可重试。
+185 -4
View File
@@ -19,7 +19,14 @@ Content-Type: application/json
"sub": "user-id",
"username": "demo",
"role": ["user"],
"tenantId": null,
"tenantId": "tenant-id",
"gatewayTenantId": "optional-gateway-tenant-id",
"tenantKey": "team-a",
"source": "server-main",
"gatewayUserId": "optional-gateway-user-id",
"userGroupId": "optional-primary-group-id",
"userGroupKey": "pro",
"userGroupKeys": ["pro", "image-plus"],
"apiKeyId": "key-id",
"apiKeySecret": "sk-...",
"apiKeyName": "production-key"
@@ -38,7 +45,180 @@ file=@result.png
AI Gateway 不维护独立 OSS 配置,也不向 `server-main` 申请预签名。需要上传本地中间产物、provider 临时 URL 转存、base64 解码结果时,统一组装 multipart 请求调用主服务开放上传接口,并记录主服务返回的 file id / URL / object key。
### 1.3 结算事件
### 1.3 租户同步
AI Gateway 在独立模式下自己维护租户;接入 `server-main` 时保存主服务租户/组织同步副本,用于任务隔离、平台可见性、租户级限流和审计。
建议新增同步接口:
```http
POST /internal/platform/tenants/sync
Authorization: Bearer ${SERVER_MAIN_INTERNAL_TOKEN}
Content-Type: application/json
Idempotency-Key: tenant:${source}:${externalTenantId}:${version}
```
请求体:
```json
{
"source": "server-main",
"externalTenantId": "tenant-id",
"tenantKey": "team-a",
"name": "Team A",
"status": "active",
"planKey": "pro",
"rateLimitPolicy": {
"rules": [
{ "metric": "rpm", "limit": 500, "windowSeconds": 60 },
{ "metric": "concurrent", "limit": 20, "leaseTtlSeconds": 900 }
]
},
"sourceUpdatedAt": "2026-05-09T12:00:00Z"
}
```
要求:
- Gateway 使用 `source + externalTenantId` 幂等 upsert 到 `gateway_tenants`
- 租户禁用后,新任务拒绝入队;已运行任务按任务策略快照继续或由管理员取消。
- 用户同步必须带可映射的 `tenantId` / `tenantKey`,使任务、用户、用户组、限流和平台可见性都能落到同一租户上下文。
### 1.4 用户同步
AI Gateway 需要在独立模式下自己维护用户,在接入 `server-main` 时保存主服务用户的同步副本。同步副本只用于模型调用策略、审计、任务归属和用户组解析,不承接主服务余额、订单、充值流水。
建议新增同步接口:
```http
POST /internal/platform/users/sync
Authorization: Bearer ${SERVER_MAIN_INTERNAL_TOKEN}
Content-Type: application/json
Idempotency-Key: user:${source}:${externalUserId}:${version}
```
请求体:
```json
{
"source": "server-main",
"externalUserId": "user-id",
"username": "demo",
"displayName": "Demo User",
"email": "demo@example.com",
"tenantId": "tenant-id",
"tenantKey": "team-a",
"roles": ["user"],
"status": "active",
"sourceUpdatedAt": "2026-05-09T12:00:00Z",
"userGroupKeys": ["pro", "image-plus"]
}
```
要求:
- Gateway 使用 `source + externalUserId` 幂等 upsert 到 `gateway_users`
- `status=disabled/locked/deleted` 后,Gateway 应拒绝创建新任务;已运行任务按任务策略快照继续或由管理员取消。
- 用户角色以主服务返回为准,但 Gateway 可以叠加本地管理角色,二者需要在 `auth_profile``metadata` 里可审计。
- 用户组关系可以随用户同步一起带,也可以通过用户组同步接口单独维护,最终都落到 `gateway_user_group_memberships`
### 1.5 用户组与折扣策略同步
用户组是跨服务策略:Gateway 需要按用户组执行模型调用折扣、TPM/RPM/并发、队列优先级;`server-main` 需要按用户组执行充值折扣、资源包赠送、余额流水。两边必须保持同一个 `groupKey`
建议新增同步接口:
```http
POST /internal/platform/user-groups/sync
Authorization: Bearer ${SERVER_MAIN_INTERNAL_TOKEN}
Content-Type: application/json
Idempotency-Key: ${groupKey}:${version}
```
请求体:
```json
{
"groupKey": "enterprise",
"name": "企业组",
"rechargeDiscountPolicy": {
"type": "tiered_bonus",
"tiers": [{ "minAmount": 1000, "bonusRatio": 0.12 }]
},
"billingDiscountPolicy": {
"defaultDiscountFactor": 0.9
},
"rateLimitPolicy": {
"rules": [
{ "metric": "rpm", "limit": 1200, "windowSeconds": 60 },
{ "metric": "concurrent", "limit": 50, "leaseTtlSeconds": 900 }
]
},
"memberships": [
{ "principalType": "user", "principalId": "user-id" },
{ "principalType": "tenant", "principalId": "tenant-id" }
]
}
```
要求:
- `server-main` 是充值、余额和订单事实源,负责执行 `rechargeDiscountPolicy`
- Gateway 是模型执行事实源,负责执行 `billingDiscountPolicy``rateLimitPolicy`、队列和并发策略。
- 用户登录 / API Key 校验返回 claim 时,建议带上命中的 `userGroupKey` / `userGroupId`;Gateway 也可以根据同步缓存二次解析。
### 1.6 任务进度回调到 server-main
AI Gateway 不直接替换原业务前端 WebSocket 通道。Gateway 配置任务进度回调地址,所有任务中间状态先写入 Gateway 本地事件表和 callback outbox,再回调给 `server-main`,由 `server-main` 内部推送流程复用原 WebSocket 网关推送给业务前端。
```http
POST /internal/platform/task-progress-callbacks
Authorization: Bearer ${SERVER_MAIN_INTERNAL_TOKEN}
Content-Type: application/json
Idempotency-Key: ${taskId}:${seq}
X-EasyAI-Event-Type: task.progress
```
请求体:
```json
{
"eventId": "uuid",
"taskId": "gateway-task-id",
"externalTaskId": "server-main-task-id",
"userId": "user-id",
"tenantId": "tenant-id",
"apiKeyId": "optional",
"kind": "images.generations",
"model": "gpt-image-1",
"seq": 12,
"event": "progress",
"status": "running",
"phase": "polling",
"progress": 0.42,
"message": "Generating video frames",
"payload": {},
"createdAt": "2026-05-09T12:00:00Z"
}
```
`server-main` 处理要求:
- 使用 `Idempotency-Key``taskId + seq` 幂等去重。
- 根据 `externalTaskId` / `taskId` / `userId` / `tenantId` 定位原业务频道。
- 复用现有 WebSocket 网关事件格式推给前端,尽量不改业务前端订阅协议。
- 只负责推送与必要状态同步,不重新执行任务、不重新计算计费。
Gateway 侧配置:
```env
TASK_PROGRESS_CALLBACK_ENABLED=true
TASK_PROGRESS_CALLBACK_URL=http://easyai-server-main:3000/internal/platform/task-progress-callbacks
TASK_PROGRESS_CALLBACK_TIMEOUT_MS=5000
TASK_PROGRESS_CALLBACK_MAX_ATTEMPTS=10
```
### 1.7 结算事件
```http
POST /internal/platform/settlements
@@ -66,6 +246,7 @@ Idempotency-Key: ${eventId}
AI_GATEWAY_ENABLED=true
AI_GATEWAY_BASE_URL=http://easyai-ai-gateway:8088
AI_GATEWAY_INTERNAL_TOKEN=change-me
AI_GATEWAY_TASK_PROGRESS_CALLBACK_ENABLED=true
```
## 3. 迁移期双写与比对
@@ -81,7 +262,7 @@ AI_GATEWAY_INTERNAL_TOKEN=change-me
- `refresh_token` 签发和刷新。
- 用户余额查询。
- 用户 API Key 的创建、撤销、列表。
- 账单锁、扣费流水。
- `server-main` 用户 API Key 的创建、撤销、列表。Gateway 独立模式会维护自己的本地 API Key。
- `server-main` 账单锁、扣费流水。Gateway 独立模式会维护自己的钱包账户、充值订单和钱包流水。
- OSS/COS/S3 上传配置和实际文件落库。
- 对话与绘图历史最终落库。