Files
Jog/doc/AI助手模型管理功能需求.md
T
2026-05-24 00:39:10 +08:00

461 lines
33 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.
# 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-PlusAdmin 鉴权 |
| 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