生成式界面与智能体渲染的界面

9 分钟读完

H16
实战手册 · 智能体体验与人机交互

让智能体挑选界面,而不是发明界面。

智能体一旦开始渲染一张表单、而不是用文字描述它,你的测试矩阵就不再有限了——你拥有的每个组件,从此都可能出现在一个没人写过用户故事的组合里,而生产环境的第一个症状,是本该出现卡片的地方留下一片空白。生成式界面值得付出这个代价的,只有一种处境:你没法把界面清单写下来。除此之外,把界面做出来,让智能体在其中挑。

STEP 1

先弄清你买的是什么,代价又是什么。

生成式界面解决的问题真实而具体。一个只会输出散文的智能体,会把每一次结构化交互都逼回聊天框:用户读完一段描述四个航班选项的文字,然后敲下"第二个,但改成周二"。任务完成率就死在这次往返里——它慢、它有歧义,而且它是一个能力足够的智能体最终产出一个被放弃的会话的头号原因。

你为修好它付出的代价,是有限测试矩阵的终结。传统界面有一张张具体的界面;每一张都有人设计、有评审看过,而且只在有人部署时才变。由智能体组合出的界面拥有的是一个界面空间,你只能对它做统计性的刻画。三件你从前逐屏做一次的事,现在必须对每一种组合都成立:渲染正确、阅读顺序合理、文案在用户的语言里。

检验方法:你能把界面清单写在一块白板上吗?如果能,那你就不需要为它们上生成式界面——把它们做出来,给智能体一个工具,让它选中其中一张并填好内容。你保住了测试、保住了无障碍评审,也保住了"说清用户看到了什么"的能力。生成式界面只在清单确实是开放式的时候才挣得回成本。

STEP 2

选能办成事的最低那一档撰写权。

智能体的撰写权有四档,而它们不是一条成熟度阶梯——它们是一份菜单,够用且最便宜的那项胜出。多数产品需要在不同界面上同时用到其中两档。

  • 散文。智能体写文字。没有结构可写错,没有渲染要评审,凡是结构化的东西都由用户再敲一遍。对大多数轮次来说,这依然是正确答案。
  • 挑选。智能体调用一个工具,点名你的某一张界面并提供它的 props。完全可穷举、完全可测试,而且是团队会跳过的那一档,因为它显得不够惊艳。它把航班选项那个问题彻底解决了。
  • 组合。智能体从你拥有的组件目录中拼装一张界面——形态由 A2UI 标准化:一个 JSON 组件列表被映射到你的原生控件上。开放式,也是本页余下部分讨论的对象。
  • 安装。第三方交付一份写好代码的界面,由你的宿主在沙箱中渲染——即 MCP Apps 的形态。这不是智能体在撰写任何东西;这是一个附带界面的依赖,该像治理其他依赖一样治理它。

值得点名的设计错误,是因为演示效果更好就从散文直接跳到组合。挑选这一档以远小的风险覆盖了多得惊人的真实场景,也是你该先榨干的那一档。多少结构是一轮对话真正需要的,见渐进式披露

STEP 3

目录是一份与不可信调用方签的合同。

一旦模型开始组合你的组件,每个组件就都成了公开 API,而它的调用方不读文档、无法被培训,还会传入你的设计师从未考虑过的组合。多数设计系统达不到这条线,因为在此之前,唯一的调用方是一个看到红波浪线就会警觉的开发者。

  • 每个组件在其 prop 空间上行为完备。值缺失、空数组、荒唐地长的字符串、类型不对——每一种都有明确定义的渲染方式,而且没有一种是崩溃或空白框。这是本页回报率最高的一条。
  • 在边界处校验,而不是在组件里校验。在任何东西挂载之前,先拿 schema 解析进来的载荷,宁可拒绝也不要渲染一半。让每个组件各自防守,产出的是一张对了一半的界面,而那比一张明显失败的界面更糟。
  • 为"未知组件"定义好行为。模型迟早会请求一个你的客户端没有实现的组件类型。悄悄丢掉它,就是那片空白区域的来源——这个模式的典型生产故障。开发环境渲染一个带标签的占位符、生产环境渲染一个干净的兜底,并对发生次数做计数。
  • 刻意把目录做小。每多一个组件,都会同时放大组合空间和描述它的 prompt token。十来个精选的原语胜过四十个专用件,而且模型组合小目录时更可靠。
  • 绝不让模型提供原始标记、样式或 URL。prop 是数据。某个 prop 一旦被当作标记来解释,你就重新发明了两套 UI 标准正是为了避免的那个问题——见安全地渲染智能体输出
STEP 4

生成出的界面永远不是记录系统。

