1
0
Files
nex/openspec/specs/model-management/spec.md
lanyuanxiaoyao feff97acbd feat: 前端适配后端新接口
适配后端统一模型 ID、协议字段、UUID 自动生成和结构化错误响应:

- 类型定义:Provider 新增 protocol 字段,Model 新增 unifiedId,CreateModelInput 移除 id
- API 客户端:提取结构化错误响应中的错误码
- 供应商管理:添加协议选择下拉框和表格列
- 模型管理:移除 ID 输入,显示统一模型 ID(只读)
- Hooks:错误码映射为友好中文消息
- 测试:所有组件测试通过,mock 数据适配新字段
- 文档:更新 README 说明协议字段和统一模型 ID
2026-04-21 20:49:37 +08:00

167 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Model Management
## Purpose
管理模型的增删改查,通过 handler → service → repository 分层实现业务逻辑和数据访问,支持供应商关联验证。
### Requirement: 前端适配统一模型 ID 显示
前端 SHALL 在模型管理界面显示统一模型 ID。
#### Scenario: 模型列表返回统一 ID
- **WHEN** 向 `/api/models` 发送 GET 请求
- **THEN** 每个模型 SHALL 包含 unified_id 字段
- **THEN** unified_id 格式 SHALL 为 `{provider_id}/{model_name}`
#### Scenario: 创建模型返回统一 ID
- **WHEN** 向 `/api/models` 发送 POST 请求创建模型
- **THEN** 返回的模型 SHALL 包含 unified_id 字段
- **THEN** unified_id SHALL 由后端根据 provider_id 和 model_name 生成
#### Scenario: 更新模型返回统一 ID
- **WHEN** 向 `/api/models/:id` 发送 PUT 请求更新模型
- **THEN** 返回的模型 SHALL 包含更新后的 unified_id
- **THEN** unified_id SHALL 反映最新的 provider_id 和 model_name 组合
### Requirement: 创建模型配置
网关 SHALL 允许为供应商创建新的模型配置。
#### Scenario: 使用有效数据创建模型
- **WHEN** 向 `/api/models` 发送 POST 请求携带有效的模型数据provider_id, model_name不提供 id 字段
- **THEN** 网关 SHALL 自动生成 UUID 作为模型 id
- **THEN** 网关 SHALL 在数据库中创建新的模型记录
- **THEN** 网关 SHALL 返回创建的模型,状态码为 201
- **THEN** 模型 SHALL 默认启用
- **THEN** 返回的模型 SHALL 包含 `unified_id` 字段,值为 `{provider_id}/{model_name}`
- **THEN** 前端 SHALL NOT 在请求体中发送 id 字段
#### Scenario: 使用不存在的供应商创建模型
- **WHEN** 向 `/api/models` 发送 POST 请求,携带不存在的 provider_id
- **THEN** 网关 SHALL 返回错误,状态码为 400 (Bad Request)
- **THEN** 错误 SHALL 指示供应商不存在
#### Scenario: 创建重复模型
- **WHEN** 向 `/api/models` 发送 POST 请求,携带已存在的 provider_id + model_name 组合
- **THEN** 网关 SHALL 返回错误,状态码为 409 (Conflict)
- **THEN** 错误 SHALL 指示同一供应商下模型名称已存在
### Requirement: 列出所有模型
网关 SHALL 允许获取所有模型配置。
#### Scenario: 成功列出模型
- **WHEN** 向 `/api/models` 发送 GET 请求
- **THEN** 网关 SHALL 返回所有模型的列表
- **THEN** 每个模型 SHALL 包含 id, provider_id, model_name, unified_id, enabled, created_at
### Requirement: 按供应商列出模型
网关 SHALL 允许获取特定供应商的模型。
#### Scenario: 列出存在供应商的模型
- **WHEN** 向 `/api/models?provider_id=<provider_id>` 发送 GET 请求
- **THEN** 网关 SHALL 返回指定供应商的模型列表
- **THEN** 每个模型 SHALL 包含 unified_id 字段
### Requirement: 更新模型配置
网关 SHALL 允许更新现有模型配置。
#### Scenario: 使用有效数据更新模型
- **WHEN** 向 `/api/models/:id` 发送 PUT 请求,携带有效的模型数据
- **THEN** 网关 SHALL 更新数据库中的模型记录
- **THEN** 网关 SHALL 返回更新后的模型
- **THEN** 返回的模型 SHALL 包含更新后的 unified_id
#### Scenario: 更新模型为重复组合
- **WHEN** 向 `/api/models/:id` 发送 PUT 请求,更新 provider_id 或 model_name 导致与已有记录重复
- **THEN** 网关 SHALL 返回错误,状态码为 409 (Conflict)
### Requirement: 删除模型配置
网关 SHALL 允许删除模型配置。
#### Scenario: 删除存在的模型
- **WHEN** 向 `/api/models/:id` 发送 DELETE 请求,携带有效的模型 ID
- **THEN** 网关 SHALL 删除模型记录
- **THEN** 网关 SHALL 返回状态码 204 (No Content)
### Requirement: 使用 service 层处理业务逻辑
Handler SHALL 通过 ModelService 处理业务逻辑。
#### Scenario: 调用 service 方法
- **WHEN** handler 收到请求
- **THEN** SHALL 调用对应的 ModelService 方法Create、Get、List、Update、Delete
- **THEN** SHALL 使用 domain.Model 类型
- **THEN** Create 时 SHALL 调用 `uuid.New()` 生成 id
#### Scenario: 供应商验证和唯一性校验
- **WHEN** 创建或更新模型
- **THEN** SHALL 在 service 层验证供应商存在
- **THEN** SHALL 在 service 层验证 provider_id + model_name 联合唯一
### Requirement: 联合唯一约束并发处理
创建或更新模型时SHALL 使用应用层校验 + 数据库约束双重保险处理联合唯一约束。
#### Scenario: 应用层快速失败
- **WHEN** 创建或更新模型前
- **THEN** SHALL 先检查 provider_id + model_name 是否已存在
- **THEN** 如已存在SHALL 返回 HTTP 409 Conflict
- **THEN** SHALL 返回错误格式:
```json
{
"error": "同一供应商下模型名称已存在",
"code": "duplicate_model"
}
```
#### Scenario: 数据库约束兜底
- **WHEN** 并发创建导致应用层校验通过但数据库写入失败
- **THEN** SHALL 捕获数据库 UNIQUE 约束错误
- **THEN** SHALL 转换为 HTTP 409 Conflict 错误返回
- **THEN** SHALL 返回错误格式:
```json
{
"error": "同一供应商下模型名称已存在",
"code": "duplicate_model"
}
```
#### Scenario: SQLite UNIQUE 约束错误检测
- **WHEN** 捕获数据库错误
- **THEN** SHALL 检查错误信息是否包含 "UNIQUE constraint failed"
- **THEN** 如匹配SHALL 识别为联合唯一约束冲突
### Requirement: 使用 repository 层访问数据
Service SHALL 通过 ModelRepository 访问数据。
#### Scenario: 联合查询
- **WHEN** service 需要按 provider 和 model_name 查询模型
- **THEN** SHALL 调用 `FindByProviderAndModelName(providerID, modelName)` 方法
#### Scenario: 查询所有启用模型
- **WHEN** proxy handler 需要聚合模型列表
- **THEN** SHALL 调用 `ListEnabled()` 方法,返回所有 enabled 的模型(关联 enabled 的供应商)