ai for designersMay 1, 202610 min read

设计流式 UI

流式输出区域是新的画布。一份实用手册,把 AI 流式 UI 当作真正的交互模型来设计,包含五个层次、真实产品拆解、反模式,以及上线前审查清单。

By Boone
XLinkedIn
designing streaming uis

流式响应是现代软件里设计最不到位的界面。大多数团队写了个 TypeScript fetch hook,接到一个 div 上,就管这叫产品设计。结果呢,一台假装成界面的打字机。

流式输出不是文字冒出来而已。它是一种交互模型,有节奏、有停顿、有滚动行为、有打断的入口,还有信任信号。只设计输入的团队,只交付了半个产品。输出区域是另一半,也是大多数 AI 产品正在流失用户的地方。

这篇是可操作版本。流式 UI 到底是什么,每个优秀流式 UI 都具备的五个层次,真实产品拆解,正在生产环境里杀死界面的反模式,以及一份上线前审查清单。

流式 UI 是一个界面,不是一个 fetch 循环

流式 UI 是模型运行期间用户回读内容的整个区域。可见的文字只是其中一部分。节奏、光标、滚动行为、结构承诺、打断控件,以及流结束后的状态,构成其余部分。

这个界面有可衡量的属性。首 token 时间。token 节奏。结构承诺。打断延迟。完成信号。流后可操作项。忽略其中任何一项,这个流就只是 API 的副作用,而不是被设计过的组件。

Cursor、Claude、v0、Lovable、Linear AI、Raycast AI。没有一个把流式输出当作原始 token 输出。每一个都交付了结构化的界面。这就是标准。

优秀流式界面的五个层次

五个层次,按用户体验到的顺序排列。少于四层的流式 UI 是不完整的。

体素风格的五层塔示意图,各层板块分别标注首 token 时间、token 节奏、结构承诺、打断与编辑、完成
体素风格的五层塔示意图,各层板块分别标注首 token 时间、token 节奏、结构承诺、打断与编辑、完成

首 token 时间,是空白变成反馈的那一刻。token 节奏,是流跑起来之后给人的感觉。结构承诺,是界面处理列表、表格和代码时如何做到不重排。打断与编辑,是用户的逃生口。完成,是流结束、产物变得可交互的那一刻。跳过任何一层,流就会从那一层开始腐烂。

第 1 层:首 token 时间

最初的 200 毫秒决定用户是否信任这个界面。200ms 以内并带有真实反馈信号,感觉是瞬时的。超过 800ms 毫无反馈,用户已经在判断这个产品坏了。

选择很具体。一个预先占好输出区域的骨架占位。一个闪烁的光标。一个输入中的小圆点。一个流式前缀,比如在内容之前 300ms 就落下的“Here is”之类的已知短语。

ChatGPT 的三个点管用,因为它们诚实。Claude 的渐变脉冲是升级版,一条柔和的动态光带,表明界面活着,又不必承诺任何假内容。Cursor 渲染一条细光标线和一个说明当前在做什么的状态标签。每种情况下,用户在 200ms 内都有东西可看。

空白才是失败。一个卡了 600ms 的空白区域,会让用户学到:AI 是需要熬着等的东西。先上光标,再上模型。

第 2 层:token 节奏

原始 token 流是抖动的。模型先吐四个 token,再吐二十个,再吐一个,即便底层传输没问题,看起来也像一个故障的终端。节奏是一项设计决策。

解法是平滑的节奏。把传入的 token 缓冲 30 到 60 毫秒,然后以稳定速率渲染。用户的阅读速度是每分钟 250 到 400 词,所以目标是让流以等于或略高于阅读速度的节奏落下,不要突刺。Claude 很早就做到了这种纪律。

Vercel 在 v0 中的流式 UI 基础组件也是同一个思路,一个把网络和视觉更新解耦的渲染循环。来自 API 的 token 流是一层。视觉流是另一层。两者永远不该是同一个东西。

光标很重要。一个跟随最后渲染的 token、带柔和拖尾淡出的光标,能锚定视线。没有它,用户的眼睛就会到处乱跳,找流到哪儿了。Cursor 在 composer 里的光标,可不只是名字上的巧合。

第 3 层:结构承诺

最难的一层。纯文本很容易。但流在响应中途承诺一个列表、表格、代码块或图表,是大多数界面崩掉的地方。

体素渲染的流式输出面板:一段完整渲染的段落,一个渲染到一半的列表,以及一个已预留布局的代码块
体素渲染的流式输出面板:一段完整渲染的段落,一个渲染到一半的列表,以及一个已预留布局的代码块

