博客.
博客.
(联系方式)

保持联系

如果你想联系我,无论是讨论合作机会、分享想法,还是只是打个招呼,都可以通过以下方式找到我。

(最后更新)

版权所有 / 2026

(快捷键)C
返回学习路线
(03 · AI Native)2026年8月

AI Native 交互范式

AI Native 不是在每个页面塞一个对话框。真正的公式是:意图输入 + 过程可见 + 结果可干预——对话框只是其中一种载体,有时甚至是最差的那个。

AI Native 交互范式

先破个题:对话框不是答案

过去两年,无数产品的「AI 化」等于在右下角加一个聊天气泡。问客服是聊天,写文档是聊天,数据分析也是聊天——仿佛对话框是 AI 的唯一合法形态。

但用得多了你会发现:有些东西用对话做,比原来的 GUI 还难用。想给表格按时间排序,原来点一下列头;现在要打一句「帮我把这个表格按创建时间倒序排列」,等三秒,然后祈祷它没理解错。这不是进步,是倒退。

AI Native 的交互设计,核心不是「加个对话框」,而是重新回答三个问题:

  • 意图输入:用户怎么告诉系统「我想要什么」——对话只是方式之一
  • 过程可见:AI 干活的几秒到几小时里,用户能不能看到它在干嘛
  • 结果可干预:用户能不能中途叫停、修改、审批,而不是只能全盘接受或重来

这一章就按这三件事展开:什么时候该用对话、什么时候对话框是灾难;什么时候模型该直接生成界面;流式输出背后的体验工程学;后台跑长任务时 UI 该怎么办;最后用微软的 Human-AI 交互准则把这些散点串成体系。


对话式 UI 的边界

对话擅长一件事:表达模糊、探索性的意图。「帮我看看这个月销量下滑的原因」——你脑子里没有明确路径,需要一来一回地澄清,对话天然合适。写作初稿、头脑风暴、陌生领域的问答,都是对话的主场。

对话不擅长的事也很明显:精确、高频、可预期的操作。举几个对话框堪称灾难的真实场景:

  • 计算器 / 单位换算:「35 美元是多少人民币」在搜索框里早就是即时答案,让 LLM 算既慢又可能算错。输入框 + 实时结果完胜对话框
  • 电商筛选:「价格 200-500、包邮、评分 4.5 以上、明天能到」——这是一组离散条件的组合,勾选筛选器比把它写成一句自然语言快得多,且可以随时单独改一项。对话里改一项要重述整句话
  • 视频剪辑 / 音频编辑:把时间轴上 00:32 到 00:45 这一段删掉——拖拽选区是直觉操作,用语言精确描述时间点纯属自虐
  • 数据看板:用户要的是「每天扫一眼」的被动监控,对话是主动查询,范式本身就是拧的
  • 打车软件:起点终点是地图上的两个点,地图选点的信息密度远高于文字描述地址

看出规律了吗?这些场景的共同点:意图是精确的、结构化的,且操作会反复发生。自然语言的强项是压缩模糊意图,弱项恰恰是表达精确结构——而 GUI 控件(滑杆、勾选框、地图、时间轴)就是为精确结构而生的编码器。

一个好的判断框架:

  • 意图越模糊,对话越值(探索、问答、创作初稿)
  • 操作越精确,GUI 越值(调整参数、批量处理、浏览结构化数据)
  • 频率越高,越该从对话固化成控件:第一次用对话发现「这个筛选组合好用」,第十次就该给它做个按钮了
  • 最好的形态是混合:对话负责「定方向」,GUI 负责「微调」。Cursor 就是这个模式的教科书——你用对话描述要改什么,它给你 diff,你用按钮逐个接受或拒绝。对话和 GUI 各干各擅长的

争议:对话是未来,还是过渡形态?

这个话题业内吵得很凶,两边都有像样的论据:

正方(对话是未来):自然语言是带宽最高的意图通道,GUI 只是算力不足时代的妥协——按钮和菜单本质上是「把意图预先枚举成有限集合」,而真实意图是无限的。模型理解力越强,需要枚举得越少,最终一切归于对话。语音成熟后这个趋势只会加速。

