461 lines
33 KiB
Markdown
461 lines
33 KiB
Markdown
# AI 助手模型管理功能 - 需求规格说明书
|
||
|
||
| 文档版本 | 修订日期 | 修订人 | 修订内容 |
|
||
| :------- | :--------- | :----- | :----------------------------------------------------------------------- |
|
||
| V1.0 | 2026-05-23 | — | 初始版本:管理员模型 CRUD、用户端模型切换及配套业务规则 |
|
||
| V1.1 | 2026-05-23 | — | 禁用模型旧会话仅可查看;模型增加图片/语音上传开关(管理端配置,用户端本期不做上传) |
|
||
| V1.2 | 2026-05-23 | — | 补充 §1.6 与润色、标签推荐等其它 AI 功能的关系说明 |
|
||
|
||
**关联文档**:[AI助手功能需求.md](./AI助手功能需求.md)(V1.2)、[AI助手功能技术实施文档.md](./AI助手功能技术实施文档.md)
|
||
|
||
---
|
||
|
||
## 1. 项目概述
|
||
|
||
### 1.1 功能背景
|
||
|
||
AI 助手(`/ai-assistant`)已上线,支持多轮对话、会话持久化与历史回看。当前调用 DashScope 时,**模型名称固定**为全局配置 `dashscope.model`(默认 `qwen-turbo`,见 `application.yml` / `DashScopeProperties`),管理员无法在后台增删或切换可用模型,用户也无法在对话时选择不同能力档位的模型。
|
||
|
||
为便于运营侧按场景上架/下架模型(如「快速」「深度推理」),并让用户自主选择,需新增 **助手模型管理**(管理后台)与 **用户端模型切换**(AI 助手页)。模型 **禁用** 主要用于该模型 **Token 额度已用尽** 等场景:禁用后用户不可再选该模型,且历史会话 **仅可查看、不可继续对话**。
|
||
|
||
### 1.2 功能目标
|
||
|
||
- 管理员在后台对「AI 助手可用模型」进行 **新增、修改、逻辑删除**
|
||
- 用户在使用 AI 助手时可 **切换当前选用的模型**(仅展示已启用且未删除的模型)
|
||
- 对话请求按所选模型调用 DashScope;会话维度记录所用模型,便于回看与排障
|
||
- 与现有 AI 助手多轮、限流、持久化规则兼容;**不改变** 摘要、润色、标签推荐等其它 AI 功能的模型来源(仍用 `dashscope.model`)
|
||
|
||
### 1.3 适用范围
|
||
|
||
| 角色 | 涉及范围 |
|
||
| :------------- | :--------------------------------------------------------------- |
|
||
| 产品经理 | 模型字段、默认模型、会话绑定、禁用/删除边界 |
|
||
| 前端开发工程师 | 管理后台模型页、助手页模型选择器、路由与 API 封装 |
|
||
| 后端开发工程师 | 模型表 Flyway、Admin/App 接口、聊天接口按 `modelId` 调 DashScope |
|
||
| 测试工程师 | CRUD、逻辑删除、默认模型约束、切换与会话绑定、异常模型 |
|
||
| 运维工程师 | 首版数据迁移(种子模型);`DASHSCOPE_API_KEY` 仍全局一份 |
|
||
|
||
### 1.4 现状说明
|
||
|
||
| 项目 | 现状 |
|
||
| :----------- | :------------------------------------------------------------------- |
|
||
| 模型配置 | `DashScopeProperties.model`,环境变量 `DASHSCOPE_MODEL`,全站默认 |
|
||
| AI 助手调用 | `AiChatServiceImpl` 请求体写死 `properties.getModel()` |
|
||
| 管理后台菜单 | `AdminLayout` 含仪表盘、用户、文章、评论、分类;**无** 模型管理入口 |
|
||
| 数据表 | 仅有 `ai_chat_session`、`ai_chat_message`;**无** 模型配置表 |
|
||
| API Key | 仍由环境变量注入,**不入库**(与现有一致) |
|
||
|
||
### 1.5 改动合理性评估
|
||
|
||
| 改动项 | 合理性说明 |
|
||
| :--------------- | :------------------------------------------------------------------------- |
|
||
| 模型配置入库 | 运营可动态上下架,无需改配置重启;与分类「启用/禁用」模式一致 |
|
||
| 逻辑删除 | 已产生历史会话的模型可下架但保留关联;符合项目 `@TableLogic` 惯例 |
|
||
| 禁用即停对话 | 禁用主因是 Token 不足;绑定该模型的旧会话 **只读回看**,避免继续消耗额度 |
|
||
| 会话绑定模型 | 同一会话多轮上下文应使用同一模型,避免中途换模导致风格与指代混乱 |
|
||
| 多模态配置预留 | 图片/语音开关先入表与后台表单;用户端上传能力后续迭代 |
|
||
| 仅 AI 助手动态化 | 控制范围;其它 AI 能力沿用全局配置,降低首期复杂度 |
|
||
|
||
### 1.6 与其它 AI 功能的关系
|
||
|
||
本期 **仅 AI 助手**(`/ai-assistant`)使用表 `ai_assistant_model` 及后台模型管理;**AI 文章润色**、**文章标签自动推荐**、**文章摘要** 仍通过 `dashscope.model` / 环境变量 `DASHSCOPE_MODEL` 调用 DashScope,**不读取** 助手模型表,亦不受助手侧「启用 / 禁用」影响(见约定 **D-10**)。
|
||
|
||
三项能力与助手 **共用** `DASHSCOPE_API_KEY` 及 `AiSummaryServiceImpl.callModel` 链路。若某 `model_code` 在百炼侧额度用尽:须在助手后台 **禁用对应模型行**,并视情况 **调整环境变量或运维配置**,润色 / 标签 / 摘要方可同步停用同一编码。助手默认模型(库内 `is_default`)与环境变量 **可不一致**,部署与排障时须分别核对。
|
||
|
||
---
|
||
|
||
## 2. 名词解释
|
||
|
||
| 术语 | 说明 |
|
||
| :---------------- | :------------------------------------------------------------------------------------- |
|
||
| 助手模型 | 可在 AI 助手对话中选用的一条 DashScope 模型配置记录 |
|
||
| 模型编码 modelCode | 调用 DashScope `chat/completions` 时 JSON 中的 `model` 字段值(如 `qwen-turbo`) |
|
||
| 展示名称 | 用户与管理后台列表中可见的中文/友好名称(如「通义 Turbo · 快速」) |
|
||
| 默认模型 | 系统指定的兜底模型;用户未手动选择或所选失效时使用 |
|
||
| 启用 / 禁用 | `enabled=true` 对用户可见可选、可新建会话;`false` 表示该模型 **Token 额度已用尽或运营下架**,用户不可再选,已绑定会话 **仅可查看** |
|
||
| 模型停用只读 | 会话绑定模型被禁用后:可加载历史消息全文,**禁止** `POST /chat`;交互同「满 5 轮只读」 |
|
||
| 逻辑删除 | `deleted=1`,列表默认不展示;历史会话仍可通过 `model_id` 关联到记录(含已删) |
|
||
| 会话绑定模型 | 每个 `ai_chat_session` 在创建时记录 `model_id`,该会话内所有轮次均用此模型 |
|
||
| 允许上传图片 | `allowImageUpload`,模型级配置;表示该模型 **能力上** 支持图片输入(本期用户端无上传 UI) |
|
||
| 允许上传语音 | `allowVoiceUpload`,模型级配置;表示该模型 **能力上** 支持语音输入(本期用户端无上传 UI) |
|
||
|
||
---
|
||
|
||
## 3. 功能需求清单
|
||
|
||
### 3.1 管理后台 - 助手模型管理
|
||
|
||
#### 3.1.1 功能描述
|
||
|
||
在管理后台(`AdminLayout`)新增菜单 **「AI 模型」**(或「助手模型」),路由建议 `/admin/ai-models`。页面提供模型列表与新增/编辑弹窗,支持逻辑删除。
|
||
|
||
#### 3.1.2 页面要素
|
||
|
||
| 列表列 | 说明 |
|
||
| :--------- | :---------------------------------------- |
|
||
| ID | 主键 |
|
||
| 展示名称 | `displayName` |
|
||
| 模型编码 | `modelCode`(DashScope 实际 model 名) |
|
||
| 描述 | 可选,列表可省略或 tooltip |
|
||
| 状态 | 启用 / 禁用(禁用表示 Token 不足或运营下架) |
|
||
| 图片 | 允许上传图片(是/否) |
|
||
| 语音 | 允许上传语音(是/否) |
|
||
| 默认 | 是否默认模型(至多一个为「是」) |
|
||
| 排序 | `sort`,升序排列 |
|
||
| 更新时间 | `updatedAt` |
|
||
| 操作 | 编辑、删除(逻辑删除) |
|
||
|
||
弹窗表单字段见 §3.3.2。
|
||
|
||
#### 3.1.3 业务规则
|
||
|
||
| 编号 | 规则项 | 业务规则说明 |
|
||
| :---------------------- | :--------------- | :---------------------------------------------------------------------------------------------------- |
|
||
| FR-AI-MODEL-ADM-01 | 权限 | 仅 **ADMIN** 角色可访问;接口挂载 `/api/admin/ai/models/**` |
|
||
| FR-AI-MODEL-ADM-02 | 新增 | 必填:`displayName`、`modelCode`;可选:`description`;默认 `enabled=true`,`allowImageUpload=false`,`allowVoiceUpload=false`,`sort=0` |
|
||
| FR-AI-MODEL-ADM-03 | 修改 | 可改展示名、编码、描述、启用、排序、是否默认、`allowImageUpload`、`allowVoiceUpload`;**不可** 修改 `id` |
|
||
| FR-AI-MODEL-ADM-03a | 多模态开关 | `allowImageUpload`、`allowVoiceUpload` 为布尔,默认 `false`;仅管理端表单配置,**本期无实际上传联调** |
|
||
| FR-AI-MODEL-ADM-04 | 逻辑删除 | 删除将 `deleted` 置 1;列表与下拉 **不再展示**;**不物理删行** |
|
||
| FR-AI-MODEL-ADM-05 | 编码唯一 | 未删除记录中 `model_code` **全局唯一**;重复则 `400` |
|
||
| FR-AI-MODEL-ADM-06 | 默认模型唯一 | 全库至多 **1** 条 `is_default=1` 且 `deleted=0`;设置新默认时自动取消原默认 |
|
||
| FR-AI-MODEL-ADM-07 | 禁止删唯一启用 | 若删除或禁用后,**不存在** 任何 `enabled=1` 且 `deleted=0` 的模型,操作拒绝并提示 |
|
||
| FR-AI-MODEL-ADM-08 | 禁止删当前默认 | 逻辑删除 **默认模型** 前须先将另一条设为默认,否则拒绝 |
|
||
| FR-AI-MODEL-ADM-09 | 列表范围 | 管理端列表默认仅 `deleted=0`;可选筛选「含禁用」 |
|
||
| FR-AI-MODEL-ADM-10 | 模型编码格式 | `modelCode` 1~64 字符,允许字母数字、点、横线、下划线;trim 后校验 |
|
||
| FR-AI-MODEL-ADM-11 | 展示名称 | `displayName` 1~32 字符 |
|
||
| FR-AI-MODEL-ADM-12 | 描述 | `description` 最长 200 字符,可空 |
|
||
| FR-AI-MODEL-ADM-13 | 排序 | `sort` 为非负整数,列表按 `sort ASC, id ASC` |
|
||
| FR-AI-MODEL-ADM-14 | 首版无连通性测试 | 保存时不强制调用 DashScope 探测;错误模型在用户使用时报既有 AI 错误码(见 §3.4) |
|
||
|
||
#### 3.1.4 验收标准
|
||
|
||
| 编号 | 验证场景 | 预期结果 |
|
||
| :---------------------- | :------------------------------- | :------------------------------------------------- |
|
||
| AC-AI-MODEL-ADM-01 | 管理员新增两条模型 | 列表可见,用户端可选列表含启用项 |
|
||
| AC-AI-MODEL-ADM-02 | 重复 modelCode 新增 | 提示编码已存在 |
|
||
| AC-AI-MODEL-ADM-03 | 将 A 设为默认后再设 B 为默认 | 仅 B 为默认 |
|
||
| AC-AI-MODEL-ADM-04 | 删除默认模型(未改默认) | 操作失败并提示 |
|
||
| AC-AI-MODEL-ADM-05 | 禁用全部模型尝试 | 最后一次禁用失败并提示须保留至少一个启用模型 |
|
||
| AC-AI-MODEL-ADM-06 | 逻辑删除后管理端列表 | 不出现;历史会话详情仍可显示当时模型名(见 §3.4) |
|
||
| AC-AI-MODEL-ADM-07 | 编辑模型勾选「允许上传图片」 | 保存成功;列表/详情展示正确;用户端助手 **无** 上传入口 |
|
||
|
||
---
|
||
|
||
### 3.2 用户端 - AI 助手模型切换
|
||
|
||
#### 3.2.1 功能描述
|
||
|
||
在 AI 助手页(`AiAssistant.vue` / `AiChatPanel` 标题栏区域)增加 **模型选择器**(`el-select` 或同级组件)。展示当前用户可选的启用模型列表;切换后影响 **后续新建会话** 的默认模型;**不改变** 已存在且已绑定模型的历史会话的模型。
|
||
|
||
#### 3.2.2 交互示意
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────┐
|
||
│ 会话标题 …… [ 模型:通义 Turbo ▼ ] 轮次 3/5 │
|
||
├──────────────────────────────────────────────────────────────┤
|
||
│ 消息区 …… │
|
||
└──────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
- 下拉项:`displayName`;可选副文案 `description`(过长截断)
|
||
- 默认选中:用户上次选择(见 FR-AI-MODEL-FE-04)或系统默认模型
|
||
|
||
#### 3.2.3 业务规则
|
||
|
||
| 编号 | 规则项 | 业务规则说明 |
|
||
| :---------------------- | :----------------- | :---------------------------------------------------------------------------------------------- |
|
||
| FR-AI-MODEL-FE-01 | 可见性 | 未登录:不展示选择器(与发送需登录一致);已登录展示 |
|
||
| FR-AI-MODEL-FE-02 | 数据来源 | `GET /api/app/ai/models`,仅 `enabled=1` 且 `deleted=0`,按 `sort` 排序 |
|
||
| FR-AI-MODEL-FE-03 | 切换生效范围 | 切换仅更新「当前选用模型」;**点击「新会话」** 创建的会话绑定新模型;已在进行的会话 **不变** |
|
||
| FR-AI-MODEL-FE-04 | 记住选择 | 将 `modelId` 存入 `localStorage`(key 建议 `jog_ai_assistant_model_id`);进入页时恢复 |
|
||
| FR-AI-MODEL-FE-05 | 失效回退 | 本地记录的 `modelId` 已禁用/删除时,回退为 **系统默认模型** |
|
||
| FR-AI-MODEL-FE-06 | 发送携带 | `POST /api/app/ai/chat` 请求体增加可选 `modelId`;**创建会话** `POST /sessions` 可带 `modelId` |
|
||
| FR-AI-MODEL-FE-07 | 首条无 session | 无 `sessionId` 时先创建会话(带当前 `modelId`)再发送 |
|
||
| FR-AI-MODEL-FE-08 | 只读会话 | **已满 5 轮** 或 **绑定模型已禁用**:输入区禁用、仅可查看历史;选择器仍可切换(为下次新会话准备) |
|
||
| FR-AI-MODEL-FE-08a | 模型停用提示 | 绑定模型 `enabled=false` 时展示提示条:「该会话所用模型已停用(额度不足),仅可查看历史,请切换模型后新建会话」 |
|
||
| FR-AI-MODEL-FE-08b | 只读判定 | `readOnly = (roundCount >= 5) OR (session.modelEnabled === false)`;二者同时满足时优先展示模型停用提示(若适用) |
|
||
| FR-AI-MODEL-FE-09 | 加载失败 | 模型列表接口失败:展示选择器占位「模型加载失败」,发送时后端用默认模型(见 BE-05) |
|
||
| FR-AI-MODEL-FE-10 | 单模型 | 仅 1 个可选模型时仍展示选择器(或禁用下拉仅展示名称,二选一,**推荐仍展示** 以利扩展) |
|
||
|
||
#### 3.2.4 验收标准
|
||
|
||
| 编号 | 验证场景 | 预期结果 |
|
||
| :---------------------- | :----------------------------------------- | :----------------------------------------------------------- |
|
||
| AC-AI-MODEL-FE-01 | 切换模型后点「新会话」并提问 | 新会话使用新模型(响应 `model` 字段与之一致) |
|
||
| AC-AI-MODEL-FE-02 | 会话进行中切换模型后继续在同会话发送 | 仍使用会话创建时绑定的模型 |
|
||
| AC-AI-MODEL-FE-03 | 刷新页面 | 恢复上次选择的模型(若仍有效) |
|
||
| AC-AI-MODEL-FE-04 | 管理员禁用某模型后用户点选绑定该模型的旧会话 | 历史消息完整展示,输入区禁用,提示模型已停用;发送被拦截 |
|
||
| AC-AI-MODEL-FE-05 | 禁用模型且会话未满 5 轮 | 仍不可继续发送(只读),与满 5 轮表现一致(除提示文案) |
|
||
|
||
---
|
||
|
||
### 3.3 后端 - 模型数据与接口
|
||
|
||
#### 3.3.1 数据模型(Flyway)
|
||
|
||
建议新增迁移 `V6__ai_assistant_model.sql`(版本号以仓库递增为准)。
|
||
|
||
**表 `ai_assistant_model`**
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
| :------------ | :------------- | :--------------------------------------------- |
|
||
| id | BIGINT PK | 主键 |
|
||
| model_code | VARCHAR(64) | DashScope model 参数,未删除记录唯一 |
|
||
| display_name | VARCHAR(32) | 展示名称 |
|
||
| description | VARCHAR(200) | 描述,可空 |
|
||
| enabled | TINYINT | 1 启用 0 禁用(Token 不足或运营下架),默认 1 |
|
||
| allow_image | TINYINT | 1 允许 0 不允许,默认 0;模型是否支持图片输入 |
|
||
| allow_voice | TINYINT | 1 允许 0 不允许,默认 0;模型是否支持语音输入 |
|
||
| is_default | TINYINT | 1 默认 0 非默认,默认 0 |
|
||
| sort | INT | 排序,默认 0 |
|
||
| created_at | DATETIME | 创建时间 |
|
||
| updated_at | DATETIME | 更新时间 |
|
||
| deleted | TINYINT | 逻辑删除,默认 0 |
|
||
|
||
**索引**:`UNIQUE uk_model_code (model_code, deleted)` 在 MySQL 下对软删唯一需用应用层校验或 `(model_code)` 唯一 + 删后改后缀;**首版采用应用层校验** `model_code` 在 `deleted=0` 间唯一。
|
||
|
||
**表 `ai_chat_session` 变更**
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
| :-------- | :------ | :---------------------------------------- |
|
||
| model_id | BIGINT | 会话绑定模型,FK 逻辑关联 `ai_assistant_model.id`,可空 |
|
||
|
||
- 迁移时对已有会话:`model_id` 设为迁移时 **默认模型** 的 id
|
||
- 新会话:创建时写入当前解析得到的 `model_id`
|
||
|
||
**表 `ai_chat_message`**:首版 **不增加** `model_id`(以会话为准)。
|
||
|
||
#### 3.3.2 管理端接口 `/api/admin/ai/models`
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
| :----- | :-------------------------------- | :--------------------------- |
|
||
| GET | `/api/admin/ai/models` | 列表(`deleted=0`,分页可选) |
|
||
| GET | `/api/admin/ai/models/{id}` | 详情 |
|
||
| POST | `/api/admin/ai/models` | 新增 |
|
||
| PUT | `/api/admin/ai/models/{id}` | 修改 |
|
||
| DELETE | `/api/admin/ai/models/{id}` | 逻辑删除 |
|
||
|
||
**新增/修改请求体示例**
|
||
|
||
```json
|
||
{
|
||
"modelCode": "qwen-plus",
|
||
"displayName": "通义 Plus",
|
||
"description": "更强推理,适合复杂问题",
|
||
"enabled": true,
|
||
"allowImageUpload": false,
|
||
"allowVoiceUpload": false,
|
||
"isDefault": false,
|
||
"sort": 10
|
||
}
|
||
```
|
||
|
||
**列表项响应字段**:`id, modelCode, displayName, description, enabled, allowImageUpload, allowVoiceUpload, isDefault, sort, createdAt, updatedAt`
|
||
|
||
#### 3.3.3 用户端接口
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
| :--- | :--------------------------- | :------------------------------------- |
|
||
| GET | `/api/app/ai/models` | 可选模型列表(仅启用、未删除) |
|
||
|
||
**列表项**:`id, displayName, description, isDefault, allowImageUpload, allowVoiceUpload`(**不返回** `modelCode`;多模态字段供后续前端使用,**本期助手页不展示上传控件**)
|
||
|
||
**扩展已有接口**
|
||
|
||
| 接口 | 变更 |
|
||
| :--------------------------- | :------------------------------------------------------------------- |
|
||
| `POST /api/app/ai/sessions` | 请求体可选 `{ "modelId": 1 }`;未传则用默认模型 |
|
||
| `POST /api/app/ai/chat` | 请求体可选 `modelId`;若传且与会话已绑定不一致,**忽略** 并以会话为准 |
|
||
| `GET /api/app/ai/sessions` | 列表项增加 `modelDisplayName`、`modelEnabled`(绑定模型是否仍启用) |
|
||
| `GET .../sessions/{id}/messages` | 可增加 `modelEnabled`、`readOnlyReason`(`ROUND_FULL` / `MODEL_DISABLED` / null) |
|
||
|
||
#### 3.3.4 聊天业务规则(相对原 AI 助手需求的增量)
|
||
|
||
| 编号 | 规则项 | 业务规则说明 |
|
||
| :---------------------- | :--------------- | :---------------------------------------------------------------------------------------------------- |
|
||
| FR-AI-MODEL-BE-01 | 解析模型 | 按 `model_id` 查模型;`deleted=1` 视为不可用;`enabled=0` 时 **禁止** 对该会话执行 `POST /chat`(返回 `400`,文案:该会话所用模型已停用,仅可查看历史) |
|
||
| FR-AI-MODEL-BE-01a | 只读与满 5 轮 | `enabled=0` 与 `round_count>=5` 均导致只读;二者独立判断,消息列表接口返回 `readOnlyReason` 供前端展示 |
|
||
| FR-AI-MODEL-BE-02 | 新会话绑定 | `createSession` 解析 `modelId`:无效则用默认模型 id |
|
||
| FR-AI-MODEL-BE-03 | 调用 DashScope | 请求体 `model` 使用记录的 `model_code`,**不再** 使用 `DashScopeProperties.model`(仅 AI 助手) |
|
||
| FR-AI-MODEL-BE-04 | 其它 AI 功能 | 摘要、润色、标签推荐 **仍** 使用 `properties.getModel()`,不读模型表 |
|
||
| FR-AI-MODEL-BE-05 | 默认模型 | 无可用默认时(数据异常),回退 `dashscope.model` 并打 **warn** 日志;正常运营不应出现 |
|
||
| FR-AI-MODEL-BE-06 | 模型不存在 | 创建会话时 `modelId` 指向已删或不存在 → `400` 模型不可用 |
|
||
| FR-AI-MODEL-BE-07 | 响应 | `AiChatResultVO` 继续返回实际 `model`(modelCode)及可增加 `modelDisplayName` |
|
||
| FR-AI-MODEL-BE-08 | 限流与 Key | 与现有一致;不按模型分限流 |
|
||
| FR-AI-MODEL-BE-09 | 种子数据 | 迁移插入一条默认模型:`model_code` = 当前 `dashscope.model`,`display_name` = 「默认模型」,`is_default=1`,`allow_image=0`,`allow_voice=0` |
|
||
| FR-AI-MODEL-BE-10 | 多模态配置 | 保存 `allow_image`/`allow_voice`;`POST /chat` **本期不接收** 图片/语音附件;后续迭代再校验「模型不允许则拒绝上传」 |
|
||
|
||
#### 3.3.5 错误码补充
|
||
|
||
| 错误码 / HTTP | 描述 | 触发条件 |
|
||
| :------------ | :----------------- | :------------------------------------- |
|
||
| 400 | 模型编码重复 | 新增/修改 modelCode 冲突 |
|
||
| 400 | 模型不可用 | 用户指定 modelId 无效或已删除 |
|
||
| 400 | 须保留启用模型 | 禁用/删除导致无启用模型 |
|
||
| 400 | 须先更换默认模型 | 删除当前默认模型 |
|
||
| 400 | 模型已停用 | 对绑定已禁用模型的会话调用 `POST /chat` |
|
||
|
||
(可在 `ErrorCode` 中新增枚举,或使用 `BusinessException` + 明确文案。)
|
||
|
||
#### 3.3.6 验收标准
|
||
|
||
| 编号 | 验证场景 | 预期结果 |
|
||
| :---------------------- | :------------------------------------ | :-------------------------------------------- |
|
||
| AC-AI-MODEL-BE-01 | 两模型分别建会话并 chat | DashScope 请求 `model` 分别为对应 modelCode |
|
||
| AC-AI-MODEL-BE-02 | 禁用某模型后旧会话继续 chat | 返回 400,模型已停用;`GET messages` 仍可查看 |
|
||
| AC-AI-MODEL-BE-03 | 新会话不传 modelId | 使用默认模型 |
|
||
| AC-AI-MODEL-BE-04 | 非管理员访问 admin 接口 | 403 |
|
||
|
||
---
|
||
|
||
### 3.4 配置与部署
|
||
|
||
| 配置项 | 说明 |
|
||
| :------------------ | :------------------------------------------------------------------- |
|
||
| `DASHSCOPE_API_KEY` | 不变,全局一份 |
|
||
| `dashscope.model` | 作 **种子** 与 **兜底**;AI 助手正常运行后以库内默认模型为准 |
|
||
| Flyway | 执行 V6 迁移 + 种子数据 |
|
||
|
||
部署检查:管理端可 CRUD;用户端下拉有数据;新会话对话返回正确 `model` 字段。
|
||
|
||
---
|
||
|
||
## 4. 交互流程
|
||
|
||
### 4.1 管理员上架新模型
|
||
|
||
```
|
||
1. 管理员进入 /admin/ai-models
|
||
2. 点击新增,填写 modelCode、displayName、enabled、sort
|
||
3. POST /api/admin/ai/models → 列表刷新
|
||
4. 用户端 GET /api/app/ai/models 出现新项(若 enabled)
|
||
```
|
||
|
||
### 4.2 用户切换模型并新会话提问
|
||
|
||
```
|
||
1. 用户在 AI 助手页将模型从 A 改为 B(写入 localStorage)
|
||
2. 点击「新会话」→ POST /sessions { modelId: B } → session 绑定 B
|
||
3. POST /chat → DashScope model = B.modelCode
|
||
4. 响应 data.model 为 B 的 modelCode
|
||
```
|
||
|
||
### 4.3 历史会话回看(模型已禁用)
|
||
|
||
```
|
||
1. 管理员因 Token 不足将模型 A 设为 disabled
|
||
2. 用户点选绑定模型 A 的旧会话(可能未满 5 轮)
|
||
3. GET /sessions/{id}/messages → 返回全文 + modelEnabled=false + readOnlyReason=MODEL_DISABLED
|
||
4. 前端输入区禁用,展示「模型已停用,仅可查看」
|
||
5. 用户 POST /chat → 400 拒绝
|
||
6. 用户切换为启用中的模型 B,点击「新会话」后可正常对话
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 接口与代码对齐(规划)
|
||
|
||
### 5.1 后端
|
||
|
||
| 模块 | 文件 | 变更说明 |
|
||
| :-------------- | :------------------------------------------------ | :-------------------------- |
|
||
| jog-admin | `db/migration/V6__ai_assistant_model.sql` | 模型表 + session.model_id |
|
||
| jog-module-blog | `entity/AiAssistantModel.java` | 实体 |
|
||
| jog-module-blog | `service/AiAssistantModelService` + impl | CRUD、默认模型、校验 |
|
||
| jog-module-blog | `controller/AdminAiModelController.java` | `/api/admin/ai/models` |
|
||
| jog-module-blog | `controller/AiChatController` 或新 App 方法 | `GET /api/app/ai/models` |
|
||
| jog-module-blog | `AiChatServiceImpl` | 按 session.model_id 调模型 |
|
||
|
||
### 5.2 前端
|
||
|
||
| 模块 | 文件 | 变更说明 |
|
||
| :----------- | :--------------------------- | :-------------------- |
|
||
| jog-frontend | `views/admin/AiModels.vue` | 模型管理页 |
|
||
| jog-frontend | `layouts/AdminLayout.vue` | 菜单项 |
|
||
| jog-frontend | `router/index.js` | `/admin/ai-models` |
|
||
| jog-frontend | `api/aiModel.js` | admin + app API |
|
||
| jog-frontend | `AiAssistant.vue` / Panel | 模型选择器 |
|
||
| jog-frontend | `api/aiChat.js` | sessions/chat 带 modelId |
|
||
|
||
---
|
||
|
||
## 6. 非功能性需求
|
||
|
||
| 编号 | 类型 | 需求说明 |
|
||
| :----- | :------- | :----------------------------------------------------------------------- |
|
||
| NFR-01 | 性能 | 模型列表接口轻量,无分页或 pageSize≤50;不增加 chat 接口 P95 目标 |
|
||
| NFR-02 | 安全 | `modelCode` 仅管理端可见;防 SQL 注入沿用 MyBatis-Plus;Admin 鉴权 |
|
||
| NFR-03 | 兼容 | 迁移后旧会话均有 `model_id`;不影响已存消息 |
|
||
| NFR-04 | 可观测性 | chat 日志记录 `modelId`、`modelCode`(不记 API Key) |
|
||
| NFR-05 | 可扩展性 | 表结构预留 `allow_image`/`allow_voice` 及后续 per-model `temperature` 等 |
|
||
|
||
---
|
||
|
||
## 7. 范围外(后续迭代)
|
||
|
||
| 项 | 说明 |
|
||
| :----------------- | :----------------------------------------- |
|
||
| 其它 AI 功能共用模型表 | 摘要/润色/标签推荐改为可选模型 |
|
||
| 模型连通性检测 | 保存时试调用 DashScope |
|
||
| 按模型差异化限流 | 不同模型不同每分钟次数 |
|
||
| 多 API Key | 不同模型不同 Key(多租户) |
|
||
| 用户级模型权限 | VIP 可用 plus 等 |
|
||
| 流式输出按模型配置 | 与 SSE 需求一并考虑 |
|
||
| 用户端图片上传 | 助手页上传图片 UI 及 `POST /chat` 附件协议 |
|
||
| 用户端语音上传 | 助手页语音录入/上传及转写联调 |
|
||
|
||
---
|
||
|
||
## 8. 风险与缓解
|
||
|
||
| 风险 | 影响 | 缓解措施 |
|
||
| :----------------------- | :------------- | :-------------------------------------------- |
|
||
| 错误 modelCode | 调用失败 | 管理端文案说明须与百炼文档一致;用户侧友好错误 |
|
||
| 删除模型后会话孤儿 | 展示异常 | 逻辑删保留行;展示时用快照名或「已下架模型」 |
|
||
| 中途换模导致上下文混乱 | 回答质量下降 | 会话级绑定,仅新会话换模(D-08) |
|
||
| 无启用模型 | 全站助手不可用 | ADM-07 + 种子默认模型 |
|
||
| 禁用后会话仍被误发 | 继续扣 Token | 前后端双重只读;`POST /chat` 校验 `enabled` |
|
||
|
||
---
|
||
|
||
## 9. 产品约定(建议默认,评审可调整)
|
||
|
||
| 编号 | 约定项 | 需求说明 |
|
||
| :--- | :----- | :------- |
|
||
| D-08 | 会话级绑定 | 模型在 **创建会话** 时绑定;同会话多轮不换模;用户切换选择器只影响 **之后的新会话** |
|
||
| D-09 | 禁用仅可查看 | 模型禁用主因:**Token 额度不足**(或运营下架);绑定该模型的会话 **仅可查看历史**,不可 `POST /chat`;新会话不可再选该模型 |
|
||
| D-10 | 仅助手用模型表 | 摘要、润色、标签推荐继续 `dashscope.model` |
|
||
| D-11 | 首版种子一条 | 迁移从当前配置插入默认模型,保证零配置升级可用 |
|
||
| D-12 | 用户不看 modelCode | App 列表只展示 `displayName`;实际编码仅管理端与日志 |
|
||
| D-13 | 多模态先配置后能力 | 管理端可配置 `allowImageUpload` / `allowVoiceUpload`;**本期用户端不提供** 图片/语音上传 UI,字段入库并随 API 返回供后续使用 |
|
||
|
||
---
|
||
|
||
## 10. 需求完整性自检
|
||
|
||
| 检查项 | 状态 | 说明 |
|
||
| :----- | :--- | :--- |
|
||
| 管理员增删改查 | ✅ | §3.1 + §3.3.2 |
|
||
| 删除为逻辑删除 | ✅ | FR-AI-MODEL-ADM-04 |
|
||
| 用户端模型切换 | ✅ | §3.2 |
|
||
| 与多轮/5 轮/持久化兼容 | ✅ | 不改变原 FR-AI-CHAT-*,仅扩展 session |
|
||
| 默认与边界约束 | ✅ | 唯一默认、至少一启用、删默认前换默认 |
|
||
| 数据迁移与旧数据 | ✅ | session.model_id 回填 |
|
||
| 安全与权限 | ✅ | Admin vs App 接口分离 |
|
||
| 前端记住选择 | ✅ | FR-AI-MODEL-FE-04(小需求,提升体验) |
|
||
| 历史回看展示模型 | ✅ | 会话列表带 modelDisplayName、`modelEnabled` |
|
||
| 禁用后会话只读 | ✅ | D-09、FR-AI-MODEL-BE-01、FE-08a |
|
||
| 图片/语音开关配置 | ✅ | 管理端表单 + 表字段;用户端上传见 §7 |
|
||
|
||
**已确认约定**:
|
||
|
||
1. **禁用模型旧会话** — D-09:仅可查看,不可继续对话(Token 不足场景)。
|
||
2. **其它 AI 功能是否纳入模型表** — D-10:首版不纳入。
|
||
3. **图片/语音** — D-13:后台可配,用户端上传 UI 本期不做。
|
||
|
||
---
|
||
|
||
**编写人:** AI 助手
|
||
**评审人:** 已确认(D-09 禁用仅查看、D-13 多模态后台配置)
|
||
**生效日期:** 2026-05-23
|