2月10号整理论文笔记时,翻到一篇让我反复停下来琢磨的工作:Code2World: A GUI World Model via Renderable Code Generation。我关心的不是“又一个前端代码生成模型”,而是它把 SFT 和 RARL 串在一条技术路线上,用“可渲染代码”去表达 GUI 世界模型。这个角度比较反直觉,也恰恰解释了为什么很多 GUI Agent 项目做到后面越来越别扭——我们一直在用图像或者 DOM 去描述界面,却很少想过,GUI 也许更适合被当作一种可以由代码生成和推演的状态机。
这篇文章不是论文复现报告,更像是我在阅读过程中形成的结构化笔记,加上自己拿内部系统页面做单步验证时的一些体会。如果你是做 GUI Agent、UI 自动化、前端智能生成或者多模态 LLM 应用的,里面关于状态表示、SFT 数据构建、对抗强化学习奖励设计的内容应该会有启发。如果你刚接触这块,我也会把基础概念揉进讲解里,尽量不让你因为一个术语卡住。
1. “GUI 世界模型”到底在解决什么样的问题
1.1 界面自动化为什么总是笨手笨脚
在做 GUI 自动化或者 GUI Agent 的时候,最核心的问题不是模型会不会写代码,而是它能不能“理解”界面变化。传统做法大致有两类:一类是截图加目标检测,模型把界面当成一张像素图;另一类是用可访问性树或 DOM,模型把界面当成一棵结构树。两类做法都有明显短板。截图像素级的信息太底层,模型分析下拉菜单时得推理几百个 patch 之间的关系。DOM 虽然结构性强,但信息量极大且冗杂,真实页面里动不动十几层嵌套,还可能包含大量脚本注入的无关节点。
Code2World 的出发点我理解是这个:与其让模型去理解图像或者裸 DOM,不如把 GUI 状态压缩成一段“可渲染代码”。模型输入当前状态和一个动作,输出的是动作之后的可执行界面代码。这个代码既能被渲染成新截图,也能被结构化检查,还能告诉研究者模型内部到底认为界面发生了什么变化。界面自动化因此有了一个可解释的中间状态,而不是黑盒猜测。
拿一个很常见的交互举例:点击“筛选”按钮后弹出下拉面板。截图视角里这是像素大面积变化;DOM 视角里这是某节点 style 或者 class 被改掉。但如果你把界面状态表达为代码,变化就是一段非常清晰的属性更新:按钮的 aria-expanded 从 false 变 true,面板的 visible 状态翻转。模型生成这段代码之后,你甚至可以直接比较两段代码差异来判断行为是否符合预期。
1.2 世界模型这个抽象对 Agent 意味着什么
“World Model”这个说法在强化学习里已经很常见,意思是让智能体拥有一套对环境的内部模拟器。真实环境交互成本高,如果模型能预测“我做了动作 A 之后世界会变成什么样”,那就可以在内部做规划,减少试错。GUI World Model 就是把这套思路搬到界面环境里,让 Agent 能预测“点击之后界面变成什么代码状态”。
关键点在于代码状态是机器可校验的。你不需要从截图去猜测界面里是不是出现了一个 toast,只需要检查生成代码里有无对应组件以及它的可见状态。这种可校验性,把“生成得看起来像”升级成“生成得行为一致”。如果你做过 GUI Agent 的评估,就知道这一点有多重要——很多模型能把界面画得很像,但点起来完全不是那么回事。可渲染代码给了一个折中:它仍然是生成式输出,但输出必须服从目标界面的语法、结构和可执行约束,模型不能靠模糊的像素分布蒙混过关。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 为什么状态一定要“渲染成代码”,而不是继续用图像或 DOM
2.1 图像、DOM 与可渲染代码的对比
很多工作尝试直接用截图作为 GUI 状态,但图像输入有几个硬伤。第一是 token 开销太大,Transformer 处理高分辨率截图时,视觉 patch 数量会迅速爆炸,一个 1440x900 的界面切分成 patch 后很长。第二是图像难以表达精确的交互状态,比如按钮是否 disabled、文本框当前的 value,这些在图像上几乎无法可靠判断。第三是截图没法稳定参与因果推理,界面变化反映在像素上是连续的,但真实的前端状态变化是离散的。
DOM 或可访问性树解决了一部分问题,具备天然的结构性,但也不是为生成模型设计的。一个生产级页面的 DOM 可能有上千个节点,很多节点与视觉表现无关,比如埋点节点、脚本标签、隐藏辅助节点。模型如果直接