反方(对话是过渡形态):对话有三大硬伤——不可发现(用户不知道能问什么,空输入框是最差的引导)、不可复现(同一句话两次结果可能不同,而按钮有肌肉记忆级的确定性)、高表达成本(打字永远比点击慢)。人类用了四十年 GUI 不是因为算力不够,是因为指向(pointing)本身就是比描述(describing)更底层的认知方式——你指着一个东西说「把这个改一下」比纯语言描述省力得多。

我的看法:两边说的不是同一层。对话吃掉的是「意图层」,GUI 守住的是「控制层」。未来的界面大概率是「对话提出、GUI 确认」的混合体——而「确认」那一半,就是下面要讲的生成式 UI。


生成式 UI:模型直接生成界面

对话输出的是文字,但很多问题的答案天生不该是文字。问「各季度营收对比」,最好的回答是一张图表;问「帮我挑个航班」,最好的回答是可点击的卡片列表。

Generative UI 的思路是:模型不输出最终渲染结果,而是输出一份结构化的「界面描述」,前端拿到描述后渲染成真实组件。

生成式 UI 流程:模型不直接吐 HTML,而是输出受 Schema 约束的界面描述,前端用组件白名单渲染成可干预的真实组件

模式一:组件白名单 + JSON Schema

关键约束是组件白名单——模型只能从你预先定义的组件库里挑,参数必须符合 schema,绝不让模型直接吐 HTML 或任意代码。一个最小的 TypeScript 实现:

// 模型只能输出这几种组件描述,用 tool_call 的参数 schema 做硬约束
type GenUI =
  | { type: "chart"; data: { label: string; value: number }[] }
  | { type: "table"; rows: string[][] }
  | { type: "text"; body: string };

function renderUI(ui: GenUI) {
  switch (ui.type) {
    case "chart":
      return <BarChart data={ui.data} />;
    case "table":
      return <DataTable rows={ui.rows} />;
    case "text":
      return <p>{ui.body}</p>;
  }
}

为什么必须是白名单而不是任意代码?三个理由:安全(模型吐的 HTML 可能带脚本注入)、样式一致性(设计系统的控制权在你手里,不在模型手里)、可干预(白名单组件你知道它有哪些交互能力,可以预埋按钮和回调)。

模式二:流式部分渲染

生成式 UI 和流式输出是可以叠加的,但有个技术难点:流式到达的是半个 JSON,直接 JSON.parse 必炸。工程上有两种解法:

  1. 容忍解析:用 partial-json 这类库解析不完整的 JSON,已完整的字段先渲染,缺的字段显示骨架屏。用户看着图表的坐标轴先出来、数据柱一根根长出来
  2. 分段协议:不让模型吐一整块 JSON,而是按组件分段输出(比如每个组件一个独立的 tool_call),收到一段渲染一段。Vercel AI SDK 走的就是这条路

Vercel AI SDK 的机制

值得单独说一下这个参考实现,因为它把上面的模式做成了标准能力。核心机制(以 streamUI 为代表):

  • 服务端定义工具集,每个工具的参数用 Zod schema 描述,同时绑定一个 生成器函数,返回 React 组件
  • 模型流式输出 tool_call,SDK 在流里实时解析,参数一完整就调用生成器,把组件本身(而不是文本)作为流的一部分推给前端
  • 基于 React Server Components 序列化,组件可以携带交互能力(按钮、回调)直达客户端
  • 前端拿到的是一个「文本和组件混排」的流,按到达顺序渲染

这套机制的价值在于把「模型决定用什么组件」和「组件怎么实现」彻底解耦:模型只懂 schema,不懂 React;组件只懂 props,不懂模型。换模型不动 UI,改 UI 不动模型。

失败降级矩阵

生成式 UI 的每一环都可能失败,设计时必须逐层想好退路:

失败点典型原因降级策略
schema 校验失败模型幻觉出不存在的字段丢弃该组件,重试一次或直接退化成纯文本
chart 渲染失败数据为空、数值越界退化成 table 展示同样的数据
table 渲染失败行列结构异常退化成 markdown 纯文本
组件流中断网络断开、生成超时已渲染部分保留 + 断点提示 + 重试按钮
白名单外组件模型编造组件名静默替换为 text,记录日志用于迭代白名单

