1
0
Files
nex/openspec/specs/model-management/spec.md
lanyuanxiaoyao 395887667d feat: 实现统一模型 ID 机制
实现统一模型 ID 格式 (provider_id/model_name),支持跨协议模型标识和 Smart Passthrough。

核心变更:
- 新增 pkg/modelid 包:解析、格式化、校验统一模型 ID
- 数据库迁移:models 表使用 UUID 主键 + UNIQUE(provider_id, model_name) 约束
- Repository 层:FindByProviderAndModelName、ListEnabled 方法
- Service 层:联合唯一校验、provider ID 字符集校验
- Conversion 层:ExtractModelName、RewriteRequestModelName/RewriteResponseModelName 方法
- Handler 层:统一模型 ID 路由、Smart Passthrough、Models API 本地聚合
- 新增 error-responses、unified-model-id 规范

测试覆盖:
- 单元测试:modelid、conversion、handler、service、repository
- 集成测试:统一模型 ID 路由、Smart Passthrough 保真性、跨协议转换
- 迁移测试:UUID 主键、UNIQUE 约束、级联删除

OpenSpec:
- 归档 unified-model-id 变更到 archive/2026-04-21-unified-model-id
- 同步 11 个 delta specs 到 main specs
- 新增 error-responses、unified-model-id 规范文件
2026-04-21 18:14:10 +08:00

4.9 KiB
Raw Blame History

Model Management

Purpose

管理模型的增删改查,通过 handler → service → repository 分层实现业务逻辑和数据访问,支持供应商关联验证。

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}

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 返回错误格式:
    {
      "error": "同一供应商下模型名称已存在",
      "code": "duplicate_model"
    }
    

Scenario: 数据库约束兜底

  • WHEN 并发创建导致应用层校验通过但数据库写入失败
  • THEN SHALL 捕获数据库 UNIQUE 约束错误
  • THEN SHALL 转换为 HTTP 409 Conflict 错误返回
  • THEN SHALL 返回错误格式:
    {
      "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 的供应商)