Files
llm-wiki/docs/spark/2026-06-22-chat-auto-scroll-design.md
T
2026-07-12 21:26:08 +08:00

186 lines
7.2 KiB
Markdown

# 对话自动跟随设计
日期: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. 启动本地应用,在浏览器里真实发送一条长回复请求,手动验证自动跟随和上翻暂停。
## 后续实现范围
后续实现应只修改对话面板和必要样式。
不改:
- 后端流式协议。
- 会话存储格式。
- 知识库选择逻辑。
- 图谱、右抽屉、搜索、导出等无关模块。
如果实现过程中发现对话区滚动容器和页面布局有冲突,应先优先修正对话区内部滚动边界,不扩大为整体布局重构。