铁律只有一条:任何情况下用户都要能看到内容,最差也是一段纯文本回答。白屏是生成式 UI 唯一不可接受的结局。


流式响应:打字机效果背后的心理学

为什么 AI 产品都爱用「打字机」式的逐字输出?不是因为模型只能一个字一个字地吐——完全可以等生成完再一次性展示。真正的原因是感知性能(perceived performance):用户体验到的速度,比客观速度更重要。

阈值的原始出处

业内常引用的「0.1 / 1 / 10 秒」三条线,原始出处是 Jakob Nielsen 1993 年的《Usability Engineering》第五章,而 Nielsen 的源头又可以追到 Robert B. Miller 1968 年的论文《Response Time in Man-Computer Conversational Transactions》。三条线的含义:

  • 0.1 秒:用户感觉界面是「即时」的,操作和反馈融为一体
  • 1 秒:用户的思路不被打断的上限,超过了就需要反馈来「接住」注意力
  • 10 秒:用户注意力能留住的上限,超过就必须给进度反馈,否则人会走

有意思的是,这套阈值来自大型机时代,硬件换了几茬,数字却经久不衰——因为它度量的不是机器,是人类注意力的生理常数。LLM 生成一段像样回答通常要 5-30 秒,远超 10 秒红线,这就是为什么流式几乎是所有 AI 产品的标配。

响应时间三条阈值线:0.1 秒感觉即时、1 秒不打断思路、10 秒是注意力红线,流式输出让首 token 在一秒内到达、把等待变成阅读

流式为什么有效

流式输出把「等待」变成了「阅读」:第一个 token 往往在 1 秒内到达,用户从那一刻起就有东西可看,主观等待时间大幅缩短。而且逐字出现的内容自带一种「它在认真工作」的暗示——这比转圈圈的 loading 动画诚实得多,因为输出本身就是进度。

流式的最小实现(浏览器端,SSE):

const res = await fetch("/api/chat", {
  method: "POST",
  body: JSON.stringify({ prompt }),
});
const reader = res.body!.getReader();
const decoder = new TextDecoder();

let acc = "";
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  acc += decoder.decode(value, { stream: true });
  setText(acc); // 每到一个 chunk 就更新 UI
}

TTFT 优化清单

流式体验的核心指标是首 token 延迟(TTFT),而不是总耗时——用户的耐心是在前 10 秒消耗掉的。优化手段按成本从低到高:

  1. 先流「思考状态」再流内容:UI 上一收到请求立刻切「正在分析…」,这是零成本的感知优化
  2. 缩短 prompt:系统提示词和塞进的上下文每多 1k token,TTFT 就实实在在地涨
  3. 命中 KV 缓存:把不变的前缀(系统提示、工具定义)放在 prompt 最前面,提高前缀缓存命中率
  4. 选小模型做前奏:简单问题路由到小模型,复杂问题才上大模型
  5. 就近部署 / 选近端接入点:跨国网络往返就是几百毫秒
  6. 连接预热:页面加载时就建立好到推理服务的连接,别等用户点了按钮再握手
  7. 投机解码(speculative decoding):推理侧用小模型起草、大模型验证,直接降低每 token 延迟
  8. 边生成边渲染 markdown:流式渲染要支持不完整语法(一个没闭合的加粗不能炸掉整段)

体验设计的四个细节

  • 必须能中途取消:AbortController 断掉请求,同时后端也要真的停止生成,否则用户省的是时间,你烧的是 token 钱
  • 不要用假流式:有些产品拿到完整结果后故意逐字播放「模拟」打字机,一旦被发现(中途没法取消、永远匀速),信任直接归零。要么真流式,要么老实转圈
  • 给「思考中」一个独立的阶段:带 reasoning 的模型可能先静默思考十几秒再输出,这段时间需要明确的状态提示,否则用户以为卡死了
  • 流完要有「完成态」:输出停止和输出完成是两回事,完成后给出明确收尾(复制/重新生成按钮亮起),别让光标一直闪

后台 Agent 与异步任务:任务跑几小时,UI 怎么设计

前面的场景都假设用户在线等。但 Agent 真正有价值的场景——深度调研、批量处理、代码迁移——动辄几十分钟到几小时。没人会盯着一个页面等两小时,此时 UI 的本质从「聊天窗口」变成了「项目管理工具」

