首页
/ LobeHub 源码级 UX 审计实战:以桌面端 Agent「话题」会话视图(Topic View)为例

LobeHub 源码级 UX 审计实战:以桌面端 Agent「话题」会话视图(Topic View)为例

2026-09-06 18:06:55作者:羿妍玫Ivan

导读

本文以仓库内 .agents/skills/ux-audit/references/example/topic.md 这份「话题(Topic)视图」UX 审计工作样本为骨架,完整拆解一次基于源码(L1 Static 层)的界面体验审计如何在 LobeHub 桌面端落地:从确定审计表面(surface)、对照模式目录与行为清单打评分,到定位「永驻骨架屏」等可复现的体验缺口,最后把结论回灌成规则库的正/反例。读完你可以掌握:审计的三层方法与覆盖面矩阵、如何用 模式 × 评分 表快速盘点一个会话界面、如何用 file:line 证据而不是直觉下结论,以及如何把审计发现沉淀为可复用的技能知识。


一、这份文档是什么:一次「输出形状」的参考样本

topic.md 不是普通的变更说明,而是 LobeHub 仓库内 ux-audit 技能worked example(工作样本),它的作用是告诉执行者一次审计报告应有的形状(output shape):包含审计对象、运行了哪些层、模式盘点表、亮点(don't regress 清单)、按严重度排序的缺口、对技能规则的回灌、以及留待 L2/L3 验证的事项。

样本对应的是一次真实审计:

  • 审计对象:桌面端 Agent 话题(Topic)视图——即把 Agent 会话限定到某个选定话题的界面;
  • 触发记录:Linear LOBE-11213(归属 LOBE-11145),时间 2026-07;
  • 执行层:仅 L1(静态/代码层) 完成;L2(视觉)、L3(动态 + CLS) 未运行;
  • 自述定位:the code moves; re-verify before citing——文档里引用的行号是快照值,引用前需要对着当前代码复验。

这正是审计方法论要求的诚实边界:L1 只能得出「代码层面是否存在该分支/状态」的结论,渲染层观感必须留给 L2/L3。样本里对「切换话题是否闪旧消息」「失败回合气泡是否带重试」都明确标注为 L1 inference, pending L2/L3,没有越层下结论。

二、三层审计法与覆盖面矩阵(方法论背景)

审计不是单一活动,执行前要先确定「哪个层能看见这类问题」。ux-audit 技能(.agents/skills/ux-audit/SKILL.md)把审计分成三层,每层有独立过程文件:

做什么 能抓住什么 成本
L1 Staticlayer-1-static.md 读代码 缺失的空/错误/重试分支、草稿未持久化、缺模式、结构性问题 低、可离线、每次必跑
L2 Visuallayer-2-visual.md 截渲染后的真实界面 视觉层级、主控按钮是否真为主操作、留白/对比/截断/溢出、暗色/亮色、响应式断点 中、需要渲染环境
L3 Dynamiclayer-3-dynamic.md 用 acceptance 驱动真实用户旅程 + 埋点 进行中/锁定态、强制错误/空态、步骤能否衔接、焦点/键盘可达、量化的 CLS/LCP/INP/long-task 高、需要运行环境与登录态

覆盖面矩阵的核心规则是:结论必须来自能看见它的那一层。例如「主按钮是否唯一/是否就是主操作」「空态/加载态/错误态真实长什么样」这类渲染结论, 不能从代码里的一个 variant prop 打勾——那是 L2 的活;而「缺错误分支、无重试、草稿没持久化」这类结构性结论,L1 就能下。分层的另一个价值是省成本:L1 每次都跑,L2 在发现与布局/层级/渲染态有关时追加,L3 在需要走旅程、强制 L1/L2 到不了的状态、或要测 CLS 等指标时才上。

三、审计范围界定:Topic 视图的表面构成

审计报告首先精确圈定「这一个 surface」的构成。话题视图是 Agent 会话的限定到已选话题形态,它的三个组成区域是:

  • 消息流(message stream):加载 → 空/欢迎 → 列表三段;
  • 输入区(composer)MainChatInput → ChatInput 链路;
  • 外围框架(chrome):ChatHeader、Portal、WorkingSidebar。

从当前仓库源码核对,路由与组件拓扑与审计快照基本一致:

  • 路由 /agent/:aid/:topicId 对应 src/routes/(main)/agent/index.tsx/agent/index.tsx>),由 ChatHydrationConversation 组合渲染;
  • Conversation 侧(src/routes/(main)/agent/features/Conversation/index.tsx/agent/features/Conversation/index.tsx>))内嵌 ConversationArea,并带 MainChatInput 输入区;
  • 消息列表组件为共享的 ChatList(src/features/Conversation/ChatList/index.tsx),它与「聊天」普通会话共用同一组件,因此本次审计把焦点放在「selected-topic」形态——一个消息从服务端拉取的话题,而不是新建的空会话。