天真的做法是把 markdown 当流式处理。渲染器解析每个数据块,每次提交都重排布局,列表重新编号,代码块在流中途换字体,页面乱跳。每一次重排都是对注意力的征税。

正确的做法是:结构一旦可检测就立刻提交,然后把内容流进已经确定的布局,不再重排。第一个连字符落下的那一刻,列表就预留空间。遇到三个反引号,代码块就预留一个等宽面板。表格立刻确定列数。Cursor 的 diff 流式输出是教科书案例。diff 面板预留布局,文件路径先落下,各行内容流入预先分配好的行。v0 的选区感知流式输出在画布侧用了同样的模式。

Linear AI 的结构化建议做到了结构承诺,却从不向用户展示“加载中”状态。建议以带类型的对象落下,字段按依赖顺序填充,工作流从不阻塞。Linear 交付的是工作成果,其他家交付的是聊天记录。

第 4 层:打断与编辑

没有打断功能的流式 UI 是敌意的。用户看着模型写一个他们早就知道是错的东西,唯一的出路是关掉标签页。这不是产品。这是一场带 token 计数器的劫持事件。

停止按钮是界面上成本最低、杠杆最高的元素。从第一个 token 起就可见,而不是第 100 个之后。Claude、Cursor、ChatGPT 和 v0 都有。大多数自研聊天 UI 都忘了。

打断是底线。编辑是天花板。大多数团队还没挣到的模式是实时编辑:用户在流中途修改提示词,界面随之改道。Cursor 在流式输出期间的接受与拒绝,是目前最接近的已上线版本。用户在 diff 落下时边读边看,接受管用的部分,拒绝不管用的部分。这才是真正的交互闭环。

ChatGPT 的重新生成则是反面。按钮覆盖上一条回复,用户失去了他们喜欢的那个版本。把重新生成做成覆盖,是破坏。把重新生成做成分支,才是设计。Claude 的历史界面做的就是分支。

第 5 层:完成与流后状态

流结束的那一刻是一个设计时刻。大多数产品把它当作什么都没有。流停了,光标消失,用户盯着一堵文字墙,不知道下一步该干什么。

Claude 的 artifact 成形是黄金标准。流式文字有一个安静的完成信号,artifact 面板在同一拍里从流式预览切换为可交互界面。用户不是“读完了”,而是现在“身处 artifact 之中”。这个过渡就是全部重点。

v0 的预览切换是设计侧的版本。流式代码结束,实时预览 iframe 用最终构建重新加载,部署按钮浮现。三个状态,一次过渡,没有冷场。

Cursor 的 diff 到接受是第三种模式。流结束,diff 仍可编辑,接受与拒绝仍在,用户不点头,文件就不会提交。流结束了,决定还没有。正是这种分离,让界面像工具而不是聊天记录。

糟糕的版本是流一结束就什么都不给。光标熄灭,文字杵在那里,用户把文本复制到另一个工具里才能真正使用。一条挂着模型的复制粘贴流水线。

真实产品拆解

Cursor 采用 composer 流式输出加 diff 成形。Composer 流式输出计划,diff 面板流式输出补丁,接受与拒绝始终有效,流后状态是一份归用户所有的待处理 diff。每一层都命中。

Claude 有平滑的 token 节奏和 artifact 面板切换。首个 token 前是渐变脉冲,节奏稳定,完成时 artifact 成形,对话历史可分支。界面之所以感觉是设计过的,是因为每一次过渡都被设计过。

v0 有选区驱动的流式输出和实时预览。用户点击画布的某个区域,提示词自动限定范围,流以代码形式落下,同时预览在 iframe 中切换。完成后交接给部署按钮。

ChatGPT 是基线。token 流式输出加三点反馈,重新生成是覆盖,“从此处分支”是近期新增。是品类默认,不是标准。

Vercel AI Playground、Lovable、Anthropic Computer Use、Raycast AI 和 GitHub Copilot Workspace 各自交付了一部分。Vercel 在流进行中实时展示模型选择器。Lovable 跑的是从流到应用的模式,用户实时看着自己的应用被构建出来。Computer Use 并行流式输出截图和推理轨迹。Raycast 流式输出到一个命令面板微型界面。Copilot Workspace 交付先规划后执行的流式输出,带检查点。

五条规则

  1. 200 毫秒内给出反馈。 光标、脉冲、输入点、流式前缀。什么都行,就是别留空白。
  2. 平滑节奏。 缓冲网络流,以阅读速度渲染,锚定光标。抖动是设计失败,不是网络状况。
  3. 提交结构,不重排。 列表、表格或代码块一旦可检测,立刻预留布局。永不重排。
  4. 在第 100 个 token 之前交付停止按钮。 可见。可达。一次点击。没有例外。
  5. 像设计流本身一样用心设计流之后的那一刻。 完成是一次交接。交接就是产品。

