easyai-ai-gateway/docs/design.md

109 KiB
Raw Blame History

EasyAI AI 网关中台设计文档

1. 建设目标

将现有 easyai-server-main / easyai-integration-api 中与 integration-platform 强相关的能力拆分为一个独立项目:

  • 独立运行:后端 Go、复用 Agent memory 的 PostgreSQL 18easyai-pgvector)、前端 React + TSX。
  • 前端 UI使用 shadcn-ui + Tailwind CSS + Radix UI + lucide-react,保持控制台形态与 EasyAI 运维后台一致。
  • 独立部署HTTP API、任务执行器、任务事件持久化与进度回调均由本服务承载接入 EasyAI 主站时,业务前端实时推送继续复用 server-main 现有 WebSocket 网关。
  • 身份双模式:支持 Gateway 本地账号注册登录,也支持沿用 easyai-server-main 的 JWT claim、角色权限和 OpenAPI sk-* 校验方式。
  • 能力对接:作为 Chat、生图、生视频等模型能力网关easyai-server-main 和前端直接调用。
  • 渐进迁移:新服务稳定后,再让 server-mainOpenaiService / IntegrationPlatformService 切为远程调用门面。

2. 迁移边界

2.1 迁入 AI Gateway

能力 新服务职责
平台管理 平台 CRUD、启停、优先级、凭证配置、可用性检测、默认折扣系数
基准模型库 维护全量 provider、基准模型、模型能力、图像/视频/文本能力标签、基准定价和默认限流模板
模型管理 平台模型、模型类型、能力标签、上下文窗口、计费配置;支持从基准模型继承、按折扣继承或自由覆盖
模型路由 复用现有 assignClientsByModelName 的平台过滤、并发负载、优先级、队列等待语义
生成任务 Chat、图片生成、图片编辑、视频生成、语音、Embedding 等任务入口
队列执行 按平台/模型/方法维度做并发控制、等待队列、超时、重试;队列状态必须持久化,服务异常重启后可恢复
测试模式 支持 simulation / dry-run不向真实平台提交任务仍完整走路由、队列、限流、重试、进度、结果归一流程
计费预估 在任务创建前或前端配置面提供 estimated billing且必须使用与真实路由一致的有效模型价格
任务结果 保存任务请求、状态、结果摘要、billings向主服务发送结算事件
推送 承接任务级进度事件,提供类似原 RxJS Observable 的中间过程返回能力;业务实时进度通过配置回调地址回调 server-main 内部任务进度接口,再由主服务复用原 WebSocket 网关推给业务前端

2.2 接入 server-main 时仍保留在 server-main

能力 原因
用户、组织、租户、角色 EasyAI 主站模式下仍是主账号体系Gateway 保存同步副本和策略快照
余额、资源包、扣费流水 需要复用现有账单锁、组织扣费、消费记录
API Key 创建与撤销 接入模式下 sk-* 生命周期属于主服务用户体系;独立模式由 Gateway 本地 API Key 模块承接
文件上传 复用 server-main 已开放的文件上传接口OSS/COS/S3 密钥和上传实现继续只落在主服务
业务 WebSocket 网关 现有前端已经订阅主服务 WebSocket 通道Gateway 通过任务进度回调接入,不直接替换业务推送链路
对话、绘图历史、工作流历史 与产品域模型绑定Gateway 只返回任务结果和结算载荷

3. 总体架构

flowchart LR
  subgraph client [调用方]
    FE[React / easyai-main-web]
    MAIN[easyai-server-main]
    OPENAPI[OpenAPI Client]
  end

  subgraph gw [API Gateway / Ingress]
    HTTP[HTTP Routes]
    PUSH[SSE / WebSocket Routes]
  end

  subgraph aigw [EasyAI AI Gateway]
    API[Go HTTP API]
    AUTH[Auth Middleware]
    ROUTER[Model Router]
    QUEUE[Queue + Runtime]
    CALLBACK[Task Progress Callback]
    VENDOR[Vendor Clients]
    ADMIN[React Admin Console]
  end

  subgraph data [Data]
    PG[(Agent memory PostgreSQL<br/>easyai-pgvector)]
    REDIS[(Redis later)]
  end

  subgraph servermain [server-main]
    USER[User / Org]
    APIKEY[API Key Verify]
    WSGW[WebSocket Gateway]
    BILL[Billing + Ledger]
    FILES[Open File Upload]
  end

  FE --> HTTP --> API
  FE <-->|business progress ws| WSGW
  ADMIN --> PUSH
  OPENAPI --> HTTP --> API
  MAIN -->|internal HTTP| API
  ADMIN --> API
  API --> AUTH
  AUTH -->|JWT local verify| API
  AUTH -->|sk-* delegate| APIKEY
  API --> ROUTER --> QUEUE --> VENDOR
  API --> PG
  QUEUE --> PG
  QUEUE --> CALLBACK -->|POST task progress callback to server-main| WSGW
  QUEUE -->|settlement event| BILL
  API -->|POST /v1/files/upload| FILES

4. Monorepo 方案

本脚手架采用 Nx + pnpm + go.work

  • Nx 负责任务编排、缓存、前后端统一命令:devbuildtestmigrate
  • go.work 管理 Go 模块,避免把 Go 项目硬塞进 Node 包管理。
  • pnpm-workspace.yaml 管理 React 前端与 TypeScript contracts。
  • 前端控制台使用 shadcn-ui 作为组件体系,配套 Tailwind CSS、Radix UI primitive、lucide-react 图标和 class-variance-authority 管理组件变体。