明确范围的意义在于:一次审计只跑一个 surface,避免全应用横扫导致深度不足;同时点名「与 [9] chat 共用元素」,提示同类结论可能跨 surface 复用。

四、模式盘点:这个界面用对了哪些设计模式

审计的第一份产出是一张「模式使用表」——把界面拆成 Tidwell《Designing Interfaces》模式语言与 LobeHub ux 行为清单的逐条对照。完整继承如下:

模式(族) 落点 评分 备注
Center Stage(布局) 消息流占主导,输入区钉在底部((chat)/_layout 教科书式
Deep-linking(导航) /:topicIdactiveTopicId?thread=activeThreadIdChatHydration 亮点 URL↔store 双向同步、replace 历史——见 §5
Escape Hatch(导航) ChatHeader 话题操作(重命名/导出/删除)、分享、面板开关 生命周期都在头部
Overview + Detail(数据) 消息 → Portal(文件/工件/文档/子线程)、WorkingSidebar 保持「面板而非跳转」的契约
Cards / Virtualized list(数据) VirtualizedList(react-virtuoso)渲染 displayMessageIds(ChatList) 亮点 长会话可扩展——见 §5
Skeleton loading(反馈) messagesInit 未就绪时 SkeletonList(ChatList) ⚠️ 没有终态失败路径——见缺口 ①
Empty-state as onboarding(反馈) AgentHome 欢迎页(Agent 信息 + 开场问题 + 最近记录)(ChatList) 真实页面;但新建话题与 0 消息共用同一页(缺口 ③)
Draft safety(输入/编辑) useChatInputDraft → draftStorage(localStorage,按话题分 key 亮点 持久化、按话题隔离、restore/flush/clear——见 §5 星标
Same-page error(反馈) 发送失败 → 可关闭 Alert(ChatInput) 亮点 有呈现而不沉默(对比首页 composer)——但缺就地重试,缺口 ②
Autocompletion(输入) @ 提及、斜杠菜单、本地目录提及(桌面端) 输入富手性
Progress / Cancelability(动作) 流式期间显示 Stop 按钮,onStop=stopGenerating 长任务可中断(generation 类常态)
Capability guardrail(反馈) 输入区上方 AgentConfigError(MainChatInput) 配置告警响应式

报告的判读结论很直接:会话表面是成熟的——亮点的承重程度与唯一缺口相当,真正的弱点是这类代码库的经典问题:反馈(失败态)——消息流无法「看得见地失败」

五、值得保留的亮点(don't regress 清单)

审计把「这个表面做对了什么」单独列出,作为下一次重构/改版时不许回归的清单。每一条都有证据支撑,以下是结合当前仓库源码的逐条验证。

✅ 星标:按话题隔离、可持久化的 composer 草稿

输入框会把每个话题未发出的内容写进 localStoragekey 按上下文区分draftKey = agent + topic + thread),全生命周期闭环:

  • 每次击键防抖保存,失焦(blur)时 flush(对应源码逻辑 saveDraftDebounced,500ms 防抖,见 src/features/ChatInput/hooks/useChatInputDraft.ts);
  • 挂载时仅向空编辑器恢复草稿(restoreDrafteditor.isEmptysetDocument);
  • 卸载时先 flush 防抖再补存非空内容;
  • 发送成功后清除草稿(draft 的 removeDraft);
  • 存储层限制 50 条草稿并按 LRU 驱逐src/features/ChatInput/draftStorage.tsMAX_DRAFTS = 50)。

仓库中还额外验证到一处审计快照之后的增强:draftStorage.ts 维护了一个响应式 draft-key 注册表useHasDraft),让话题列表能在草稿出现/消失时刷新并显示 [draft] 前缀提示(见 src/features/AgentSidebar/Topic/List/Item/index.tsx)。这条链路的承重价值在于:重载 / 崩溃 / 切换话题都不会蒸发最高流量输入框里已敲的内容,且草稿不会跨话题串味——它正是首页 ux Edit §2.1 反例所指的「纯内存 composer」的对立面。

