跳转到主要内容

对话分支作为一等公民:为什么线性线程迫使用户不断杀死并重启对话

阅读需 1 分钟Tian PanTian Pan

你的聊天产品需要分支功能的最明显信号,往往也是最容易被忽略的:用户不断地将旧对话复制粘贴到新的会话中。他们不是在更换供应商,也不是因为无聊。他们是在尝试询问“如果我早点反驳那个假设会怎样?”,同时又不想丢失花费了 40 轮对话建立的上下文。线性线程只为他们提供了两个选项——要么覆盖下一条消息并丢失原始回复,要么开始新聊天并丢失前置内容。于是,他们利用剪贴板发明了第三种方案。

每当用户这样做时,你的产品就在通过这种变通方法泄露一个功能需求。这个变通方法很糟糕:它剥离了消息元数据,破坏了工具调用(tool-call)的联动,丢失了文件附件,并产生了不再映射到连贯任务的孤立线程。但它之所以存在,是因为另一种选择——放弃花费 30 分钟建立的上下文——更糟糕。对话在结构上是一棵树,而 UI 却坚持它是一个列表。用户只能手动填补这个鸿沟。

将分支作为一等公民,意味着像版本控制系统处理分支那样对待发散:将其视为一种保存历史、支持并行探索并允许合并回来的正常操作。OpenAI 在 2025 年末在 ChatGPT 中以“在新聊天中分支”的形式发布了此功能。Claude Code 将对话存储为消息的 DAG(有向无环图),其中编辑会创建分支而非覆盖。LangGraph 检查点将 fork_at(checkpoint_id) 作为原语暴露。这种模式正在趋同,因为线性线程的抽象一直是有损的——只是经过几年的使用数据,这种损失才变得不可否认。

线性线程迫使的三种失败模式

线性聊天 UI 将三种截然不同的用户意图压缩到了同一个 UI 动作中。当用户想要改变方向时,他们会编辑最后一条消息。但“改变方向”隐藏了至少三种不同的需求,每种需求都值得一个不同的状态转换。

第一种是纠偏(course correction):用户认为模型理解有误并想要重新陈述。原来的回复不再需要;覆盖是可以的。第二种是替代探索(alternative exploration):用户得到了一个合理的答案,但想看看不同的表述会产生什么结果——两者都有价值。第三种是回滚到分支点(rollback to a fork point):用户意识到十轮对话前他们应该给出不同的约束,现在想在这些约束下重试后续的整个对话,同时保留原始分支作为参考。

在线性线程中,这三者看起来完全一样:用户点击消息上的编辑并重写它。系统无法区分“丢弃剩余部分”和“两者都保留”。大多数产品默认选择丢弃,因为保留会产生线性 UI 无法表示的导航问题。想要“两者都保留”语义的用户如果不离开产品就无法实现。

这种成本表现为重复劳动。进行对比分析的研究人员会打开同一个聊天的四个浏览器标签页。测试语气变化的营销人员会开启新的会话,并重新将简报粘贴到每个会话中。调试多步骤计划的工程师要求模型“回到第三步”,然后眼睁睁地看着模型编造之前的上下文,因为模型引用的对话已经被更改了。分支模式从底层涌现——虽然笨拙、摩擦力大,且模型无法提供帮助,因为每个分支都存在于不同的会话中。

分支时复制(Copy-on-Branch)是正确的状态模型

大多数团队在第一次尝试时犯的错误是将分支视为对话的深拷贝。在用户开始频繁使用分支之前,这还能应付,但随后存储成本和更新语义就会成为问题。一个拥有 60 轮对话的用户如果在第 50 条消息处创建了 5 个分支,不应该为 300 条消息的存储付费,也不应该在共享前缀之间出现任何不一致的情况。

正确的模型是带有结构共享的分支时复制(copy-on-branch with structural sharing):消息是不可变的,分支是指向 DAG 的指针,共享前缀在磁盘上只存在一份。这正是使 Git 具备可扩展性的核心洞察。分支不是树的副本;它是指向某个提交(commit)的新引用(ref),而提交是追加式图中的内容寻址节点。转化为聊天场景:每条消息都是一个带有父级指针的节点,分支是叶子引用,用户看到的“对话”是在读取时从根节点到叶子节点重建的一条路径。

这使得几个原本昂贵的操作变得廉价。分叉(Forking)的时间复杂度是 O(1)——你只需分配一个指向分叉点消息的新叶子引用。切换分支只是指针更改,而非副本制作。对比两个分支变成了路径之间的树差异对比(tree-diff),这对于向用户展示“对话是在这里分叉的”非常有用。垃圾回收变成了可达性分析:没有叶子引用指向的消息是可以删除的,但绝不能静默删除——它们是某人的历史。

会员专享

余下内容仅对会员开放。

会员可读完整内容 —— 每一个公开发布的观点背后,那些框架、决策与推理的全貌。

  • 完整文章,包含未公开存档的部分
  • 可落地的工作框架,附带权衡与决策依据
  • 新文章抢先看,先于公开发布

随时取消 · 一次订阅,畅读全部

参考资料

保持联系,关注我获取更多内容

阅读需 11 分钟

Session Stitching:为什么你的会话 ID 是个谎言

框架交付的是会话 ID;而用户生活在任务中。两者之间的鸿沟导致了一半的智能体 UX 体验流失,解决方案是使用任务 ID,而不是延长会话时间。

insider
agent-ux
阅读需 10 分钟

Agent 撤销按钮是 Saga,而非栈

多工具 Agent 撤销本质上是一个伪装的 Saga 模式问题。预计算逆操作、残留 UX 和级联限制决定了撤销是会成功,还是会在 40% 的情况下静默失败。

insider
ai-agents
阅读需 11 分钟

异步智能体需要收件箱,而非聊天框

当智能体的运行时间超过 30 秒时,聊天界面的用户体验就会崩坏。收件箱这一原语——持久化的运行 ID、完成通知以及“结果重于过程”的架构——才是长程智能体真正需要的产品形态。

insider
agent-ux
阅读需 12 分钟

对话中途耗尽的 Token 预算:为什么免费用户觉得你的模型变笨了

按用户分配的 Token 预算往往在对话中途咬人最狠——静默截断、丢弃工具调用、模型回退都会被用户读成质量退化,而升级转化的对话从未发生。

insider
ai-product
阅读需 10 分钟

那个记得你撤回了什么的智能体:将删除作为一等公民的记忆操作

只增(append-only)的智能体记忆存储在存储的事实失效的那一刻就开始腐烂。为什么删除、撤回和失效必须是一等公民操作 —— 以及如何设计可被查找、反驳和移除的记忆写入。

insider
ai-agents