任务状态机:完整设计

设计这类界面,先想清楚任务的完整生命周期,并用状态机显式建模:

type TaskState =
  | { status: "queued" }
  | { status: "running"; step: string; percent: number }
  | { status: "waiting_approval"; draft: string } // 检查点:等人拍板
  | { status: "paused" }
  | { status: "done"; result: string }
  | { status: "failed"; error: string; resumeFrom: string }
  | { status: "cancelled" };

合法的迁移路径要显式定义,不允许乱跳:

任务状态机:queued 进入 running 后可转 done、failed、paused、waiting_approval,waiting_approval 是一等公民状态,queued/running/paused 随时可取消

注意 waiting_approval 是一等公民,不是 running 的子状态。原因很简单:它和 running 的 UI 完全不同(前者需要醒目的审批入口,后者只需要进度展示),通知策略也不同。把它并进 running,代码里就会到处长 if 分支。

通知策略:分级触达

任务在后台跑,人就走了。通知是把用户「叫回来」的机制,但不能什么都推——通知通货膨胀的结果是全被关掉。按打扰程度分级:

  • waiting_approval:强提醒(应用内角标 + IM webhook / 邮件)。用户在阻塞任务,越早回来越好。内容带摘要和直达链接,点一下落到审批界面
  • failed:立即通知。带失败原因和「从断点重试」按钮,不要只甩一句「任务失败」
  • done:弱提醒(应用内通知即可,不打扰)。带结果摘要,让用户决定要不要细看
  • running:不通知,进度变化只更新在任务面板里,主动查看而不是被动推送

恢复语义:失败必须可恢复

跑了 50 分钟挂了,用户最恨的是「从头再来」。恢复能力是个工程组合拳:

  • 幂等:子任务重复执行不产生重复副作用(写结果前先查是否已写,或用幂等键去重)
  • 检查点持久化:每完成一个子任务,把 resumeFrom 指向的进度写进数据库——不能只在内存里,服务重启、用户刷新都不能丢
  • 副作用与状态分离:已经发出的邮件、已经提交的 PR 是「真实世界的副作用」,恢复时必须先查副作用记录再决定是否重做,否则重试=重复发邮件
  • 终态补偿cancelled 不是简单停掉,已完成的副作用要不要回滚,得逐个定义(能撤销的撤销,不能的在报告里如实列出)

检查点审批:用可干预换信任

跑两小时全自动听起来美,实际是「两小时后给你一个大惊喜/惊吓」。好的设计是在关键决策点(比如「计划修改 12 个文件,是否继续?」)暂停,把草案/diff 摆出来等人审批。审批界面给的不该是「是/否」两个按钮,而是完整的上下文:要改什么、为什么、改完之后是什么样(diff 预览)。用户批准的是理解之后的方案,不是开盲盒。

看 Claude Code、Devin 这类产品的界面:左边是任务列表,右边是当前任务的实时日志和 diff,顶部是审批按钮——没有一个元素是传统聊天框,但意图输入、过程可见、结果可干预三样一样不少。这就是 AI Native 交互的成熟形态。


用 Human-AI 交互准则收个尾

上面这些散点经验,其实早有体系化的总结。微软研究院 2019 年在 CHI 上发表的《Guidelines for Human-AI Interaction》,从 150 多篇文献和 20 多轮验证中提炼出 18 条准则。挑和本章最相关的四条展开:

G1:明确系统能做什么(Make clear what the system can do)。 空输入框是对话式 UI 最大的反模式——用户不知道能问什么,试探三次失败后就把功能判了死刑。落地做法:输入框里放会轮换的示例提示、首次使用给三个可点的能力卡片、做不到的事明确说「这个我不会」。能力边界本身就是 UI 的一部分。

G9:支持高效的纠正(Support efficient correction)。 AI 会错,这是前提不是意外,所以「纠正」必须是和「生成」同级的一等交互。落地做法:每个结果旁边有「不对」的低成本反馈入口;局部可改(重新生成这一段,而不是整个重来);纠正后的偏好要记住(用户改了三次标题风格,第四次就该主动对齐)。