正在生产环境中杀死流的反模式

死转圈。 模型在一个关闭的渲染层后面流式输出,前面却在转圈。删掉转圈。把流交付出来。

token 抖动。 原始 token 输出,没有缓冲,节奏在爆发和停顿之间闪烁。平滑它。

和用户作对的自动滚动。 用户正在读前面的段落,页面却自动滚动去跟随流。检测手动滚动,暂停自动滚动,直到用户重新锚定。Claude 和 Cursor 处理了这一点。

没有停止按钮的错误。 打断藏在设置菜单里,或者 30 秒后才出现,或者压根不存在。从第一个 token 起就要可见。

流结束后让用户干瞪眼。 没有完成信号,没有下一步。设计流后状态。

破坏性重新生成。 新回复覆盖旧回复,用户失去了喜欢的版本。重新生成要做成分支,绝不是覆盖。

把原始 markdown 当流式处理。 渲染器每个数据块都重排,页面乱跳。结构提交一次,内容流入预留的布局。

修复都很小。做了这些的界面感觉像 2026 年。没做的,感觉像是把 2022 年的聊天侧边栏接在了 2026 年的模型上。

流式界面审查

任何 AI 流式界面上线前都跑一遍这些检查。

体素渲染的竖直审查卡片堆叠,带珊瑚色复选框,代表流式界面审查
体素渲染的竖直审查卡片堆叠,带珊瑚色复选框,代表流式界面审查
  1. 首次反馈。 提交后 200 毫秒内,界面是否显示了东西?
  2. 节奏。 token 流是否被平滑到阅读速度,还是原始的网络抖动?
  3. 结构承诺。 内容到达之前,界面是否为列表、表格和代码块预留了布局?
  4. 停止入口。 停止按钮是否从第一个 token 起就可见,一次点击就能用?
  5. 编辑入口。 用户能否在流中途修改、接受或拒绝?
  6. 完成设计。 流结束的那一刻,是否交接到一个真实的下一步?
  7. 流后产物。 流结束后输出是否可交互,还是只是一份冻结的记录?

七项全过的界面,感觉像一个被设计过的组件。三项或以上不过的界面,感觉像挂着模型的控制台日志。这个差距,就是 AI 原生产品设计与 AI 外挂的分界。

如此用心交付流式界面的团队,也正是在输入侧把提示界面当作真正组件对待、并在系统层面为 AI 延迟做设计的团队。再配合空状态、agent UI 模式和信任信号,让流式输出赢得用户的阅读。

FAQ

什么是流式 UI 设计?

流式 UI 设计是一门学问,研究如何塑造 AI 输出在模型生成时出现在屏幕上的方式。它涵盖首 token 时间、token 节奏、结构承诺、打断入口和流后产物。流式 UI 不是一个被文字填满的文本框。它是一个有可衡量属性的被设计过的界面,而当下领先的产品都是这样对待它的。

为什么 token 流式输出在不同产品里感觉不一样?

因为节奏是设计决策,不是网络结果。原始 token 流会抖动。经过缓冲、平滑的流以阅读速度落下。Claude 用一个把网络和视觉更新解耦的渲染循环来平滑节奏。ChatGPT 更接近原始传输。同一类模型,不同的界面手感。

流式 UI 最常见的错误是什么?

交付一个没有可见停止按钮的流。用户看着模型写一个他们知道是错的东西,却无路可退。其他常见失败:死转圈、和用户作对的自动滚动、破坏性重新生成、每个数据块都重排的原始 markdown,以及交接给虚无的完成。每一个都能通过一个小小的界面改动修好。

把流当作画布来打造

流式输出区域是新的画布。AI 产品的生死,取决于这个界面在最初 800 毫秒里的手感,以及它在 30 秒的响应中如何保持可读。大多数团队把它当打字机。交付标杆的团队把它当基础设施。

交付五个层次。跑一遍审查。避开反模式。最后做出来的产品,感觉像一个工具,而不是一个假装成工具的聊天侧边栏。

如果你想要一个把流式界面当作完整组件来交付、而不是外挂 token 循环的团队,雇用 Brainy。我们端到端设计 AI 原生产品 UI,从第一个 token 到流后产物,在第一个用户点下发送之前,信任信号和打断入口就已内置其中。

Want a streaming surface that feels designed instead of bolted on? Brainy ships AI-native product UI end to end, from the first token to the post-stream artifact.

Get Started

More from Brainy Papers

Keep reading