ChatGPT Intelligent UI 拆解:从 DIL 到交互界面
聊天回答可以直接成为一个能操作的界面:调整人数,购物清单随之变化;拖动滑块,报价立即更新;选择偏好,再把结果发给模型继续规划。
Rabi Shanker Guha 在 X 上分享了 Thesys 团队对 ChatGPT Intelligent UI 的逆向分析。最值得关注的是背后的分工:模型描述界面与逻辑,服务端编译,客户端在隔离环境里运行,再交给 ChatGPT 自己的组件系统绘制。
本文根据原帖及其长文和作者网站上的详细分析整理,后半部分补充工程解读。
这些机制来自第三方对自己账号的会话数据、网络流量和公开客户端 JavaScript 的观察,时间为 2026 年 10 月,使用 GPT-6 与 GPT-6 Thinking。它们属于特定版本的逆向结果,并非 OpenAI 官方架构文档;作者没有直接检查手机端实现。
1. 一次回答经过哪些层
可以把主路径画成下面这条链:
用户提出需求 |
组件目录与设计系统贯穿整个过程:模型从中选择组件,编译器据此检查属性,渲染器知道怎样画出来。
这里的“原生组件”指 ChatGPT 自有的界面组件。Web 端最终仍由浏览器显示,不能据此断言每个元素都是操作系统控件。作者从协议和运行时兼容性推测手机端可能复用这套运行时,再接各自的渲染器,但没有实机验证。
2. DIL:让模型写得出,也让半成品能显示
作者观察到的生成格式叫 DIL,混合了三类表达:
| 内容 | 表达方式 | 用途 |
|---|---|---|
| 解释文字 | Markdown | 标题、段落、强调 |
| 界面结构 | 类似 JSX 的标签 | 容器、滑块、表格、图表 |
| 状态与计算 | JavaScript 语句和表达式 | 保存输入、计算结果、响应事件 |
详细版用团队订阅报价解释这套机制:人数初始为 8,每人每月 29 美元,价格由人数乘单价得到;滑块绑定人数状态。拖到 9 人后,价格变成 261 美元。
模型输出里既有普通文字,也有组件标签和状态声明。它还能使用条件、循环及事件处理器,所以它并非只是一份静态组件清单。
专用格式的一项关键价值是适应逐 token 生成。输出经常停在半个标签或未完成的表达式中;编译器需要保留已经完整的内容,临时舍弃不完整语句,并给可恢复的元素补上闭合结构。这样用户可以边等边看,界面不必等整篇回答结束才出现。
3. 服务端编译:把生成内容变成可运行的协议
客户端收到的不是直接照抄执行的原始 DIL。作者发现,服务端把它编译成
JavaScript 程序,并配上保存文字、工具数据等内容的 JSON,存放在消息的
model_dil_v2 元数据中。
编译阶段主要解决五件事:
- 转换结构。 Markdown 和组件标签进入同一棵树,标签被转换成运行时函数调用。
- 隔离局部错误。 表达式有异常保护,某个表达式抛错时,相关内容可以消失,避免整张界面一起失败。
- 分离文字和程序。 静态文字移入常量表。只有文字增长时,可以更新常量,减少程序结构变化。
- 赋予状态稳定的 key。 新版本程序不断到达时,运行时能找回同一个状态槽位,保留用户已经调整的值。
- 修复和校验。 处理半成品语法,并依据组件 schema 移除不存在的属性或类型不正确的字面量,记录诊断信息。
这也是“能渲染”和“逻辑正确”的分界:校验可以发现属性类型错误,却无法保证模型写出的报价、统计或条件判断符合业务含义。
4. 客户端:运行逻辑与绘制界面分开
作者观察到,Web 端通过隐藏的 iframe 启动 Web Worker。运行时会限制生成程序可接触的全局能力,包含网络、计时器和动态求值等,并设有超时监控;程序无响应时会被隔离,Worker 会重启。
这里有个容易误读的细节:详细版同时提到运行时内部使用
new Function
求值。限制的是生成程序可使用的环境能力,不能简单概括成“整个实现没有动态执行
JavaScript”。
Worker 负责执行程序、保存状态、生成界面树,再与旧树比较,输出操作列表。主页面负责把这些操作映射到 ChatGPT 组件。Worker 本身不直接绘制页面。
事件处理函数也不直接跨出 Worker,而是以标识符传递。用户拖动滑块时,页面把处理器标识和参数送回 Worker;Worker 更新人数、重算价格,再返回界面更新操作。
拖动滑块 → 事件送到 Worker → 更新状态与计算 → 返回 UI 操作 |
整个过程可以不调用模型。因此,界面上的每一次点击,并不都意味着一次新的推理请求。
5. 流式 UI 的难点:半成品、状态和异步数据
文本流通常只需追加字符。界面流还要回答三个问题:程序没写完怎么办,用户已经改过的输入怎么办,图片等数据稍后才到怎么办。
作者观察到的方式是通过 SSE 给结构化消息发送类似 JSON Patch 的更新,在同一条消息里维护原始 DIL、编译程序、文字常量和外部数据。
详细版指出,观察到的服务端会反复编译目前已生成的全部源内容,而不是采用真正的增量编译。传输时则有不同情况:
| 生成进展 | 界面更新方式 |
|---|---|
| 组件结构改变 | 替换整个编译程序 |
| 只有文字增长 | 可以只更新常量 |
| 仍在未完成标签内部 | 原始文本继续增长,界面暂时不变 |
| 图片搜索完成 | 单独补入数据 |
客户端用新程序重新计算界面,同时通过稳定 key 保留已有状态。如果新程序执行失败,就继续显示最后一个成功版本。
代价是重复传输。作者的一次样本包含 6,341 个字符,文本流持续 18.7 秒,总计 84 次更新;约 275 KB 的补丁数据中,83% 是重复发送的编译程序。这是单次抓包结果,不能当作所有回答的平均成本。
淡入、滑入、图表绘制与容器高度过渡,则让这些离散更新看起来更连贯。
6. 数据与动作:哪些事交给模型,哪些交给宿主
详细版补充了短帖里容易忽略的数据通道。
对于部分图片组件,模型只描述要找什么图片。标签完整后,由服务端搜索、检查 URL,再把结果放入响应数据。对于部分商品信息,模型可以引用工具结果 ID 对应的价格、商家等字段,服务端提供真实字段值,避免让模型重新抄写。
这能减少某些复制错误,但不代表所有数据都绕过模型。作者也观察到,部分天气数据仍由模型写进回答;图片搜索也可能找错,而且模型未必看到最终图片。
动作则通过宿主提供的有限接口执行,例如复制文字、打开链接、查看实体,以及
issueNewTurn。
其中 issueNewTurn
用于把界面里的选择组织成一条新用户消息。例如用户先选风格和颜色,再按按钮,程序把这些值写入消息,让模型继续生成。
本地状态不会自动成为模型上下文。 按作者观察,模型看到的是动作提交的文本;如果没有把相关状态放进去,模型就不知道用户刚刚选了什么。后续回答也会生成新界面,而非直接修改原来那张界面。
7. 组件目录之外,还有 AppBlock
常规回答受组件目录约束。作者在客户端注册表中找到约 70 个组件,其中 39 个出现在抓取样本里;这是当时版本与样本的统计。
预定义组件让样式更统一,也给属性校验提供明确边界。但鼓机、音频合成等需求可能超出组件能力。
对此,作者观察到 AppBlock 路径:模型可以生成包含 HTML、CSS 和 JavaScript 的独立小应用,由独立域名上的可见 iframe 承载。它使用另一套宿主机制,通过基础样式、主题变量和尺寸适配融入聊天页面。
所以原帖“模型不写原始代码”的简述需要加上范围:常规 Intelligent UI 组件路径使用 DIL;AppBlock 允许生成完整网页代码。 DIL 自身也包含 JavaScript 逻辑。
8. 作者披露的局限
这套方案把生成界面拆成了清晰的层次,但详细版没有回避实际问题:
- 刷新可能丢失状态。 流式重编译期间保留状态,不等于刷新后能够恢复。
- 模型不自动感知界面状态。 需要明确提交给下一轮对话。
- 交互操作仍有冗余。 一次定价控件点击产生 158 个操作,其中只有 4 个带来实际变化。
- 运行成功不代表计算正确。 作者展示过切换图表指标后金额异常变化的例子;错误表达式也可能静默消失。
- Markdown 降级会损失信息。 服务端提供
fallbackMarkdown,但交互部分会静态化,部分计算内容和循环内容没有出现在降级结果中。 - 布局与图片仍可能出错。 样本里存在固定列数、固定像素宽度和图片检索偏差。
这些都是作者对当时样本的观察,不能据此认定每个版本、每种界面都有同样问题。
9. 工程解读:做自己的生成式 UI,可以借鉴什么
以下是基于原文的工程判断。
这篇分析最有价值的地方,是把生成式 UI 拆成了可设计、可测试的责任边界:模型负责组合表达,编译器负责格式恢复和校验,运行时负责状态与计算,宿主负责绘制、数据和外部动作。
如果用在旅行规划里,可以让模型选择地图、地点卡片和偏好表单;把删除地点、切换选项等操作留在本地;在用户点击“重新规划”时,再明确提交当前行程和约束。价格、地址等关键字段尽量绑定工具结果,同时为计算结果加入业务校验。
这里尤其要区分三个层次:流式生成时状态不丢、刷新后状态可恢复、下一轮模型知道当前状态。它们需要分别实现,不能由一个状态 key 自动解决。
Thesys 还发布了 Open Intelligent UI,用 OpenUI 和自定义旅行组件实现类似的地图、图片、可编辑行程体验。它可以作为公开参考,但使用自己的 OpenUI Lang 与组件系统,不能视为 ChatGPT 内部协议的完整复制。
该仓库当前示例依赖 OpenUI Gateway 和服务端密钥,包含图片搜索等在线服务。接入本地模型需要另行调整推理和数据通路,“界面框架可以接不同模型”并不意味着这个示例已经完全离线运行。
对应用开发者来说,值得带走的是这套分工,以及对状态、工具数据、错误恢复和宿主动作的明确约定。把这些约定做好,生成出来的界面才有机会从一次漂亮演示变成可持续使用的产品能力。
来源
- Rabi Shanker Guha 的原帖与 X 长文
- Thesys Engineering Team:How ChatGPT Intelligent UI works,2026-10-08,本文技术细节的主要来源。
- Open Intelligent UI 源码与 README,用于核对开源示例的实现方式与依赖。