Files
Jog/doc/AI助手功能需求.md
2026-05-23 23:33:27 +08:00

31 KiB
Raw Permalink Blame History

AI 助手功能 - 需求规格说明书

文档版本 修订日期 修订人 修订内容
V1.0 2026-05-23 初始版本,定义首页 AI 助手聊天功能需求
V1.1 2026-05-23 增加多轮上下文(最多 5 轮/会话)、会话持久化、左侧历史会话列表与回看能力
V1.2 2026-05-23 产品约定(D-01~D-06)经确认纳入正式需求,移除待确认表述

1. 项目概述

1.1 功能背景

当前 Jog 博客系统公开站点顶部导航(BlogLayout)仅提供 「首页」 入口。访客与登录用户无法在站内直接获得与博客、写作相关的智能问答能力。为提升站点互动性与 AI 能力曝光,在首页导航区新增 「AI 助手」 入口,提供独立的对话页面:用户可 多轮追问(单会话最多 5 轮),问答内容 持久化存储;页面 左侧展示历史会话,点选可 完整回看 当时的全部提问与 AI 回复。

1.2 功能目标

  • 在公开站点顶部导航增加「AI 助手」入口,与「首页」并列,便于发现与访问
  • 支持 多轮上下文对话(单会话最多 5 轮),超出后引导用户 新建会话 继续提问
  • 持久化 用户每条提问与 AI 每条回复,刷新或换设备登录后可恢复历史
  • 页面 左侧会话列表 + 右侧对话区,点选历史会话可只读回看完整往来记录
  • 复用现有 DashScope(阿里云百炼)OpenAI 兼容接入与 dashscope.* 配置
  • 通过登录鉴权与用户级限流,控制调用成本与滥用风险

1.3 适用范围

角色 涉及范围
产品经理 验证导航、多轮上限、新会话流程、左侧历史与回看交互
前端开发工程师 左右分栏布局、会话列表、多轮发送、新会话、历史回看
后端开发工程师 对话 API、会话/消息持久化、多轮上下文组装、Flyway 表结构
测试工程师 多轮边界、持久化、历史加载、5 轮上限等用例
运维工程师 复用 DASHSCOPE_API_KEY;关注对话表容量与备份策略

1.4 现状说明