✅ 发送失败有呈现,而非沉默

发送失败时渲染一个可关闭的、携带错误信息的 AlertonClose=clearSendMessageError,源码见 src/features/Conversation/ChatInput/index.tsx 中基于 @lobehub/ui Alert 的错误呈现)。对比 ux Act §3.1 反例点名的 console.error 即焚路径(Pages 侧栏、Task 任务控制),这里用户确实被告知发送失败了。缺口只在于 Alert 缺少就地 Retry——见缺口 ②,呈现本身是对的。

✅ 流式生成可中断

生成进行中显示的是 Stop 按钮(接到 stopGenerating),不是只有一个 spinner。这满足了 generation 类界面「运行中可取消」的规范,是承重能力:核心表面上长任务永远可以中断。

✅ 深链是干净的双向同步

ChatHydration:topicId / ?thread= 镜射进 store(useLayoutEffect),同时用 subscribe 把 store 变化写回 URL 且走 replace 历史(对应源码 src/routes/(main)/agent/features/Conversation/ChatHydration/useChatRouteSync.ts/agent/features/Conversation/ChatHydration/useChatRouteSync.ts>))。承重价值:分享/收藏的话题 URL 能精确还原状态,导航永远不会和渲染的内容脱钩。

✅ 消息列表虚拟化

VirtualizedList(react-virtuoso)只渲染可视行,数据源是 displayMessageIds(当前实现见 src/features/Conversation/ChatList/index.tsx<VirtualizedList dataSource={displayMessageIds} .../>)。承重价值:上千条消息的话题依旧保持响应——符合「面向扩展设计」的规范。

六、体验缺口(按严重度排序)

① 🔴 消息流没有终态失败路径——拉取失败将永久骨架屏(ux Feedback §4.2 / Read §1.1)

审计快照描述的核心机制:消息列表的渲染被 messagesInit 门控——if (!messagesInit && !isNewConversation) return <SkeletonList/>,而 messagesInit 是一个只在成功路径上置位的「数据在场」伪装初始化标志

于是当 messageService.getMessages() 对已选话题抛错(500 / 网络 / 鉴权)时,messagesInit 永不翻转 → SkeletonList 永久渲染,没有原因、没有 Reload/Retry——出现在产品最高流量表面上。这是教科书式的「success-only-init-flag」陷阱(Task 列表 / Eval / Memory / generation 已出现同型问题),归档为 LOBE-11222

当前仓库复验(重要):审计样本自述"代码在移动,引用前需复验"。检查当前 src/features/Conversation/ChatList/index.tsx 可见列表已引入 useMessageRefreshErrorresolveMessageListFeedback,并新增了 AsyncError(首次加载失败整页 + Retry)与 RefreshError(后台失败底部条 + Retry)两条错误分支——即该缺口很可能已被后续迭代修复。引用「永久骨架屏」这一结论时应以当前代码为准复核,勿直接照搬快照描述。

② 🟡 发送错误的 Alert 没有就地重试(ux Act §3.1 / Feedback §4.2)

发送失败 Alert(见 §5)可关闭但没有 Retry / resend;而编辑器在发送时已被清空。恢复路径推测存在于失败回合消息气泡上的「重新生成」——审计标注为 pending L2:需要确认失败回合的气泡确实存在且带重试;若没有,该缺口升为 🟠。

③ 🟡 空话题与新建会话共用同一欢迎页(ux Read §1.1,轻微)

