← 博客
团队手记阅读约 9 分钟

GenUI 中的粒度问题:LLM 生成应该在哪里停止?

构建 AirJelly GenUI 引擎的笔记——以及为什么给 LLM 更多自由反而让结果变差。

Translated by AI

这篇博客来自我们在 AirJelly 项目中对 GenUI 引擎的亲身探索。我们并非从理论出发,而是从一个说实话相当令人沮丧的实验开始:为什么当我们给 LLM 更多生成 UI 的自由时,结果反而变差了?

01 · 背景

为什么 GenUI 值得认真对待

在深入细节之前,有必要明确为什么 GenUI 是一个严肃的工程问题,而不只是一个演示花招。在Generative Interfaces for Language Models中,SALT-NLP / Stanford 团队比较了用户对 GenUI 和传统基于文本的聊天之间的偏好。结论很明确:当 AI 系统需要传达结构化的、信息密集的内容时,动态生成的界面可以远远优于一大段文字。

GenUI 浪潮在 2023 到 2025 年间加速,因为两个条件同时成熟了:LLM 在代码生成方面变得强得多,而像 shadcn/ui 和 Radix 这样的组件生态也变得足够稳定,可以在此基础上构建。一旦这些条件到位,工具自然涌现——Vercel v0 是最具代表性的行业实现之一。

02 · 起点

我们让 LLM 自由发挥,结果却变差了

在feat/genui-real-content-experiment分支上,我们进行了一组对比。旧方案有固定布局和统一组件——精致且可预测。新方案让布局更灵活,但视觉变得杂乱,组件样式也不一致。

这与我们的直觉相悖。我们给模型的自由越多,我们的控制就越少,视觉一致性也越差。Gen-UI-Lang 论文也提出了同样的观点:让 LLM 输出原始 HTML 或 JSX,输出会冗长、脆弱且容易出错。这不是提示词质量的问题——而是意味着我们把 LLM 推到了一个它并非处于最佳状态的粒度。

03 · 核心矛盾

GenUI 中的结构性矛盾

通过实验,我们发现了一个几乎适用于所有 GenUI 系统的内在矛盾。

LLM 拥有的自由越多,就越难保证视觉一致性。约束越强,GenUI 就越失去意义。

这是范式中的结构性张力,而不是某个实现中的缺陷。每个 GenUI 系统都必须在这两股力量之间的某处找到立足点。于是问题变得非常具体:LLM 的生成边界应该停在哪里?

04 · 领域现状

现有的粒度选择

在确定我们自己的答案之前,先看看其他人是如何处理同一个问题的,这会有所帮助。

Vercel v0——一直生成到组件代码

v0让 LLM 一路向下,生成完整的 React 组件代码。它的视觉一致性来自shadcn/ui的语义令牌系统——它把一致性外包给了库的主题。代价是:生成逻辑与组件生态紧密耦合,因此脱离 shadcn/ui + Next.js + Vercel 技术栈会产生真正的摩擦。

v0 风格组件代码的典型形态
<Card className={cn("flex flex-col",
  plan.recommended && "border-primary shadow-lg scale-105"
)}>

arXiv 方法——结构化中间表示

SALT-NLP / Stanford 的方法在自然语言和 UI 代码之间插入了一个结构化中间表示,分为两个层级:高层交互流程(用户路径和任务阶段的有向图)和底层有限状态机(每个组件的状态和事件响应)。最终输出仍然是 HTML、CSS 和 JavaScript——该表示是护栏,而不是终点。

Gen-UI-Lang——定义 UI 意图层

Gen-UI-Lang设计了一种专用 DSL,让 LLM 只输出结构化节点描述。节点结构明确、浅层且一致——正是 LLM 能够可靠生成的内容。与直接生成 HTML 相比,它报告token 使用量减少了 65.3%,同时提升了稳定性,并且可以从同一份描述渲染为 HTML、React JSX 或 Gradio。