项目 现状
顶部导航 jog-frontend/src/layouts/BlogLayout.vueel-menu 仅含「首页」
路由 公开布局子路由仅有 //article/:id
AI 能力 已有摘要、润色等 /api/app/** 接口,均依赖 DashScope
数据存储 尚无 AI 对话相关表,需新增 Flyway 迁移

1.5 改动合理性评估(V1.1

改动项 合理性说明
多轮 + 最多 5 轮 满足追问与指代理解;限制轮次可控制 Token 成本与模型超时风险,与现有 AI 功能限流思路一致
问答持久化 与「左侧历史、完整回看」强依赖;需登录态绑定 user_id,避免数据串户
左侧历史列表 常见聊天产品形态;列表按 会话 聚合(见 2 名词解释),避免每条提问占一行导致列表过长
新会话 5 轮上限后的自然出口;同时用于用户主动开启新话题

2. 名词解释

术语 说明
AI 助手 面向站点用户的通用问答对话功能
会话(Session 一次连续对话线程,拥有唯一 sessionId;左侧历史列表的 每一行对应一个会话
轮次(Round 1 轮 = 1 条用户提问 + 1 条 AI 回复(均成功落库后计 1 轮);单会话最多 5 轮
新会话 用户主动点击「新会话」,创建新的 sessionId,右侧对话区清空,轮次计数从 0 开始
只读回看 从左侧点选 已满 5 轮 的会话,或用户仅查看历史时:展示完整消息记录,不可再发送
继续对话 点选 未满 5 轮 的历史会话时:加载历史消息,可在该 sessionId 下继续追问
会话标题 列表展示用,默认取该会话 首条用户提问 前 30 字(超出以 结尾)
DashScope 阿里云百炼 API,本系统通过 OpenAI 兼容 chat/completions 调用

3. 功能需求清单

3.1 导航入口(前端)

(与 V1.0 一致,编号保留。)

3.1.2 业务规则

编号 规则项 业务规则说明
FR-AI-CHAT-NAV-01 按钮位置 位于 BlogLayout 顶部 el-menu 内,紧挨「首页」之后,文案为「AI 助手」
FR-AI-CHAT-NAV-02 路由 跳转 /ai-assistant,路由 name 建议 AiAssistant,页面标题「AI 助手」
FR-AI-CHAT-NAV-03 激活态 当前路由为 /ai-assistant 时菜单项高亮
FR-AI-CHAT-NAV-04 可见性 未登录可见入口;发送消息、查看历史列表 需登录(见 3.2
FR-AI-CHAT-NAV-05 样式 与「首页」一致,可选聊天图标

3.1.3 验收标准

编号 验证场景 预期结果
AC-AI-CHAT-NAV-01 任意公开页查看顶部导航 可见「首页」与「AI 助手」
AC-AI-CHAT-NAV-02 点击「AI 助手」 进入 /ai-assistant
AC-AI-CHAT-NAV-03 在 AI 助手页刷新 「AI 助手」为激活态

3.2 AI 助手对话页(前端)

3.2.1 功能描述

新增 AiAssistant.vueBlogLayout 子路由)。页面为 左右分栏

  • 左侧(约 260px:顶部「新会话」按钮 + 当前用户的 历史会话列表(按最近更新时间倒序)
  • 右侧:当前会话的 完整消息流(用户/AI 气泡)+ 底部输入区与「发送」;显示当前会话 轮次指示(如 3/5

用户发送问题时携带当前 sessionId(新会话时由后端创建或前端先调创建接口获得)。成功后消息入库并在右侧追加。左侧列表在首条提问成功后出现/更新该会话项。

3.2.2 页面布局

┌────────────────────────────────────────────────────────────────────┐
│  Jog Logo    [首页]  [AI助手]                         登录/用户     │
├──────────────┬─────────────────────────────────────────────────────┤
│ [ 新会话 ]   │  当前会话标题(首问摘要)              轮次 3/5      │
│──────────────│─────────────────────────────────────────────────────│
│ 历史会话列表 │  · 用户:……(右/主色)                              │
│ · 如何在…    │  · AI:……(左/灰底)                                │
│   05-23 14:20│  · 用户:……                                        │
│ · Spring…    │  · AI:……                                          │
│   05-22 09:10│─────────────────────────────────────────────────────│
│ (滚动)     │  [ 请输入您的问题...          ]  [ 发送 ]            │
└──────────────┴─────────────────────────────────────────────────────┘

3.2.3 业务规则

编号 规则项 业务规则说明
FR-AI-CHAT-FE-01 分栏布局 左侧固定宽约 260px,右侧 flex:1;小屏(<768px)可折叠左侧为抽屉(可选,首版允许左右同时展示并横向滚动)
FR-AI-CHAT-FE-02 新会话按钮 左侧顶部主按钮「新会话」;点击后:清空右侧消息、清空当前 sessionId、轮次显示 0/5、输入区可用;不删除 已有历史会话
FR-AI-CHAT-FE-03 历史列表项 展示会话标题(首问前 30 字)+ 最后更新时间;当前选中会话高亮;默认进入页面时选中 最近一次活跃会话(若无则空状态)
FR-AI-CHAT-FE-04 点选历史 调用 GET .../sessions/{id}/messages 加载 该会话全部消息(按时间正序),右侧完整展示用户提问与 AI 回复全文
FR-AI-CHAT-FE-05 继续 vs 只读 若该会话 roundCount < 5:加载后可继续发送(sessionId 设为当前);若 roundCount >= 5只读回看,输入区禁用,展示提示条
FR-AI-CHAT-FE-06 五轮上限提示 当前会话已达 5 轮时:禁用发送;提示「当前会话已满 5 轮,请点击左侧 新会话 开始新的对话」;ElMessage.warning 可选
FR-AI-CHAT-FE-07 轮次指示 右侧标题栏展示 当前轮次/5(仅统计已成功完成的 user+assistant 一对)
FR-AI-CHAT-FE-08 输入框 textarea,占位符「请输入您的问题…」,1~6 行自适应
FR-AI-CHAT-FE-09 发送 主按钮「发送」;Ctrl/Cmd+Enter 发送;trim 后 1~2000 字符
FR-AI-CHAT-FE-10 登录校验 未登录:左侧列表为空或展示「登录后查看历史」;发送时提示并跳转 /login?redirect=/ai-assistant
FR-AI-CHAT-FE-11 Loading 请求中发送按钮 loading、输入只读;列表末「正在思考…」
FR-AI-CHAT-FE-12 消息展示 用户/AI 分色气泡;AI 文本 pre-wrap;首版不做 Markdown
FR-AI-CHAT-FE-13 失败处理 若 AI 调用失败: 将本轮计入 roundCount;用户消息可保留为「发送失败」状态或允许重试(见 3.3 FR-AI-CHAT-BE-15
FR-AI-CHAT-FE-14 刷新恢复 刷新页面后重新拉取会话列表与当前/最近会话消息,不依赖 localStorage 存对话正文
FR-AI-CHAT-FE-15 空状态 无会话时右侧展示欢迎文案;左侧列表空状态「暂无对话,点击新会话开始」
FR-AI-CHAT-FE-16 列表分页 会话列表默认加载最近 50 条,底部「加载更多」分页(page/size
FR-AI-CHAT-FE-17 滚动 右侧消息区内部滚动;新消息后滚到底部;回看历史会话打开时滚到底部

3.2.4 验收标准

编号 验证场景 预期结果
AC-AI-CHAT-FE-01 已登录,点击「新会话」后连续问答 3 次 右侧 3 组问答,指示 3/5,左侧出现 1 个会话项
AC-AI-CHAT-FE-02 当前会话第 5 轮成功后尝试第 6 次发送 发送被拦截,提示点击「新会话」
AC-AI-CHAT-FE-03 点击「新会话」后再提问 新会话独立入库,左侧新增或切换到新会话项
AC-AI-CHAT-FE-04 点选已满 5 轮的历史会话 完整展示 5 轮共 10 条消息,输入区禁用,提示只读
AC-AI-CHAT-FE-05 点选仅 2 轮的历史会话并继续提问 加载 2 轮历史后继续,第 3 轮成功后为 3/5
AC-AI-CHAT-FE-06 刷新页面 会话列表与最近会话消息与刷新前一致
AC-AI-CHAT-FE-07 未登录进入页面 无法发送;引导登录

3.3 AI 对话与会话接口(后端)

3.3.1 功能描述

提供会话管理与多轮对话能力:

  1. 创建/继续会话并发送消息(调用大模型时带入 当前会话已成功落库的全部历史,最多 5 轮 = 10 条消息
  2. 查询当前用户会话列表
  3. 查询指定会话下的全部消息(供左侧点选回看)

所有问答 写入数据库;仅允许操作 当前登录用户 自己的会话。

3.3.2 数据模型(Flyway

建议新增迁移 V5__ai_chat_tables.sql(版本号以仓库实际递增为准):

ai_chat_session

字段 类型 说明
id BIGINT PK 会话 ID
user_id BIGINT 所属用户,索引
title VARCHAR(64) 会话标题,首条用户消息截断
round_count TINYINT 已完成轮次,0~5
last_message_at DATETIME 最后一条消息时间,列表排序用
created_at DATETIME 创建时间
updated_at DATETIME 更新时间
deleted TINYINT 逻辑删除,默认 0(与项目 @TableLogic 一致)

ai_chat_message

字段 类型 说明
id BIGINT PK 消息 ID
session_id BIGINT 外键 → ai_chat_session.id
role VARCHAR(16) user / assistant
content TEXT 提问或回复 全文
sort_order INT 会话内顺序,从 1 递增
created_at DATETIME 创建时间

3.3.3 接口清单

方法 路径 说明
POST /api/app/ai/sessions 创建空会话,返回 sessionId
GET /api/app/ai/sessions 分页查询当前用户会话列表
GET /api/app/ai/sessions/{sessionId}/messages 查询会话全部消息(正序)
POST /api/app/ai/chat 在指定会话中发送用户消息并返回 AI 回复

3.3.4 发送消息接口 POST /api/app/ai/chat

请求体

{
  "sessionId": 1001,
  "message": "那和 GraphQL 有什么区别?"
}
字段 必填 说明
sessionId 会话 ID;须属于当前用户且 round_count < 5
message 本条用户提问,1~2000 字符(trim 后)

处理流程

  1. 校验登录、sessionId 归属、round_count < 5message 合法
  2. 插入 ai_chat_messagerole=user
  3. 读取该会话已有消息(最多 5 轮历史),按 sort_order 组装 messages 数组送入 DashScope(含 System Prompt
  4. 调用模型,得到 reply
  5. 插入 ai_chat_messagerole=assistantcontent=全文)
  6. 更新 session.round_count += 1last_message_at;若为首条用户消息则更新 title
  7. 返回 reply 及更新后的 roundCount

响应 data 示例

{
  "sessionId": 1001,
  "reply": "GraphQL 与 REST 的主要区别在于……",
  "roundCount": 3,
  "maxRounds": 5,
  "model": "qwen-turbo",
  "promptTokens": 512,
  "completionTokens": 180,
  "costMillis": 2400
}

3.3.5 业务规则

编号 规则项 业务规则说明
FR-AI-CHAT-BE-01 鉴权 全部接口需登录;sessionId 必须属于当前 userId,否则 403404
FR-AI-CHAT-BE-02 轮次上限 round_count >= 5 时拒绝 POST /chat,返回 400,message:「当前会话已满 5 轮,请新建会话」
FR-AI-CHAT-BE-03 多轮上下文 调用模型时传入:System Prompt + 该会话已落库的 user/assistant 消息(按时间序),最多 10 条(5 轮);不含本次尚未入库的 user 消息则先入库 user 再调模型
FR-AI-CHAT-BE-04 上下文长度保护 组装后的总字符数超过 dashscope.max-input(默认 8000)时,从最早的用户/助手对开始丢弃,直至不超限(System 与当前 user 消息保留)
FR-AI-CHAT-BE-05 存储 用户 message 与 AI reply 全文 写入 ai_chat_message.content,供历史回看
FR-AI-CHAT-BE-06 会话列表 GET /sessionslast_message_at 降序;返回 id, title, roundCount, lastMessageAt;默认 size=50
FR-AI-CHAT-BE-07 消息列表 GET /sessions/{id}/messages 返回 id, role, content, sortOrder, createdAt 全量正序
FR-AI-CHAT-BE-08 新会话 POST /sessions 创建 round_count=0 的记录;前端「新会话」优先调此接口拿到 sessionId 再提问
FR-AI-CHAT-BE-09 模型与 Key 复用 DashScopePropertiesKey 缺失返回既有 AI_API_KEY_MISSING
FR-AI-CHAT-BE-10 System Prompt 与 V1.0 一致,并补充:「当前为同一会话的多轮对话,请结合上文回答,避免重复已说过的内容。」
FR-AI-CHAT-BE-11 回复截断 单条 reply 超过 4000 字符截断并
FR-AI-CHAT-BE-12 超时/限流/异常 超时 30s → 5002;用户每分钟最多 10 次 POST /chatRedis ai_chat:rate:);DashScope 失败 → 5001
FR-AI-CHAT-BE-13 日志 日志中 不打印 问答全文,可记录 sessionId、轮次、字符长度、token、耗时
FR-AI-CHAT-BE-14 软删除 会话表支持逻辑删除(为后续「删除历史」预留);首版前端 不提供 删除入口
FR-AI-CHAT-BE-15 失败不落 assistant 模型调用失败时:已插入的 user 消息 保留;不插入 assistant、不增加 round_count;返回错误码,前端允许用户 重试发送(同 sessionId 不重复插 user,或后端按幂等键去重——首版允许重复 user 消息则需在需求中禁止,采用:失败时仅重试模型,不重复插入 user

FR-AI-CHAT-BE-15 实现约定:发送接口在步骤 2 插入 user 后若模型失败,user 消息保留;重试时若上一条为未配对的 user,则 不再插入新 user,仅重新请求模型并写入 assistant。

3.3.6 错误码补充

错误码 / HTTP 描述 触发条件
400 参数错误 message 非法
400 会话轮次已满 round_count >= 5
403/404 会话不存在或无权访问 sessionId 非本人
401 未登录 无 Token
429 请求过于频繁 限流
5001/5002 AI 不可用 / 超时 DashScope 异常

3.3.7 验收标准

编号 验证场景 预期结果
AC-AI-CHAT-BE-01 新会话连续 5 次成功 /chat round_count=5,第 6 次返回 400
AC-AI-CHAT-BE-02 第 3 轮提问含指代「它」 模型请求体含前 2 轮共 4 条历史消息
AC-AI-CHAT-BE-03 GET .../messages 返回条数与轮次一致,content 为当时全文
AC-AI-CHAT-BE-04 用户 A 访问用户 B 的 sessionId 403/404
AC-AI-CHAT-BE-05 模型失败后重试 不重复 user 行,成功后 round_count 正确 +1

3.4 配置与部署

仍复用 dashscope.*DASHSCOPE_API_KEY。新增表由 Flyway 自动迁移。部署后验证:多轮对话、刷新恢复、第 5 轮后新建会话。


4. 交互流程

4.1 首次提问(新会话)

1. 用户进入 /ai-assistant(已登录)
2. 点击「新会话」→ POST /sessions → 获得 sessionId
3. 输入问题 → POST /chat { sessionId, message }
4. 后端存 user → 调模型(仅 System + 本条 user)→ 存 assistant → roundCount=1
5. 右侧展示问答;左侧列表出现该会话(标题=首问截断)

4.2 同会话多轮追问

1. 用户在当前 session 继续输入(roundCount < 5
2. POST /chat → 后端载入已有消息作为上下文 → 返回 reply
3. roundCount 递增;满 5 后 FR-AI-CHAT-FE-06 拦截发送

4.3 回看历史会话

1. 用户点击左侧某会话项
2. GET /sessions/{id}/messages → 右侧展示全部 user/assistant 全文
3. 若 roundCount < 5:可继续发送;若 = 5:只读 + 提示新会话

4.4 满 5 轮后继续提问

1. 用户在本会话第 5 轮成功后再次发送
2. 前端拦截并提示「请点击新会话」
3. 用户点击「新会话」→ 新 sessionId → 重新开始 0/5

5. 接口与代码对齐(规划)

5.1 后端

模块 文件 变更说明
jog-admin db/migration/V5__ai_chat_tables.sql 会话与消息表
jog-module-blog entity/AiChatSession.java, AiChatMessage.java 实体
jog-module-blog mapper/... MyBatis-Plus Mapper
jog-module-blog dto/*, vo/* 请求/响应对象
jog-module-blog service/AiChatService + impl 多轮组装、持久化、DashScope 调用
jog-module-blog controller/AiChatController.java 上述 REST 接口

5.2 前端

模块 文件 变更说明
jog-frontend layouts/BlogLayout.vue 「AI 助手」导航
jog-frontend router/index.js /ai-assistant
jog-frontend views/AiAssistant.vue 左右分栏主页面
jog-frontend components/AiChatSidebar.vue(可选拆分) 左侧列表 + 新会话
jog-frontend components/AiChatPanel.vue(可选拆分) 右侧消息 + 输入
jog-frontend api/aiChat.js 会话与 chat API 封装

6. 非功能性需求

编号 类型 需求说明
NFR-01 性能 95 分位 ≤ 15s;5 轮上下文受 max-input 截断保护
NFR-02 可用性 AI 不可用时仍可回看已存历史;失败可重试当前轮
NFR-03 安全性 会话严格按 user_id 隔离;API Key 不入库/日志/仓库;HTTPS 传输
NFR-04 隐私 对话正文存业务库,仅本人可读;管理后台 不提供 查看他人工单(首版)
NFR-05 可扩展性 轮次上限、列表条数可配置化;预留流式 SSE、删除会话
NFR-06 容量 首版会话列表 仅分页加载(默认每页 50 条),不设单用户数量硬上限,不自动删除 历史会话
NFR-07 可观测性 记录 sessionId、轮次、耗时、token;日志不打印全文

7. 范围外(后续迭代)

说明
流式输出 SSE 逐字展示回复
删除会话 前端删除 + 逻辑删除接口
未登录试用 公开 API + IP 限流
Markdown渲染 AI 回复富文本(需 XSS 防护)
会话重命名 用户自定义左侧标题
导出对话 导出 Markdown/PDF

8. 风险与缓解

风险 影响 缓解措施
5 轮上下文 Token 过大 超时/费用 max-input 截断最早轮次
历史表数据增长 存储成本 分页列表;后续归档策略
满 5 轮体验断裂 用户困惑 明确提示 +「新会话」一键
失败重试重复 user 轮次与展示错乱 BE-15 幂等重试约定

9. 产品约定(已确认)

以下约定已于 2026-05-23 与产品方确认,作为 V1.1 正式需求的一部分,开发与测试须按此实现。

编号 约定项 需求说明
D-01 左侧列表按 会话 聚合 每会话占列表一行;标题取首条用户提问前 30 字;点选后右侧展示该会话下 全部 问答全文(非按单条提问分行)
D-02 历史会话可继续对话 roundCount < 5 的会话:加载历史后 可继续发送roundCount >= 5 的会话:只读回看,输入区禁用并引导「新会话」
D-03 新会话不删除旧数据 点击「新会话」仅创建并切换至新 sessionId,清空右侧编辑区;不删除、不覆盖 已有会话数据
D-04 首版不提供删除与重命名 前端无删除会话、无重命名入口;ai_chat_session.deleted 字段预留供后续迭代(见 §7
D-05 失败不计轮、支持同轮重试 模型调用失败时不插入 assistant、不增加 round_count;允许对未配对的 user 消息重试,不重复插入 user(见 FR-AI-CHAT-BE-15
D-06 进入页默认最近会话 已登录用户进入 /ai-assistant 时,默认选中 最近更新 的会话并加载其消息;无任何会话时展示空状态,等同待「新会话」
D-07 会话保留策略 历史会话 仅分页展示(默认每页 50 条),不设 单用户数量硬上限,不自动删除 最旧会话(与 NFR-06 一致)

编写人: AI 助手
评审人: 已确认(产品约定 D-01~D-07)
生效日期: 2026-05-23