「新会话」(isNewConversation,无 topicId)与「已加载的 0 消息话题」(displayMessageIds.length === 0)渲染同一个 AgentHome 欢迎页(当前代码中 (showWelcome || displayMessageIds.length === 0) && welcome 的分支仍如此)。一个真正为空的既有话题,看起来和一个全新的会话没有区别。影响较小,记录以求完整。

七、从审计到回灌:技能知识的闭环

审计结论并不止于报告,而是被回灌进 ux 技能的规则库,形成"好案例 + 缺口案例"的双向闭环:

  • 新 ✅ 案例落地(好案例回灌):§5 星标的「按话题持久化草稿」被加为 ux Edit §2.1 旁的 ✅ 案例(.agents/skills/ux/references/edit.md),作为该规则既有首页 composer ❌ 反例的正面对照。
  • 新 ❌ 案例落地(缺口回灌):缺口 ① 被加为 ux Feedback §4.2 下的旗舰 ❌ 案例(.agents/skills/ux/references/feedback.md)——同一个 success-only-init-flag / data-presence-disguisedmessagesInit)永久骨架屏问题,如今出现在核心聊天消息流上。
  • 验证了既有规则(作为实例而非新增条目):发送错误呈现(§5)是 Act §3.1「surface failure」的 ✅ 实例;流式 Stop 是 Act §3.1「Cancel-while-running」的 ✅ 实例。
  • 没有新增通用规则:每个缺口都能映射到既有清单项(Feedback §4.2、Act §3.1)。按技能收尾规则,明确写出:本次运行是"打磨两条既有条目的正反两半",而非新增条目。
  • 过期案例提示:Edit §2.1 的「首页 composer ❌」在首页若与 Topic 共用同一条 ChatInput / draftStorage 路径时可能已过时——标记为需要单独一轮验证,本次不动它。

「回灌」机制的意义在于:审计不是一次性动作,而是持续的——每次运行要么给既有规则补一个正/反实例,要么沉淀一条新规则,让下一次审计的基准越来越准。

八、Pending:留给 L2 视觉与 L3 动态的验证清单

审计报告如实列出代码层看不到、必须由更上层裁决的问题:

  • L2(视觉):确认发送按钮在视觉上确实读作「唯一主导控件」;确认失败回合的消息气泡渲染出可见的 retry(裁决缺口 ② 是否升级);检查切换话题时是否会先闪旧消息、再换到新话题的骨架/数据(dbMessagesMap 键交换)——这是 L2/L3 裁决,不是 L1。
  • L3(动态):强制让 getMessages 报错,现场确认缺口 ①(永久骨架屏、无重试);驱动一个中途失败的发送,端到端确认缺口 ② 的恢复路径;量化骨架→消息交换与流式追加过程中的会话 CLS。

这份 pending 清单本身就是审计严谨性的体现:只对能看见的层下结论,把看不见的交给对应层验证,避免拿代码结构臆断渲染结果。

九、如何把这份样本复用到下一次审计

若要在仓库内开展新的 surface 审计,建议按以下顺序操作:

  1. 界定一个 surface:一条路由 + 它的 state 形态(如本文的 selected-topic 限定态),而非整个应用;
  2. 跑 L1:对照 pattern-catalog.md 的模式目录与 ux 技能清单(act.mdedit.mdfeedback.mdread.md)逐条核对,产出「模式 × 评分」表;
  3. 按需追加 L2/L3:结论涉及视觉层级、渲染态、旅程衔接或 CLS 时才升级到截屏/自动化层;
  4. 每条结论给证据file:line(L1)或经工具验证的截图/数值(L2/L3),不做无证据断言;
  5. 收尾回灌:新亮点进 ✅ 案例、新缺口进 ❌ 案例,并为无法归入既有规则的新问题起草新清单项;
  6. 标注快照时点:报告里写清审计日期与 Linear/issue 关联,并明确 re-verify before citing——代码在移动,本文所有行号都是快照值。

仓库内 topic.md 的兄弟样本(如 chat.mdmemory.mdtasks.md 等)展示了不同 surface 的同类输出形状,可交叉参考以校准篇幅与深度。


登录后查看全文
热门项目推荐
相关项目推荐