Gen-UI-Lang UI 意图描述
genui(
  row(
    text("Sales Overview"),
    btn("Load", on_load=lambda: get_graph(2001, 2002))
  ),
  chart(type="line", data="sales_q4"),
)
05 · 我们的选择

止步于产品语义层

这三种方法都把 LLM 向上推,远离渲染层。它们只是在停止的位置上有所不同。我们选择比它们都停得更高:停产品语义层。

LLM 不输出像row或btn这样的通用 UI 节点。它输出产品概念——“这是一张任务摘要卡片,信息密度高,来源于今天的日历。”渲染哪个组件,以及如何布局,完全由组件库决定——而不是 LLM。

01失败案例带来的直接教训

一旦我们放松 LLM 的生成自由,视觉结果就变差了。LLM 越接近渲染层,其随机性的代价就越高。

02与浏览器渲染引擎的类比

浏览器不让页面 JavaScript 直接控制像素。它们接受受控的 DOM 描述,由引擎决定像素。GenUI 引擎也应该以同样的方式工作。

03结构化 LLM 输出的可靠性

OpenAI 在 2024 年推出 Structured Outputs,正是为了对抗格式漂移。输出越接近渲染层,格式错误的代价就越高。

04对可替换组件库的长期需求

止步于产品语义层,组件库就变成了可插拔的渲染后端——明天就能更换设计系统,而无需触碰语义层。

06 · 一个未经验证的方向

两轮生成

在调试复杂的GenUIPager组件时,我们发现单次 LLM 处理难以同时优化内容质量和布局质量。这引导我们走向两轮架构——作为一个假设。

两轮生成假设
First-round LLM:  content orchestration + page-structure decisions
                  (product semantics layer)
      ↓
Second-round LLM / component library:  concrete rendering decisions

动机是合理的:内容编排和渲染是两种不同的认知任务,强行将它们塞进单次处理可能会让它们相互干扰。

但我们必须诚实:这只是一个假设,我们还没有完全验证它。

它出现在这里,是因为它指向一个值得探索的方向——而不是因为它是一个已确定的结论。

07 · 地图

粒度选择的权衡地图

没有哪种粒度选择是普遍正确的。它取决于产品对视觉不一致的容忍度、组件库的预期生命周期,以及生成内容的结构化程度。

方法LLM 输出到如何保证一致性库可替换?适用场景
Vercel v0组件代码层shadcn/ui 语义令牌否,紧密耦合Vercel 生态内的快速原型开发
Gen-UI-Lang通用 UI 意图层多目标渲染器是,框架无关跨框架原型开发、效率优先的工作流
arXiv 方法HTML / CSS / JS结构化中间表示作为护栏视情况而定交互复杂度高的场景
AirJelly产品语义层组件库完全掌控渲染是,可插拔对产品 UI 一致性要求高的应用

如果产品对视觉不一致的容忍度低,粒度就应该更高,更接近产品语义。如果组件库可能演进或被替换,粒度也应更高。而如果生成内容高度结构化,就更适合在更高层级上以语义方式描述它。

来源

来源与延伸阅读

结语

粒度是 GenUI 的核心设计决策。

最大的收获并不是我们找到了正确答案,而是我们厘清了问题本身:GenUI 并不是让 LLM 来绘制界面,而是要在 LLM 与渲染系统之间设计出清晰的职责划分。

粒度的选择决定了这条线画在哪里——而这条线画在哪里,又决定了系统的可维护性、视觉稳定性以及长期演进的能力。

2025 年 10 月,W3C 设计令牌社区组发布了稳定的 Design Tokens 2025.10 规范——这标志着将语义与视觉分离正在成为一项工程标准。GenUI 中的粒度问题,正是这一趋势在 AI 生成界面内部的体现。

我们仍在路上。如果你也在探索类似的方向,我很乐意交流。

更多来自 AirJelly 团队的内容 →