选择这个组合的原因:

  • 与 EasyAI 现有 Nx 使用习惯接近,便于团队统一命令。
  • Go 后端保持 Go 原生模块边界,后续可以拆 apps/workerlibs/go/*
  • 前端仍可复用 React 生态和 TSX 风格contracts 可给前端、SDK、BFF 共用。
  • shadcn-ui 代码是可拷贝进仓库的 TSX 组件,不绑定运行时 UI 框架,适合后续沉淀平台管理、队列监控、模型计费配置等复杂表单。

4.1 前端 UI 约束

  • 基础组件统一从 apps/web/src/components/ui/* 引入,不直接散落自定义 button/input/table 样式。
  • 首期需要引入并固化:ButtonInputTextareaSelectSwitchCheckboxTabsDialogSheetTableBadgeAlertToast/SonnerTooltipProgressDropdownMenuForm
  • 图标统一使用 lucide-react,按钮类动作优先用语义图标加 tooltip。
  • 控制台不是营销页,布局以高密度管理视图为主:平台列表、模型配置、队列监控、任务详情、客户端运行状态、限流配置、重试策略。
  • 主题 token 以 CSS variables 管理,后续可与 EasyAI 全局后台色板对齐。

5. 授权设计

5.1 身份模式与 JWT 用户授权

Gateway 支持三种身份模式:

  • standaloneGateway 本地账号注册登录,签发 Gateway JWT。
  • server-main:只接受 server-main JWT / OpenAPI sk-* 校验结果,用户与租户从主服务同步。
  • hybrid:同时接受 Gateway 本地账号和 server-main 身份,按 source 区分。

接入 server-main 时兼容主服务 JWT

  • secret读取 CONFIG_JWT_SECRET,默认值与现有 jwtConstants.secret 保持一致。
  • token 有效期:由 server-main 签发控制,当前 access token 为 600srefresh token 为 7d
  • claim 兼容:
    • sub:用户 ID
    • username
    • role
    • tenantId
    • gatewayTenantId
    • tenantKey
    • source
    • gatewayUserId
    • userGroupId / userGroupKey / userGroupKeys
    • sso_id
    • API Key 场景扩展:apiKeyIdapiKeySecretapiKeyName

Gateway 本地登录首期只签发短期 access token不做 refresh token接入 server-main 的刷新仍走主服务。

5.1.1 本地账号注册登录

首期普通账号只做用户名/邮箱 + 密码:

Method Path Permission 说明
POST /api/v1/auth/register public 注册 Gateway 本地账号,创建或加入租户,返回 access token
POST /api/v1/auth/login public 本地账号登录,返回 access token

注册字段:

  • username / email:至少一个必填。
  • password:至少 8 位,落库为 bcrypt hash。
  • tenantKey / tenantName:可选;未传时创建个人租户。

安全边界:

  • 普通注册首期只给 user 角色。
  • 允许注册时填写已有 tenantKey 只是脚手架行为;正式上线前需要租户邀请、域名校验或管理员审批。
  • server-main 模式可关闭本地注册登录,只保留外部 token 入口。

5.2 权限等级

权限枚举与 server-main 保持一致:

Permission 用途
public 健康检查、公开模型列表等
basic 普通用户任务创建、任务查询
creat 创作者级能力
power 平台配置、模型配置、计费配置
manager 超级管理与危险操作

角色映射与 server-main 一致:usercreatoroperatormanageradmin

5.3 OpenAPI API Key

对于 Authorization: Bearer sk-*x-comfy-api-key

  1. Gateway 不直接持有 API Key hash。
  2. Gateway 调用 server-main 的内部校验接口。
  3. server-main 返回标准用户 claim。
  4. Gateway 将 claim 放入请求上下文,后续任务、结算事件都带 apiKeyId / apiKeyName

建议在 server-main 增加内部接口:

POST /internal/platform/auth/verify-api-key
Authorization: Bearer ${SERVER_MAIN_INTERNAL_TOKEN}
Content-Type: application/json

{ "apiKey": "sk-..." }

5.4 内部服务授权

server-main 调 Gateway 内部接口时使用服务令牌:

Authorization: Bearer ${SERVER_MAIN_INTERNAL_TOKEN}
X-EasyAI-Actor: easyai-server-main

内部令牌只用于服务间调用,不替代用户上下文。用户发起的任务仍应透传用户 JWT 或 API Key claim。

6. 接口规范与兼容路由

6.1 兼容优先原则

AI Gateway 的外部接口必须以“兼容现有 EasyAI 路由、请求 DTO、响应结构、错误码、流式语义”为第一目标不能要求前端或 server-main 因拆分服务而大面积改调用路径。

  • 管理面兼容:沿用原 integration-platformintegration/platform-apiintegration-platform/snapshots 路由。
  • 站内生成接口兼容:沿用原 OpenaiController 根路径接口,例如 /chat/completions/images/generations
  • OpenAPI 兼容:沿用 /v1/* 路由,例如 /v1/chat/completions/v1/images/generationsAPI Key 语义与原来一致。
  • 新增接口隔离/api/v1/* 只用于 Gateway 自身控制台、调试、内部 SDK 或新能力,不作为迁移期替代原路由。
  • 响应包装:对原来返回 ResOp 的管理接口继续返回同形态;对 OpenAI-compatible 接口保持原 JSON / stream chunk 结构;对任务类接口保持原 taskIdstatusurlbillings 等字段语义。
  • 路径匹配顺序:迁移 integration-platform 时必须保留静态路径优先于 :id / :action/:id 的规则,避免 models/list/enableddynamic-priority/:idscene-script/:id/partial 被动态路由误吞。

6.2 平台管理兼容路由

Method Path Permission 说明
POST /integration-platform power 创建平台
POST /integration-platform/preset power 创建预置平台
GET /integration-platform power 平台列表
GET /integration-platform/list/ops-compact power 运维精简列表
GET /integration-platform/queue-stats power 队列统计
POST /integration-platform/clear-queue/:platformId power 清理平台队列
POST /integration-platform/find-by-ids power 按 ID 批量查平台
POST /integration-platform/find-by-model basic 按模型查候选平台
GET /integration-platform/models/list/enabled basic 启用模型列表
GET /integration-platform/models/list/all power 全量模型列表
PATCH /integration-platform/dynamic-priority/:id power 动态优先级
DELETE /integration-platform/dynamic-priority/:id power 删除动态优先级
POST /integration-platform/disable/:id power 禁用平台
POST /integration-platform/enable-model/:id power 启用平台模型
PATCH /integration-platform/scene-script/:id/partial power 局部更新场景脚本
PATCH /integration-platform/:action/:id power 兼容启停等 action
PATCH /integration-platform/:id power 更新平台
DELETE /integration-platform/:id manager 删除平台
GET /integration-platform/models/:type basic 按类型查模型
GET /integration-platform/models/strict/:type basic 按类型严格查模型
POST /integration-platform/models/estimatedBilling basic 预估扣费
POST /integration-platform/models/estimatedBilling/:workflowId basic 工作流预估扣费
POST /integration-platform/resetException/:id power 重置异常状态
POST /integration-platform/:id/copy power 复制平台
GET /integration-platform/:id power 平台详情

兼容表中的旧权限用于保持原接口语义;在新 Gateway 第一阶段,所有写入 provider / platform 凭证、启停平台、删除平台、复制平台的接口都要额外要求全局管理员,即 manager/admin 角色。

6.3 平台 API 配置兼容路由

Method Path Permission 说明
POST /integration/platform-api power 创建 API 配置
GET /integration/platform-api power API 配置列表
GET /integration/platform-api/:id power API 配置详情
PATCH /integration/platform-api/:id power 更新 API 配置
DELETE /integration/platform-api/:id manager 删除 API 配置
POST /integration/platform-api/execute power 调试执行
GET /integration-platform/snapshots/platform/:platformId power 平台快照

6.4 站内生成兼容路由

Method Path 说明
GET /models/list 站内模型列表
POST /chat/completions 站内 Chat
POST /chat/completions/cancel/:requestId 取消 Chat
POST /chat/structured-output 结构化输出
POST /images/generations 生图
POST /images/edits 图片编辑
POST /video/generations 生视频
POST /embeddings Embeddings
GET /embeddings/models Embedding 模型
GET /ai/result/:taskId 任务结果

6.5 OpenAPI 兼容路由

Method Path 说明
POST /v1/chat/completions OpenAI-compatible Chat
POST /v1/chat/completions/cancel/:requestId 取消 Chat
POST /v1/images/generations 生图
POST /v1/images/edits 图片编辑
POST /v1/video/generations 生视频
GET /v1/ai/result/:taskId 任务结果
GET /v1/ai/cancel/:taskId 取消任务
POST /v1/embeddings Embeddings
GET /v1/embeddings/models Embedding 模型
GET /v1/models OpenAI-compatible 模型列表
GET /v1/models/list EasyAI 模型列表

/v1/balance/v1/files/upload/v1/creatToken/v1/removeToken 与用户余额、文件、API Key 生命周期强绑定,默认仍由 server-main 保留;若网关暴露同路径,只能做兼容代理或调用 server-main 内部接口。

6.6 Gateway 新增接口

Method Path Permission 说明
POST /api/v1/auth/register public Gateway 本地账号注册,invitationCode 可选
POST /api/v1/auth/login public Gateway 本地账号登录
GET /api/v1/me basic 网关当前身份调试
GET /api/v1/catalog/providers power 基准 provider 列表
GET /api/v1/catalog/base-models power 基准模型库列表
GET /api/v1/catalog/base-models/:id power 基准模型详情
GET /api/v1/tenants power 网关租户列表,支持本地租户和 server-main 同步租户
GET /api/v1/tenants/:id power 租户详情、来源、策略和同步状态
POST /api/v1/tenants/sync power server-main 拉取或接收租户同步
GET /api/v1/tenant-invitations power 本地租户邀请码列表
POST /api/v1/tenant-invitations power 创建本地注册邀请码
GET /api/v1/users power 网关用户列表,支持本地用户和 server-main 同步用户
GET /api/v1/users/:id power 用户详情、来源、角色、用户组和同步状态
POST /api/v1/users/sync power server-main 拉取或接收用户同步
GET /api/v1/user-groups power 用户组策略列表
GET /api/v1/user-groups/:id power 用户组详情、成员与策略
POST /api/v1/user-groups/:id/sync power 同步用户组策略到 server-main
GET /api/v1/wallet/accounts basic 独立模式本地余额账户
GET /api/v1/wallet/transactions basic 独立模式本地余额流水
GET /api/v1/recharge/orders basic 独立模式充值订单
POST /api/v1/recharge/orders basic 独立模式创建充值订单
GET /api/v1/api-keys basic 独立模式 API Key 列表
POST /api/v1/api-keys basic 独立模式创建 API Key
PATCH /api/v1/api-keys/:id/disable basic 禁用本地 API Key
POST /api/v1/pricing/estimate basic 使用 effective pricing resolver 做价格预估
GET /api/v1/pricing/rules power 定价规则列表
GET /api/v1/tasks/:taskId basic Gateway 任务详情
GET /api/v1/tasks/:taskId/events basic SSE 任务进度
GET /api/v1/runtime/clients power 客户端运行状态
GET /api/v1/runtime/queues power 队列与限流状态
GET /api/v1/runtime/rate-limit-windows power TPM/RPM 当前窗口与并发 lease 状态
POST /api/v1/runtime/tasks/:taskId/replay power 重放任务事件
POST /api/v1/runtime/tasks/:taskId/callbacks/replay power 重放任务进度回调 outbox

6.7 内部接口

Method Path 调用方 说明
POST /internal/v1/settlements Gateway worker 回调主服务结算失败时补偿
POST ${TASK_PROGRESS_CALLBACK_URL} Gateway worker 任务进度回调到 server-main 内部任务进度接口,实际路径由配置决定
POST /internal/platform/tenants/sync server-main 同步租户增量、禁用状态和租户策略到 Gateway
POST /internal/platform/users/sync server-main 同步用户增量、禁用状态、角色和用户组关系到 Gateway
POST /internal/platform/user-groups/sync server-main 同步用户组、折扣和限流策略到 Gateway
POST /internal/v1/task-callbacks server-main 迁移期主服务回写历史或任务绑定

7. 数据模型

数据模型按“基准模型库 -> 平台实例 -> 平台模型覆盖 -> 任务运行态”分层:

  • 基准模型库保存 provider、canonical model、能力 schema、默认能力、基准价格、默认限流模板是所有平台模型的 fallback。
  • 创建平台时可以设置 default_discount_factor,平台模型默认按“基准价格 x 折扣系数”计算;没有任何平台侧配置时,能力和价格都 follow 基准模型。
  • 平台模型可以覆盖能力、定价和限流。覆盖只作用于该平台模型,不能反向污染基准模型库。
  • 租户是隔离域:独立模式下 Gateway 管理 gateway_tenants;接入模式下同步 server-main 租户/组织,任务、用户、平台可见性、限流与计费策略都需要带租户上下文。
  • 用户是身份域:独立部署时 Gateway 自己维护 gateway_users、登录、API Key、余额、充值订单和钱包流水接入 server-main 时 Gateway 保存用户同步副本和策略快照,认证、余额、充值、订单仍可由 server-main 作为事实源。
  • 用户组是策略作用域不同用户组可以绑定充值折扣、模型计费折扣、TPM/RPM/并发、队列优先级、API Key 配额等策略。独立模式由 Gateway 完整执行;server-main 模式下充值和余额执行归主服务Gateway 执行模型调用侧策略。
  • estimated billing、真实任务 billings、控制台价格预览必须走同一个 effective pricing resolver。

7.0 身份运行模式

Gateway 需要支持三种身份运行模式,默认配置为 IDENTITY_MODE=hybrid

模式 配置 用户事实源 API Key / 登录 用户组策略 适用场景
Standalone IDENTITY_MODE=standalone Gateway gateway_users Gateway 本地用户、密码/SSO、API Key Gateway 维护并执行充值折扣、调用折扣、限流和并发 独立商业化或单独部署
Server-main gateway IDENTITY_MODE=server-main server-main JWT 复用主服务 secretsk-* 调用主服务校验 server-main 与 Gateway 同步;主服务执行充值/余额Gateway 执行调用折扣和限流 EasyAI 主站拆分后的 AI 网关
Hybrid IDENTITY_MODE=hybrid Gateway + server-main 两种方式并存,按 source 区分 source + group_key 合并,冲突以更高优先级策略为准 迁移灰度或私有化集成

本地注册规则:

  • 普通注册默认开放,invitationCode 可选;不填邀请码时创建或复用 tenantKey 对应的 Gateway 本地租户,未填 tenantKey 时生成个人租户。
  • 填写邀请码时必须命中 gateway_tenant_invitations 的有效记录,注册用户加入邀请码指定租户,并可绑定邀请码指定用户组。
  • 平台凭证、provider 凭证和全局模型配置暂时只允许全局管理员维护;租户侧先只做模型使用、用量查看和策略展示。

身份解析流程:

  1. 从 JWT / API Key / 内部调用 token 解析出外部身份。
  2. 根据 source + external_user_idgateway_users 找到或创建同步副本。
  3. 按用户、租户、API Key、组织命中 gateway_user_group_memberships
  4. 根据用户组优先级和策略合并规则得到 effective policy。
  5. 创建任务时把 gateway_user_iduser_sourceuser_group_iduser_group_keyuser_group_policy_snapshot 写入 gateway_tasks,后续重试和结算不受同步变更影响。

7.0.1 多租户模型

多租户支持不能只停留在 claim 的 tenantId 字符串Gateway 需要有自己的租户表和执行上下文:

  • gateway_tenants 保存租户事实或同步副本,使用 source + external_tenant_id 幂等同步。
  • gateway_users.gateway_tenant_id 关联 Gateway 租户,tenant_id / tenant_key 保留与 server-main 兼容的外部标识。
  • gateway_tasks 固化 gateway_tenant_idtenant_idtenant_key,确保任务恢复、重试、结算和审计不受后续租户变更影响。
  • integration_platforms.visibility_scope 区分 globaltenantprivate,租户专属平台只能被对应租户路由到。
  • 限流、定价、用户组和 quota 都可以以租户作为 scope同一请求会同时命中 global、tenant、user_group、user、api_key 等策略。
  • 控制台数据查询默认按当前用户租户过滤;power/manager 可跨租户查看和管理。

7.1 integration_platforms

保存平台实例与凭证:

  • provider:平台类型,如 openairunninghubjimeng
  • name:运营可识别名称。
  • base_url
  • auth_type
  • credentials:加密后的凭证 JSON后续应接入 KMS。
  • config:限流、超时、重试、平台私有配置。
  • visibility_scopeglobaltenantprivate,用于多租户平台可见性。
  • tenant_id / tenant_key:租户专属平台的归属。
  • default_discount_factor:平台默认折扣系数,基于基准模型价计算平台有效价。
  • priority
  • status

7.2 platform_models

保存平台模型配置:

  • platform_id
  • base_model_id:关联基准模型库,未配置能力/价格时 follow 基准模型。
  • model_name
  • model_typechatimagevideoaudio 等。
  • capabilities:平台模型有效能力,来自基准模型能力与平台覆盖合并。
  • pricing_modeinheritinherit_discountcustom
  • discount_factor:模型级折扣,未设置时使用平台默认折扣。
  • billing_config:平台模型有效计费配置,来自基准价、折扣和自定义覆盖。
  • enabled

7.3 gateway_tasks

保存任务请求与状态:

  • kindchat.completionsimages.generationsvideos.generations
  • user_id:请求 claim 中的用户 ID独立模式为 Gateway 用户 ID接入模式为 server-main 用户 ID。
  • gateway_user_idGateway 本地用户表 ID用于关联同步副本和审计。
  • user_sourcegatewayserver-mainsync
  • tenant_id
  • user_group_id / user_group_key
  • user_group_policy_snapshot:任务创建时解析出的用户组策略快照,用于审计和重试稳定性。
  • model
  • request
  • statusqueuedrunningsucceededfailedcancelled
  • queue_key:限流队列 key例如 ${platformKey}-${model}${provider}-${methodName}
  • priority
  • idempotency_key
  • remote_task_id
  • remote_task_payload
  • run_modeproductionsimulation
  • simulation_profile
  • simulation_seed
  • locked_by
  • locked_at
  • heartbeat_at
  • next_run_at
  • result
  • billings
  • error

7.4 gateway_task_attempts

保存每一次客户端尝试,支持“上一个客户端失败,下一个客户端重试”的完整审计:

  • task_id
  • attempt_no
  • platform_id
  • client_id
  • model_id
  • statussubmittedpollingsucceededfailedskipped
  • retryable
  • error_code
  • error_message
  • remote_task_id
  • simulated
  • request_snapshot
  • response_snapshot
  • started_at
  • finished_at

7.5 gateway_task_events

保存任务执行过程中的事件,用于控制台 SSE / WebSocket 重放、进度回调 outbox 投递与服务重启后的进度恢复:

  • task_id
  • seq:单任务内递增序号
  • event_typequeue_statusnode_statusprogresspartial_resultcompletedfailed
  • status
  • progress
  • message
  • payload
  • created_at

客户端断线重连时可通过 Last-Event-IDafterSeq 回放事件。

7.5.1 gateway_task_callback_outbox

保存投递给 server-main 内部任务进度接口的回调。Gateway 产生事件后先写 gateway_task_events,再写 callback outbox由独立 worker 按配置的 TASK_PROGRESS_CALLBACK_URL 投递,失败后可重试。

  • task_id
  • event_id / seq:与 gateway_task_events 对应,用于幂等与顺序控制。
  • callback_url:当前使用的回调地址快照,避免配置变化影响已排队事件。
  • payload:回调给 server-main 的标准事件载荷。
  • statuspendingdeliveringdeliveredfailedskipped
  • attempts
  • next_attempt_at
  • last_error
  • delivered_at

7.6 runtime_client_states

保存平台客户端的运行时状态:

  • client_id
  • platform_id
  • provider
  • method_name
  • queue_key
  • running_count
  • waiting_count
  • limiter_ratio
  • cooldown_until
  • last_assigned_at
  • last_error
  • updated_at

该表用于恢复与观测;实时并发计数仍可通过事务锁、SKIP LOCKED、Redis token bucket 或内存计数加 PG 校验组合实现,但 PG 是最终事实源。

7.7 gateway_upload_assets

保存网关任务引用的上传资产:

  • task_id
  • sourceserver-main-open-uploadremote-urlmultipartsimulation
  • server_main_file_id:主服务返回的文件 ID。
  • object_key
  • url
  • content_type
  • size
  • checksum
  • metadata

7.8 settlement_outbox

保存结算事件 outbox

  • task_id
  • event_type
  • payload
  • status
  • attempts
  • next_attempt_at

结算事件必须按 eventId / taskId 幂等,不能因为 Gateway 重启、HTTP 回调失败或 MQ 抖动重复扣费。

7.9 表结构草案

以下为首期 PostgreSQL 表结构草案。字段类型以后续 migration 为准,但语义和索引边界应保持稳定。

7.9.1 model_catalog_providers

字段 类型 约束 说明
id uuid PK 基准 provider ID
provider_key text unique, not null 稳定 provider keyopenairunninghubjimeng
display_name text not null 展示名称
provider_type text not null openai_compatibleworkflow_appvideo_vendoraudio_vendor
capability_schema jsonb not null, default {} provider 支持的能力字段定义
default_rate_limit_policy jsonb not null, default {} provider 默认 TPM/RPM/并发模板
status text not null activedeprecatedhidden
metadata jsonb not null, default {} 文档链接、logo、排序等
created_at timestamptz not null 创建时间
updated_at timestamptz not null 更新时间

索引:

  • uniq_model_catalog_provider_key(provider_key)
  • idx_model_catalog_provider_status(status)

7.9.2 base_model_catalog

保存全量基准模型。这个表不代表某个平台已经开通该模型,而是标准模型与价格来源。

字段 类型 约束 说明
id uuid PK 基准模型 ID
provider_id uuid FK 所属基准 provider
provider_key text not null 冗余 provider key方便查询
canonical_model_key text unique, not null Gateway 内部标准模型 key
provider_model_name text not null 供应商原始模型名
model_type text not null chatimagevideoaudioembeddingmusicdigital_humanmodel_3d
display_name text not null 展示名称
capabilities jsonb not null, default {} 上下文、多模态、参考图/视频/音频、尺寸、时长、质量等基准能力
base_billing_config jsonb not null, default {} 基准计费配置
default_rate_limit_policy jsonb not null, default {} 默认 TPM/RPM/并发限制模板
pricing_version int not null, default 1 基准价格版本
status text not null activedeprecatedhidden
metadata jsonb not null, default {} 供应商文档、排序、标签
created_at timestamptz not null 创建时间
updated_at timestamptz not null 更新时间

索引:

  • uniq_base_model_catalog_key(canonical_model_key)
  • idx_base_model_catalog_provider(provider_key, model_type, status)
  • idx_base_model_catalog_capabilities 使用 GIN(capabilities)

7.9.3 model_pricing_rules

保存基准模型和平台模型的可版本化价格规则。平台模型没有自定义规则时,使用 base_model_catalog.base_billing_config 并应用折扣。

字段 类型 约束 说明
id uuid PK 价格规则 ID
scope_type text not null base_modelplatformplatform_model
scope_id uuid nullable 对应基准模型、平台或平台模型 ID
resource_type text not null text_inputtext_outputimagevideoaudiomusicdigital_humanmodel
unit text not null 1k_tokensimage5ssecondcharacter_1kitem
base_price numeric not null 基准单价,单位使用 EasyAI resource / credit
currency text not null, default resource resourcecreditcnyusd
base_weight jsonb not null, default {} 固定权重,如默认倍率
dynamic_weight jsonb not null, default {} 分辨率、质量、时长、有无音频等动态权重
effective_from timestamptz nullable 生效开始
effective_to timestamptz nullable 生效结束
created_at timestamptz not null 创建时间
updated_at timestamptz not null 更新时间

索引:

  • idx_model_pricing_scope(scope_type, scope_id, resource_type)
  • idx_model_pricing_effective(effective_from, effective_to)

7.9.4 gateway_tenants

保存 Gateway 可识别的租户。独立模式下它是租户事实表;接入 server-main 时它是租户/组织同步副本。

字段 类型 约束 说明
id uuid PK Gateway 租户 ID
tenant_key text unique, not null Gateway 内稳定租户 key
source text not null gatewayserver-mainsync
external_tenant_id text nullable 外部租户/组织 ID
name text not null 租户名称
description text nullable 说明
default_user_group_id uuid FK nullable 默认用户组
plan_key text nullable 套餐或商业计划 key
billing_profile jsonb not null, default {} 独立模式账务资料或接入模式同步摘要
rate_limit_policy jsonb not null, default {} 租户级 TPM/RPM/并发/队列策略
auth_policy jsonb not null, default {} 注册、邀请、SSO、域名限制等认证策略
metadata jsonb not null, default {} 同步、运营、展示扩展信息
status text not null activedisabledlockeddeleted
synced_at timestamptz nullable 最近同步时间
source_updated_at timestamptz nullable 外部源更新时间
created_at timestamptz not null 创建时间
updated_at timestamptz not null 更新时间
deleted_at timestamptz nullable 软删除时间

索引:

  • uniq_gateway_tenants_tenant_key(tenant_key)
  • uniq_gateway_tenants_source_external(source, external_tenant_id)
  • idx_gateway_tenants_status(status, created_at)

7.9.5 gateway_users

保存 Gateway 可识别的用户。独立模式下它是用户事实表,并与本地 API Key、钱包、充值订单形成闭环接入 server-main 时它是用户同步副本和策略执行缓存,不迁入主服务余额、订单、充值流水。

字段 类型 约束 说明
id uuid PK Gateway 用户 ID
user_key text unique, not null Gateway 内稳定用户 key
source text not null gatewayserver-mainsync
external_user_id text nullable 外部用户 IDserver-main 模式为主服务用户 ID
username text not null 登录名或同步用户名
display_name text nullable 展示名
email text nullable 邮箱
phone text nullable 手机号
avatar_url text nullable 头像
password_hash text nullable 仅独立模式使用,接入主服务时为空
gateway_tenant_id uuid FK nullable Gateway 租户 ID
tenant_id text nullable 外部租户 ID 或兼容 claim
tenant_key text nullable Gateway 租户 key
default_user_group_id uuid FK nullable 默认用户组
roles jsonb not null, default [] usercreatoroperatoradmin 等角色
auth_profile jsonb not null, default {} SSO、MFA、API Key 策略等认证资料
metadata jsonb not null, default {} 同步、运营、展示扩展信息
status text not null activedisabledlockeddeleted
last_login_at timestamptz nullable 最近登录时间
synced_at timestamptz nullable 最近同步时间
source_updated_at timestamptz nullable 外部源更新时间
created_at timestamptz not null 创建时间
updated_at timestamptz not null 更新时间
deleted_at timestamptz nullable 软删除时间

索引:

  • uniq_gateway_users_user_key(user_key)
  • uniq_gateway_users_source_external(source, external_user_id)
  • idx_gateway_users_status(status, created_at)
  • idx_gateway_users_tenant(tenant_id, tenant_key, status)

同步规则:

  • source='gateway':用户由 Gateway 创建和禁用可独立使用充值、余额、API Key 由 Gateway 本地模块承接。
  • source='server-main'用户由主服务同步Gateway 只保存执行模型调用所需字段;禁用、角色、用户组变更以主服务事件或同步任务为准。
  • 同一个外部用户以 source + external_user_id 幂等 upsert避免用户名变更造成重复用户。
  • 用户被禁用后,新任务拒绝进入队列;已运行任务按任务策略快照继续或按管理员策略取消。

7.9.6 gateway_user_groups

保存用户组及其策略。用户组可以由 Gateway 管理,也可以从 server-main 同步;独立模式下 Gateway 执行全部策略,接入模式下充值和余额仍以 server-main 为事实源。

字段 类型 约束 说明
id uuid PK 用户组 ID
group_key text unique, not null 稳定用户组 keyfreeproenterprise
name text not null 展示名称
description text nullable 说明
source text not null gatewayserver-mainsync
priority int not null, default 100 多组命中时优先级,越小越优先
recharge_discount_policy jsonb not null, default {} 充值折扣/赠送资源策略;独立模式由 Gateway 执行,接入模式由 server-main 执行
billing_discount_policy jsonb not null, default {} 模型调用计费折扣策略,用于 estimated billing 和 billings
rate_limit_policy jsonb not null, default {} 用户组 TPM/RPM/并发/队列策略
quota_policy jsonb not null, default {} 日/月额度、API Key 额度、最大任务数
metadata jsonb not null, default {} 展示、运营、同步元数据
status text not null activedisabled
created_at timestamptz not null 创建时间
updated_at timestamptz not null 更新时间

示例:

{
  "recharge_discount_policy": {
    "type": "tiered_bonus",
    "tiers": [
      { "minAmount": 100, "bonusRatio": 0.05 },
      { "minAmount": 1000, "bonusRatio": 0.12 }
    ]
  },
  "billing_discount_policy": {
    "defaultDiscountFactor": 0.9,
    "modelTypeDiscounts": { "chat": 0.85, "image": 0.95 }
  },
  "rate_limit_policy": {
    "rules": [
      { "metric": "rpm", "limit": 1200, "windowSeconds": 60 },
      { "metric": "tpm_total", "limit": 300000, "windowSeconds": 60 },
      { "metric": "concurrent", "limit": 50, "leaseTtlSeconds": 900 }
    ]
  }
}

7.9.7 gateway_user_group_memberships

保存用户组成员关系。一个用户、租户或 API Key 可命中多个组,运行时按组优先级和策略合并规则解析有效策略。

字段 类型 约束 说明
id uuid PK 成员关系 ID
group_id uuid FK 用户组 ID
principal_type text not null usertenantapi_keyorganization
principal_id text not null 对应 Gateway 用户 ID、server-main 外部用户 ID、租户 ID、API Key ID 或组织 ID
source text not null gatewayserver-mainsync
priority int not null, default 100 关系级优先级
effective_from timestamptz nullable 生效开始
effective_to timestamptz nullable 生效结束
status text not null activedisabled
metadata jsonb not null, default {} 同步和运营元数据
created_at timestamptz not null 创建时间
updated_at timestamptz not null 更新时间

索引:

  • uniq_user_group_membership(group_id, principal_type, principal_id)
  • idx_user_group_membership_principal(principal_type, principal_id, status)
  • idx_user_group_membership_effective(effective_from, effective_to)

成员解析规则:

  • 独立模式优先使用 principal_type='user' + gateway_users.id
  • 接入 server-main 时可使用 principal_type='user' + external_user_id,并通过 gateway_users.source='server-main' 反查同步副本。
  • 多个组同时命中时,先按 gateway_user_group_memberships.priority,再按 gateway_user_groups.priority 合并策略。

7.9.8 gateway_tenant_invitations

本地注册邀请码。邀请码不是普通注册的必填项,但填写后必须可校验,并决定用户加入哪个租户和用户组。

字段 类型 约束 说明
id uuid PK 邀请 ID
tenant_id uuid FK 加入的 Gateway 租户
invite_code text unique, not null 注册邀请码
role text not null, default user 注册后角色,默认普通用户
user_group_id uuid FK nullable 注册后默认用户组
max_uses int nullable 最大使用次数
used_count int not null 已使用次数
expires_at timestamptz nullable 过期时间
status text not null activedisabled
metadata jsonb not null 渠道、备注、审批信息

7.9.9 gateway_api_keys

独立模式本地 API Key 表。server-main 接入模式下,sk-* 仍调用主服务校验Gateway 只记录执行快照和策略。

字段 类型 约束 说明
id uuid PK API Key ID
gateway_tenant_id / gateway_user_id uuid FK 所属租户与用户
key_prefix text not null 展示和快速定位前缀
key_hash text unique, not null secret hash不保存明文
name text not null 用户命名
scopes jsonb not null 可调用能力范围
user_group_id uuid nullable API Key 级策略组
rate_limit_policy / quota_policy jsonb not null Key 级限流和额度覆盖
status text not null activedisabledrevoked
expires_at / last_used_at timestamptz nullable 过期与最近使用

7.9.10 gateway_wallet_accounts

独立模式本地钱包账户。Phase 1 先支持资源余额闭环,后续可扩展人民币、美元或企业额度。

字段 类型 约束 说明
id uuid PK 钱包账户 ID
gateway_tenant_id / gateway_user_id uuid FK 所属租户与用户
currency text not null resourcecreditcnyusd
balance numeric not null 可用余额
frozen_balance numeric not null 冻结余额
total_recharged numeric not null 累计充值
total_spent numeric not null 累计消费
status text not null activefrozendisabled

7.9.11 gateway_wallet_transactions

独立模式钱包流水。任务扣费、充值到账、退款、人工调整都必须写流水,并使用 idempotency_key 防重。

字段 类型 约束 说明
id uuid PK 流水 ID
account_id uuid FK 钱包账户
direction text not null creditdebitfreezeunfreeze
transaction_type text not null rechargebillingrefundadjustment
amount numeric not null 金额
balance_before / balance_after numeric not null 变动前后余额
idempotency_key text nullable 幂等 key
reference_type / reference_id text nullable 关联任务、订单或人工工单

7.9.12 gateway_recharge_orders

独立模式充值订单。第一阶段先闭合订单、折扣、入账和流水;支付渠道可以从手工确认开始,再接真实支付。

字段 类型 约束 说明
id uuid PK 充值订单 ID
gateway_tenant_id / gateway_user_id uuid FK 所属租户与用户
amount numeric not null 入账基础额度
bonus_amount numeric not null 用户组充值折扣或赠送额度
payable_amount numeric not null 实际应付
currency text not null 币种或资源类型
channel text not null manualwechatalipaystripe
status text not null createdpendingpaidclosedfailed
external_order_id text nullable 第三方支付订单
idempotency_key text nullable 创建订单幂等 key
paid_at timestamptz nullable 支付完成时间

7.9.13 integration_platforms

字段 类型 约束 说明
id uuid PK 平台实例 ID
provider text not null 平台类型,如 openairunninghubjimeng
platform_key text unique, not null 稳定平台 key用于队列和客户端注册
name text not null 展示名称
base_url text nullable 平台 API 地址
auth_type text not null bearerapi_keybasiccustom
credentials jsonb not null, default {} 加密后的凭证 JSON
config jsonb not null, default {} 超时、重试、限流、平台私有配置
visibility_scope text not null, default global globaltenantprivate
tenant_id text nullable 租户外部 ID 或兼容 claim
tenant_key text nullable Gateway 租户 key
default_pricing_mode text not null, default inherit_discount 平台默认价格模式:inheritinherit_discountcustom
default_discount_factor numeric not null, default 1 平台默认折扣系数,创建平台时可统一基于基准模型打折
retry_policy jsonb not null, default {} 平台级重试策略
rate_limit_policy jsonb not null, default {} 平台级限流策略
priority int not null, default 100 静态优先级,越小越优先
dynamic_priority int nullable 动态优先级覆盖
status text not null enableddisabledexception
disabled_reason text nullable 禁用原因
cooldown_until timestamptz nullable 熔断/冷却到期时间
created_at timestamptz not null 创建时间
updated_at timestamptz not null 更新时间
deleted_at timestamptz nullable 软删除

索引:

  • idx_integration_platforms_provider_status(provider, status)
  • idx_integration_platforms_status_priority(status, priority, dynamic_priority)
  • idx_integration_platforms_cooldown(cooldown_until)
  • idx_integration_platforms_tenant_scope(visibility_scope, tenant_id, tenant_key, status)

7.9.14 platform_models

字段 类型 约束 说明
id uuid PK 模型配置 ID
platform_id uuid FK 所属平台
base_model_id uuid FK nullable 关联基准模型;为空时表示纯自定义模型
model_name text not null 请求使用的模型名
model_alias text nullable 对外展示/兼容别名
model_type text not null chatimagevideoaudioembedding
display_name text not null 展示名称
capability_override jsonb not null, default {} 相对基准模型的能力覆盖
capabilities jsonb not null, default {} 解析后的有效能力,用于路由和前端展示
pricing_mode text not null, default inherit_discount inheritinherit_discountcustom
discount_factor numeric nullable 模型级折扣,空值时继承平台默认折扣
billing_config_override jsonb not null, default {} 自定义计费覆盖
billing_config jsonb not null, default {} 解析后的有效计费配置,用于 estimated billing 和真实 billings
permission_config jsonb not null, default {} 平台维度权限过滤配置
retry_policy jsonb not null, default {} 模型级重试策略
rate_limit_policy jsonb not null, default {} 模型级限流策略
enabled boolean not null, default true 是否启用
created_at timestamptz not null 创建时间
updated_at timestamptz not null 更新时间

索引与约束:

  • uniq_platform_model_type(platform_id, model_name, model_type)
  • idx_platform_models_base(base_model_id)
  • idx_platform_models_lookup(model_type, model_name, enabled)
  • idx_platform_models_alias(model_alias)
  • idx_platform_models_capabilities 使用 GIN(capabilities)

7.9.15 gateway_tasks

字段 类型 约束 说明
id uuid PK Gateway 任务 ID
external_task_id text nullable server-main / 前端兼容的外部任务 ID
kind text not null chat.completionsimages.generations
run_mode text not null productionsimulation
user_id text not null 请求 claim 中的用户 ID
gateway_user_id uuid nullable Gateway 用户表 ID
user_source text not null, default gateway gatewayserver-mainsync
gateway_tenant_id uuid nullable Gateway 租户 ID
tenant_id text nullable 外部租户 ID 或兼容 claim
tenant_key text nullable Gateway 租户 key
api_key_id text nullable OpenAPI Key ID
user_group_id uuid nullable 命中的用户组 ID
user_group_key text nullable 命中的用户组 key
user_group_policy_snapshot jsonb not null, default {} 用户组策略快照
model text not null 请求模型
model_type text nullable 模型类型
request jsonb not null 原始请求快照
normalized_request jsonb not null, default {} 参数处理后的请求
status text not null queuedleasedrunningpollingsucceededfailed_retryablefailed_finalcancelled
queue_key text not null 队列与限流 key
priority int not null, default 100 任务优先级
idempotency_key text nullable 幂等 key
remote_task_id text nullable 供应商任务 ID
remote_task_payload jsonb nullable 供应商任务载荷
simulation_profile jsonb nullable 模拟配置
simulation_seed text nullable 模拟种子
locked_by text nullable worker ID
locked_at timestamptz nullable 租约时间
heartbeat_at timestamptz nullable worker 心跳
next_run_at timestamptz not null 下次可运行时间
attempt_count int not null, default 0 已尝试次数
max_attempts int not null, default 1 最大尝试次数
result jsonb nullable 归一化结果
billings jsonb nullable 计费结果
error_code text nullable 错误码
error_message text nullable 错误信息
created_at timestamptz not null 创建时间
updated_at timestamptz not null 更新时间
finished_at timestamptz nullable 完成时间

索引:

  • idx_gateway_tasks_queue(status, next_run_at, priority, created_at)
  • idx_gateway_tasks_lease(status, heartbeat_at)
  • idx_gateway_tasks_user_created(user_id, created_at desc)
  • idx_gateway_tasks_external(external_task_id)
  • uniq_gateway_tasks_idempotency(user_id, idempotency_key) where idempotency_key is not null

7.9.16 gateway_task_attempts

字段 类型 约束 说明
id uuid PK attempt ID
task_id uuid FK 所属任务
attempt_no int not null 第几次尝试
platform_id uuid nullable 尝试平台
platform_model_id uuid nullable 尝试模型配置
client_id text nullable 客户端实例 ID
queue_key text not null 限流 key
status text not null submittedpollingsucceededfailedskipped
retryable boolean not null, default false 是否可重试
simulated boolean not null, default false 是否模拟
remote_task_id text nullable 供应商任务 ID
request_snapshot jsonb not null, default {} 本次请求快照
response_snapshot jsonb nullable 本次响应快照
error_code text nullable 错误码
error_message text nullable 错误信息
started_at timestamptz not null 开始时间
finished_at timestamptz nullable 结束时间

索引:

  • uniq_gateway_attempt_no(task_id, attempt_no)
  • idx_gateway_attempts_task(task_id)
  • idx_gateway_attempts_client(client_id, started_at desc)

7.9.17 gateway_task_events

字段 类型 约束 说明
id uuid PK 事件 ID
task_id uuid FK 所属任务
seq bigint not null 单任务递增序号
event_type text not null queue_statusprogresspartial_resultcompletedfailed
status text nullable 任务状态
phase text nullable routingqueuedsubmitpollingupload
progress numeric nullable 0 到 1
message text nullable 展示消息
payload jsonb not null, default {} 事件载荷
simulated boolean not null, default false 是否模拟
created_at timestamptz not null 创建时间

索引:

  • uniq_gateway_events_seq(task_id, seq)
  • idx_gateway_events_task_created(task_id, created_at)

7.9.18 gateway_task_callback_outbox

字段 类型 约束 说明
id uuid PK 回调 outbox ID
task_id uuid FK 任务 ID
event_id uuid FK nullable 对应 gateway_task_events.id
seq bigint not null 单任务事件序号
callback_url text not null 投递地址快照,来自 TASK_PROGRESS_CALLBACK_URL
payload jsonb not null 回调载荷
status text not null pendingdeliveringdeliveredfailedskipped
attempts int not null, default 0 已投递次数
next_attempt_at timestamptz not null 下次投递时间
last_error text nullable 最近错误
delivered_at timestamptz nullable 投递成功时间
created_at timestamptz not null 创建时间
updated_at timestamptz not null 更新时间

索引:

  • uniq_task_callback_seq(task_id, seq, callback_url)
  • idx_task_callback_outbox_pending(status, next_attempt_at)
  • idx_task_callback_outbox_task(task_id, seq)

7.9.19 runtime_client_states

字段 类型 约束 说明
client_id text PK 客户端实例 ID
platform_id uuid nullable 所属平台
provider text not null provider
method_name text not null 方法名
queue_key text not null 队列 key
running_count int not null, default 0 当前运行数
waiting_count int not null, default 0 当前等待数
limiter_ratio numeric not null, default 0 负载比
cooldown_until timestamptz nullable 冷却截止
last_assigned_at timestamptz nullable 上次分配时间
last_error text nullable 最近错误
updated_at timestamptz not null 更新时间

索引:

  • idx_runtime_client_queue(queue_key, cooldown_until)
  • idx_runtime_client_platform(platform_id)

7.9.20 gateway_upload_assets

字段 类型 约束 说明
id uuid PK 资产 ID
task_id uuid FK nullable 关联任务
source text not null 固定为 server-main-open-uploadremote-url / simulation
server_main_file_id text nullable 主服务返回的 file id
url text not null 主服务返回 URL
object_key text nullable 主服务返回对象 key
content_type text nullable MIME
size bigint nullable 文件大小
checksum text nullable 校验和
metadata jsonb not null, default {} 上传响应与业务元数据
created_at timestamptz not null 创建时间

索引:

  • idx_gateway_upload_task(task_id)
  • idx_gateway_upload_file(server_main_file_id)

7.9.21 gateway_retry_policies

字段 类型 约束 说明
id uuid PK 策略 ID
scope_type text not null globalproviderplatformmodelmethod
scope_key text not null 作用域 key
enabled boolean not null 是否启用重试
policy jsonb not null 重试策略 JSON
created_at timestamptz not null 创建时间
updated_at timestamptz not null 更新时间

约束:

  • uniq_retry_policy_scope(scope_type, scope_key)

7.9.22 gateway_rate_limit_policies

字段 类型 约束 说明
id uuid PK 策略 ID
scope_type text not null globalproviderplatformclientbase_modelplatform_modelmethodtenantuser_groupuserapi_key
scope_key text not null 作用域 key
policy jsonb not null TPM、RPM、并发、队列长度、冷却策略
created_at timestamptz not null 创建时间
updated_at timestamptz not null 更新时间

约束:

  • uniq_rate_limit_policy_scope(scope_type, scope_key)

示例:

{
  "rules": [
    { "metric": "tpm_total", "limit": 90000, "windowSeconds": 60, "consume": "reserve_then_reconcile" },
    { "metric": "rpm", "limit": 600, "windowSeconds": 60, "consume": "fixed_window" },
    { "metric": "concurrent", "limit": 20, "leaseTtlSeconds": 900 },
    { "metric": "queue_size", "limit": 1000 }
  ]
}

7.9.23 gateway_rate_limit_counters

保存一分钟窗口内的 TPM/RPM 使用量。Redis 可做加速,但 PG counter 是重启恢复和审计的事实源。

字段 类型 约束 说明
scope_type text not null 限流作用域
scope_key text not null 作用域 key
metric text not null tpm_totaltpm_inputtpm_outputrpm
window_start timestamptz not null 分钟窗口开始时间
limit_value numeric not null 当前窗口限制
used_value numeric not null, default 0 已确认消耗
reserved_value numeric not null, default 0 已预占但待回填消耗
reset_at timestamptz not null 窗口结束时间
updated_at timestamptz not null 更新时间

约束:

  • pk_rate_limit_counter(scope_type, scope_key, metric, window_start)

7.9.24 gateway_concurrency_leases

保存并发请求租约,服务异常重启后可释放过期并发。

字段 类型 约束 说明
id uuid PK 并发租约 ID
task_id uuid FK 任务 ID
attempt_id uuid FK nullable attempt ID
scope_type text not null 限流作用域
scope_key text not null 作用域 key
lease_value numeric not null, default 1 占用并发数
acquired_at timestamptz not null 获取时间
expires_at timestamptz not null 过期时间
released_at timestamptz nullable 释放时间

索引:

  • idx_concurrency_leases_active(scope_type, scope_key, released_at, expires_at)
  • idx_concurrency_leases_task(task_id)

8. 模型路由、限流与失败切换

迁移时不要做简单的 first-match。路由器需要复用现有语义

  1. 先按模型名、模型类型、平台启用状态筛候选。
  2. 保留平台维度权限过滤,同名模型不能跨平台混用。
  3. 按平台优先级排序。
  4. 结合并发是否已满、limiter ratio、等待队列、lastAssignedAt 做负载均衡。
  5. 对 app-style provider例如 RunningHub 模板类能力,使用 provider + methodName 的队列 key。

一期脚手架只预留接口,迁移实现时把 IntegrationModelFactory.assignClientsByModelNameassignClientsByProviderMethod 的行为写成 Go 版单元测试再实现。

8.1 限流维度

限流策略需要支持以下维度组合:

  • 全局:global
  • Provider 级:provider_key
  • 平台级:platform_id
  • 客户端级:client_id
  • 基准模型级:base_model_id / canonical_model_key
  • 平台模型级:platform_model_id / model_name / model_type
  • 方法级:method_name,例如 runAIApp$
  • 租户/用户级:gateway_tenant_id / tenant_id / tenant_key / user_id
  • 用户组级:user_group_id / user_group_key
  • OpenAPI Key 级:api_key_id

同一请求可能命中多个策略,默认以最严格策略为准;如后续需要不同优先级,可在 policy 中增加 mergeStrategy

8.1.1 一分钟窗口核心指标

限流必须把 TPM、RPM、并发作为一等指标而不是只看 running count

指标 含义 适用能力 执行方式
tpm_total 一分钟内输入 + 输出 token 总数 Chat、Responses、Embedding、可 token 化文本任务 提交前按 prompt / max_tokens 预估并预占,完成后用实际 token 回填
tpm_input 一分钟内输入 token 数 Chat、Responses、Embedding 提交前按 tokenizer 或近似估算预占
tpm_output 一分钟内输出 token 数 Chat、Responses stream 场景可按 chunk 增量累计,完成后 reconcile
rpm 一分钟内请求数 所有同步/异步模型提交 任务 attempt 提交前扣减;失败切换的新 attempt 也算一次 provider 请求
concurrent 同时运行或轮询中的请求数 所有 provider client 通过 gateway_concurrency_leases 获取租约,完成、失败、取消或过期释放
queue_size 等待队列长度 所有队列 超过后按策略返回兼容错误或降级到 simulation / fallback

TPM 的预占策略:

  • 文本任务:优先使用模型 tokenizer没有 tokenizer 时用字符数估算,并把估算方式写入 event payload。
  • Chat stream提交前按 input_tokens + max_tokens 预占stream 中可累计输出 token完成后用 usage 精确回填。
  • 未提供 max_tokens 的请求:使用模型默认输出上限或策略中的 defaultOutputReserveTokens
  • 失败且未提交到供应商:释放预占 token已提交但失败的 attempt 按供应商是否计费决定保留或部分释放。
  • 生图/生视频通常不计 TPM但如果 provider 对多模态 token 有限制,可在 capabilities.tokenPolicy 中启用对应估算器。

RPM 和并发的边界:

  • RPM 以“向 provider 发起一次 submit / sync request”为计数点排队但未提交不消耗 RPM。
  • 失败切换到下一个客户端时,新客户端 attempt 会重新消耗该客户端、平台、provider 维度的 RPM。
  • 并发租约从 submit 前获取,到同步响应完成、异步任务进入可安全释放阶段或任务终态时释放;长轮询 provider 可拆成 submit_concurrentpoll_concurrent 两类 scope。
  • 服务重启后扫描过期 lease结合 gateway_tasks.heartbeat_at 判断释放或续租,避免并发永久泄漏。

除核心指标外,还保留每日/月度配额、错误冷却、余额不足拦截等策略,但这些属于调度前置校验,不替代 TPM/RPM/并发。

8.2 候选客户端选择

候选客户端排序规则必须可测试、可复现:

  1. 过滤禁用平台、禁用模型、不可用凭证、权限不满足的客户端。
  2. 过滤与请求能力不匹配的客户端,例如不支持视频参考、音频参考、多图输入时不能作为候选。
  3. 根据指定平台 / 指定客户端优先收窄候选。
  4. priority、是否满载、limiter_ratio、等待队列长度、last_assigned_at、轻微 jitter 排序。
  5. 选中客户端后在同一事务内写入 last_assigned_at 和任务锁,避免并发请求都抢到同一个客户端。

8.3 失败切换与重试策略

一个模型请求进来,如果多个客户端满足要求,必须具备“上一个客户端失败,下一个客户端重试”的能力,且可配置是否允许:

{
  "retry": {
    "enabled": true,
    "failoverClients": true,
    "maxAttempts": 3,
    "maxSameClientAttempts": 1,
    "backoff": { "type": "exponential", "baseMs": 500, "maxMs": 5000 },
    "retryableStatusCodes": [408, 409, 429, 500, 502, 503, 504],
    "retryableErrorCodes": ["timeout", "rate_limit", "temporary_unavailable"],
    "nonRetryableErrorCodes": ["invalid_request", "insufficient_quota", "content_policy"],
    "retryOnSubmitUnknown": false
  }
}

策略可挂在全局、provider、platform、model、method 四层,优先级为:请求显式配置 > 模型配置 > 平台配置 > provider 默认 > 全局默认。

重试要求:

  • 每次尝试都写入 gateway_task_attempts,包括跳过原因和失败分类。
  • 已明确提交成功但轮询失败的任务,优先继续轮询原 remote_task_id,不能盲目重复提交造成供应商侧重复任务。
  • 提交状态未知时,根据 retryOnSubmitUnknown 决定是否切换客户端;默认保守处理,标记为 unknown 并进入人工/补偿检查。
  • 非重试错误直接终止任务,不再切换客户端。
  • 重试产生的新客户端必须仍满足同一请求的能力、权限和计费要求。

9. 基准模型库与定价体系

定价不直接散落在平台模型里。Gateway 先有一个基准模型库,基准模型库存所有 provider、模型、能力、默认限流模板和基准价格平台创建和平台模型配置都基于这个库继承或覆盖。

9.1 基准模型库内容

每个基准模型至少包含:

  • provideropenairunninghubjimeng
  • canonical model keyGateway 内部稳定模型 key。
  • provider model name供应商真实请求模型名。
  • model typechatimagevideoaudioembeddingmusicdigital_humanmodel_3d
  • capabilities上下文窗口、stream、多模态输入、参考图、参考视频、参考音频、支持尺寸、质量、时长、有无音频、最大 batch 等。
  • base billing config文本、图像、视频、音频等不同能力的基准价格。
  • default rate limit policyprovider 或模型默认 TPM/RPM/并发模板。

9.2 平台价格继承与覆盖

创建平台时有三种方式:

模式 配置 说明
inherit 不填价格 完全 follow 基准模型价格和能力
inherit_discount default_discount_factor 或模型级 discount_factor 有效价 = 基准价 x 折扣系数;能力默认 follow 基准模型,可局部覆盖
custom billing_config_override / capability_override 平台模型完全自定义价格或能力,未覆盖字段仍从基准模型补齐

有效配置解析顺序:

  1. 平台模型 capability_override / billing_config_override
  2. 平台模型 discount_factor
  3. 平台 default_discount_factor
  4. 用户组 billing_discount_policy,用于用户组级模型调用折扣。
  5. 基准模型 capabilities / base_billing_config

如果没有配置平台模型价格,必须 follow 基准模型;不能出现空价格导致预估扣费为 0 的隐式行为。

接入 server-main 时,充值折扣不在 Gateway 内直接变更余额。Gateway 只保存 recharge_discount_policy 并与主服务同步;充值订单、资源包发放、余额流水仍由 server-main 作为事实源执行。独立模式下,充值、余额、订单和钱包流水由 Gateway 本地账务模块闭环。

9.3 各能力计价模型

文本类:

  • 1k_tokens 计价。
  • 输入和输出分开计价:text_inputtext_output
  • 如果模型只配置总价,可 fallback 到 text_total,但 resolver 对外仍展开成输入/输出明细。
  • 预估时用输入 token + 输出 token 预估值;最终结算用 provider usage 或 Gateway tokenizer 回填。

图像类:

  • 基础单位为 image
  • 动态权重至少支持:分辨率、质量、张数、编辑/生成模式。
  • 分辨率示例:512x5121024x10241K2K4K8K
  • 质量示例:standardhdhighultra
  • 公式示例:count * basePrice * resolutionWeight * qualityWeight * modeWeight

视频类:

  • 基础单位建议为 5ssecond,与原 provider 配置保持可映射。
  • 动态权重至少支持:时长、分辨率、是否包含音频、是否使用参考视频、是否指定声音/音色、生成数量。
  • 分辨率示例:480p720p1080p2160p
  • 公式示例:count * ceil(durationSeconds / unitSeconds) * basePrice * resolutionWeight * audioWeight * referenceWeight

音频、音乐、数字人、3D 模型:

  • TTS / audio 可按 character_1k 或秒计费。
  • 音乐可按首数、时长、模型权重计费。
  • 数字人可按时长、分辨率、音频驱动方式计费。
  • 3D / model 类按任务数、模型复杂度或 provider 返回的计费单位映射。

9.4 estimated billing 一致性

/integration-platform/models/estimatedBilling/integration-platform/models/estimatedBilling/:workflowId 和真实任务结算必须使用同一个 resolver

request -> normalize params -> resolve effective platform model
-> resolve effective capabilities -> resolve effective pricing
-> estimate billing -> route / submit -> final billing reconcile

要求:

  • 预估扣费不能只按模型名查第一条,必须使用真实候选平台过滤、权限过滤和优先级排序后的有效平台模型。
  • 同名模型跨平台时,平台权限和平台模型价格都不能串。
  • 测试模式使用同样的预估逻辑,但 billings 标记 simulated=true
  • 基准模型价格变更时,平台模型可选择自动 follow 最新版本或 pin 到指定 pricing_version,避免历史价格被静默改变。

10. Base Client 与 Provider 实现架构

Gateway 需要保留类似原 BaseModelClient 的整体架构:公共基类定义通用生命周期,不同 provider/client 只实现平台差异。这样才能把参数预处理、限流、日志、进度、重试、计费和结果归一放在同一层处理。

10.1 Client 接口

Go 侧建议抽象为:

type ModelClient interface {
  Provider() string
  MethodName() string
  BuildParams(ctx context.Context, task TaskContext) (VendorRequest, error)
  SubmitTask(ctx context.Context, request VendorRequest) (RemoteTask, error)
  PollResult(ctx context.Context, remote RemoteTask) (PollResult, error)
  NormalizeResult(ctx context.Context, result PollResult) (NormalizedResult, error)
  EstimateBilling(ctx context.Context, task TaskContext) ([]BillingItem, error)
  Cancel(ctx context.Context, remote RemoteTask) error
}

10.2 Base Client 公共职责

BaseClient / BaseModelClient 负责:

  • 调用参数处理链:尺寸、画幅、时长、多模态内容过滤、默认值填充。
  • 校验模型能力图片参考、视频参考、音频参考、文件输入、stream 支持等。
  • 发出进度事件:构建参数、排队、提交、轮询、下载、上传、完成。
  • 执行通用 timeout、backoff、错误分类、重试和 failover 策略。
  • 统一记录 gateway_task_attemptsgateway_task_events、运行指标。
  • 统一提取 billingsresult,交给 outbox 做结算事件。
  • 统一处理文件资产:已上传文件引用、远程 URL 转存、provider 临时 URL 拉取后调用 server-main /v1/files/upload

10.3 Provider Client 实现职责

具体 client 只负责供应商协议:

  • OpenAI-compatible同步/stream chat、responses、image generation。
  • GeminiChat、多模态图片输入、生图、图像编辑优先进入第一阶段迁移。
  • RunningHub模板类 app 提交、轮询、结果提取,队列 key 使用 ${provider}-${methodName}
  • Jimeng / Vidu / Kling / Hunyuan Video视频任务提交与轮询。
  • Suno / Speech / Digital Human各自的提交和结果归一。
  • SimulationClient用于测试模式和 dry-run完整模拟提交、轮询、进度、失败、结果不参与真实生产候选。
  • MockTest用于 provider contract 回归和 loopback不能和生产路由混在同一个职责里应由独立 registry / loopback service 管理。

每个 provider 至少需要:

  • contract test固定输入输出 DTO。
  • retry classification test哪些错误可重试、哪些不可重试。
  • progress event snapshot确保前端进度面板兼容。
  • billing snapshot确保预估扣费和最终 billings 语义一致。

11. 队列持久化、恢复与限流执行

11.1 持久化队列原则

队列必须以 PostgreSQL 为事实源Redis / 内存只作为加速和通知层。服务异常重启后,任务状态必须可从 PG 恢复。

任务生命周期:

created -> queued -> leased -> running -> polling -> succeeded
                                  |           |
                                  |           -> failed_retryable -> queued
                                  -> failed_final / cancelled

核心规则:

  • 入队时写 gateway_tasks,状态为 queued,并写初始 gateway_task_events
  • worker 获取任务时使用事务、FOR UPDATE SKIP LOCKED 或 advisory lock写入 locked_bylocked_atheartbeat_at
  • worker 运行中定期刷新 heartbeat_at
  • 服务启动时扫描 running/polling/leased 且 heartbeat 超时的任务。
  • remote_task_id 的任务优先进入 reconciliation poller继续取回供应商结果。
  • 没有 remote_task_id 的任务按 retry 策略回到 queued 或进入 failed_final
  • 结算 outbox 独立重试,任务成功不等于结算成功。

11.2 恢复策略

重启前状态 恢复动作
queued 保持队列,等待 worker 重新租约
leased 但无 heartbeat 释放锁,回到 queued
running 且无 remote_task_id 视为提交前失败,按 retry 策略重试
running/polling 且有 remote_task_id 进入 poller 继续取回结果
succeeded 但 settlement pending outbox 继续补偿
failed_retryable 且未超最大次数 next_run_at 回队列
failed_final/cancelled 不自动恢复

11.3 限流执行

worker 租约任务前必须先拿到限流令牌:

  • TPM 令牌:按 gateway_rate_limit_counters 的一分钟窗口预占 token完成后 reconcile 实际 token。
  • RPM 令牌:提交 provider 前扣减一分钟窗口请求数,失败切换的新 attempt 重新评估。
  • 并发令牌:按 queue_key / client_id / method_name / platform_model_id 维度写 gateway_concurrency_leases
  • 排队令牌:超过 max_waiting 后直接返回兼容错误。
  • 冷却令牌:客户端错误达到阈值后设置 cooldown_until

如果 worker 拿不到令牌,任务保持 queued 并更新 next_run_at,不能占用 worker 长时间空等。

12. 进度流与 RxJS-like 中间结果

原系统里很多 provider 使用 RxJS Observable 在中间过程返回进度。Go 侧需要提供等价语义:

type ProgressPublisher interface {
  Publish(ctx context.Context, event ProgressEvent) error
  Subscribe(ctx context.Context, taskID string, afterSeq int64) (<-chan ProgressEvent, error)
}

12.1 ProgressEvent 结构

{
  "taskId": "uuid",
  "seq": 12,
  "event": "progress",
  "status": "running",
  "phase": "polling",
  "progress": 0.42,
  "message": "Generating video frames",
  "payload": {},
  "createdAt": "2026-05-09T12:00:00Z"
}

12.2 推送通道

  • 业务实时进度主通道Gateway 按 TASK_PROGRESS_CALLBACK_URL 回调 server-main,由 server-main 复用原 WebSocket 网关推送给业务前端。
  • 控制台 SSEGET /api/v1/tasks/:taskId/events,支持 Last-Event-ID 回放,用于 Gateway 控制台、调试和故障诊断。
  • Gateway WebSocket用于网关控制台高频队列监控、运行态监控不替代业务前端现有 WebSocket 通道。
  • OpenAI stream/chat/completions/v1/chat/completions/responses 需要保持原 stream chunk 格式。

任务进度回调示例:

POST ${TASK_PROGRESS_CALLBACK_URL}
Authorization: Bearer ${SERVER_MAIN_INTERNAL_TOKEN}
Content-Type: application/json
Idempotency-Key: ${taskId}:${seq}
X-EasyAI-Event-Type: task.progress
{
  "eventId": "uuid",
  "taskId": "uuid",
  "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 收到后不重新执行任务,只做三件事:

  1. Idempotency-KeytaskId + seq 幂等落库/去重。
  2. 根据 externalTaskIdtaskIduserIdtenantId 找到原业务会话或任务频道。
  3. 通过原 WebSocket 网关推送给业务前端,保持前端订阅协议不大改。

12.3 进度持久化要求

  • 所有对用户可见的状态变化都必须先写 gateway_task_events,再写 gateway_task_callback_outbox,最后广播/投递。
  • 客户端断线后能从 seqLast-Event-ID 补齐。
  • 任务恢复后必须先重放最近状态,再继续发布新进度。
  • 完成态事件必须包含足够的结果摘要,前端无需额外轮询才能更新卡片状态。
  • 回调投递失败不能阻塞任务执行,但必须进入 outbox 重试,并在控制台显示滞留状态。
  • 同一任务的回调按 seq 保序投递;允许不同任务并发投递。

13. 测试模式与全链路模拟

AI Gateway 需要内置测试模式,目标是在不触达真实供应商、不真实扣费、不调用主服务生产上传接口的前提下,把请求完整跑过路由、候选客户端选择、队列、限流、失败切换、进度流、结果归一、任务恢复等核心链路。

13.1 启用方式

支持三种启用粒度:

粒度 配置 说明
全局 `AI_GATEWAY_RUN_MODE=production simulation`
请求级 X-EasyAI-Test-Mode: simulation 或 body test_mode=true 仅对单次请求模拟,默认只允许 power/manager 或内部服务使用
平台/模型级 platform.config.testModemodel.config.testMode 指定平台、模型在测试环境永远走模拟

安全要求:

  • 生产环境默认禁止普通用户请求级 test mode需要显式开启 ALLOW_REQUEST_TEST_MODE=true
  • OpenAPI sk-* 默认不能打开 test mode除非 API Key 或租户配置允许。
  • 进入 simulation 后必须在 task、attempt、event、response 中标记 simulated=true,避免和真实任务混淆。

13.2 模拟链路

测试模式仍走完整执行链:

HTTP route -> auth -> route compatibility adapter -> model router
-> persistent queue -> rate limiter -> SimulationClient
-> progress events -> normalized result -> dry-run billing -> task completed

不会执行的动作:

  • 不调用真实 provider 的 submit / poll / cancel API。
  • 不生成真实供应商订单或任务。
  • 不向 server-main 发真实扣费结算事件。
  • 不调用 server-main 的生产文件上传,除非显式使用测试环境上传接口。
  • 不消耗真实平台并发额度。

仍会执行的动作:

  • 真实鉴权。
  • 真实路由和候选客户端排序。
  • 真实队列持久化、锁、heartbeat、恢复。
  • 真实限流令牌计算。
  • 真实进度事件持久化和推送。
  • 真实任务记录、attempt 记录、dry-run outbox 记录。

13.3 Simulation Profile

SimulationClient 根据 simulation_profile 生成确定性行为:

{
  "simulation_profile": {
    "latencyMs": [300, 800, 1200],
    "progressSteps": [0.1, 0.35, 0.7, 1],
    "resultKind": "image",
    "resultCount": 2,
    "failures": [
      { "attempt": 1, "errorCode": "timeout", "retryable": true },
      { "attempt": 2, "errorCode": "rate_limit", "retryable": true }
    ],
    "seed": "task-id-or-custom-seed"
  }
}

用途:

  • 模拟成功:返回固定格式图片、视频、音频、文本或 embedding 结果。
  • 模拟失败:按 attempt 注入可重试 / 不可重试错误。
  • 模拟慢任务:验证进度、断线重连、任务恢复。
  • 模拟限流验证排队、等待上限、cooldown。
  • 模拟未知提交态:验证 retryOnSubmitUnknown 和人工补偿路径。

13.4 失败切换测试

测试模式必须能验证“上一个客户端失败,下一个客户端重试”:

  1. router 仍按真实规则选出多个候选客户端。
  2. SimulationClient 为第一个候选返回 retryable error。
  3. runtime 写入 failed attempt。
  4. retry policy 判断可切换。
  5. router 排除已失败且不可复用的 client选下一个候选。
  6. 第二个候选成功后,任务以 succeeded 完成,并记录完整 attempts。

禁用重试时,同样的失败应直接进入 failed_final,不能切换客户端。

13.5 Dry-run 计费与结算

  • EstimateBilling 仍使用真实计费配置计算,结果标记 simulated=true
  • settlement_outbox 可写入 dry_run 事件,但默认状态为 skipped,不触发主服务扣费。
  • 若需要联调主服务结算接口,只能调用 server-main 的 dry-run settlement endpoint不能复用真实扣费 endpoint。

13.6 模拟结果资产

测试模式下的文件结果有三种来源:

  • 内置静态占位 URL例如 /static/simulation/image.png
  • data URL / inline metadata仅用于接口契约测试。
  • 测试文件上传接口:只有显式启用 AI_GATEWAY_SIMULATION_UPLOAD=true 时才允许调用 server-main 测试环境上传接口;默认使用内置静态占位资产。

结果必须带:

{
  "simulated": true,
  "assetSource": "simulation",
  "provider": "simulation"
}

13.7 观测与审计

控制台需要能筛选 run_mode=simulation 的任务,展示:

  • 使用的 simulation profile。
  • 每次 attempt 的模拟错误和重试决策。
  • 生成的 progress events。
  • dry-run billing。
  • 是否触发了恢复流程。

14. server-main 对接方式

14.1 短期server-main 仍保留入口

server-main 对外接口不变:

  • /chat/completions
  • /images/generations
  • /video/generations
  • /v1/chat/completions
  • /v1/images/generations
  • /v1/video/generations

内部 OpenaiService 变成薄门面:

sequenceDiagram
  participant FE as Frontend
  participant MAIN as server-main
  participant GW as AI Gateway
  participant V as Vendor

  FE->>MAIN: POST /images/generations
  MAIN->>MAIN: create history / task id
  MAIN->>GW: POST /api/v1/images/generations
  GW->>V: submit task
  GW-->>MAIN: POST task progress callback
  MAIN-->>FE: WebSocket task progress
  V-->>GW: result
  GW-->>MAIN: POST task completed callback
  MAIN-->>FE: WebSocket task completed
  GW-->>MAIN: settlement event with billings
  MAIN->>MAIN: billing + history update
  GW-->>MAIN: task result
  MAIN-->>FE: response

14.2 实时任务进度回调

AI Gateway 不直接替换原业务前端的 WebSocket 订阅方式。Gateway 在配置中指定任务进度回调地址:

TASK_PROGRESS_CALLBACK_URL=http://easyai-server-main:3000/internal/platform/task-progress-callbacks
TASK_PROGRESS_CALLBACK_ENABLED=true
TASK_PROGRESS_CALLBACK_TIMEOUT_MS=5000
TASK_PROGRESS_CALLBACK_MAX_ATTEMPTS=10

运行时要求:

  • BaseClient / runtime 每产生一个进度事件,先写 gateway_task_events,再写 gateway_task_callback_outbox
  • callback worker 使用 SERVER_MAIN_INTERNAL_TOKEN 调用 TASK_PROGRESS_CALLBACK_URL
  • server-main 收到事件后进入主服务内部推送流程,再由原 WebSocket 网关推送给业务前端。
  • Gateway 控制台仍可通过 SSE 读 gateway_task_events,用于运维诊断,不影响业务前端推送通道。
  • 如果 server-main 短暂不可用Gateway 按 outbox 重试;超过最大次数后标记 failed,控制台可手动 replay。

14.3 中期:前端直接打 Gateway

前端配置 VITE_GATEWAY_API_BASE_URL,生成类请求直接走网关路由到 AI Gateway。server-main 只处理登录、刷新、余额、历史、开放文件上传、扣费。

即使生成请求改为前端直连 Gateway业务实时进度默认仍回调 server-main 内部任务进度接口,除非某个新业务明确迁移到 Gateway 自身的事件通道。

14.4 结算事件

Gateway 任务成功后向 server-main 发送结算事件:

{
  "eventId": "uuid",
  "taskId": "uuid",
  "userId": "user-id",
  "tenantId": "tenant-id",
  "apiKeyId": "optional",
  "kind": "images.generations",
  "model": "gpt-image-1",
  "billings": [
    {
      "resourceType": "image",
      "amount": 1,
      "unit": "item",
      "cost": 100
    }
  ],
  "resultRef": {
    "url": "https://..."
  }
}

要求:

  • server-maineventId / taskId 做幂等。
  • Gateway 保留 outbox 或重试表,避免结算事件丢失。
  • 扣费失败时任务结果仍可先保存,但前端展示需要明确异常状态。

15. 文件上传

文件上传策略收敛为:AI Gateway 不维护自己的 OSS/COS/S3 配置,不做预签名,不直接写对象存储;所有需要上传或转存的文件,统一调用 server-main 已开放的文件上传接口。这样可以复用主服务现有 OSS 配置、权限、文件记录、MIME 推断和后续审计。

15.1 ServerMainUploadClient 抽象

type ServerMainUploadClient interface {
  UploadMultipart(ctx context.Context, input UploadMultipartInput) (UploadedAsset, error)
  UploadFromURL(ctx context.Context, input UploadFromURLInput) (UploadedAsset, error)
  ResolveAsset(ctx context.Context, ref AssetRef) (ResolvedAsset, error)
}

15.2 调用接口

默认调用 server-main 的开放上传接口:

Method Path 说明
POST /v1/files/upload OpenAPI 兼容 multipart 文件上传

调用要求:

  • 用户请求:透传用户 JWT 或 OpenAPI sk-*,保持与原主服务上传权限一致。
  • Gateway 内部上传:使用服务令牌加原始用户上下文头,例如 X-EasyAI-User-IdX-EasyAI-Tenant-IdX-EasyAI-Task-Id,具体以 server-main 内部约定为准。
  • 上传返回值以主服务响应为准Gateway 只做字段归一并写入 gateway_upload_assets
  • 测试模式默认不调用上传接口,除非显式启用测试上传。

15.3 上传场景

场景 处理方式
前端已经通过主服务上传 请求中携带主服务返回的 URL / file idGateway 只校验和记录
Gateway 需要转存远程 URL Gateway 下载远程内容,作为 multipart 调 /v1/files/upload 上传到主服务
Provider 返回临时 URL Gateway 拉取结果,再调 /v1/files/upload 转存,最终结果使用主服务 URL
OpenAPI multipart 上传 继续由 server-main/v1/files/upload 承接Gateway 不新增并行上传入口
base64 小文件 Gateway 解码为 multipart再调用 /v1/files/upload

15.4 安全与可靠性

  • 限制最大文件大小、content-type、扩展名。
  • 远程 URL 下载必须禁止内网地址、metadata 地址、超长重定向链。
  • 上传到 server-main 时带 Idempotency-Key,避免重启或 retry 造成重复文件记录。
  • gateway_upload_assets 记录主服务返回的 file id、URL、object key、checksum、响应快照。
  • 如果上传失败,任务按 provider retry 策略判断是否可重试;上传失败本身也要写 attempt/event。
  • Gateway 不保存长期文件密钥,不暴露 OSS 配置页面。

16. 前端页面设计

前端使用 React + TypeScript + TSX + shadcn-ui定位不是单纯后台控制台而是“AI 能力门户 + 用户工作台 + 管理工作台 + API 文档中心”。页面根据 IDENTITY_MODE 切换身份来源:独立模式走 Gateway 本地登录 / API Key接入 server-main 时走主服务 JWT / OpenAPI Key 授权。普通用户只能进入模型、用户工作台和 API 文档,管理员额外进入管理工作台。

16.1 一级导航

一级模块 路由 默认权限 定位
登录 /login/register public Gateway 本地账号登录注册、外部 token 入口
首页 / public/basic 服务入口、模型能力概览、用量摘要、最近任务、快捷入口
模型 /models public/basic 可用模型浏览、能力筛选、价格/限流展示、模型调用入口
用户工作台 /workspace basic 个人中心、余额充值、API Key、任务记录
管理工作台 /admin power/manager 用户与用户组、全局模型配置、平台管理、队列限流、结算与系统设置
API 文档 /docs public/basic 开放接口文档、鉴权说明、示例代码、在线调用测试

16.2 登录与注册

首期登录页先提供普通账号能力和可选邀请码注册,后续再接 SSO、验证码、MFA

页面 路由 权限 说明
登录 /login public 用户名/邮箱 + 密码登录 Gateway 本地账号
注册 /register public 创建 Gateway 本地账号;可填写租户 key / 租户名称 / 邀请码,邀请码不是必填
外部 Token 入口 /login?mode=external public 粘贴 server-main access token用于接入模式和开发调试

登录成功后统一获得 Gateway 可校验的 access token本地账号 token 中包含 source=gatewaygatewayUserIdgatewayTenantIdtenantKey。外部 token 保留 source=server-main 或主服务返回的 claim。

16.3 首页

首页不是营销页,首屏应直接提供可操作入口和运行状态。

页面 路由 权限 说明
首页总览 / public/basic 推荐模型、最近任务、余额摘要、API Key 状态、服务公告
能力概览 /capabilities public/basic Chat、生图、生视频、音频、Embedding 等能力入口
服务状态 /status public/basic 网关健康、模型可用性、平台异常公告、限流提示

首页组件:

  • HeroStatusBand:显示 Gateway 健康、可用模型数、今日任务数、当前余额。
  • QuickStartActionsChat 调用、生图调用、生视频调用、创建 API Key、查看 API 文档。
  • ModelCapabilityGrid按文本、图像、视频、音频、Embedding 展示可用能力。
  • RecentTasks:最近任务状态、进度、失败原因和重试入口。
  • UsageSnapshot本月调用量、token、图片/视频任务、费用趋势。

16.4 模型

模型页面面向普通用户和管理员,但展示内容按权限裁剪。

页面 路由 权限 说明
模型广场 /models public/basic 按能力、provider、价格、上下文、多模态筛选模型
模型详情 /models/:modelKey public/basic 能力、价格、限流、参数 schema、示例请求、在线试用
模型价格 /models/:modelKey/pricing basic 文本输入/输出、图像分辨率/质量、视频时长/分辨率等价格
模型调用测试 /models/:modelKey/playground basic 选择 API Key 或 JWT在线测试 Chat/生图/生视频

模型页能力:

  • 筛选模型类型、provider、是否支持 stream、多模态、参考图/视频/音频、上下文窗口、价格区间。
  • 展示有效模型价、TPM/RPM/并发限制、是否支持测试模式、常见错误码。
  • 管理员视角:展示平台模型来源、基准模型映射、平台折扣、能力覆盖和实际候选平台。

16.5 用户工作台

用户工作台关注“我能用什么、用了多少、怎么调用、历史任务在哪里”。

页面 路由 权限 说明
个人中心总览 /workspace/overview basic 账号信息、身份来源、角色、用户组、余额、API Key 数、最近任务、用量摘要
余额与充值 /workspace/billing basic 余额、资源包、充值入口、消费记录、用户组充值折扣、发票/订单状态
API Key 管理 /workspace/api-keys basic API Key 列表、创建、禁用、重置、权限范围、最近调用
任务记录 /workspace/tasks basic Chat/生图/生视频等任务列表,按状态、模型、时间筛选
任务详情 /workspace/tasks/:id basic 请求、进度事件、结果、计费、上传资产、失败原因

边界:

  • 独立模式下用户资料、API Key、余额、充值订单和钱包流水由 Gateway 本地模块闭环;接入 server-main余额、充值、订单、API Key 生命周期仍归 server-mainGateway 前端可以通过 server-main API 或兼容代理展示。
  • 用户组影响充值折扣、调用折扣和并发/限流工作台需要展示当前用户命中的用户组、折扣说明、TPM/RPM/并发限制。
  • 任务记录以 Gateway 任务为执行事实源,但业务历史最终仍可由 server-main 汇总。
  • API Key 创建时必须显示一次性 secret后续只展示 key 名称、前缀、权限和最近使用时间。

16.6 管理工作台

管理工作台只对 power/manager 开放,负责全局模型、平台、限流、重试、运行态和系统集成。当前阶段平台凭证和 provider 凭证仅允许全局管理员配置,租户管理员暂不拥有自助配置入口。

页面 路由 权限 说明
管理总览 /admin power 服务健康、任务吞吐、成功率、队列积压、异常平台、回调 outbox
租户管理 /admin/tenants power 本地租户、同步租户、租户策略、状态和用量隔离
用户管理 /admin/users power 本地用户、同步用户、角色、状态、同步差异和用户组命中
用户组管理 /admin/user-groups power 用户组、成员关系、充值折扣、调用折扣、并发/限流策略
全局模型配置 /admin/models/global power 基准模型库、能力 schema、基准定价、默认限流模板
基准 Provider /admin/catalog/providers power provider 列表、协议类型、能力 schema、启停状态
基准模型详情 /admin/catalog/base-models/:id power 能力、价格版本、默认 TPM/RPM/并发、引用平台模型
定价规则 /admin/pricing/rules power 文本/图像/视频/音频价格、动态权重、版本生效时间
平台管理 /admin/platforms power 平台 CRUD、启停、优先级、凭证状态、复制、异常重置
平台详情 /admin/platforms/:id power 基础信息、凭证、模型、折扣、限流、重试、运行态、快照
平台模型 /admin/platform-models power 平台模型列表、基准映射、能力覆盖、价格覆盖、权限过滤
API 配置 /admin/platform-apis power 兼容原 integration/platform-api 的 CRUD 与执行测试
队列监控 /admin/runtime/queues power queue key、等待数、运行数、租约、恢复状态
客户端运行态 /admin/runtime/clients power running、waiting、limiter ratio、cooldown、last error
限流策略 /admin/policies/rate-limit power TPM、RPM、并发、队列长度、冷却策略
重试策略 /admin/policies/retry power global/provider/platform/model/method 重试策略
任务审计 /admin/tasks power 全量任务、attempt、失败切换、用户/模型/平台筛选
上传记录 /admin/uploads power 主服务上传记录映射、任务关联、失败重试
结算 outbox /admin/settlements manager 结算事件、重试、跳过、幂等 key
回调 outbox /admin/callbacks power 任务进度回调状态、失败原因、手动 replay
测试模式 /admin/simulation power simulation profile、失败注入、慢任务、dry-run billing
系统设置 /admin/settings manager server-main 地址、内部令牌、运行模式、安全开关

关键管理页面:

  • 全局模型配置:维护 model_catalog_providersbase_model_catalogmodel_pricing_rules,支持导入旧项目配置。
  • 租户管理:维护 gateway_tenants,支持本地租户 CRUD、从 server-main 增量同步、禁用状态同步、租户策略和用量隔离审计。
  • 用户管理:维护 gateway_users,支持本地用户 CRUD、从 server-main 增量同步、禁用状态同步、角色同步和同步差异审计。
  • 用户组管理:维护 gateway_user_groupsgateway_user_group_memberships,支持从 server-main 同步成员关系;独立模式执行全部策略,接入模式下充值折扣由 server-main 执行Gateway 执行调用折扣和并发/限流。
  • 平台管理:创建平台时选择基准 provider配置默认折扣系数平台模型可 follow 基准、按折扣继承或自定义覆盖。
  • 队列与限流:展示 TPM/RPM 窗口、预占值、并发 lease、cooldown、next run。
  • 回调 outbox展示 Gateway 到进度回调目标的投递结果,支持按 task replay。

16.7 API 文档与在线调用测试

API 文档面向开发者,需要能完成从鉴权到真实调用的闭环。

页面 路由 权限 说明
文档首页 /docs public/basic 快速开始、鉴权方式、模型列表、错误码、限流说明
鉴权 /docs/auth public/basic JWT、OpenAPI sk-*、Header、权限范围、API Key 安全
Chat /docs/api/chat public/basic /v1/chat/completions、stream、工具调用、示例代码
Responses /docs/api/responses public/basic /v1/responses 请求、取消、结构化输出
图片 /docs/api/images public/basic /v1/images/generations/v1/images/edits、文件输入
视频 /docs/api/videos public/basic /v1/video/generations、进度查询、结果取回
音频/语音 /docs/api/audio public/basic speech、music、digital human 等接口
Embeddings /docs/api/embeddings public/basic embedding 模型、批量输入、维度说明
文件上传 /docs/api/files public/basic 说明仍调用 server-main /v1/files/upload
任务结果 /docs/api/tasks public/basic /v1/ai/result/:taskId、取消、状态、回调语义
错误码 /docs/errors public/basic 兼容错误结构、retryable 分类、限流错误
在线调试 /docs/playground basic 选择模型、API Key、请求模板执行在线调用测试

在线调试器:

  • 左侧选择接口类型Chat、Responses、生图、图像编辑、生视频、Embedding、语音。
  • 中间为参数表单 + JSON editor 双模式,表单字段来自模型能力 schema。
  • 右侧展示 curl、JavaScript、Python 示例代码和实时响应。
  • 支持 stream 结果面板、任务进度时间线、结果预览、usage / billings。
  • 支持测试模式开关;开启后标记 simulation,不触达真实 provider、不真实扣费。
  • 调试前展示当前 API Key 的权限、余额、TPM/RPM/并发限制。

16.8 前端模块目录

apps/web/src/
  app/
    routes.tsx
    providers.tsx
  components/
    ui/                 # shadcn-ui generated components
    layout/
    data-table/
    json-viewer/
    status-badge/
  features/
    auth/
      login/
      register/
    home/
    models/
    workspace/
      overview/
      billing/
      api-keys/
      tasks/
    admin/
      dashboard/
      catalog/
      tenants/
      users/
      user-groups/
      pricing/
      platforms/
      platform-apis/
      runtime/
      policies/
      tasks/
      callbacks/
      uploads/
      settlements/
      simulation/
      settings/
    docs/
      api-reference/
      playground/
  lib/
    api-client.ts
    auth.ts
    format.ts
    query-keys.ts
  contracts/
    dto.ts              # 或从 packages/contracts 引入

16.9 前端数据流

  • 使用 @tanstack/react-query 管理列表、详情、轮询和 mutation。
  • 表格使用 @tanstack/react-table,配合 shadcn Table
  • 表单使用 react-hook-form + zod,校验策略与后端 DTO 对齐。
  • 用户工作台在独立模式下调用 Gateway 本地身份/账务模块;接入 server-main 时余额、充值、API Key 生命周期优先调用 server-main APIGateway 展示执行侧任务、模型能力、用户同步状态和用户组执行策略。
  • Gateway 控制台事件统一封装为 useTaskEvents(taskId);业务前端实时进度仍由原 WebSocket 网关推送。
  • 所有 destructive action 使用 shadcn Dialog 二次确认。
  • 页面级权限由路由 loader 或 wrapper 判断,不在每个按钮里重复散落判断。

17. 迁移计划

Phase 0脚手架与契约

  • 建立 monorepo、Go API、React 控制台、PG migration。
  • 前端接入 shadcn-ui,建立基础组件目录和主题 token。
  • PG 目标版本为 PostgreSQL 18复用 Agent memory 的 easyai-pgvector 实例,但使用独立数据库 easyai_ai_gateway,避免与 easyai_memory 的记忆表混库。
  • 容器网络内默认连接串为 postgresql://easyai:easyai2025@easyai-pgvector:5432/easyai_ai_gateway?schema=public;宿主机直跑时必须改成宿主机可访问的 host/port例如 localhost 或实际映射端口。
  • 如果只提供 MEMORY_DATABASE_URLGo 侧只借用其中的 host/user/password并按 AI_GATEWAY_DATABASE_NAME 替换数据库名;同时会把 Prisma 风格的 schema=public 转成 PostgreSQL search_path 参数。
  • 建立 JWT / API Key 授权中间件骨架和 standalone / server-main / hybrid 身份模式配置,默认 hybrid
  • 固化 API、事件、数据库设计。
  • 建立 simulation / dry-run 模式配置与安全开关,默认禁止生产环境普通用户随意开启。
  • 建立基准 provider、基准模型库、价格规则、用户、用户组策略、邀请码、本地 API Key、钱包、充值订单和 TPM/RPM/并发限流表结构。

Phase 1模型库 + 首批生成能力

第一阶段只做可落地的核心闭环模型库、大模型对话、生图、图像编辑。Client 只迁移 OpenAI 和 Gemini 两个,视频和其他 provider 后移。

  • 导入 OpenAI、Gemini 的基准 provider、基准模型、能力 schema、默认限流模板形成首批 base_model_catalog
  • 建立全局模型配置:模型类型、上下文、多模态能力、图片输入/输出能力、stream 支持、价格规则。
  • 平台创建支持选择基准模型、设置默认折扣系数;平台模型支持 follow 基准模型、折扣继承和自定义覆盖。
  • 建立 gateway_users 同步副本和 gateway_user_groups 策略解析,支持本地用户与 server-main 用户在同一套策略链路里命中不同折扣和限流。
  • 建立本地账号闭环:普通注册可选邀请码,独立模式支持本地 API Key、余额、充值订单和钱包流水。
  • 迁移大模型对话路由:/chat/completions/v1/chat/completions,并为 /responses / /v1/responses 保留兼容契约。
  • 迁移生图和图像编辑路由:/images/generations/v1/images/generations/images/edits/v1/images/edits
  • 建立 OpenAI Chat / Image Client 与 Gemini Chat / Image Client 的 Base Client 实现和 contract test。
  • 支持文本输入/输出 token 计费,图像按分辨率、质量、数量、生成/编辑模式计费。
  • 实现调用 server-main 开放上传接口的 ServerMainUploadClient覆盖参考图、mask、provider 临时 URL 转存、base64 小文件上传。
  • 实现 SimulationClient支持 Chat、生图、图像编辑的成功、失败、慢任务、限流、未知提交态等 profile。

Phase 2路由、队列与稳定性补强

  • 迁移 IntegrationModelFactory.assignClientsByModelName 行为。
  • 建立 Base Client 生命周期:构建参数、提交任务、轮询结果、归一化结果、估算计费、取消任务。
  • 实现客户端失败切换策略:上一个客户端失败后按配置切到下一个候选客户端。
  • 补队列持久化、TPM/RPM/并发限流、重启恢复、重试、超时、任务事件。
  • 实现任务进度 callback outbox将 Gateway 进度回调给实时推送通道;同时保留 Gateway 控制台 SSE / WebSocket 和 OpenAI stream。
  • 为 OpenAI、Gemini 增加 retry classification test、billing snapshot、progress event snapshot。

Phase 3server-main 切薄门面与灰度

  • OpenaiService 内部先将 Chat、生图、图像编辑切到 Gateway HTTP SDK。
  • 结算事件接入 server-main 扣费链路。
  • 前端逐步改 Gateway API Base URL
  • 开启 shadow / dry-run比对旧实现和 Gateway 的候选模型、预估扣费、参数预处理结果。

Phase 4视频与更多 provider

  • 在 Phase 1 稳定后再迁移生视频、音频、Embedding、音乐、数字人等能力。
  • 迁移 RunningHub、Jimeng、Vidu、Kling、Hunyuan Video、Suno 等 provider。
  • 对 app-style provider 补 assignClientsByProviderMethodprovider + methodName 队列 key。
  • 每个 provider 增加 contract test、retry classification test、billing snapshot。

Phase 5server-main 清理旧实现

  • 删除或冻结 server-main 中重复的 runtime client。
  • 保留必要 BFF、历史、账单、文件上传能力。

18. 验收标准

  • pnpm nx run api:migrate 可在 Agent memory PostgreSQL 中初始化 AI Gateway 表。
  • pnpm nx run api:test 通过。
  • pnpm nx run web:build 通过。
  • 控制台使用 shadcn-ui 组件,不出现散落的独立 UI 体系。
  • 使用 server-main 签发的 JWT 能访问 /api/v1/me
  • OpenAPI sk-* 能委托 server-main 校验并获得用户 claim。
  • integration-platform、站内生成、/v1/* 核心路由可用DTO 与响应结构兼容。
  • 基准 provider、基准模型库、基准价格和默认限流模板可在控制台维护。
  • 用户、用户组、成员关系、充值折扣、调用折扣、TPM/RPM/并发策略可在管理工作台维护;独立模式可本地闭环,接入模式下充值执行仍以 server-main 为事实源。
  • 接入 server-main 时,用户、角色、禁用状态和用户组成员关系支持增量同步;任务保存用户和用户组策略快照。
  • 平台创建可设置默认折扣系数;平台模型未配置时 follow 基准模型,配置折扣时按基准价折扣计算,自定义覆盖时覆盖价格和能力。
  • 文本定价支持输入/输出 token 分开计费;图像定价支持分辨率和质量权重;视频定价支持时长、分辨率、有无音频等权重。
  • estimated billing 与真实任务 billings 使用同一个 effective pricing resolver不能出现预估和真实路由价格来源不一致。
  • 队列任务在服务异常重启后可恢复:已提交供应商的任务继续 poll未提交任务重新排队。
  • 限流策略覆盖 TPM、RPM、并发并支持平台、客户端、基准模型、平台模型、方法、租户、用户组、用户、API Key 维度。
  • TPM/RPM 一分钟窗口和并发 lease 在服务重启后可恢复或释放,不产生永久占用。
  • 多客户端候选下,一个客户端可重试失败后按策略切换下一个客户端;禁用重试时必须直接失败。
  • Base Client 架构覆盖构建参数、提交任务、取回结果、归一化结果、计费估算、取消任务。
  • 任务中间进度可通过 SSE / WebSocket / stream 返回,并支持断线重放。
  • 业务前端实时进度通过 TASK_PROGRESS_CALLBACK_URL 回调到 server-main 内部任务进度接口,再由主服务复用原 WebSocket 网关推送callback outbox 支持失败重试和手动 replay。
  • 文件上传统一调用 server-main 开放上传接口Gateway 不维护自己的 OSS 配置。
  • 测试模式下不会向真实平台提交任务、不会真实扣费、不会调用主服务生产上传接口,但会完整经过路由、队列、限流、重试、进度和结果归一。
  • 测试模式支持 profile 注入可重试错误,能验证客户端失败切换;禁用重试时能验证直接失败。
  • Phase 1 至少完成 Chat / 生图 / 图像编辑各一个 provider 的端到端任务;生视频放到 Phase 4 后续迁移。
  • 结算事件在 server-main 幂等扣费。
  • 同名模型跨平台权限过滤与旧逻辑一致。

19. 本轮设计复核结论与已确认决策

本轮复核后已修正:

  • 身份边界:不再写成“用户/租户只能留在 server-main”,改为 standaloneserver-mainhybrid 三种模式。
  • 多租户:补 gateway_tenants,并把用户、任务、平台可见性、限流和策略解析都接入租户上下文。
  • 登录注册:补 Gateway 本地账号注册登录接口和前端登录页规划。
  • 进度回调:统一表述为回调 server-main 内部任务进度接口,不直接回调 ws-gateway。
  • Phase 1 范围继续限定为模型库、Chat、生图、图像编辑、OpenAI 和 Gemini视频迁移放到后续阶段。

已确认决策:

  1. 默认身份模式就是 hybrid,用于同时支持本地账号和 server-main token / API Key。
  2. 普通注册支持填写邀请码,但邀请码不是必填项;填写后按邀请码加入指定租户和用户组。
  3. 先做本地闭环:独立模式下本地 API Key、余额、充值订单和钱包流水由 Gateway 承接。
  4. 当前阶段仅允许全局管理员配置 provider / platform 凭证和全局模型,不开放租户管理员自助配置凭证。