docs(readme): 更新项目文档为智能模型网关
chore(database): 优化模型配置表结构和索引设计 - 重新设计 model_gateway_models 表的字段结构和约束 - 新增 billing_config 和 special_params 配置字段 - 优化索引策略,包括复合索引和条件索引的创建 - 统一表注释格式和字段说明文档 - 移除过时的配置字段和冗余索引
This commit is contained in:
@@ -1,206 +1,434 @@
|
||||
# model-asynch(模型异步中间件)[2026.5.12前,暂时弃置]
|
||||
# Model Gateway — 智能模型网关
|
||||
|
||||
一个独立的异步中间件服务:按模型配置路由调用不同模型服务,统一生成 `task_id`,后台异步执行,结果上传 OSS,并提供查询/批量领取/自动重试/自动清理能力,便于业务方“拿走结果并转移”。
|
||||
|
||||
> 分支约定:`dev` 为开发分支;`main`(或 master)为线上主分支。
|
||||
统一的 AI 模型网关服务,负责多模态(文本、图像、音频、向量、视频、全模态)模型调用的路由、执行与管理。基于 Go (GoFrame v2) 构建,使用 PostgreSQL、Redis 和 Consul 服务发现。
|
||||
|
||||
---
|
||||
|
||||
## 1. 核心功能
|
||||
## 架构概览
|
||||
|
||||
### 1.1 模型配置(asynch_models)
|
||||
- 增删改查模型服务配置(`model_name` 唯一标识)
|
||||
- 支持配置:
|
||||
- 请求地址:`base_url + route`
|
||||
- 请求方式:`http_method`(GET/POST)
|
||||
- 请求头:`head_msg`(以请求头注入,支持多个 header)
|
||||
- 超时:`timeout_seconds`
|
||||
- 并发:`max_concurrency`(按租户+模型的 Redis 分布式信号量限流)
|
||||
- 重试:`retry_times`(失败后最多再重试 N 次)
|
||||
- 保留:`auto_clean_seconds`(任务被业务领取到 `state=4` 后的保留秒数,到期清理)
|
||||
```
|
||||
客户端 ──> HTTP API ──> Controller ──> Service ──> DAO ──> PostgreSQL
|
||||
│ └─> Redis(信号量/队列)
|
||||
│
|
||||
├──> AI 模型服务商(OpenAI、阿里云、火山引擎等)
|
||||
├──> OSS 文件服务
|
||||
├──> Admin-go(租户/余额)
|
||||
├──> Prompts-core(会话回调)
|
||||
└──> Skill 技能服务
|
||||
```
|
||||
|
||||
### 1.2 异步任务(asynch_task)
|
||||
- 创建任务:生成 `task_id`,入库排队
|
||||
- 后台 Worker:
|
||||
- PostgreSQL `FOR UPDATE SKIP LOCKED` 抢占任务,支持多实例不重复消费
|
||||
- 调用模型服务(GET/POST)
|
||||
- 结果上传 OSS(调用你们的 OSS 文件服务 `oss/file/uploadFile`,透传 `Authorization/X-User-Info`)
|
||||
- 批量领取结果:批量查询 `task_id` 列表,返回 `task_id/state/oss_file`,并把成功的任务从 `state=2` 更新为 `state=4`
|
||||
- 自动重试:失败 `state=3` 会由清理器按 `retry_times` 重新入队到队尾
|
||||
- 自动清理:
|
||||
- `state=4` 且 `expire_at` 到期 → 硬删除任务
|
||||
- 失败重试耗尽仍失败 → 硬删除任务
|
||||
- `state=0/1` 超时 → 标记失败(防止卡死)
|
||||
系统分为六个层次:
|
||||
|
||||
### 1.3 统计(asynch_model_stat)
|
||||
- 按天统计:`day + tenant_id + creator + model_name -> request_count`
|
||||
- 统计口径:仅在 Worker 真正调用模型服务时计数(OSS 重试不计数)
|
||||
- 用途:给其他服务提供全局限流/监控依据
|
||||
| 层次 | 目录 | 职责 |
|
||||
|---|---|---|
|
||||
| **控制器层** | `controller/` | HTTP 路由注册与请求绑定 |
|
||||
| **业务逻辑层** | `service/` | 模型配置 CRUD、异步任务执行、提示词构建、队列管理、统计 |
|
||||
| **数据访问层** | `dao/` | PostgreSQL 数据访问(GoFrame ORM) |
|
||||
| **模型层** | `model/` | DTO 请求/响应结构与数据库实体定义 |
|
||||
| **通用工具层** | `common/` | 计费、类型转换、文件处理、请求头、映射、提示词、流式解析等工具 |
|
||||
| **常量层** | `consts/` | 公共常量和表名定义 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 使用流程(业务方如何接入)
|
||||
## 核心功能
|
||||
|
||||
### 第一步:创建模型配置
|
||||
业务方(或运维)先在中间件里创建/更新模型配置(`model_name` 为唯一键),例如:
|
||||
- `POST /model/createModel`(或 `/model/updateModel`)
|
||||
### 1. 模型配置管理 (`model_gateway_models`)
|
||||
|
||||
提供 AI 模型服务配置的完整增删改查:
|
||||
|
||||
| 字段 | 说明 |
|
||||
|---|---|
|
||||
| `model_name` | 模型名称(唯一标识) |
|
||||
| `model_type` | 模型分类(100=推理, 200=图像, 300=音频, 400=向量, 500=全模态, 600=视频) |
|
||||
| `operator_name` | 运营商标识(OpenAI、阿里云、火山引擎等) |
|
||||
| `base_url` | 模型服务地址 |
|
||||
| `http_method` | GET / POST |
|
||||
| `head_msg` | 每次调用注入的请求头 |
|
||||
| `form_json` | 动态表单定义(用于前端按模型渲染参数表单) |
|
||||
| `request_mapping` / `response_mapping` | 标准格式与提供商 API 之间的参数映射 |
|
||||
| `call_mode` | 0=同步, 1=异步, 2=流式 |
|
||||
| `max_concurrency` | 单模型最大并发数(按租户维度限流) |
|
||||
| `timeout_seconds` | 请求超时时间(秒) |
|
||||
| `retry_times` | 失败重试次数 |
|
||||
| `billing_config` | 计费规则(推理阶梯计价 / 视频分辨率计价) |
|
||||
| `stream_config` | SSE 流式解析配置 |
|
||||
| `query_config` | 异步任务轮询/查询配置 |
|
||||
|
||||
**支持的模型类型:**
|
||||
|
||||
| 类型码 | 类别 | 子类型 |
|
||||
|---|---|---|
|
||||
| 100 | 推理模型 | 文本生成、对话 |
|
||||
| 200-205 | 图像模型 | 文生图、图生图、图片编辑、图片变体、图文生图 |
|
||||
| 300-303 | 音频模型 | 文生语音、语音转文字、语音转语音 |
|
||||
| 400-402 | 向量模型 | 文本嵌入、重排序 |
|
||||
| 500-502 | 全模态模型 | 文图音频、视觉理解 |
|
||||
| 600-604 | 视频模型 | 文生视频、图生视频、图文生视频、视频生视频 |
|
||||
|
||||
### 2. 异步任务执行 (`model_gateway_task`)
|
||||
|
||||
任务生命周期如下:
|
||||
|
||||
```
|
||||
CreateTask ──> state=0(排队中)
|
||||
│
|
||||
Worker 抢占(state=1,执行中)
|
||||
│
|
||||
├── 同步模式:直接调用模型
|
||||
├── 异步模式:提交任务,通过 QueryConfig 轮询
|
||||
└── 流式模式:通过 StreamConfig 解析 SSE 事件
|
||||
│
|
||||
├── 成功(state=2)──> 上传结果到 OSS
|
||||
│ └──> 触发回调(如有配置)
|
||||
└── 失败(state=3)──> 重试(最多 retry_times 次)
|
||||
│
|
||||
客户端下载(state=4,已下载)
|
||||
```
|
||||
|
||||
**关键特性:**
|
||||
|
||||
- **任务创建**:立即返回 `taskId`,执行在 goroutine 中异步完成
|
||||
- **并发控制**:基于 Redis 的分布式信号量,按模型维度限制并发数
|
||||
- **队列门控**:基于 Redis Lua 脚本的严格队列插槽机制,防止分布式创建下超限
|
||||
- **自动重试**:临时性错误(超时、内部错误)自动重试;硬错误直接失败
|
||||
- **OSS 上传**:结果以 JSON 格式上传到 OSS 文件服务,OSS URL 存入任务记录
|
||||
- **回调通知**:任务完成时可选触发 HTTP 回调(`TriggerCallback`、`TriggerPromptsCallback`、`CallbackBuildResult`)
|
||||
- **阶梯计费**:支持推理 token 阶梯计价和视频分辨率计价两种模型
|
||||
|
||||
### 3. 提示词构建 (`/buildMessages`)
|
||||
|
||||
异步构建推理模型的结构化消息:
|
||||
|
||||
- 从配置合并系统提示词(`modelPrompts.types`)
|
||||
- 拉取技能 Markdown 内容(`SkillMdContent`)
|
||||
- 通过 `GetSessionHistory` 注入会话历史
|
||||
- 根据附件数量自动拆分多轮(`SplitByAttachment`)
|
||||
- 支持视频模型通过对话模型编排的多轮生成
|
||||
|
||||
### 4. 动态调参 (`/autoTune`)
|
||||
|
||||
周期性自动调参(建议每小时触发),基于近期 P90 执行耗时和到达率动态调整 `max_concurrency` 和队列上限:
|
||||
|
||||
- 读取模型配置(数据库中的上限值 cap)
|
||||
- 根据时间窗口内已完成任务统计 P90 执行耗时
|
||||
- 使用 Little 定律(到达率 × P90 / 利用率)计算新的并发数
|
||||
- 单次调整幅度限制在 ±50%
|
||||
- 运行时参数写入 Redis(2 小时 TTL),不修改数据库中的上限值
|
||||
|
||||
### 5. 日统计 (`model_gateway_log_stat`)
|
||||
|
||||
按天、租户、创建人、模型维度的请求计数,使用原子 upsert(`ON DUPLICATE KEY UPDATE`)。
|
||||
|
||||
按天、租户、创建人、模型维度的请求计数,使用原子 upsert(`ON DUPLICATE KEY UPDATE`)。
|
||||
|
||||
### 6. 核心接口详细说明
|
||||
|
||||
#### 6.1 构建消息结构 `/buildMessages`
|
||||
|
||||
构建推理模型的提示词消息体,将系统提示词、技能知识、会话历史、用户自定义提示词合并为最终的消息结构。
|
||||
|
||||
**请求示例(JSON):**
|
||||
|
||||
请求示例(JSON):
|
||||
```json
|
||||
{
|
||||
"modelName": "model-service",
|
||||
"modelsType": "1,2,3",
|
||||
"baseUrl": "http://127.0.0.1:8000",
|
||||
"route": "/api/v1/chat",
|
||||
"httpMethod": "POST",
|
||||
"headMsg": "API_KEY:model-key,API_STATE:true,API_NUM:123",
|
||||
"enabled": 1,
|
||||
"maxConcurrency": 5,
|
||||
"queueLimit": 20,
|
||||
"timeoutSeconds": 1800,
|
||||
"expectedSeconds": 600,
|
||||
"retryTimes": 3,
|
||||
"retryQueueMaxSeconds": 600,
|
||||
"autoCleanSeconds": 3600,
|
||||
"remark": "Model-Service 模型服务"
|
||||
"modelName": "gpt-4o",
|
||||
"buildType": 1,
|
||||
"skillName": "code-review",
|
||||
"callbackUrl": "http://callback.example.com/result",
|
||||
"nodeId": "node_001",
|
||||
"sessionId": "session_abc",
|
||||
"customPrompt": "请用中文回答",
|
||||
"messages": {
|
||||
"model": "gpt-4o",
|
||||
"max_tokens": 4096,
|
||||
"messages": [
|
||||
{"role": "system", "content": [{"type": "text", "text": "你是一名助手"}]},
|
||||
{"role": "user", "content": [{"type": "text", "text": "写一封邮件"}]}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
参数说明:
|
||||
- `modelName`:模型名称(唯一标识/路由键)
|
||||
- `modelsType`:模型类型ID列表(逗号分隔),示例:`1,2,3`(关联 `asynch_models_type.type_id`)
|
||||
| 请求字段 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `modelName` | string | 是 | 网关模型名称 |
|
||||
| `buildType` | int | 是 | 构建类型:1=单轮构建, 2=多轮构建 |
|
||||
| `skillName` | string | 否 | 技能名称,用于拉取技能 MD 知识 |
|
||||
| `callbackUrl` | string | 否 | 构建完成后的回调地址 |
|
||||
| `nodeId` | string | 否 | 节点 ID(用于查询会话历史) |
|
||||
| `sessionId` | string | 否 | 会话 ID |
|
||||
| `messages` | object | 是 | 前端构建的消息结构 |
|
||||
| `customPrompt` | string | 否 | 用户自定义提示词 |
|
||||
|
||||
### 模型类型同步
|
||||
- `POST /model/type/createModelType` 创建成功后,会同步 `POST` 到 `prompts-core` 的 `/prompt/createPrompt`
|
||||
- 同步字段映射:
|
||||
- `typeId` -> `modelTypeId`
|
||||
- `type` -> `modelType`
|
||||
- `promptInfo` -> `promptInfo`
|
||||
- `responseJsonSchema` -> `responseJsonSchema`
|
||||
- `version` -> `version`
|
||||
- 若 `prompts-core` 同步失败,`model-gateway` 会回滚本地新建的模型类型,避免两边数据不一致
|
||||
- `form`:动态表单配置(JSON数组),用于前端按模型渲染参数表单(字段示例:field/label/type/required)
|
||||
- `baseUrl`:模型服务地址(Base URL)
|
||||
- `route`:模型服务路由(拼接到 baseUrl 后)
|
||||
- `httpMethod`:请求方式(GET/POST)
|
||||
- `headMsg`:请求头绑定(支持多个 header,逗号分隔,格式 `Key:Value`;布尔/数字也会以字符串形式注入 header)
|
||||
- `enabled`:是否启用(0禁用/1启用)
|
||||
- `maxConcurrency`:单模型最大并发(按租户+模型维度限流)
|
||||
- `queueLimit`:排队上限(严格控制)。创建任务时通过 Redis Lua 原子闸门校验并占位,保证分布式并发创建不会超限;任务进入成功/失败态后释放占位,失败重试重新入队时会再次占位。
|
||||
- `timeoutSeconds`:调用模型服务超时(秒)
|
||||
- `expectedSeconds`:模型预计执行时间(秒,用于超时判定/排队策略等)
|
||||
- `retryTimes`:失败后最多再重试 N 次(不含首次)
|
||||
- `retryQueueMaxSeconds`:失败重试最大排队时间(秒);0 表示重试插队到队首;>0 表示排队超过该时间后插队,否则仍到队尾
|
||||
- `autoCleanSeconds`:任务被领取到 `state=4` 后的保留时间(秒),到期清理
|
||||
- `remark`:备注说明
|
||||
**响应:**
|
||||
|
||||
### 第二步:创建任务拿到 task_id
|
||||
业务方发起推理请求时调用:
|
||||
- `POST /task/createTask`(传 `modelName + requestPayload + bizName + callbackUrl(可选) + modelKey(可选)`)
|
||||
- 中间件返回 `task_id`
|
||||
- 业务方将 `task_id` 落到自己的业务表,并把业务状态置为「生成中」
|
||||
|
||||
> `modelKey` 用于“动态覆盖/补充”模型配置中的 `head_msg`(例如每次请求携带不同的 `X-API-Key:xxx`)。
|
||||
>
|
||||
> `callbackUrl` 用于任务成功后的回调通知:当任务 `state=2` 成功时,中间件会发起一次 GET 请求:
|
||||
> - 实际回调地址:`callbackUrl/{bizName}`
|
||||
> - query 参数:`task_id/state/oss_file/file_type/text(可选,最多2000字符)`
|
||||
|
||||
### 第三步:同步任务进度(推荐批量)
|
||||
业务方通过轮询/定时任务同步进度:
|
||||
- 推荐:`POST /task/getTaskBatch`(批量传 `taskIds`,返回每个任务的 `state + oss_file`)
|
||||
- 或单条:`GET /task/getTaskResult?taskId=...`
|
||||
|
||||
业务侧拿到 `oss_file` 后自行做资源处理(直接保存或转存),并把业务状态更新为「成功/失败」。
|
||||
|
||||
> 说明:批量接口对 `state=2(成功)` 的任务会自动标记为 `state=4(已下载)` 并写入 `expire_at`,用于后续清理。
|
||||
|
||||
### 后台执行(由上层定时任务控制)
|
||||
本项目不再在服务进程内常驻轮询 worker/cleaner,而是提供两个接口供上层定时任务触发:
|
||||
- `POST /task/runWork`:执行一次 Worker(抢占并处理一批排队任务;适合处理 createTask 立即执行时未处理到的任务和积压队列)
|
||||
- `POST /task/cleanWork`:执行一次 Cleaner(清理过期任务、失败重试、超时任务失败等)
|
||||
|
||||
创建任务执行策略:
|
||||
- `POST /task/createTask` 成功入库后,会立即异步尝试执行当前任务。
|
||||
- 若当前模型并发已满,或当前任务未成功抢占,则会按 `asynch.worker.intervalSeconds` 对当前任务做轻量级定向轮询;只要任务仍为 `state=0` 就继续尝试,一旦进入 `state=1/2/3/4` 就立即停止,不会一直轮询。
|
||||
- 若任务执行成功且配置了 `callbackUrl + bizName`,会在成功落库后异步触发回调钩子。
|
||||
|
||||
本地调试(可选):
|
||||
可在 `config.yml` 中开启自动执行,避免手工频繁调用接口:
|
||||
```yml
|
||||
asynch:
|
||||
worker:
|
||||
enabled: true
|
||||
intervalSeconds: 5
|
||||
batchSize: 10
|
||||
goroutines: 1
|
||||
cleaner:
|
||||
enabled: true
|
||||
intervalSeconds: 30
|
||||
```
|
||||
|
||||
### 动态并发/队列调参(接口请求控制)
|
||||
为支持根据最近一段时间的耗时与吞吐对 `max_concurrency/queue_limit` 做动态调整,本项目提供接口供上层定时任务触发(建议每小时一次):
|
||||
- `POST /model/autoTune`
|
||||
|
||||
请求参数(JSON,可选):
|
||||
```json
|
||||
{
|
||||
"windowSeconds": 3600
|
||||
"taskId": "550e8400-e29b-41d4-a716-446655440000"
|
||||
}
|
||||
```
|
||||
> `windowSeconds` 不传/<=0 默认 3600(1小时)。
|
||||
|
||||
动态调参口径(默认近 1 小时窗口,按 `model_name` 维度):
|
||||
- 执行耗时:`finished_at - started_at`(取 P90)
|
||||
- 吞吐:近 1 小时完成数 / 3600
|
||||
**处理流程:**
|
||||
|
||||
调参结果不会覆盖 `asynch_models` 中配置的最大上限(cap),而是写入 Redis 运行时参数(带 TTL,默认 2 小时):
|
||||
- `asynch:runtime:max_concurrency:{model_name}`
|
||||
- `asynch:runtime:queue_limit:{model_name}`
|
||||
1. **查模型配置** — 根据 `modelName` 查询 `model_gateway_models` 获取模型定义
|
||||
2. **创建构建记录** — 写入 `model_gateway_build_record`,状态为处理中
|
||||
3. **异步执行构建**(goroutine):
|
||||
- **推理模型(type=100)**:
|
||||
- 从配置读取系统提示词(`modelPrompts.types.100`)
|
||||
- 若有 `skillName`,通过 `GetSkillUser` 拉取技能 ZIP,提取 MD 内容
|
||||
- 合并系统提示词 + 技能知识 + 用户自定义提示词到 `messages`
|
||||
- 通过 `GetSessionHistory` 注入会话历史
|
||||
- 按附件数量自动拆分多轮(`SplitByAttachment`,按 video/image/audio 的 `maxCount` 约束)
|
||||
- 返回单轮或多轮消息结构
|
||||
- **视频模型(type=600-699)**:
|
||||
- 查找当前用户的对话模型(`is_chat_model=1`)
|
||||
- 获取该对话模型的协议模板(`prompts_provider_protocol`)
|
||||
- 构建对话模型请求体,调用对话模型生成视频分镜的 JSON rounds
|
||||
- 将 rounds 上传 OSS,存入构建记录
|
||||
4. **回写结果** — 更新构建记录状态(成功/失败 + 耗时)
|
||||
5. **触发回调** — 若有 `callbackUrl`,POST 回调通知任务完成
|
||||
|
||||
生效位置:
|
||||
- CreateTask 入队时,严格 queue_limit 闸门会优先使用运行时 `queue_limit`(若无运行时值则回退 cap)。
|
||||
- Worker 获取并发令牌时,优先使用运行时 `max_concurrency`(若无运行时值则回退 cap)。
|
||||
**对应源码:**
|
||||
|
||||
- Controller:[controller/model_gateway_task_controller.go](`ModelGatewayTask.BuildMessages`)
|
||||
- Service:[service/task/task_service.go](`taskService.BuildMessages` → `executeBuild` → `buildResult`)
|
||||
- Util(提示词合并):[common/util/prompt.go](`MergePrompt`、`InjectHistory`、`SplitByAttachment`)
|
||||
- Util(技能知识):[service/prompt/prompt_files_handle_service.go](`SkillMdContent`)
|
||||
|
||||
#### 6.2 创建异步任务 `/createTask`
|
||||
|
||||
创建异步模型调用任务,立即返回 `taskId`,后端 goroutine 异步执行模型调用、结果上传与计费。
|
||||
|
||||
**请求示例(JSON):**
|
||||
|
||||
```json
|
||||
{
|
||||
"modelName": "dall-e-3",
|
||||
"bizName": "image-generator",
|
||||
"callbackUrl": "http://callback.example.com/result",
|
||||
"epicycleId": 12345,
|
||||
"buildModelName": "gpt-4o",
|
||||
"requestPayload": {
|
||||
"model": "dall-e-3",
|
||||
"prompt": "一只站在树枝上的猫头鹰,水墨风格",
|
||||
"n": 1,
|
||||
"size": "1024x1024"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| 请求字段 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `modelName` | string | 是 | 模型名称 |
|
||||
| `bizName` | string | 否 | 业务名称,用于统计区分 |
|
||||
| `callbackUrl` | string | 否 | 任务完成后的回调地址 |
|
||||
| `requestPayload` | object | 是 | 透传给模型服务的请求参数 |
|
||||
| `epicycleId` | int64 | 否 | 轮次 ID(prompts-core 场景) |
|
||||
| `buildModelName` | string | 否 | 构建阶段使用的模型名(prompts-core 场景) |
|
||||
|
||||
**响应:**
|
||||
|
||||
```json
|
||||
{
|
||||
"taskId": "550e8400-e29b-41d4-a716-446655440000"
|
||||
}
|
||||
```
|
||||
|
||||
**处理流程:**
|
||||
|
||||
1. **鉴权与参数校验** — 获取用户信息,校验模型配置是否存在且已启用
|
||||
2. **队列门控(可选)** — 通过 Redis Lua 脚本做严格的分布式队列插槽校验,避免并发超限
|
||||
3. **写入任务记录** — 状态为 `1(执行中)`,记录 `requestPayload`、`callbackUrl`、`bizName` 等
|
||||
4. **操作日志** — 记录创建任务的审计日志到 `model_gateway_logs_op`
|
||||
5. **计费预处理** — 若模型配置了 `billing_config`,从请求参数中提取计费维度数据
|
||||
6. **异步执行**(goroutine `AsyncWorker.handleOne`):
|
||||
|
||||
```
|
||||
检查租户余额 ──> 调用模型服务 ──> 解析响应映射 ──> 计费计算并扣费
|
||||
│
|
||||
┌── 同步模式(call_mode=0):直接调用,等待 HTTP 响应
|
||||
├── 异步模式(call_mode=1):提交任务后通过 QueryConfig 轮询结果
|
||||
└── 流式模式(call_mode=2):通过 StreamConfig 解析 SSE 事件流
|
||||
│
|
||||
┌── prompts-core 场景:对模型输出做 ParseAndValidate + 重试机制
|
||||
└── 普通场景:直接映射响应
|
||||
│
|
||||
上传 OSS ──> 更新任务为成功 ──> 触发回调
|
||||
```
|
||||
|
||||
7. **重试机制**:超时、内部错误等可重试错误会按 `retry_times` 重试;硬错误(参数错误等)直接失败
|
||||
8. **回调通知**:任务成功或失败后,若有 `callbackUrl` 则 POST 回调;prompts-core 场景额外触发 `TriggerPromptsCallback`
|
||||
|
||||
**调用模式对比:**
|
||||
|
||||
| 模式 | 值 | 行为 |
|
||||
|---|---|---|
|
||||
| 同步 | 0 | 直接 HTTP 调用模型,等待完整响应后返回 |
|
||||
| 异步 | 1 | 提交任务后通过 `QueryConfig` 配置的轮询地址定时查询结果 |
|
||||
| 流式 | 2 | 对 SSE 事件流按 `StreamConfig` 规则解析(支持 concat/base64_concat/collect/final) |
|
||||
|
||||
**对应源码:**
|
||||
|
||||
- Controller:[controller/model_gateway_task_controller.go](`ModelGatewayTask.CreateTask`)
|
||||
- Service:[service/task/task_service.go](`taskService.Create`)
|
||||
- Worker:[service/task/worker.go](`asyncWorker.handleOne`、`InvokeModel`)
|
||||
- 队列门控:[service/queue/queue_gate.go](`AcquireQueueSlot`、`ReleaseQueueSlot`)
|
||||
- 运行时调参:[service/queue/runtime_tune.go](`GetRuntimeMaxConcurrency`、`GetRuntimeQueueLimit`)
|
||||
- 异步轮询:[common/util/pull_task.go](`PullTaskResult`)
|
||||
- 流式解析:[common/util/streaming.go](`ParseStreamResponse`)
|
||||
- 计费:[common/util/billing.go](`CalculateBilling`、`ExtractRequestBilling`)
|
||||
|
||||
### 7. 全量 API 接口一览
|
||||
|
||||
| 分类 | 接口路径 | 方法 | 说明 |
|
||||
|---|---|---|---|
|
||||
| **模型配置** | `/createModel` | POST | 创建模型配置 |
|
||||
| | `/updateModel` | PUT | 更新模型配置 |
|
||||
| | `/deleteModel` | DELETE | 删除模型配置 |
|
||||
| | `/getModel` | GET | 获取模型详情 |
|
||||
| | `/listModel` | GET | 模型列表(分页+筛选) |
|
||||
| | `/listType` | GET | 模型类型列表 |
|
||||
| | `/listOperator` | GET | 运营商列表 |
|
||||
| | `/updateChatModel` | POST | 设置当前用户的对话模型 |
|
||||
| | `/getIsChatModel` | GET | 获取当前对话模型 |
|
||||
| | `/autoTune` | POST | 触发动态调参 |
|
||||
| **任务管理** | `/createTask` | POST | 创建异步任务 |
|
||||
| | `/jobTask` | POST | 定时批量任务处理器 |
|
||||
| | `/getTaskResult` | GET | 获取单条任务结果 |
|
||||
| | `/getTaskBatch` | POST | 批量查询任务(成功任务自动标记为已下载) |
|
||||
| | `/listTask` | GET | 任务列表分页查询 |
|
||||
| | `/modelCallback` | POST | 接收异步模型回调通知 |
|
||||
| | `/queryPending` | GET | 轮询进行中的异步任务 |
|
||||
| **提示词** | `/buildMessages` | POST | 构建结构化提示词消息(异步) |
|
||||
| **统计** | `/listModelStat` | GET | 日使用量统计 |
|
||||
--
|
||||
|
||||
## 技术栈
|
||||
|
||||
| 组件 | 技术选型 |
|
||||
|---|---|
|
||||
| 语言 | Go 1.26 |
|
||||
| 框架 | GoFrame v2(`github.com/gogf/gf/v2`) |
|
||||
| 数据库 | PostgreSQL(GoFrame pgsql 驱动) |
|
||||
| 缓存/队列 | Redis(分布式信号量、队列门控、运行时调参存储) |
|
||||
| 服务发现 | Consul |
|
||||
| 链路追踪 | Jaeger(OTLP HTTP) |
|
||||
| 模型调用 | 原生 HTTP(可定制请求头、鉴权、超时) |
|
||||
| 文件存储 | OSS 文件上传服务(multipart 表单) |
|
||||
|
||||
## 数据库表
|
||||
|
||||
| 表名 | 说明 |
|
||||
|---|---|
|
||||
| `model_gateway_models` | 模型服务配置(动态表单、请求/响应映射、计费规则) |
|
||||
| `model_gateway_task` | 异步任务记录(状态机、重试、OSS 结果文件) |
|
||||
| `model_gateway_build_record` | 提示词构建记录 |
|
||||
| `model_gateway_logs_op` | 操作审计日志 |
|
||||
| `model_gateway_logs_stat` | 日维度请求量统计 |
|
||||
| `prompts_provider_protocol` | 视频模型编排的提供商协议模板 |
|
||||
|
||||
## 配置说明
|
||||
|
||||
详见 `config.yml`。主要配置块:
|
||||
|
||||
- `database` — PostgreSQL 连接(双数据源:`default` + `model_gateway`)
|
||||
- `redis` — Redis 连接
|
||||
- `consul` — Consul 地址
|
||||
- `jaeger` — Jaeger OTLP HTTP 端点
|
||||
- `queryPending` — 异步任务自动轮询配置(调试开关)
|
||||
- `jobTask` — 批量处理器间隔、批大小、协程池大小
|
||||
- `modelPrompts.types` — 各模型类型的系统提示词(100/200/300/400/500)
|
||||
- `nodePrompts` — 节点路由提示词模板
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 环境要求
|
||||
|
||||
- Go 1.26+
|
||||
- PostgreSQL
|
||||
- Redis
|
||||
- Consul(可选,用于服务发现)
|
||||
|
||||
### 本地开发
|
||||
|
||||
1. 克隆仓库
|
||||
2. 在 PostgreSQL 中执行 `update.sql` 创建所有表
|
||||
3. 修改 `config.yml` 中的数据库、Redis 和 Consul 配置
|
||||
4. 启动服务:
|
||||
```bash
|
||||
go run main.go
|
||||
```
|
||||
5. 服务默认监听 `3004` 端口(可在 `config.yml` 中修改)
|
||||
|
||||
### Docker 构建
|
||||
|
||||
```bash
|
||||
docker build -t model-gateway .
|
||||
docker run -p 3004:3004 model-gateway
|
||||
```
|
||||
|
||||
Dockerfile 使用多阶段构建,基于 `golang:alpine` 镜像,配置了国内 Go 代理,输出剥离调试信息的精简二进制。
|
||||
|
||||
---
|
||||
|
||||
## 3. 状态机说明(asynch_task.state)
|
||||
## 项目目录结构
|
||||
|
||||
| state | 含义 | 产生方 |
|
||||
|---:|---|---|
|
||||
| 0 | 排队中 | 创建任务/重试入队 |
|
||||
| 1 | 执行中 | Worker 抢占后 |
|
||||
| 2 | 成功(已上传 OSS) | Worker |
|
||||
| 3 | 失败 | Worker / 超时处理 |
|
||||
| 4 | 已下载(已领取) | 批量领取接口(2→4) |
|
||||
|
||||
字段补充:
|
||||
- `retry_count`:已重试次数(不含首次)
|
||||
- `enqueue_at`:入队时间(用于排队顺序,重试会更新为 NOW() 放到队尾)
|
||||
- `expire_at`:仅对 `state=4` 生效,表示保留到期时间
|
||||
```
|
||||
.
|
||||
├── main.go # 入口:路由注册、自动执行器启动
|
||||
├── config.yml # 应用配置
|
||||
├── Dockerfile # 多阶段 Docker 构建
|
||||
├── go.mod / go.sum # Go 模块依赖
|
||||
├── update.sql # 数据库 DDL
|
||||
│
|
||||
├── controller/ # HTTP 接口控制器
|
||||
│ ├── model_gateway_models_controller.go
|
||||
│ ├── model_gateway_task_controller.go
|
||||
│ └── model_gateway_logs_stat_controller.go
|
||||
│
|
||||
├── service/ # 业务逻辑层
|
||||
│ ├── gateway/ # OSS 上传、回调、余额、技能/会话查询
|
||||
│ ├── model/ # 模型 CRUD、对话模型管理
|
||||
│ ├── prompt/ # 文件拉取、技能 Markdown、提示词构建
|
||||
│ ├── queue/ # 动态调参、信号量、队列门控、运行时调参
|
||||
│ ├── stat/ # 使用量统计
|
||||
│ └── task/ # 任务创建、Worker 执行、异步结果处理
|
||||
│
|
||||
├── dao/ # 数据访问层
|
||||
│ ├── model_gateway_models_dao.go
|
||||
│ ├── model_gateway_task_dao.go
|
||||
│ ├── model_gateway_build_record_dao.go
|
||||
│ ├── model_gateway_logs_stat_dao.go
|
||||
│ ├── model_gateway_logs_op_dao.go
|
||||
│ └── provider_protocol_dao.go
|
||||
│
|
||||
├── model/ # 数据模型
|
||||
│ ├── dto/ # 请求/响应结构体
|
||||
│ └── entity/ # 数据库实体
|
||||
│
|
||||
├── common/ # 通用工具
|
||||
│ └── util/ # 计费、类型转换、文件处理、请求头、映射、提示词、流式、异步轮询
|
||||
│
|
||||
└── consts/ # 常量定义
|
||||
└── public/ # 模型类型、任务状态、运营商列表、表名
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 配置说明(config.yml)
|
||||
## 任务状态机
|
||||
|
||||
关键配置:
|
||||
- `database.default`: PostgreSQL 连接
|
||||
- `redis.default`: Redis 连接(并发令牌、可扩展用途)
|
||||
| 状态码 | 含义 | 转换来源 |
|
||||
|---|---:|---|
|
||||
| 0 | 排队中 | 创建任务或重试入队 |
|
||||
| 1 | 执行中 | Worker 抢占成功 |
|
||||
| 2 | 成功(已上传 OSS) | Worker 执行完成 |
|
||||
| 3 | 失败 | Worker 执行出错或超时 |
|
||||
| 4 | 已下载 | 批量查询接口标记 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 数据库初始化
|
||||
## License
|
||||
|
||||
项目根目录提供 `update.sql`:首次部署执行建表 SQL。
|
||||
内部项目 — 红未来科技
|
||||
|
||||
---
|
||||
|
||||
## 6. 开发与发布建议(Git)
|
||||
|
||||
- `dev`:日常开发与联调
|
||||
- `main`:线上稳定分支
|
||||
- 推荐流程:
|
||||
1) 从 `main` 拉出 `dev`
|
||||
2) 功能完成后提 MR/PR 合并回 `main`
|
||||
3) 打 tag / 发布镜像
|
||||
|
||||
+184
-215
@@ -1,233 +1,202 @@
|
||||
-- =========================
|
||||
-- model_gateway_models
|
||||
-- =========================
|
||||
CREATE TABLE IF NOT EXISTS model_gateway_models (
|
||||
id int8 PRIMARY KEY,
|
||||
tenant_id int8 NOT NULL DEFAULT 0,
|
||||
creator varchar(64) NOT NULL,
|
||||
created_at timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updater varchar(64) NOT NULL,
|
||||
updated_at timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at timestamp(6),
|
||||
model_name varchar(128) NOT NULL,
|
||||
model_type int2 NOT NULL DEFAULT 0,
|
||||
operator_name varchar(64) NOT NULL DEFAULT '',
|
||||
base_url varchar(256) NOT NULL,
|
||||
http_method varchar(8) NOT NULL DEFAULT 'POST',
|
||||
head_msg jsonb NOT NULL DEFAULT '{}',
|
||||
api_key varchar(256) NOT NULL DEFAULT '',
|
||||
is_private int2 NOT NULL DEFAULT 0,
|
||||
enabled int2 NOT NULL DEFAULT 1,
|
||||
is_chat_model int2 NOT NULL DEFAULT 0,
|
||||
is_owner int2 NOT NULL DEFAULT 99,
|
||||
form_json jsonb NOT NULL DEFAULT '{}',
|
||||
request_mapping jsonb NOT NULL DEFAULT '{}',
|
||||
response_mapping jsonb NOT NULL DEFAULT '{}',
|
||||
response_body varchar(128) NOT NULL DEFAULT '',
|
||||
token_config jsonb NOT NULL DEFAULT '{}',
|
||||
extend_mapping jsonb NOT NULL DEFAULT '{}',
|
||||
query_config jsonb NOT NULL DEFAULT '{}',
|
||||
stream_config jsonb NOT NULL DEFAULT '{}',
|
||||
first_frame varchar(128) NOT NULL DEFAULT '',
|
||||
last_frame varchar(128) NOT NULL DEFAULT '',
|
||||
max_concurrency int4 NOT NULL DEFAULT 10,
|
||||
timeout_seconds int4 NOT NULL DEFAULT 600,
|
||||
retry_times int2 NOT NULL DEFAULT 3,
|
||||
auto_clean_seconds int4 NOT NULL DEFAULT 86400,
|
||||
response_token_field varchar(128) NOT NULL DEFAULT '',
|
||||
call_mode int2 NOT NULL DEFAULT 0,
|
||||
required_fields jsonb NOT NULL DEFAULT '[]',
|
||||
max_tokens int4 DEFAULT 0
|
||||
);
|
||||
-- ============================================
|
||||
-- 模型网关 (model-gateway) 建表语句
|
||||
-- ============================================
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uk_model_gateway_models_tenant_creator_model ON model_gateway_models (tenant_id, creator, model_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_model_gateway_models_model_name ON model_gateway_models (model_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_model_gateway_models_model_type ON model_gateway_models (model_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_model_gateway_models_tenant_id ON model_gateway_models (tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_model_gateway_models_deleted_at ON model_gateway_models (deleted_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_model_gateway_models_enabled ON model_gateway_models (enabled);
|
||||
-- 1. 模型配置表
|
||||
CREATE TABLE "public"."model_gateway_models" (
|
||||
"id" int8 NOT NULL,
|
||||
"tenant_id" int8 NOT NULL DEFAULT 0,
|
||||
"creator" varchar(64) NOT NULL,
|
||||
"created_at" timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updater" varchar(64) NOT NULL,
|
||||
"updated_at" timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"deleted_at" timestamp(6),
|
||||
"model_name" varchar(128) NOT NULL,
|
||||
"model_type" int2 NOT NULL DEFAULT 0,
|
||||
"operator_name" varchar(64) NOT NULL DEFAULT '',
|
||||
"base_url" varchar(256) NOT NULL,
|
||||
"http_method" varchar(8) NOT NULL DEFAULT 'POST',
|
||||
"head_msg" jsonb NOT NULL DEFAULT '{}',
|
||||
"api_key" varchar(256) NOT NULL DEFAULT '',
|
||||
"is_private" int2 NOT NULL DEFAULT 0,
|
||||
"enabled" int2 NOT NULL DEFAULT 1,
|
||||
"is_chat_model" int2 NOT NULL DEFAULT 0,
|
||||
"form_json" jsonb NOT NULL DEFAULT '{}',
|
||||
"request_mapping" jsonb NOT NULL DEFAULT '{}',
|
||||
"response_mapping" jsonb NOT NULL DEFAULT '{}',
|
||||
"extend_mapping" jsonb NOT NULL DEFAULT '{}',
|
||||
"query_config" jsonb NOT NULL DEFAULT '{}',
|
||||
"stream_config" jsonb NOT NULL DEFAULT '{}',
|
||||
"max_concurrency" int4 NOT NULL DEFAULT 10,
|
||||
"timeout_seconds" int4 NOT NULL DEFAULT 600,
|
||||
"retry_times" int2 NOT NULL DEFAULT 3,
|
||||
"call_mode" int2 NOT NULL DEFAULT 0,
|
||||
"required_fields" jsonb NOT NULL DEFAULT '[]',
|
||||
"billing_config" jsonb NOT NULL DEFAULT '{}',
|
||||
"special_params" jsonb NOT NULL DEFAULT '{}',
|
||||
CONSTRAINT "model_gateway_models_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
COMMENT ON TABLE model_gateway_models IS '模型配置表';
|
||||
COMMENT ON COLUMN model_gateway_models.id IS '主键ID(非自增)';
|
||||
COMMENT ON COLUMN model_gateway_models.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN model_gateway_models.creator IS '创建人';
|
||||
COMMENT ON COLUMN model_gateway_models.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN model_gateway_models.updater IS '更新人';
|
||||
COMMENT ON COLUMN model_gateway_models.updated_at IS '更新时间';
|
||||
COMMENT ON COLUMN model_gateway_models.deleted_at IS '删除时间(软删)';
|
||||
COMMENT ON COLUMN model_gateway_models.model_name IS '模型名称';
|
||||
COMMENT ON COLUMN model_gateway_models.model_type IS '模型类型';
|
||||
COMMENT ON COLUMN model_gateway_models.operator_name IS '运营商名称';
|
||||
COMMENT ON COLUMN model_gateway_models.base_url IS '模型地址';
|
||||
COMMENT ON COLUMN model_gateway_models.http_method IS '请求方式 GET/POST';
|
||||
COMMENT ON COLUMN model_gateway_models.head_msg IS '请求头信息';
|
||||
COMMENT ON COLUMN model_gateway_models.api_key IS '调用凭证/密钥';
|
||||
ALTER TABLE "public"."model_gateway_models" OWNER TO "postgres";
|
||||
|
||||
COMMENT ON COLUMN model_gateway_models.is_private IS '是否私有化:0-私有 1-公共';
|
||||
COMMENT ON COLUMN model_gateway_models.enabled IS '是否启用:0-停用 1-启用';
|
||||
COMMENT ON COLUMN model_gateway_models.is_chat_model IS '是否为对话模型:0-否 1-是';
|
||||
COMMENT ON COLUMN model_gateway_models.is_owner IS '1=当前用户创建 0=超级管理员';
|
||||
CREATE INDEX "idx_models_deleted_at" ON "public"."model_gateway_models" ("deleted_at");
|
||||
CREATE INDEX "idx_models_enabled" ON "public"."model_gateway_models" ("enabled");
|
||||
CREATE INDEX "idx_models_model_name" ON "public"."model_gateway_models" ("model_name");
|
||||
CREATE INDEX "idx_models_model_type" ON "public"."model_gateway_models" ("model_type");
|
||||
CREATE INDEX "idx_models_tenant_id" ON "public"."model_gateway_models" ("tenant_id");
|
||||
CREATE INDEX "idx_models_tenant_creator" ON "public"."model_gateway_models" ("tenant_id", "creator");
|
||||
CREATE INDEX "idx_models_tenant_creator_model_deleted" ON "public"."model_gateway_models" ("tenant_id", "creator", "model_name") WHERE deleted_at IS NULL;
|
||||
CREATE UNIQUE INDEX "uk_models_tenant_creator_model" ON "public"."model_gateway_models" ("tenant_id", "creator", "model_name");
|
||||
|
||||
COMMENT ON COLUMN model_gateway_models.form_json IS '动态表单结构';
|
||||
COMMENT ON COLUMN model_gateway_models.request_mapping IS '请求映射';
|
||||
COMMENT ON COLUMN model_gateway_models.response_mapping IS '返回映射';
|
||||
COMMENT ON COLUMN model_gateway_models.response_body IS '返回主体';
|
||||
COMMENT ON COLUMN model_gateway_models.token_config IS 'Token计算配置';
|
||||
COMMENT ON COLUMN model_gateway_models.extend_mapping IS '附加映射';
|
||||
COMMENT ON COLUMN model_gateway_models.query_config IS '查询/回调配置';
|
||||
COMMENT ON COLUMN model_gateway_models.stream_config IS '流式输出配置';
|
||||
COMMENT ON COLUMN model_gateway_models.first_frame IS '首帧图片参数';
|
||||
COMMENT ON COLUMN model_gateway_models.last_frame IS '尾帧图片参数';
|
||||
COMMENT ON COLUMN model_gateway_models.max_concurrency IS '最大并发数';
|
||||
COMMENT ON COLUMN model_gateway_models.timeout_seconds IS '调用模型超时(秒)';
|
||||
COMMENT ON COLUMN model_gateway_models.retry_times IS '失败重试次数';
|
||||
COMMENT ON COLUMN model_gateway_models.auto_clean_seconds IS '任务完成后自动清理时间(秒)';
|
||||
COMMENT ON COLUMN model_gateway_models.response_token_field IS '响应中消耗token的字段映射';
|
||||
COMMENT ON COLUMN model_gateway_models.call_mode IS '调用模式:0-同步 1-异步 2-流式';
|
||||
COMMENT ON COLUMN model_gateway_models.required_fields IS '必选字段列表';
|
||||
COMMENT ON COLUMN model_gateway_models.max_tokens IS '最大 token 数,0 表示不传';
|
||||
COMMENT ON TABLE "public"."model_gateway_models" IS '模型配置表';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."model_name" IS '模型名称';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."model_type" IS '模型类型';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."operator_name" IS '运营商名称';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."base_url" IS '模型地址';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."http_method" IS '请求方式 GET/POST';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."head_msg" IS '请求头信息';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."api_key" IS '调用凭证/密钥';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."is_private" IS '是否私有化:0-私有 1-公共';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."enabled" IS '是否启用:0-停用 1-启用';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."is_chat_model" IS '是否为对话模型:0-否 1-是';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."form_json" IS '动态表单结构';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."request_mapping" IS '请求映射';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."response_mapping" IS '返回映射';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."extend_mapping" IS '附加映射';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."query_config" IS '查询/回调配置';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."stream_config" IS '流式输出配置';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."max_concurrency" IS '最大并发数';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."timeout_seconds" IS '调用模型超时(秒)';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."retry_times" IS '失败重试次数';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."call_mode" IS '调用模式:0-同步 1-异步 2-流式';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."required_fields" IS '必选字段列表';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."billing_config" IS '计费配置';
|
||||
COMMENT ON COLUMN "public"."model_gateway_models"."special_params" IS '请求特殊参数';
|
||||
|
||||
|
||||
-- 2. 模型网关任务表
|
||||
CREATE TABLE "public"."model_gateway_task" (
|
||||
"id" int8 NOT NULL,
|
||||
"tenant_id" int8 NOT NULL DEFAULT 0,
|
||||
"creator" varchar(64) NOT NULL,
|
||||
"created_at" timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updater" varchar(64) NOT NULL,
|
||||
"updated_at" timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"deleted_at" timestamp(6),
|
||||
"model_name" varchar(128) NOT NULL,
|
||||
"task_id" varchar(64) NOT NULL,
|
||||
"biz_name" varchar(128) NOT NULL DEFAULT '',
|
||||
"callback_url" varchar(512) DEFAULT '',
|
||||
"state" int2 NOT NULL DEFAULT 0,
|
||||
"retry_count" int4 NOT NULL DEFAULT 0,
|
||||
"error_msg" text DEFAULT '',
|
||||
"result_file" jsonb NOT NULL DEFAULT '{}',
|
||||
"request_payload" jsonb NOT NULL DEFAULT '{}',
|
||||
"duration_seconds" int8 NOT NULL DEFAULT 0,
|
||||
"epicycle_id" varchar(64) NOT NULL DEFAULT '',
|
||||
"billing_data" jsonb NOT NULL DEFAULT '[]',
|
||||
"build_model_name" varchar(128) NOT NULL DEFAULT '',
|
||||
CONSTRAINT "model_gateway_task_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- =========================
|
||||
-- model_gateway_task
|
||||
-- =========================
|
||||
CREATE TABLE IF NOT EXISTS model_gateway_task (
|
||||
id int8 PRIMARY KEY,
|
||||
tenant_id int8 NOT NULL DEFAULT 0,
|
||||
creator varchar(64) NOT NULL,
|
||||
created_at timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updater varchar(64) NOT NULL,
|
||||
updated_at timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at timestamp(6),
|
||||
model_name varchar(128) NOT NULL,
|
||||
task_id varchar(64) NOT NULL,
|
||||
biz_name varchar(128) NOT NULL DEFAULT '',
|
||||
callback_url varchar(512) DEFAULT '',
|
||||
state int2 NOT NULL DEFAULT 0,
|
||||
retry_count int4 NOT NULL DEFAULT 0,
|
||||
phase int2 NOT NULL DEFAULT 0,
|
||||
tmp_file text DEFAULT '',
|
||||
error_msg text DEFAULT '',
|
||||
result_file jsonb NOT NULL DEFAULT '{}',
|
||||
request_payload jsonb NOT NULL DEFAULT '{}',
|
||||
text_result jsonb NOT NULL DEFAULT '{}',
|
||||
expend_tokens int8 NOT NULL DEFAULT 0,
|
||||
duration_seconds int8 NOT NULL DEFAULT 0,
|
||||
epicycle_id varchar(64) NOT NULL DEFAULT ''
|
||||
);
|
||||
ALTER TABLE "public"."model_gateway_task" OWNER TO "postgres";
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uk_model_gateway_task_tenant_creator_task_id ON model_gateway_task (tenant_id, creator, task_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_model_gateway_task_task_id ON model_gateway_task (task_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_model_gateway_task_state ON model_gateway_task (state);
|
||||
CREATE INDEX IF NOT EXISTS idx_model_gateway_task_deleted_at ON model_gateway_task (deleted_at);
|
||||
CREATE INDEX "idx_task_creator_created" ON "public"."model_gateway_task" ("creator", "created_at" DESC);
|
||||
CREATE INDEX "idx_task_model_state" ON "public"."model_gateway_task" ("model_name", "state");
|
||||
CREATE INDEX "idx_task_state" ON "public"."model_gateway_task" ("state");
|
||||
CREATE INDEX "idx_task_state_created" ON "public"."model_gateway_task" ("state", "created_at");
|
||||
CREATE INDEX "idx_task_task_id" ON "public"."model_gateway_task" ("task_id");
|
||||
CREATE INDEX "idx_task_tenant_model" ON "public"."model_gateway_task" ("tenant_id", "model_name");
|
||||
CREATE UNIQUE INDEX "uk_task_task_id" ON "public"."model_gateway_task" ("task_id");
|
||||
|
||||
COMMENT ON TABLE model_gateway_task IS '模型网关任务表';
|
||||
COMMENT ON COLUMN model_gateway_task.id IS '主键ID';
|
||||
COMMENT ON COLUMN model_gateway_task.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN model_gateway_task.creator IS '创建人';
|
||||
COMMENT ON COLUMN model_gateway_task.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN model_gateway_task.updater IS '更新人';
|
||||
COMMENT ON COLUMN model_gateway_task.updated_at IS '更新时间';
|
||||
COMMENT ON COLUMN model_gateway_task.deleted_at IS '删除时间(软删)';
|
||||
COMMENT ON COLUMN model_gateway_task.model_name IS '模型名称';
|
||||
COMMENT ON COLUMN model_gateway_task.task_id IS '任务ID(对外返回)';
|
||||
COMMENT ON COLUMN model_gateway_task.biz_name IS '业务名称(调用方模块/系统)';
|
||||
COMMENT ON COLUMN model_gateway_task.callback_url IS '回调地址';
|
||||
COMMENT ON COLUMN model_gateway_task.state IS '0排队中/1执行中/2成功/3失败/4已下载';
|
||||
COMMENT ON COLUMN model_gateway_task.retry_count IS '已重试次数';
|
||||
COMMENT ON COLUMN model_gateway_task.phase IS '执行阶段:0模型阶段/1OSS阶段';
|
||||
COMMENT ON COLUMN model_gateway_task.tmp_file IS '临时结果文件路径';
|
||||
COMMENT ON COLUMN model_gateway_task.error_msg IS '错误信息';
|
||||
COMMENT ON COLUMN model_gateway_task.result_file IS '结果文件:{oss_file, file_type, file_size}';
|
||||
COMMENT ON COLUMN model_gateway_task.request_payload IS '请求参数(JSON)';
|
||||
COMMENT ON COLUMN model_gateway_task.text_result IS '文本类结果';
|
||||
COMMENT ON COLUMN model_gateway_task.expend_tokens IS '消耗token数';
|
||||
COMMENT ON COLUMN model_gateway_task.duration_seconds IS '耗时(秒)';
|
||||
COMMENT ON COLUMN model_gateway_task.epicycle_id IS '轮次ID';
|
||||
COMMENT ON TABLE "public"."model_gateway_task" IS '模型网关任务表';
|
||||
COMMENT ON COLUMN "public"."model_gateway_task"."model_name" IS '模型名称';
|
||||
COMMENT ON COLUMN "public"."model_gateway_task"."task_id" IS '任务ID(对外返回)';
|
||||
COMMENT ON COLUMN "public"."model_gateway_task"."biz_name" IS '业务名称';
|
||||
COMMENT ON COLUMN "public"."model_gateway_task"."callback_url" IS '回调地址';
|
||||
COMMENT ON COLUMN "public"."model_gateway_task"."state" IS '0排队中/1执行中/2成功/3失败/4已下载';
|
||||
COMMENT ON COLUMN "public"."model_gateway_task"."retry_count" IS '已重试次数';
|
||||
COMMENT ON COLUMN "public"."model_gateway_task"."error_msg" IS '错误信息';
|
||||
COMMENT ON COLUMN "public"."model_gateway_task"."result_file" IS '结果文件:{oss_file, file_type, file_size}';
|
||||
COMMENT ON COLUMN "public"."model_gateway_task"."request_payload" IS '请求参数(JSON)';
|
||||
COMMENT ON COLUMN "public"."model_gateway_task"."duration_seconds" IS '耗时(秒)';
|
||||
COMMENT ON COLUMN "public"."model_gateway_task"."epicycle_id" IS '轮次ID';
|
||||
COMMENT ON COLUMN "public"."model_gateway_task"."billing_data" IS '计费数据';
|
||||
COMMENT ON COLUMN "public"."model_gateway_task"."build_model_name" IS '构建模型名称';
|
||||
|
||||
|
||||
-- 3. 操作日志表
|
||||
CREATE TABLE "public"."model_gateway_logs_op" (
|
||||
"id" int8 NOT NULL,
|
||||
"tenant_id" int8 NOT NULL DEFAULT 0,
|
||||
"creator" varchar(64) NOT NULL,
|
||||
"created_at" timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updater" varchar(64) NOT NULL,
|
||||
"updated_at" timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"deleted_at" timestamp(6),
|
||||
"ip" varchar(64) DEFAULT '',
|
||||
"user_agent" varchar(256) DEFAULT '',
|
||||
"api_path" varchar(256) DEFAULT '',
|
||||
"http_method" varchar(16) DEFAULT '',
|
||||
"biz_name" varchar(128) NOT NULL DEFAULT '',
|
||||
"model_name" varchar(128) NOT NULL DEFAULT '',
|
||||
"task_id" varchar(64) NOT NULL DEFAULT '',
|
||||
"op_type" varchar(64) NOT NULL DEFAULT 'createTask',
|
||||
"success" int2 NOT NULL DEFAULT 1,
|
||||
"error_msg" text DEFAULT '',
|
||||
"cost_ms" int8 NOT NULL DEFAULT 0,
|
||||
"request_payload" jsonb,
|
||||
"response_payload" jsonb,
|
||||
CONSTRAINT "model_gateway_logs_op_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- =========================
|
||||
-- model_gateway_log_stat
|
||||
-- =========================
|
||||
CREATE TABLE IF NOT EXISTS model_gateway_log_stat (
|
||||
day date NOT NULL,
|
||||
tenant_id int8 NOT NULL DEFAULT 0,
|
||||
creator varchar(64) NOT NULL DEFAULT '',
|
||||
model_name varchar(128) NOT NULL DEFAULT '',
|
||||
request_count int8 NOT NULL DEFAULT 0,
|
||||
created_at timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (day, tenant_id, creator, model_name)
|
||||
);
|
||||
ALTER TABLE "public"."model_gateway_logs_op" OWNER TO "postgres";
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_model_gateway_log_stat_day ON model_gateway_log_stat (day);
|
||||
CREATE INDEX IF NOT EXISTS idx_model_gateway_log_stat_creator ON model_gateway_log_stat (creator);
|
||||
CREATE INDEX IF NOT EXISTS idx_model_gateway_log_stat_model_name ON model_gateway_log_stat (model_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_model_gateway_log_stat_tenant_day ON model_gateway_log_stat (tenant_id, day);
|
||||
CREATE INDEX "idx_op_log_biz_name" ON "public"."model_gateway_logs_op" ("biz_name");
|
||||
CREATE INDEX "idx_op_log_deleted_at" ON "public"."model_gateway_logs_op" ("deleted_at");
|
||||
CREATE INDEX "idx_op_log_model_name" ON "public"."model_gateway_logs_op" ("model_name");
|
||||
CREATE INDEX "idx_op_log_op_type" ON "public"."model_gateway_logs_op" ("op_type");
|
||||
CREATE INDEX "idx_op_log_task_id" ON "public"."model_gateway_logs_op" ("task_id");
|
||||
CREATE INDEX "idx_op_log_tenant_time" ON "public"."model_gateway_logs_op" ("tenant_id", "created_at");
|
||||
CREATE INDEX "idx_op_log_model_time" ON "public"."model_gateway_logs_op" ("model_name", "created_at");
|
||||
|
||||
COMMENT ON TABLE model_gateway_log_stat IS '按天统计表';
|
||||
COMMENT ON COLUMN model_gateway_log_stat.day IS '天(YYYY-MM-DD)';
|
||||
COMMENT ON COLUMN model_gateway_log_stat.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN model_gateway_log_stat.creator IS '创建人';
|
||||
COMMENT ON COLUMN model_gateway_log_stat.model_name IS '模型名称';
|
||||
COMMENT ON COLUMN model_gateway_log_stat.request_count IS '请求次数';
|
||||
COMMENT ON COLUMN model_gateway_log_stat.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN model_gateway_log_stat.updated_at IS '更新时间';
|
||||
COMMENT ON TABLE "public"."model_gateway_logs_op" IS '操作日志表';
|
||||
COMMENT ON COLUMN "public"."model_gateway_logs_op"."ip" IS '客户端IP';
|
||||
COMMENT ON COLUMN "public"."model_gateway_logs_op"."user_agent" IS 'User-Agent';
|
||||
COMMENT ON COLUMN "public"."model_gateway_logs_op"."api_path" IS '接口路径';
|
||||
COMMENT ON COLUMN "public"."model_gateway_logs_op"."http_method" IS 'HTTP方法';
|
||||
COMMENT ON COLUMN "public"."model_gateway_logs_op"."biz_name" IS '业务名称';
|
||||
COMMENT ON COLUMN "public"."model_gateway_logs_op"."model_name" IS '模型名称';
|
||||
COMMENT ON COLUMN "public"."model_gateway_logs_op"."task_id" IS '任务ID';
|
||||
COMMENT ON COLUMN "public"."model_gateway_logs_op"."op_type" IS '操作类型';
|
||||
COMMENT ON COLUMN "public"."model_gateway_logs_op"."success" IS '是否成功:1成功/0失败';
|
||||
COMMENT ON COLUMN "public"."model_gateway_logs_op"."error_msg" IS '错误信息';
|
||||
COMMENT ON COLUMN "public"."model_gateway_logs_op"."cost_ms" IS '耗时(毫秒)';
|
||||
COMMENT ON COLUMN "public"."model_gateway_logs_op"."request_payload" IS '请求 JSON';
|
||||
COMMENT ON COLUMN "public"."model_gateway_logs_op"."response_payload" IS '响应 JSON';
|
||||
|
||||
|
||||
-- =========================
|
||||
-- model_gateway_logs_op
|
||||
-- =========================
|
||||
CREATE TABLE IF NOT EXISTS model_gateway_logs_op (
|
||||
id int8 PRIMARY KEY,
|
||||
tenant_id int8 NOT NULL DEFAULT 0,
|
||||
creator varchar(64) NOT NULL,
|
||||
created_at timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updater varchar(64) NOT NULL,
|
||||
updated_at timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at timestamp(6),
|
||||
ip varchar(64) DEFAULT '',
|
||||
user_agent varchar(256) DEFAULT '',
|
||||
api_path varchar(256) DEFAULT '',
|
||||
http_method varchar(16) DEFAULT '',
|
||||
biz_name varchar(128) NOT NULL DEFAULT '',
|
||||
model_name varchar(128) NOT NULL DEFAULT '',
|
||||
task_id varchar(64) NOT NULL DEFAULT '',
|
||||
op_type varchar(64) NOT NULL DEFAULT 'createTask',
|
||||
success int2 NOT NULL DEFAULT 1,
|
||||
error_msg text DEFAULT '',
|
||||
cost_ms int8 NOT NULL DEFAULT 0,
|
||||
request_payload jsonb,
|
||||
response_payload jsonb
|
||||
);
|
||||
-- 4. 按天统计表
|
||||
CREATE TABLE "public"."model_gateway_logs_stat" (
|
||||
"day" date NOT NULL,
|
||||
"tenant_id" int8 NOT NULL DEFAULT 0,
|
||||
"creator" varchar(64) NOT NULL DEFAULT '',
|
||||
"model_name" varchar(128) NOT NULL DEFAULT '',
|
||||
"request_count" int8 NOT NULL DEFAULT 0,
|
||||
"created_at" timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_at" timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_model_gateway_logs_op_task_id ON model_gateway_logs_op (task_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_model_gateway_logs_op_biz_name ON model_gateway_logs_op (biz_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_model_gateway_logs_op_model_name ON model_gateway_logs_op (model_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_model_gateway_logs_op_op_type ON model_gateway_logs_op (op_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_model_gateway_logs_op_deleted_at ON model_gateway_logs_op (deleted_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_model_gateway_logs_op_tenant_time ON model_gateway_logs_op (tenant_id, created_at);
|
||||
ALTER TABLE "public"."model_gateway_logs_stat" OWNER TO "postgres";
|
||||
|
||||
COMMENT ON TABLE model_gateway_logs_op IS '操作日志表';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.id IS '主键ID(非自增)';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.creator IS '创建人';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.updater IS '更新人';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.updated_at IS '更新时间';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.deleted_at IS '删除时间(软删)';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.ip IS '客户端IP';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.user_agent IS 'User-Agent';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.api_path IS '接口路径';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.http_method IS 'HTTP方法';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.biz_name IS '业务名称(调用方模块/系统)';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.model_name IS '模型名称';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.task_id IS '任务ID';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.op_type IS '操作类型';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.success IS '是否成功:1成功/0失败';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.error_msg IS '错误信息(失败时)';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.cost_ms IS '耗时(毫秒)';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.request_payload IS '请求 JSON';
|
||||
COMMENT ON COLUMN model_gateway_logs_op.response_payload IS '响应 JSON';
|
||||
CREATE INDEX "idx_stat_creator" ON "public"."model_gateway_logs_stat" ("creator");
|
||||
CREATE INDEX "idx_stat_day" ON "public"."model_gateway_logs_stat" ("day");
|
||||
CREATE INDEX "idx_stat_model_name" ON "public"."model_gateway_logs_stat" ("model_name");
|
||||
CREATE INDEX "idx_stat_tenant_day" ON "public"."model_gateway_logs_stat" ("tenant_id", "day");
|
||||
|
||||
COMMENT ON TABLE "public"."model_gateway_logs_stat" IS '按天统计表';
|
||||
COMMENT ON COLUMN "public"."model_gateway_logs_stat"."day" IS '天(YYYY-MM-DD)';
|
||||
COMMENT ON COLUMN "public"."model_gateway_logs_stat"."tenant_id" IS '租户ID';
|
||||
COMMENT ON COLUMN "public"."model_gateway_logs_stat"."creator" IS '创建人';
|
||||
COMMENT ON COLUMN "public"."model_gateway_logs_stat"."model_name" IS '模型名称';
|
||||
COMMENT ON COLUMN "public"."model_gateway_logs_stat"."request_count" IS '请求次数';
|
||||
Reference in New Issue
Block a user