G11:说明行为的原因(Make clear why the system did what it did)。 过程可见的理论版。落地做法:引用来源(这句话来自哪个文档)、展示推理的关键步骤(不是全文思维链,是可读的摘要)、审批点解释「为什么需要你拍板」。解释不是免责声明,是让用户建立准确心智模型的材料。

G17:提供全局控制(Provide global controls)。 用户要能全局性地约束 AI 的行为,而不是每次任务单独叮嘱。落地做法:全局的「自动执行到什么程度」开关(只建议 / 建议并预览 / 直接执行)、隐私与数据使用的总开关、通知频率的总开关。这些开关要放在设置里稳定的位置,不能每次换地方。

对照一下会发现:本章的三要素和这 18 条准则是同一个东西的两层抽象——三要素是架构,18 条准则是验收清单


常见误区

  • 万物皆对话框:把精确操作硬塞进自然语言,交互效率反而低于传统 GUI。先问「不用对话框怎么设计」
  • 让模型直接吐 HTML/任意代码:安全和样式双重失控。生成式 UI 一定要走组件白名单 + schema 约束
  • 假流式:完整结果拿到后再匀速播放,无法取消、破坏信任。要么真流式,要么老实转圈
  • 长任务无状态:进度只存在内存里,刷新即丢失;失败只能重来。异步任务必须持久化状态机 + 断点恢复
  • 只优化总耗时,不优化 TTFT:用户的耐心是在前 10 秒消耗掉的,首 token 延迟比总时长更值得投入
  • 审批走过场:检查点只给「是/否」不给上下文,用户只能开盲盒,久而久之要么全批(检查点形同虚设)要么弃用

术语表

名词定义一句话直觉常见混淆
Generative UI模型输出结构化界面描述,前端据此渲染真实组件的交互模式模型不当画师,当排版编辑≠ 让模型直接生成 HTML/代码
组件白名单生成式 UI 中允许模型调用的预定义组件集合模型只能从菜单上点菜≠ 对模型输出做关键词过滤
TTFTTime To First Token,从发请求到收到首个 token 的延迟用户耐心开始倒计时的那一刻≠ 总生成耗时;优化 TTFT ≠ 优化吞吐
SSEServer-Sent Events,服务器向浏览器单向推送的流式协议一根只能往下流的水管≠ WebSocket(双向);SSE 够用于绝大多数流式场景
感知性能用户主观体验到的速度,与实际耗时可不一致让人有事可看,比真的更快更重要≠ 客观性能指标(QPS、延迟分位数)
假流式拿到完整结果后匀速逐字播放,伪装成实时生成录播冒充直播≠ 真流式;假流式无法中途取消
意图输入用户向系统表达「想要什么」的环节,对话只是载体之一说话、点击、拖拽都是在「输入意图」≠ 提示词工程(那是表达技巧,不是交互层)
检查点(Checkpoint)长任务中暂停等待人工审批的决策点高速公路上的收费站≠ 断点/快照(那是恢复机制,检查点是审批机制)
断点恢复任务失败后从上次进度继续而非重来的能力游戏存档读档≠ 重试(重试是同一个动作再来一遍,恢复是接着走)
幂等同一操作执行多次与执行一次效果相同按十次电梯按钮和按一次一样≠ 去重(去重是手段,幂等是性质)
任务状态机用显式状态和迁移规则建模异步任务生命周期任务的「户口本」,只能在规定路线上迁户口≠ 一堆布尔标志位(isRunning、isDone…)
异步任务 vs 后台任务前者是用户发起的长耗时任务,后者是系统自发的例行作业异步任务有人等结果,后台任务没有混为一谈会导致通知策略错配:后台任务不该打扰用户

参考材料


小结

记住一个公式:AI Native 交互 = 意图输入 + 过程可见 + 结果可干预。对话框只是意图输入的一种载体,模糊意图用它,精确操作用 GUI,高频操作迟早固化成控件;生成式 UI 让模型的输出从文字升级成可操作的真实组件,白名单和降级矩阵是它的安全带;流式响应本质是感知性能工程,核心指标是首 token 延迟;长任务场景下,UI 要长成项目管理工具的样子——状态机、进度可读、检查点审批、分级通知、断点恢复。最后拿微软 18 条准则当验收清单过一遍。三要素齐了,用什么「框」反而不重要。