first
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
# 对话自动跟随设计
|
||||
|
||||
日期:2026-06-22
|
||||
状态:设计已确认,待实现
|
||||
当前分支:`codex/fix-chat-auto-scroll`
|
||||
|
||||
## 目的
|
||||
|
||||
这份设计用于解决 llm-wiki-agent 对话区在发送消息后不会自动向下推进的问题。
|
||||
|
||||
当前现象是:用户发送消息后,AI 回复已经开始生成,但对话内容不会自动滚到最新位置。用户需要手动用滚轮向下滚,才能看到新回复或回复后续内容。这会打断对话连续性,尤其在长回复和工具调用之后更明显。
|
||||
|
||||
目标体验是一句话:
|
||||
|
||||
**用户在看最新回复时,对话自动跟随;用户主动上翻看历史时,界面尊重用户,不强行拉回底部。**
|
||||
|
||||
## 背景依据
|
||||
|
||||
llm-wiki-agent 的产品定位是“以对话为中心的本地知识库工作台”。对话主区是核心入口,自动跟随最新回复属于基础对话体验。
|
||||
|
||||
本设计不是新增复杂功能,也不是改变对话模型、消息协议或会话存储。它只收口一件事:对话区应该在正确的时候展示最新内容。
|
||||
|
||||
已确认的现状:
|
||||
|
||||
- 对话消息区本身是可滚动区域。
|
||||
- 发送消息会立即新增用户消息和空的 AI 回复气泡。
|
||||
- AI 回复是流式生成的,内容会持续变长。
|
||||
- 当前没有专门的“是否跟随底部”的状态管理。
|
||||
|
||||
## 设计结论
|
||||
|
||||
采用“智能跟随 + 向下箭头按钮”的方案。
|
||||
|
||||
1. 用户发送消息后,对话区立即滚到最新消息位置。
|
||||
2. AI 回复生成过程中,如果用户仍在底部附近,对话区持续跟随最新内容。
|
||||
3. 如果用户主动上翻历史,对话区暂停自动跟随。
|
||||
4. 暂停跟随后,显示向下箭头按钮,提醒用户有最新内容可回到。
|
||||
5. 用户点击向下箭头按钮,或自己手动滚回底部附近后,恢复自动跟随。
|
||||
|
||||
这里的“底部附近”指用户距离消息区底部很近,已经是在看最新内容。实现时可使用一个固定容差,例如 80-120 px;具体数值以不误判用户上翻为优先。
|
||||
|
||||
不采用以下方案:
|
||||
|
||||
- 不做“永远强制滚到底部”,因为会打断用户阅读历史消息。
|
||||
- 不做“只在发送时滚一次”,因为 AI 回复流式变长时仍可能看不到后续内容。
|
||||
|
||||
## 用户体验规则
|
||||
|
||||
### 1. 发送消息
|
||||
|
||||
用户点击发送或使用快捷键发送后:
|
||||
|
||||
- 输入框清空。
|
||||
- 新的用户消息和 AI 回复占位出现在对话尾部。
|
||||
- 对话区自动滚到尾部。
|
||||
- 自动跟随状态开启。
|
||||
|
||||
这样用户能立即看到“消息已发出,AI 正在回复”。
|
||||
|
||||
### 2. 回复生成中
|
||||
|
||||
AI 回复逐步生成时:
|
||||
|
||||
- 如果用户没有上翻,最新回复始终保持在可见范围内。
|
||||
- 回复内容变长、工具状态出现、工具状态完成、Markdown 表格展开等情况,都应继续跟随。
|
||||
- 跟随不需要动画夸张,重点是稳定地看到最新内容。
|
||||
|
||||
### 3. 用户主动上翻
|
||||
|
||||
如果用户把对话区往上滚,离开底部一段距离:
|
||||
|
||||
- 自动跟随暂停。
|
||||
- 后续 AI 回复继续生成,但不强行滚动页面。
|
||||
- 显示向下箭头按钮。
|
||||
|
||||
这里的产品原则是:一旦用户主动查看历史,系统不能替用户夺回滚动位置。
|
||||
|
||||
### 4. 恢复跟随
|
||||
|
||||
有两种方式恢复:
|
||||
|
||||
- 用户点击向下箭头按钮。
|
||||
- 用户自己滚回底部附近。
|
||||
|
||||
恢复后:
|
||||
|
||||
- 对话区滚到最新内容。
|
||||
- 向下箭头按钮消失。
|
||||
- 如果 AI 仍在生成,继续自动跟随。
|
||||
|
||||
### 5. 切换会话或知识库
|
||||
|
||||
切换会话或知识库后,新的对话面板应按当前会话历史展示:
|
||||
|
||||
- 如果进入的是已有长对话,默认展示底部最新消息。
|
||||
- 如果是空会话,展示空状态。
|
||||
- 切换动作不继承上一个会话的“暂停跟随”状态。
|
||||
|
||||
## 界面边界
|
||||
|
||||
回到底部入口采用类似 Codex 的向下箭头图标按钮,不使用文字按钮。
|
||||
|
||||
按钮规则:
|
||||
|
||||
- 使用单个向下箭头表达“回到底部”。
|
||||
- 按钮为轻量圆形或近圆形,视觉上像悬浮的小控制点。
|
||||
- 放在对话区底部中间附近,悬浮在输入区上方,不遮挡消息正文。
|
||||
- 样式跟随当前主题,使用柔和背景、细边框和轻微阴影;暗色和浅色模式都要自然。
|
||||
- 鼠标悬停时只做轻微强调,不做夸张动画。
|
||||
- 只在用户离开底部且有必要回到底部时出现。
|
||||
- 按钮本身不显示文字,但可访问名称应是“回到底部”。
|
||||
- 本次不增加未读数量;如果以后需要未读计数,另开设计,不混入本次实现。
|
||||
|
||||
本次不做:
|
||||
|
||||
- 未读消息数量。
|
||||
- 跳转到某一条消息。
|
||||
- 对话搜索定位。
|
||||
- 历史消息虚拟列表。
|
||||
- 全局页面滚动重构。
|
||||
|
||||
## 组件与数据流
|
||||
|
||||
实现应集中在对话面板内部完成,不改变后端接口。
|
||||
|
||||
需要维护的前端状态:
|
||||
|
||||
- 当前是否处于自动跟随状态。
|
||||
- 当前是否离底部足够近。
|
||||
- 是否需要显示向下箭头按钮。
|
||||
|
||||
主要数据流:
|
||||
|
||||
1. 用户发送消息,消息列表新增内容,开启自动跟随。
|
||||
2. AI 流式回复更新消息内容。
|
||||
3. 消息内容变化后,如果自动跟随开启,则滚到尾部。
|
||||
4. 用户滚动消息区时,判断是否离开底部。
|
||||
5. 离开底部则暂停自动跟随并显示向下箭头按钮。
|
||||
6. 用户点击向下箭头按钮或滚回底部,则恢复自动跟随。
|
||||
|
||||
## 异常与边界
|
||||
|
||||
需要覆盖以下情况:
|
||||
|
||||
- 对话为空时不显示向下箭头按钮。
|
||||
- 只有图标按钮时,键盘和读屏仍能识别它是“回到底部”。
|
||||
- 回复出错时,如果用户在底部附近,错误提示也应可见。
|
||||
- 用户停止生成时,滚动状态不应乱跳。
|
||||
- 工具调用状态展开或收起时,如果用户在底部附近,应继续跟随。
|
||||
- 大段 Markdown、表格、代码块渲染后高度变化时,仍能保持跟随。
|
||||
- 用户正在上翻时,即使回复继续增长,也不能强行滚回底部。
|
||||
|
||||
## 验收标准
|
||||
|
||||
实现完成后至少验证以下场景:
|
||||
|
||||
1. 发出一条普通消息后,不需要滚轮就能看到 AI 回复开始。
|
||||
2. 长回复生成过程中,页面持续停在最新内容附近。
|
||||
3. 回复生成时用户上翻历史,页面不再被自动拉到底部。
|
||||
4. 用户上翻后看到符合当前主题的向下箭头按钮,而不是文字按钮。
|
||||
5. 用户点击向下箭头按钮后,立即回到最新回复,并恢复自动跟随。
|
||||
6. 用户自己滚回底部后,向下箭头按钮消失,后续回复继续自动跟随。
|
||||
7. 切换到已有长会话时,默认看到最新消息。
|
||||
8. 回复出错或停止生成时,界面没有异常跳动。
|
||||
|
||||
## 验证方式
|
||||
|
||||
推荐验证分三层:
|
||||
|
||||
1. 增加前端组件测试,覆盖发送、流式更新、用户上翻、向下箭头按钮显示与恢复。
|
||||
2. 运行现有前端测试和类型检查,确认没有破坏输入框、导出按钮、消息气泡和工具状态。
|
||||
3. 启动本地应用,在浏览器里真实发送一条长回复请求,手动验证自动跟随和上翻暂停。
|
||||
|
||||
## 后续实现范围
|
||||
|
||||
后续实现应只修改对话面板和必要样式。
|
||||
|
||||
不改:
|
||||
|
||||
- 后端流式协议。
|
||||
- 会话存储格式。
|
||||
- 知识库选择逻辑。
|
||||
- 图谱、右抽屉、搜索、导出等无关模块。
|
||||
|
||||
如果实现过程中发现对话区滚动容器和页面布局有冲突,应先优先修正对话区内部滚动边界,不扩大为整体布局重构。
|
||||
Reference in New Issue
Block a user