← [ BACK_TO_NOTES ]

AI 对话中的 Optimistic UI

解释通用乐观更新模式如何落到 AI 对话的临时消息、流式占位、确认、失败与重试状态,并明确与通用 Optimistic Update 的职责边界。

#synthesis #evergreen #frontend #ai

[!info] related notes

AI 对话中的 Optimistic UI

一句话定义

本页不是重新定义 Optimistic Update,而是解释 乐观更新 在 AI 对话状态机中的具体组合:用户消息先入本地状态,随后与服务端确认、assistant 流式占位、失败与重试共同收敛。

覆盖范围与排除项

  • 覆盖:临时消息 ID、sending/sent/error 状态、assistant streaming 占位、失败重试与服务端确认后的状态收敛。
  • 不覆盖:通用 Optimistic Update 定义与可逆性原则,统一由 乐观更新 维护。
  • 不覆盖:完整聊天 UI 组件结构,见 Chat UI;完整消息状态模型见 Message State Management。

它解决什么问题

如果用户发送消息后要等后端确认才显示:

  1. 网络延迟导致 UI 卡顿
  2. 用户不确定消息是否发送成功
  3. 快速连续发送时体验差

Optimistic UI 让界面立即响应,后端异步确认。

核心原理

传统流程:
  用户输入 → 发送请求 → 等待响应 → 显示消息
  (延迟 200-500ms)

Optimistic 流程:
  用户输入 → 立即显示消息 → 发送请求 → 后台确认/回滚
  (延迟 0ms)

实现

function useChat() {
  const [messages, setMessages] = useState([]);

  const sendMessage = async (content: string) => {
    // 1. 立即添加用户消息(乐观更新)
    const tempId = `temp_${Date.now()}`;
    setMessages(prev => [...prev, {
      id: tempId,
      role: 'user',
      content,
      status: 'sending', // 临时状态
    }]);

    // 2. 创建 assistant 消息占位
    setMessages(prev => [...prev, {
      id: `assistant_${tempId}`,
      role: 'assistant',
      content: '',
      status: 'streaming',
    }]);

    // 3. 发送请求
    try {
      const response = await fetch('/api/chat', { ... });
      // 成功:更新为正式 ID
      setMessages(prev => prev.map(msg =>
        msg.id === tempId
          ? { ...msg, id: response.messageId, status: 'sent' }
          : msg
      ));
    } catch (err) {
      // 失败:标记为错误
      setMessages(prev => prev.map(msg =>
        msg.id === tempId
          ? { ...msg, status: 'error' }
          : msg
      ));
    }
  };

  return { messages, sendMessage };
}

常见设计模式

1. 临时 ID

乐观更新使用临时 ID,后端确认后替换为正式 ID。

2. 状态标记

sending → sent / error

3. 回滚机制

请求失败时回滚 UI 状态,显示错误提示。

常见坑

  1. 不做回滚: 请求失败后 UI 仍然显示已发送
  2. ID 不替换: 临时 ID 没有替换为正式 ID,后续操作引用错误
  3. 不做重试: 发送失败后没有重试机制
  4. 状态不一致: 多个乐观更新并发时状态冲突

学习检查

  1. AI 对话为什么比“点赞”更难做乐观更新?
  2. 用户消息临时 ID、服务端正式 ID 与 assistant 流式消息之间如何收敛?
  3. 请求失败时,哪些 UI 状态应该保留,哪些应该回滚或转为可重试?
  4. 什么内容属于通用乐观更新,什么内容只属于 AI 对话状态机?

参考资料

创建于 2026/6/30 更新于 2026/10/1
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本