本文是「Agent 工程实战」系列的第 14 篇,属于界面线。
系列索引(21 篇阅读路线):Agent 放权前,先补权限、出站、发现这三道口子
摘要:OpenAI 发完 Intelligent UI 的当天晚上,我在本地沙箱里搭了个模拟器,让 AI 生成一个"销售运营日报"页面。结果它把「今日销售额」排到了第 6 位,导出报表按钮放在最后一个。功能全对——数据都有、组件类型也都对——但页面就是没法用。复盘走完现象、定位、根因、修复、边界五步,根因收敛为"渐进生成机制先到先得,模型没有全局信息架构规划",对应官方自己承认的"设计判断力还在提升路上"。
文章目录
- 一、现象:报表出来了,但没人会用
- 二、定位:光靠眼看不够,我写了条校验脚本
- 三、根因:局部全对,全局全错
- 四、修复:先规划,再用验收清单兜底
- 五、边界:这套东西的限制
- 总结
- 参考资料
OpenAI 发布 Intelligent UI 的当晚,我在本地沙箱里搭了个界面生成的模拟器,想看看这套"AI 自己画界面"的机制到底靠不靠谱。结果第一轮就翻车了,翻得还挺典型。
先说清楚口径:官方这套能力没开放 API,我接不到真的。所以我用本地能跑的通用大模型,模拟了它的机制——组件库、渐进生成、先到先得。模拟的是机制,不是 OpenAI 的组件库,这个区别很关键。
为什么这样模拟能说明问题?因为 Intelligent UI 的核心机制是"组件库 + 生成顺序决定渲染顺序",我用同样的机制约束(先到先得、位置不可回改)去跑通用模型,测的就是机制本身会不会导致信息架构失控——顺序问题是机制问题,跟具体模型关系不大,OpenAI 自己也承认设计判断力还在提升路上。环境是 Node 25.8.2,模型用的 deepseek-v4-flash(OpenAI 兼容接口的通用大模型)。
一、现象:报表出来了,但没人会用
任务很简单:让 AI 给"销售运营日报"页面生成组件树。我给了它 21 个数据字段,要求按顺序输出组件,位置确定后不能改——这模拟的就是渐进渲染的"先到先得",先输出的组件先显示在页面顶部。这个机制画出来就是这样:
模型"先到先得"式生成: 想到什么先画什么 ──► 生成顺序 = 显示顺序 ┌────────┬────────┬──────┬────────┐ │ 区域图 │ 品类图 │ 商品明细 │ 缺货列表 │ …… └────────┴────────┴──────┴────────┘ 字段表靠前,先生成 …… ┌────────────┐ │ 今日销售额 │ ← 核心指标被埋到第 6 位 └────────────┘ …… ┌────────────┐ │ 导出报表 │ ← 操作按钮在最后一位 └────────────┘它生成完,我对着组件顺序看了半天,说不出哪里错——数据都在、类型也对——但就是觉得这页面没法用。直到我把顺序列出来:
| 位置 | 组件 | 内容 |
|---|---|---|
| 1-3 | chart ×3 | 各区域/品类/渠道销售额 |
| 4-5 | table ×2 | 在售商品明细、缺货商品列表 |
| 6 | metricCard | 今日销售额 |
| 7-13 | metricCard ×7 | 昨日销售额、订单量、转化率、客单价…… |
| 14-17 | chart+table | 各时段趋势、待发货、已发货、售后记录 |
| 18-20 | metricCard ×3 | 优惠券核销数、会员新增数、复购率 |
| 21 | button | 导出报表 |
看明白问题了吗。一个销售日报,最先该让运营看到的"今日销售额"被排到了第 6 位,前面全是区域、品类、渠道的拆分图和商品明细。而导出报表——这种页面最常见的操作——被放在了最后一个位置,运营要导个数据得一路滚到底。
功能全对,信息架构全反。
二、定位:光靠眼看不够,我写了条校验脚本
"觉得不好用"是感觉,要被 AI 生成界面的流程接受,得能自动化判断。我按自己多年做后台的经验,把"好的销售日报"拆成了 5 条校验规则:
- R1 核心指标(销售额/订单/转化)必须在组件序列前 3 位
- R2 趋势类数据必须用图表
- R3 明细类数据必须用表格
- R4 导出/刷新按钮必须出现在序列前半段
- R5 销售/订单/转化核心信息至少覆盖 2 项
规则是数据,脚本就能跑。核心就一段:
// 对 AI 生成的组件序列做信息架构校验constkpiIdx=items.findIndex(it=>["kpiSummary","metricCard"].includes(it.type)&&/销售|GMV|营收|订单|转化|客单|总额/.test(it.title+" "+(it.desc||"")));// R1:核心指标必须在前3位r1=kpiIdx!==-1&&kpiIdx<3;// R4:导出/刷新按钮要在序列前50%constbtnIdx=items.findIndex(it=>it.type==="button"&&/导出|刷新|下载/.test(it.title));r4=btnIdx!==-1&&btnIdx<items.length/2;为什么要看这段:这不是业务代码,是"把人工经验固化成机器规则"的示范——你想让 AI 生成的界面可控,前提就是把这些判断写成脚本。跑一遍,第一轮结果:
校验 3/5 FAIL R1 核心指标前置(KPI 在前3位): 核心指标「今日销售额」出现在第 6 位 PASS R2 趋势数据用图表: 趋势类组件 1 个,其中 0 个未用图表 PASS R3 明细用表格: 明细类组件 5 个,其中 0 个未用表格 FAIL R4 导出/刷新操作可见(前50%): 导出按钮出现在第 21 位(总 21 个) PASS R5 核心业务信息完整: 覆盖 3/3(销售 true 订单 true 转化 true)3/5,两个 Fatal 级问题被揪出来了。注意一个细节:R2、R3、R5 全过——单个组件它选得都对,趋势用了图、明细用了表、数据也没漏。
三、根因:局部全对,全局全错
这是整件事最值得琢磨的地方:为什么 AI 单组件全对、整体编排全错?我的判断是两件事叠在一起。
第一,渐进生成机制的"先到先得"。它是一次性按顺序输出的,先输出的先显示。但模型没有在生成前做"全局信息架构规划"——它基本是照着后台字段表的顺序(区域、品类、渠道排在最前面)+ 自己想到什么先画什么,一路往下排。核心指标恰好不在字段表前面,就被埋到了第 6 位。生成顺序决定显示顺序,而模型把"生成顺序"当成了"重要性顺序"——这是这个机制最坑人的地方。
第二,设计判断力不足。OpenAI 自己在发布文里承认了:“There’s still work ahead to improve the model’s design judgment.”(模型的设计判断力还有提升空间。)单组件是什么、用什么类型,模型已经学得不错;但"整个页面哪个信息最重要、用户会先看什么、下一步操作在哪"这种整体判断,它还没形成。这跟 AI 写代码翻车是同一个模式——局部正确、全局错误。我之前在代码上下文那篇里也说过类似的话。
三种模式摆在一起,核心指标和导出按钮的位置变化一目了然:
模式一:直接渐进生成(翻车) 组件数 21,得分 3/5 ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬─────┐ │区域│品类│渠道│明细│缺货│★今日│昨日│订单│转化│客单│… │… │… │趋势│待发│已发│售后│券核│会员│复购│导出 │ │图 │图 │图 │表 │表 │销售额│销售│量 │率 │价 │ │ │ │图 │货 │货 │记录│销 │新增│率 │报表 │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴─────┘ 位置: 1 2 3 4 5 6 7 8 9 10 … … … … … … … … … … 21 ▲ 核心指标埋在第6位 ▲ 导出按钮在最后一位 模式二:先生成规划再生成 组件数 9,得分 2/5 ┌──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┐ │★核心 │区域图 │品类图 │渠道图 │明细表 │缺货表 │趋势图 │待发货 │售后记录│ │指标总览│ │ │ │ │ │ │ │ │ └──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┘ 位置: 1 2 3 4 5 6 7 8 9 ▲ 核心指标提到第1位 ✗ 导出按钮:规划里直接漏了,不存在 模式三:规划 + 验收清单 组件数 11,得分 4/5 ┌──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┐ │★核心 │区域图 │品类图 │导出 │渠道图 │明细表 │缺货表 │趋势图 │待发货 │售后记录│异常预警│ │指标总览│ │ │报表 │ │ │ │ │ │ │列表 │ └──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┘ 位置: 1 2 3 4 5 6 7 8 9 10 11 ▲ 核心指标第1位 ▲ 导出按钮第4位(前50%内)一眼就能看出修复路径:核心指标从第 6 位提到第 1 位,导出按钮从第 21 位(或直接消失)提到第 4 位——规划把核心指标顶到最前,验收清单把导出按钮从"漏掉"变成"可见"。
四、修复:先规划,再用验收清单兜底
知道了根因,修复方向就很明确:让它在生成之前先规划信息架构,再用验收清单兜底。我试了两个版本。
第一版,只加"先生成信息架构规划再生成":先让模型输出页面的区块规划(从上到下排优先级),再按规划生成组件。核心指标确实提到了第 1 位——但翻车换了个姿势:规划里根本没有导出按钮,直接漏了。校验 2/5,R4 反而从"太靠后"变成"不存在"。
第二版,规划之外再把验收清单写进生成约束:核心指标前 3 位、趋势用图表、明细用表格、必须包含导出按钮且在前半段、信息覆盖至少 2 项。这一轮:
把这两步串成一段可运行的伪代码,流程就清楚了——先让模型输出区块优先级规划,再按规划生成组件,最后用验收清单兜底:
// ========== 第一步:定义"规划 prompt"模板 ==========// 关键:让模型在生成组件之前,先输出"从上到下的区块优先级列表",// 把"重要性顺序"显式地交给模型,而不是让它边生成边想。constPLAN_PROMPT=`你是销售运营日报的信息架构师。 请先输出页面区块的优先级列表(从上到下,最重要的排最前), 只输出区块名,不要生成具体组件。字段如下:${FIELDS.join(", ")}要求:核心指标(销售额/订单/转化)必须排在前 3 位; 导出/刷新按钮必须出现在序列前半段。`;// ========== 第二步:定义验收规则数组(R1-R5) ==========// 规则是数据,脚本就能跑——这正是"把人工经验固化成机器规则"。constRULES=[{id:"R1",desc:"核心指标前置",check:items=>kpiIdx(items)!==-1&&kpiIdx(items)<3},{id:"R2",desc:"趋势用图表",check:items=>trendItems(items).every(it=>it.type==="chart")},{id:"R3",desc:"明细用表格",check:items=>detailItems(items).every(it=>it.type==="table")},{id:"R4",desc:"导出按钮可见",check:items=>btnIdx(items)!==-1&&btnIdx(items)<items.length/2},{id:"R5",desc:"核心信息覆盖",check:items=>coveredCount(items)>=2},];// ========== 第三步:规划 → 生成 → 验收,串成完整流程 ==========asyncfunctiongenerateWithPlanAndCheck(){// 1) 先生成"区块优先级规划",而不是直接生成组件constplan=awaitcallModel(PLAN_PROMPT);// 例:["核心指标总览", "区域图", "品类图", "导出报表", ...]// 2) 按规划顺序生成组件序列(规划里漏了导出按钮?这里就会暴露)constitems=awaitcallModel(`按以下区块规划生成组件:${plan.join(" > ")},位置确定后不可回改。`);// 3) 用验收清单兜底:逐条跑 R1-R5,输出通过/失败constreport=RULES.map(r=>({id:r.id,pass:r.check(items)}));constscore=report.filter(r=>r.pass).length;// 例:4/5// 4) 有 Fatal 级失败(如 R1/R4)就重规划重生成,而不是直接交付if(report.some(r=>(r.id==="R1"||r.id==="R4")&&!r.pass)){returnregenerateWithPlan(plan,report);// 把失败项写回 prompt 再跑一轮}return{items,score,report};}这段代码把「规划定方向、验收兜底线」落成了可执行流程:规划 prompt 负责把核心指标顶到最前,验收规则数组负责把导出按钮从"漏掉"变成"可见",两者缺一不可。
校验 4/5 PASS R1 核心指标前置: 核心指标「核心业绩指标总览」出现在第 1 位 FAIL R2 趋势数据用图表: 趋势类组件 2 个,其中 1 个未用图表 PASS R3 明细用表格: 明细类组件 1 个,其中 0 个未用表格 PASS R4 导出/刷新操作可见: 导出按钮出现在第 4 位(总 11 个) PASS R5 核心业务信息完整: 覆盖 3/3三个模式摆一起看:
| 模式 | 组件数 | R1核心前置 | R4操作可见 | 得分 |
|---|---|---|---|---|
| 直接渐进生成(翻车) | 21 | FAIL 第6位 | FAIL 第21位 | 3/5 |
| 先生成规划再生成 | 9 | PASS 第1位 | FAIL 找不到 | 2/5 |
| 规划+验收清单 | 11 | PASS 第1位 | PASS 第4位 | 4/5 |
结论很清楚:光有规划不够——模型规划时可能自己漏掉关键东西;光有验收清单不够——生成完再纠错成本高。规划定方向,验收兜底线,两个一起才是完整修复。
五、边界:这套东西的限制
有几个点得说清楚,免得有人照着做踩坑。验收规则是我按自己团队的业务经验拍的,不是官方标准。不同团队的报表信息架构不一样——有的团队就是先看明细再看汇总,那 R1 就不适用。规则本身要按业务校准,第二版那个 4/5 里唯一没过的 R2,其实是规则边缘误判:一个"异常预警列表"用表格展示是合理的,但规则把它当趋势类数据误判了。这说明规则要留白,不能机械。
针对这类误判,更通用的做法是给规则加组件类型白名单/黑名单:白名单声明"哪些组件类型天然豁免某条规则",黑名单声明"哪些组件类型绝不适用某条规则"。比如 R2 的本意是"趋势类数据要可视化",但"异常预警列表"本质是明细枚举,用表格反而更清晰——那就给 R2 加一条"表格类型豁免":
// R2 增加"表格类型豁免":趋势类数据若用表格承载,且标题命中豁免词,则跳过校验constR2_EXEMPT_TITLES=/异常|预警|告警|清单|列表/;// 黑名单:这些语义用表格合理constr2=trendItems(items).every(it=>it.type==="chart"||// 用图表,通过(it.type==="table"&&R2_EXEMPT_TITLES.test(it.title))// 表格+豁免词,跳过);这样规则就从"一刀切必须用图表"变成"图表优先、表格可豁免",误判自然消失——规则要能自我校准,而不是靠人肉改 prompt。
模型生成有随机性。我同一个任务跑过两轮,组件顺序不完全一样——正因为这样,验收兜底才必须是生成流程的一部分,不能指望"它上次排对了"。
最后还是口径:这是本地沙箱用通用大模型模拟的机制演练,不是 OpenAI Intelligent UI 的真实输出。我验证的是"生成顺序 → 信息架构"这一层——组件树的顺序就是界面的信息架构,这一层在文本输出阶段就能暴露。真实界面还有布局、视觉、交互细节这些层,要等官方 API 开放后才能实测,但"渐进生成先到先得 + 设计判断力不足"这个翻车模式,大概率还是存在的。
总结
这次演练给我最大的收获不是"AI 会翻车"——这个早就知道了。而是翻车的形态变了:以前是代码逻辑错、数据错,现在是界面编排错。功能全对,但没人会用,这种错最隐蔽,因为看起来什么都对。
AI 生成界面要真正可用,前端的工作就多了一层:把"好不好用"翻译成可执行的验收规则,让 AI 生成完自己过一遍。这活儿,跟代码 review 是一回事,只是对象从代码换成了界面。
参考资料
- OpenAI 发布文:GPT-6 for Everyone —— Intelligent UI 能力官方介绍,文中引用了官方对设计判断力的表述。
- OpenAI Intelligent UI 官方文档 —— 官方 API 与组件库说明,待能力开放后可对照实测。
- OpenAI 官方博客 —— 追踪 Intelligent UI 及后续设计能力更新的第一手来源。
「Agent 工程实战」系列
- 路线:界面线(computer use / Agent UI)
- 上一篇:13 GPT-6 自己画界面
- 系列索引(21 篇阅读路线):Agent 放权前,先补权限、出站、发现这三道口子
- 专栏:Agent 工程实战
- 如果这篇对你有用,欢迎收藏;想追更可以关注「Agent 工程实战」专栏。