GPU_GUARD_MONOREPO/docs/superpowers/specs/2026-04-12-model-channel-management-design.md
2026-05-20 21:39:12 +08:00

251 lines
10 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.

# 模型渠道管理设计文档
> **日期**: 2026-04-12
> **范围**: Neta-monorepo 后端 + 前端
> **参照**: AI_flow_BackEnd 模型渠道管理实现
---
## 1. 目标
为 Neta-monorepo 新增集中式 LLM 模型渠道管理能力,参照 AI_flow 的三级结构(供应商 → 渠道 → 模型),同时适配 Neta 的 `provider:model` 运行时机制。改造 Agent 和 Skill 的模型配置为渠道级联选择器。
**核心价值**:
- API Key 集中管理,一处修改全局生效
- 支持同一供应商多套渠道(如测试/生产各一套 Key
- 渠道启停、连通性测试等运维能力
- Agent/Skill 编辑时通过选择器引用,避免手动填凭证
---
## 2. 数据模型
### 2.1 新增表: `netaclaw_model_channel`
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | int | PK, auto | 主键 |
| name | varchar(100) | unique | 渠道名称,如"Anthropic-生产" |
| supplier | varchar(50) | indexed | 供应商类型代码 |
| baseUrl | varchar(500) | not null | API 基础地址 |
| apiKey | varchar(500) | nullable | API 密钥 |
| models | json | not null | 模型列表 `[{name, capability}]` |
| description | text | nullable | 描述 |
| status | int | indexed, default 1 | 0=禁用 1=启用 |
| createTime | datetime | auto | 创建时间 |
| updateTime | datetime | auto | 更新时间 |
| deleteTime | datetime | nullable | 软删除时间 |
**models JSON 结构**:
```json
[
{ "name": "claude-sonnet-4-20250514", "capability": "text" },
{ "name": "claude-sonnet-4-20250514", "capability": "multimodal" }
]
```
### 2.2 系统参数 (`base_sys_param`)
新增 2 条参数记录:
| keyName | name | dataType | data (JSON) |
|---------|------|----------|-------------|
| `model_suppliers` | AI模型供应商 | 0 | `[{"value":"openai","label":"OpenAI","tagType":""},{"value":"anthropic","label":"Anthropic","tagType":"purple"},{"value":"deepseek","label":"DeepSeek","tagType":"success"},{"value":"zhipu","label":"智谱AI","tagType":"success"},{"value":"tongyi","label":"通义千问","tagType":"warning"},{"value":"minimax","label":"MiniMax","tagType":"danger"},{"value":"volcengine","label":"火山引擎","tagType":"warning"},{"value":"ollama","label":"Ollama","tagType":"info"},{"value":"azure","label":"Azure OpenAI","tagType":""}]` |
| `model_capabilities` | 模型能力类型 | 0 | `[{"value":"text","label":"纯文本"},{"value":"multimodal","label":"多模态"},{"value":"vision","label":"视觉"}]` |
供应商和能力类型均通过系统参数表管理,前端不做硬编码。供应商配置包含 `tagType` 字段用于渲染标签颜色,后续可在参数列表页面自由扩展新供应商或新能力类型。
### 2.3 Agent `modelConfig` 字段语义扩展
**新格式** (选择渠道时):
```json
{ "channelId": 5, "modelId": "claude-sonnet-4-20250514", "contextWindow": 200 }
```
**自定义格式** (channelId 为 0 或 null 时,回退手动模式):
```json
{ "channelId": 0, "apiUrl": "https://...", "apiKey": "sk-xxx", "modelId": "custom-model", "contextWindow": 200 }
```
**兼容性**: 已有 Agent 的 modelConfig 中无 channelId视为自定义配置模式无需数据迁移。
---
## 3. 后端架构
### 3.1 新增文件
| 文件 | 路径 | 说明 |
|------|------|------|
| Entity | `packages/backend/src/modules/netaclaw/entity/model_channel.ts` | TypeORM 实体 |
| Service | `packages/backend/src/modules/netaclaw/service/model_channel.ts` | 业务逻辑 |
| Controller | `packages/backend/src/modules/netaclaw/controller/admin/model_channel.ts` | Admin API |
### 3.2 API 端点
| 端点 | 方法 | 功能 | 来源 |
|------|------|------|------|
| `/admin/netaclaw/model_channel/page` | POST | 分页查询 | @CoolController 自动生成 |
| `/admin/netaclaw/model_channel/add` | POST | 新增渠道 | @CoolController 自动生成 |
| `/admin/netaclaw/model_channel/update` | POST | 更新渠道 | @CoolController 自动生成 |
| `/admin/netaclaw/model_channel/delete` | POST | 删除渠道 | @CoolController 自动生成 |
| `/admin/netaclaw/model_channel/info` | GET | 渠道详情 | @CoolController 自动生成 |
| `/admin/netaclaw/model_channel/allModels` | GET | 所有启用渠道的模型列表 | 自定义方法 |
| `/admin/netaclaw/model_channel/testConnection` | POST | 测试渠道连通性 | 自定义方法 |
### 3.3 Service 关键方法
**`allModels()`**:
- 查询所有 `status=1` 的渠道
- 标准化 models 字段(兼容旧格式字符串数组 → `{name, capability}` 对象)
- 返回渠道列表及其模型
**`testConnection(id: number)`**:
- 根据 supplier 类型初始化对应 LLM 客户端
- 发送简单测试请求验证连通性
- 返回 `{ success, elapsed, message }`
- 供应商到 Provider 的映射:
- openai/azure → OpenAI SDK
- anthropic → Anthropic SDK
- deepseek → OpenAI SDK (自定义 baseUrl)
- zhipu/tongyi/minimax/volcengine → OpenAI SDK (自定义 baseUrl)
- ollama → OpenAI SDK (本地 baseUrl)
**`resolveForAgent(channelId: number, modelId: string)`**:
- 查询渠道获取 `supplier``baseUrl``apiKey`
- 将 supplier 映射为 Neta 的 provider 名称
- 返回 `{ provider, model, apiKey, baseUrl }` 供 Agent 运行时使用
- supplier → provider 映射规则:
- `openai``openai`
- `anthropic``anthropic`
- `deepseek``deepseek`
- 其他 (zhipu/tongyi/minimax/volcengine/ollama/azure) → `openai`(均使用 OpenAI 兼容协议)
### 3.4 运行时改造
**文件**: `packages/backend/src/modules/netaclaw/runtime/agent.ts`
`runAgent()` 函数中,执行前解析模型配置:
1. 读取 Agent 的 `modelConfig`
2.`channelId > 0`,调用 `resolveForAgent(channelId, modelId)` 获取凭证
3.`channelId` 为 0/null 或无该字段,使用 modelConfig 中的 `apiUrl`/`apiKey`(向后兼容)
4. 构建 `provider:model` 格式字符串传入运行时
### 3.5 Entity 注册
`packages/backend/src/entities.ts` 中添加新 Entity 的导入。
---
## 4. 前端架构
### 4.1 新增文件
| 文件 | 路径 | 说明 |
|------|------|------|
| 模型渠道管理页 | `packages/frontend/src/modules/agent/views/model-channel.vue` | 渠道 CRUD 页面 |
| 渠道选择器组件 | `packages/frontend/src/modules/agent/components/model-channel-selector.vue` | 级联选择器 |
### 4.2 模型渠道管理页面 (`model-channel.vue`)
**布局**:
- 顶部工具栏: 新增渠道按钮、供应商筛选下拉、关键词搜索、查询/重置
- 数据表格: 渠道名称、供应商(Tag)、Base URL、模型汇总(按能力分组计数)、状态(Switch)、操作(编辑/测试/删除)
- 分页控件
- 编辑抽屉 (600px 宽度):
- 渠道名称 (必填)
- 供应商类型 (下拉,选项从 `model_suppliers` 参数加载,必填)
- Base URL (必填)
- API Key (密码输入)
- 描述
- 模型列表 (表格式编辑: 模型名 + 能力类型下拉)
- 添加单行 + 批量导入按钮
- 批量导入对话框: 默认能力类型 + 文本域(逗号/换行分隔模型名)
**供应商 Tag 颜色**: 从 `model_suppliers` 参数的 `tagType` 字段读取,不硬编码。
**API 调用**:
- 参数加载: `GET /admin/base/sys/param/dataByKey?key=model_suppliers`
- 参数加载: `GET /admin/base/sys/param/dataByKey?key=model_capabilities`
- 分页查询: `POST /admin/netaclaw/model_channel/page`
- 新增: `POST /admin/netaclaw/model_channel/add`
- 更新: `POST /admin/netaclaw/model_channel/update`
- 删除: `POST /admin/netaclaw/model_channel/delete`
- 测试: `POST /admin/netaclaw/model_channel/testConnection`
### 4.3 渠道选择器组件 (`model-channel-selector.vue`)
**Props**:
- `modelValue?: { channelId?, modelId?, apiUrl?, apiKey?, contextWindow? }` (v-model)
- `capabilityFilter?: string` (按能力类型过滤可选模型)
**Emits**:
- `update:modelValue`
- `change`
**UI**:
- 渠道选择下拉 (显示: "渠道名称N个模型")
- 额外选项: "自定义配置(手动输入)" (value=0)
- 模型选择下拉 (filterable显示: 模型名 + 能力类型 Tag)
- 自定义模式时展示: API URL + API Key + Model ID 手动输入框
**数据流**:
1. 初始化时调用 `GET /admin/netaclaw/model_channel/allModels` 获取所有启用渠道
2.`capabilityFilter` 过滤渠道和模型
3. 用户选择渠道 → 展示该渠道的模型列表
4. 用户选择模型 → emit `{ channelId, modelId }`
5. 若选「自定义配置」→ 展示手动输入表单 → emit `{ channelId: 0, apiUrl, apiKey, modelId }`
### 4.4 改造: Agent 编辑页
**文件**: `packages/frontend/src/modules/agent/views/agent-edit.vue`
**「模型配置」Tab 改造**:
- 移除原有 apiUrl/apiKey/modelId/contextWindow 4 个输入框
- 替换为 `<model-channel-selector v-model="form.modelConfig" />`
- 选择器下方保留 contextWindow 输入框
- 保留「填入默认」按钮(从 netaclaw 配置读取默认渠道)和「清空」按钮
### 4.5 改造: Skill 模型配置
**文件**: `packages/frontend/src/modules/agent/components/skill-model.vue`
- 将手动输入替换为 `<model-channel-selector :capability-filter="skillType" />`
- Skill 类型为 `multimodal` 时只展示 multimodal 能力的模型
- Skill 类型为 `llm` 时展示 text 能力的模型
### 4.6 路由配置
**文件**: `packages/frontend/src/modules/agent/config.ts`
新增路由:
```typescript
{ path: '/agent/model-channel', meta: { label: '模型管理' } }
```
---
## 5. 文件变更清单
| 操作 | 位置 | 文件 |
|------|------|------|
| 新增 | backend | `src/modules/netaclaw/entity/model_channel.ts` |
| 新增 | backend | `src/modules/netaclaw/service/model_channel.ts` |
| 新增 | backend | `src/modules/netaclaw/controller/admin/model_channel.ts` |
| 新增 | frontend | `src/modules/agent/views/model-channel.vue` |
| 新增 | frontend | `src/modules/agent/components/model-channel-selector.vue` |
| 修改 | frontend | `src/modules/agent/views/agent-edit.vue` |
| 修改 | frontend | `src/modules/agent/components/skill-model.vue` |
| 修改 | frontend | `src/modules/agent/config.ts` |
| 修改 | backend | `src/modules/netaclaw/runtime/agent.ts` |
| 修改 | backend | `src/entities.ts` |
| 数据 | database | `base_sys_param` 表新增 2 条参数记录 |
---
## 6. 兼容性
- **无数据迁移**: 已有 Agent 的 modelConfig 中无 channelId自动视为自定义配置模式
- **渐进式采用**: 新建/编辑 Agent 时可选择渠道或自定义,不影响已有 Agent 运行
- **运行时兼容**: channelId 有值走渠道查询,无值走原有 apiUrl/apiKey 逻辑