一张渲染出来的表单最危险之处,在于它看上去多么可信。用户看到一个带标签的字段、一个金额和一个"确认"按钮,会理所当然地以为它背后是与你产品其余部分同一套机器。那就把这个假设变成真的——让一切都走已经存在的那条路。

  • 提交要走一张人工搭建的界面会走的同一次带校验的工具调用,带同样的授权检查、同样的服务端校验。界面本身什么都不校验,也绝不能是某条规则唯一被执行的地方。
  • 智能体提供的是数据,不是权限。即便字段里的金额是模型挑的,写入路径依然要检查这个用户是否可以动这笔钱。一张组合出来的界面是你系统的一项输入,与一个请求体处在同一信任等级。
  • 确认必须以服务端的视角复述后果。一个文案由模型撰写的"确认"按钮,不构成对该工具将要真正执行的那次操作的同意。要展示解析后的动作——见审批与确认的交互设计
  • 任何不可逆的操作都保留它原有的护栏。"发生在一张生成出来的界面里"不是跳过撤销路径的理由;真要说的话,一张用户从没见过的界面更需要它。

用一句话表述:一张生成出来的界面可以展示任何东西,但不能决定任何东西。它看起来做出的每一个决定,实际上都由它背后的某个工具做出,遵照那个工具本来就有的规则。

STEP 5

只在生产环境才会现身的那些故障。

五个,按团队实际撞上的顺序:

  • 没被测过的组合。一个没有表单包着的字段;一张值缺失的卡片;两个组件叠在一起、读起来像一句完整的话,而那句话是假的。什么都没抛异常。只有 STEP 3 能防住它。
  • 无障碍从缝里漏掉了。每个组件都可能完美无障碍,而组合起来依然无法使用——阅读顺序、焦点管理与地标结构都是"装配"的性质,而没有人评审过装配。如果这里你只做一件事,那就做一次纯键盘走查,覆盖十来个抽样的真实组合。
  • 翻译了一半的界面。组件外壳来自你的目录,会翻译;模型写的每一句文案都不会,除非你告诉了它 locale 并在同一口气里提醒它。中英混排的界面是这个模式里最显眼的缺陷,也是最容易预防的。
  • 延迟悬崖。在载荷到达足够多之前,一张组合出的界面渲染不出来。A2UI 那种带 ID 引用的扁平组件列表,存在的意义恰恰是让客户端可以渐进渲染——用上它,别让一个转圈动画替换掉用户本可以已经在读的文字。见等待与延迟的交互设计
  • 无声的漂移。改一句 prompt 或升一次模型,组合出的东西就变了,而你这边没有任何部署。你的发布流程管不住这块界面,于是它是一个监控问题,而不是设计问题。
STEP 6

把它当作一个分布来测,并留一条通往纯文本的出口。

你没法穷举输出,那就别再试,改用测试任何生成式行为的办法。三种机制覆盖了其中大部分:

  • 快照载荷,而不是像素。每一个发生渲染的轮次都记录组件列表与数据模型——或模板 ID 与版本。它很小、可 diff,而且当有人报告"界面是错的"时,它是唯一能告诉你他们当时在看什么的产物。截图事后无法重建;载荷可以重放。
  • 在 CI 里把一组黄金样本重放过渲染器。几百份采集来的载荷,无头渲染,断言那些便宜的不变量:没有空白、没有未知组件类型、没有缺失的必填 prop、非英文 locale 下没有未翻译的字符串。这能抓住目录级的回归——也就是会一次命中所有用户的那类。
  • 直接对目录做模糊测试。从 schema 而不是从模型生成组合——随机类型、缺失值、深层嵌套——然后断言什么都不崩。它比模型驱动的测试便宜,而且更快地找出 STEP 3 里那些完备性缺陷。

然后去测那个能为这个特性正名的指标:不退回聊天框就完成任务的比例。而不是对渲染界面的互动量——那个数字仅仅因为界面是新的就会上涨。如果用户仍然在把结构化答案敲回对话记录,那说明组合并没有真正承载这次交互,你等于白白背上了一个开放式的测试面。

先上挑选、再上组合——一个点名你已搭好的界面并填入内容的工具,一周之内就能解决真实问题的大部分,而你的测试套件毫发无损。如果确实要上组合,把第一个迭代花在完备性上:每个组件对缺失值、空值与超长值都有定义,外加对未知组件类型的显式渲染。从第一天起就在每个渲染轮次记录载荷;它不花什么钱,而且事后补不回来。再留一个能把整块界面退回散文的开关,因为当某次模型升级改变了组合结果的那天,那个开关是你唯一的快速控制手段。

延伸:为失败而设计讲这里需要的降级路径,为信任与校准而设计讲为什么一张可信的界面抬高而不是降低了标准,智能体互操作讲 A2UI 与 MCP Apps 在协议栈中的位置。