|
| 1 | +# Manager Provider Template API Proposal |
| 2 | + |
| 3 | +## 背景 |
| 4 | + |
| 5 | +当前前端 `Provider Catalog` 已升级为可视化模板编辑器(字段卡片),不再依赖手写 JSON。 |
| 6 | +为了让后端可落地实现,需要把前端行为拆成稳定的接口和数据结构。 |
| 7 | + |
| 8 | +本提案目标: |
| 9 | + |
| 10 | +- 支持 `category + provider` 维度的模板管理 |
| 11 | +- 支持模板字段类型化约束(text/number/integer/select) |
| 12 | +- 模板字段支持多级路径(dot path,例如 `audio.codec.sample_rate_hz`) |
| 13 | +- `base_url` 与 `access_key` 作为资源顶层必填字段,不放入模板 |
| 14 | +- 支持资源创建时按模板渲染表单并校验 |
| 15 | + |
| 16 | +## UI 侧核心实体 |
| 17 | + |
| 18 | +### ProviderTemplate |
| 19 | + |
| 20 | +- `id`: string(uuid) |
| 21 | +- `category`: `llm | asr | tts` |
| 22 | +- `provider`: string(建议小写,`^[a-z][a-z0-9-]*$`) |
| 23 | +- `status`: `active | inactive` |
| 24 | +- `version`: number(模板版本,>=1) |
| 25 | +- `fields`: `ProviderTemplateField[]` |
| 26 | +- `created_at` / `updated_at` |
| 27 | + |
| 28 | +### ProviderTemplateField |
| 29 | + |
| 30 | +- `key`: string(建议 `^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*$`) |
| 31 | +- `label`: string |
| 32 | +- `type`: `text | number | integer | select` |
| 33 | +- `required`: boolean |
| 34 | +- `default_value`: string | number | null |
| 35 | +- `helper_text`: string |
| 36 | +- `placeholder`: string |
| 37 | +- `min`: number |
| 38 | +- `max`: number |
| 39 | +- `step`: number |
| 40 | +- `options`: `[{ value: string, label: string }]`(仅 `select`) |
| 41 | + |
| 42 | +保留关键字(不允许作为模板字段): |
| 43 | + |
| 44 | +- `base_url` |
| 45 | +- `access_key` |
| 46 | + |
| 47 | +## 推荐后端接口(MVP) |
| 48 | + |
| 49 | +统一响应结构继续沿用: |
| 50 | + |
| 51 | +```json |
| 52 | +{ |
| 53 | + "code": "OK", |
| 54 | + "message": "", |
| 55 | + "data": {} |
| 56 | +} |
| 57 | +``` |
| 58 | + |
| 59 | +### 1) 查询模板(登录可读) |
| 60 | + |
| 61 | +- `GET /api/v1/provider-templates` |
| 62 | +- Query: |
| 63 | + - `category` 可选 |
| 64 | + - `provider` 可选 |
| 65 | + - `status` 可选 |
| 66 | + |
| 67 | +返回: |
| 68 | + |
| 69 | +```json |
| 70 | +{ |
| 71 | + "items": [ |
| 72 | + { |
| 73 | + "id": "uuid", |
| 74 | + "category": "llm", |
| 75 | + "provider": "zhipu", |
| 76 | + "status": "active", |
| 77 | + "version": 3, |
| 78 | + "fields": [ |
| 79 | + { |
| 80 | + "key": "model", |
| 81 | + "label": "Model", |
| 82 | + "type": "text", |
| 83 | + "required": true, |
| 84 | + "default_value": "glm-4-flash" |
| 85 | + } |
| 86 | + ], |
| 87 | + "created_at": "2026-02-16T10:00:00Z", |
| 88 | + "updated_at": "2026-02-16T10:00:00Z" |
| 89 | + } |
| 90 | + ] |
| 91 | +} |
| 92 | +``` |
| 93 | + |
| 94 | +### 2) 创建模板(admin) |
| 95 | + |
| 96 | +- `POST /api/v1/admin/provider-templates` |
| 97 | + |
| 98 | +请求体: |
| 99 | + |
| 100 | +```json |
| 101 | +{ |
| 102 | + "category": "llm", |
| 103 | + "provider": "zhipu", |
| 104 | + "status": "active", |
| 105 | + "fields": [ |
| 106 | + { |
| 107 | + "key": "model", |
| 108 | + "label": "Model", |
| 109 | + "type": "text", |
| 110 | + "required": true, |
| 111 | + "default_value": "glm-4-flash" |
| 112 | + } |
| 113 | + ] |
| 114 | +} |
| 115 | +``` |
| 116 | + |
| 117 | +### 3) 更新模板(admin) |
| 118 | + |
| 119 | +- `PATCH /api/v1/admin/provider-templates/:id` |
| 120 | + |
| 121 | +可更新字段: |
| 122 | + |
| 123 | +- `status` |
| 124 | +- `fields`(建议全量替换) |
| 125 | + |
| 126 | +语义建议:每次成功更新自动 `version + 1`。 |
| 127 | + |
| 128 | +### 4) 删除模板(admin) |
| 129 | + |
| 130 | +- `DELETE /api/v1/admin/provider-templates/:id` |
| 131 | + |
| 132 | +建议默认软删除(`status=inactive` 或 `deleted_at`),避免影响历史资源。 |
| 133 | + |
| 134 | +## 资源接口联动建议 |
| 135 | + |
| 136 | +现有 `platform_resources` 接口保留不变,但建议新增字段: |
| 137 | + |
| 138 | +- `provider_template_id`(可选) |
| 139 | +- `provider_template_version`(可选) |
| 140 | + |
| 141 | +创建/更新资源时建议请求体包含: |
| 142 | + |
| 143 | +- `base_url`(required) |
| 144 | +- `access_key`(create required,edit optional) |
| 145 | + |
| 146 | +并由后端做两步校验: |
| 147 | + |
| 148 | +1. `category + provider` 存在可用模板 |
| 149 | +2. `config` 满足模板字段规则 |
| 150 | + |
| 151 | +这样前端和后端校验逻辑可对齐,减少“前端通过、后端失败”的情况。 |
| 152 | + |
| 153 | +## 建议表结构(MVP) |
| 154 | + |
| 155 | +### `provider_templates` |
| 156 | + |
| 157 | +- `id` uuid pk |
| 158 | +- `category` text not null |
| 159 | +- `provider` text not null |
| 160 | +- `status` text not null default `active` |
| 161 | +- `version` int not null default 1 |
| 162 | +- `fields` jsonb not null |
| 163 | +- `created_by` uuid not null |
| 164 | +- `created_at` timestamptz not null |
| 165 | +- `updated_at` timestamptz not null |
| 166 | + |
| 167 | +唯一约束建议: |
| 168 | + |
| 169 | +- 若只允许单活模板:`unique(category, provider)` |
| 170 | +- 若允许多版本并存:`unique(category, provider, version)` + status 控制活跃版本 |
| 171 | + |
| 172 | +## 错误码建议 |
| 173 | + |
| 174 | +- `400 ERR_INVALID_ARGUMENT`:字段结构、类型、范围不合法 |
| 175 | +- `401 ERR_UNAUTHORIZED` |
| 176 | +- `403 ERR_FORBIDDEN` |
| 177 | +- `404 ERR_NOT_FOUND` |
| 178 | +- `409 ERR_CONFLICT`:同 category/provider 重复冲突 |
| 179 | +- `422 ERR_TEMPLATE_VALIDATION`:资源 config 不满足模板 |
0 commit comments