1. 设计到代码的闭环为什么突然成了焦点
1.1 从“切图仔”到“Agent 编排者”的角色转变
做了七八年设计工具链相关的工作,我最大的感受是:设计稿和代码之间的那道墙,从来不是靠某一个工具推倒的,而是靠工作流的重构慢慢磨掉的。早些年我们讲“设计规范落地”,本质上还是人肉翻译——设计师出稿,前端照着量、照着切、照着还原,中间靠标注工具和口头沟通补位。后来出现了设计令牌(Design Token)和组件库同步的方案,算是把“样式”这一层做了半自动化,但布局逻辑、交互状态、响应式规则这些真正吃时间的东西,依然得靠人写。
现在的情况变了。大模型驱动的代码生成能力成熟之后,整个链路的重心从“怎么把样式搬过去”变成了“怎么让 Agent 理解设计意图并自主完成实现”。这就是标题里说的“设计-代码闭环”——它不是单向的导出,而是一个可以来回校验、自动修正的循环。设计侧改一个间距,代码侧能感知;代码侧发现某个断点下布局塌了,设计侧能收到反馈。听起来像科幻,但拆开看,每一步都有对应的技术支撑。
我之所以关注这个方向,是因为它直接决定了一件事:前端工程师和设计师的协作模式会被重新定义。以前是“你设计我实现”,以后是“我定义规则,Agent 执行,我验收”。这个转变对个人能力的要求不是降低了,而是转移了——从写样式的手速,转移到对设计系统、组件契约、生成约束的理解深度上。
1.2 为什么是现在:三个前提条件同时成熟
这个闭环能在这个时间点被拿出来讨论,不是偶然。我梳理了一下,至少有三个条件同时到位了。
第一个是设计工具的结构化程度足够高。以 Figma 为代表的工具,早就不是单纯的矢量绘图软件了。它的底层数据模型里有完整的节点树、样式引用、组件实例、变体(Variant)和自动布局(Auto Layout)信息。这些东西如果只是给人看,那它就是一张图;但如果给程序读,它就是一份结构化的 UI 描述文件。自动布局尤其关键,它把“间距”“对齐”“填充”这些原本靠肉眼判断的东西,变成了明确的约束关系,Agent 可以直接解析成 Flexbox 或 Grid 的配置。
第二个是代码生成模型对 UI 语义的理解能力上来了。早期的代码生成基本是模板填充,你给它一个按钮的截图,它给你一段写死宽高的 div。现在不一样了,模型能识别出“这是一个带图标的次要按钮,处于禁用态”,然后生成符合组件库规范的代码。这个进步的核心不在于模型参数变大了,而在于训练数据里有了大量“设计稿-代码”的配对样本,以及模型对设计系统语义的建模能力。
第三个是Agent 框架让“闭环”有了执行主体。单纯的代码生成只是一次性动作,闭环需要有人去比对、去发现差异、去决定下一步改哪里。Agent 的价值就在这里:它可以拿着设计稿的预期结果和代码的实际渲染结果做对比,定位差异,然后自主决定是调整样式、修改结构还是反馈给设计侧。这个“感知-决策-执行”的循环,才是闭环的真正含义。
注意:这里说的 Agent 不是指某个具体产品,而是一种架构模式。任何能完成“读取设计数据、生成代码、渲染验证、比对差异、迭代修正”这一串动作的系统,都可以叫设计-代码闭环 Agent。
2. 拆解闭环的核心环节:从设计数据到可运行代码
2.1 设计数据的结构化提取:不只是导出 JSON
很多人以为把 Figma 文件导出成 JSON 就完事了,实际上远没有那么简单。Figma 的 API 返回的节点树非常庞大,一个中等复杂度的页面动辄几千个节点,里面混杂着分组、蒙版、辅助线、隐藏图层这些对代码生成毫无价值的信息。直接丢给模型,token 消耗巨大不说,生成的代码也会被噪音干扰。
我实际操作下来的经验是,提取阶段至少要做三层过滤。
第一层是语义过滤。把纯装饰性的节点(比如背景渐变层、阴影层)和结构性节点(比如容器、文本、按钮)区分开。判断依据可以看节点名称的命名规范,也可以看它是否绑定了组件或样式。如果一个节点既没有子节点、又没有绑定任何样式、还不在自动布局的约束体系里,大概率是装饰元素,可以合并到父级的样式描述里。
第二层是层级压缩。Figma 里设计师习惯用大量分组来组织图层,但代码里不需要那么多嵌套的 div。我的做法是,如果某个分组没有自己的布局属性(比如没有设置自动布局、没有独立的背景或边框),就把它拍平,把子节点直接提升到上一层。这样能把节点数量压缩 40% 到 60%。
第三层是约束提取。自动布局的信息要完整保留,包括方向、间距、内边距、对齐方式、是否换行。这些直接对应到 Flexbox 的属性。对于非自动布局的绝对定位元素,要记录它的坐标和尺寸,生成绝对定位代码或者提示需要人工介入。
// 一个简化的节点过滤逻辑示意 function shouldKeepNode(node) { // 保留有组件引用的节点 if (node.componentId) return true; // 保留有文本内容的节点 if (node.type === 'TEXT' && node.characters) return true; // 保留有自动布局的容器 if (node.layoutMode && node.layoutMode !== 'NONE') return true; // 保留有样式绑定的节点 if (node.styles && Object.keys(node.styles).length > 0) return true; // 其余视为装饰或冗余分组 return false; }这段逻辑不是万能的,但能过滤掉大部分噪音。实际用的时候还要结合具体项目的设计规范做调整,比如有些团队会把图标做成组件,那就应该保留;有些团队用矢量图形直接画图标,那就需要判断是否要转成 SVG 还是用图标库替代。
2.2 代码生成策略:模板、模型与混合方案的选择
拿到结构化的设计数据之后,下一步是生成代码。这里有三条路线,各有各的适用场景。
纯模板方案是最可控的。你预先定义好组件映射规则,比如“Figma 里叫 Button/Primary 的组件,对应代码里的<Button variant="primary">”。然后写一个转换器,把设计节点的属性映射到组件 props 上。这种方案生成速度快、结果稳定,但灵活性差,遇到设计稿里没有对应组件的情况就抓瞎。
纯模型方案是把设计数据序列化成文本描述,直接让大模型生成代码。好处是灵活,能处理各种奇怪的设计稿;坏处是不稳定,同一个设计稿生成两次可能得到不同的代码,而且容易产生幻觉,比如引用不存在的组件或属性。
我现在用的是混合方案,核心思路是“模板保底,模型补位”。具体来说:
- 对于设计系统里已有的组件,走模板映射,保证生成的代码符合团队规范。
- 对于设计系统覆盖不到的部分,比如一些一次性的营销页面布局,走模型生成,但生成结果要经过一层校验,检查它引用的组件和样式是否存在。
- 对于布局结构,优先用自动布局信息生成 Flexbox 代码,模型只负责填充内容和处理边界情况。
这个策略的关键在于组件映射表的维护。我建议把它做成一个独立的配置文件,设计侧的组件名和代码侧的组件路径一一对应,新增组件时两边同步更新。这个表越完善,模板方案的覆盖率就越高,整体稳定性就越好。
| 方案类型 | 生成速度 | 稳定性 | 灵活性 | 适用场景 |
|---|---|---|---|---|
| 纯模板 | 快 | 高 | 低 | 设计系统覆盖度高的常规页面 |
| 纯模型 | 慢 | 低 | 高 | 一次性活动页、探索性设计 |
| 混合方案 | 中等 | 较高 | 较高 | 大多数生产环境 |
2.3 渲染验证与差异比对:闭环的“感知”环节
代码生成出来只是第一步,真正让闭环转起来的是验证环节。我的做法是:把生成的代码在一个无头浏览器里渲染出来,截图,然后和设计稿的截图做像素级比对。听起来很粗暴,但实际效果出奇地好。
比对的时候不能只看整体差异率,那样只能告诉你“像不像”,不能告诉你“哪里不像”。我用的方法是分区域比对:把页面按照设计稿的节点树切分成若干个区域,每个区域单独比对,然后按差异程度排序。差异最大的区域优先处理,这样 Agent 的修正动作就有了明确的优先级。
差异的类型也要分类。我大致分成四种:
- 布局差异:元素位置偏移、尺寸不对、换行行为不一致。这类差异通常对应 Flexbox 属性配置错误,修正起来最直接。
- 样式差异:颜色、字体、圆角、阴影对不上。这类差异往往是设计令牌映射出了问题,需要检查令牌配置。
- 内容差异:文本内容缺失或错误。这类差异一般是数据绑定问题,需要检查数据源。
- 结构差异:元素缺失或多余。这类差异最麻烦,可能是节点过滤逻辑有误,也可能是组件映射缺失。
分类之后,Agent 就可以针对不同类型的差异采取不同的修正策略。布局差异直接调整样式代码;样式差异回查设计令牌;内容差异检查数据填充逻辑;结构差异则需要重新审视设计数据的提取过程。
实操心得:像素级比对对字体渲染的差异非常敏感。不同操作系统、不同浏览器的字体抗锯齿策略不一样,会导致大量误报。我的解决办法是在比对前对截图做一次高斯模糊,把 1-2 像素的差异抹掉,只关注结构性的偏移。这个阈值需要根据项目实际情况调,太严了误报多,太松了漏报多。
3. 实操落地:搭建一个最小可用的闭环原型
3.1 环境准备与工具链选型
要跑通这个闭环,不需要一上来就搞得很复杂。我用的是一个最小化的工具链,核心就四样东西:设计数据导出脚本、代码生成模块、无头浏览器渲染环境、差异比对工具。
设计数据导出用 Figma 的 REST API 或者插件 API 都行。REST API 的好处是不依赖 Figma 客户端,可以跑在服务器上;插件 API 的好处是能拿到一些 REST API 拿不到的运行时信息。我选的是 REST API,因为闭环流程里需要定时拉取最新设计稿,插件方式做不到自动化。
代码生成模块我用 Node.js 写,因为前端生态的解析工具最全。核心依赖就两个:一个用来解析设计节点树,一个用来生成代码字符串。生成代码的时候我推荐用 AST(抽象语法树)的方式,而不是字符串拼接。AST 的好处是生成的代码结构可控,而且可以反向解析回来做校验。字符串拼接看起来快,但后期维护是噩梦。
无头浏览器我用的是 Playwright,因为它对多种浏览器的支持比较均衡,截图 API 也稳定。启动一个浏览器实例,加载生成的页面,等网络空闲后截图,整个流程大概 3 到 5 秒。如果页面有动画,需要额外等待动画结束,或者禁用动画。
差异比对我用的是 pixelmatch 这个库,轻量、快、可配置阈值。它输出一张差异图和一个差异像素比例,够用了。如果要更精细的分析,可以配合 OpenCV 做轮廓检测,但那是后期优化的事了。
# 最小依赖安装 npm install playwright pixelmatch pngjs # 如果要用 Figma REST API npm install axios环境准备好之后,整个闭环的目录结构大概是这样的:
design-code-loop/ ├── config/ │ ├── component-map.json # 组件映射表 │ └── token-map.json # 设计令牌映射表 ├── src/ │ ├── fetch-design.js # 拉取设计数据 │ ├── filter-nodes.js # 节点过滤与压缩 │ ├── generate-code.js # 代码生成 │ ├── render.js # 渲染截图 │ └── compare.js # 差异比对 ├── output/ │ ├── design-snapshot.png # 设计稿截图 │ ├── render-snapshot.png # 渲染截图 │ └── diff.png # 差异图 └── index.js # 主流程入口这个结构不复杂,但每个环节的细节决定了闭环能不能真正跑通。
3.2 关键步骤拆解:从拉取设计稿到生成差异报告
整个流程我拆成六步,每一步都有踩过的坑。
第一步:拉取设计数据。通过 Figma REST API 的/v1/files/:key接口拿到整个文件的节点树。这里要注意,如果文件很大,接口返回的数据可能超过几兆,需要做分页或者只拉取特定页面。我的做法是在请求参数里指定ids,只拉取当前需要转换的那个 Frame,减少数据量。
第二步:节点过滤与压缩。前面说的三层过滤在这里执行。过滤完之后,我会把节点树转成一种中间格式,我管它叫“UI 描述对象”。这个对象里只保留对代码生成有用的信息:节点类型、布局属性、样式引用、文本内容、组件引用。其他的一律丢掉。
第三步:代码生成。遍历 UI 描述对象,对每个节点生成对应的代码片段。容器节点生成布局代码,文本节点生成文本组件,组件实例生成对应的组件调用。生成过程中要维护一个上下文,记录当前的缩进层级和父级布局方向,因为 Flexbox 的某些属性(比如align-items)是继承自父级的。
第四步:渲染截图。把生成的代码写到一个临时文件里,用 Playwright 加载。这里有个细节:生成的代码可能依赖项目里的组件库和样式文件,所以临时页面要能正确引用这些依赖。我的做法是在项目根目录下建一个沙箱页面,动态 import 生成的代码模块,这样依赖解析和正常开发时一致。
第五步:差异比对。把设计稿截图和渲染截图对齐后做像素比对。对齐这一步很关键,如果两张图的尺寸不一致,比对结果全是噪音。我的做法是强制把两张图缩放到相同的宽度,高度按比例缩放,然后以顶部左对齐的方式裁剪到相同高度。
第六步:生成差异报告。比对结果不能只是一个数字,要能指导下一步动作。我的报告里包含:整体差异率、差异区域列表(按差异程度排序)、每个区域的差异类型分类、以及建议的修正方向。这个报告既是给 Agent 看的,也是给人看的。
// 差异报告的数据结构示意 { "overallDiffRate": 0.032, "regions": [ { "id": "header-nav", "diffRate": 0.15, "type": "layout", "suggestion": "检查导航项的间距配置,设计稿为 24px,渲染结果疑似为 16px" }, { "id": "hero-title", "diffRate": 0.08, "type": "style", "suggestion": "字体权重不匹配,设计稿为 600,渲染结果疑似为 700" } ] }这个报告出来之后,Agent 就可以根据type和suggestion决定下一步动作。布局问题改样式代码,样式问题查令牌映射,结构问题回退到节点过滤阶段重新处理。
3.3 参数调优:差异阈值与迭代次数的平衡
闭环跑起来之后,最需要调的就是两个参数:差异阈值和最大迭代次数。
差异阈值决定了“多大的差异算通过”。设得太高,生成的代码质量差;设得太低,Agent 会陷入无限微调的循环。我的经验值是:整体差异率低于 2% 可以认为通过,单个区域的差异率低于 5% 可以接受。但这个值不是固定的,文本密集的页面阈值可以放宽到 3%,因为字体渲染差异很难完全消除;图形密集的页面阈值要收紧到 1%,因为形状和颜色的差异更容易被用户感知。
最大迭代次数决定了 Agent 最多尝试修正几次。设得太少,复杂页面修不完;设得太多,token 消耗和时间成本都上去了。我一般设 5 次,超过 5 次还有大差异的,就标记为“需要人工介入”,不再自动处理。实际跑下来,80% 的页面在 3 次迭代内能达到通过标准。
还有一个隐藏参数是每次迭代的修正幅度。如果 Agent 每次只改一个属性,迭代次数会很多;如果一次改太多,可能引入新的差异。我的策略是:第一次迭代允许大幅调整(比如重写整个区域的布局代码),后续迭代只做微调(每次只改一个属性)。这样既能快速收敛,又能避免震荡。
注意:迭代过程中要保留每次的代码快照和差异报告,方便回溯。有时候 Agent 改了两轮之后差异反而变大了,这时候需要回退到上一轮的结果。没有快照的话,就只能从头再来。
4. 常见问题与排查技巧实录
4.1 生成代码“看起来对但跑不起来”的几种典型情况
这个问题我遇到太多次了。差异报告显示差异率很低,但代码一跑就报错。排查下来,原因基本集中在几个地方。
组件引用路径错误。模板映射表里配置的组件路径和实际项目结构不一致。比如映射表里写的是@/components/Button,但项目里实际是@/components/base/Button。这种错误在生成阶段不会暴露,只有渲染的时候才会报模块找不到。解决办法是在生成代码之后加一步静态检查,用 TypeScript 的类型检查或者简单的 import 解析来验证路径有效性。
样式作用域冲突。生成的代码用了全局样式类名,和项目里已有的样式冲突了。比如生成代码里写了一个.container类,但项目全局样式里也有.container且定义了不同的宽度。这种问题在隔离环境里渲染时看不出来,一集成到项目里就出问题。我的做法是给生成代码的类名加统一前缀,比如gen-,降低冲突概率。
响应式断点缺失。设计稿通常只给一个或两个断点的设计,但实际项目需要适配更多断点。生成的代码如果只写了固定宽度,在小屏幕上就会溢出。这个问题在差异比对时也发现不了,因为比对用的视口宽度和设计稿一致。解决办法是在渲染验证阶段增加多个视口宽度的截图比对,至少覆盖移动端、平板、桌面三个尺寸。
交互状态未处理。设计稿里的按钮通常只展示默认态,但代码里需要处理 hover、active、disabled 等状态。生成的代码如果只实现了默认态,功能上是不完整的。这个问题需要在前端验收阶段人工检查,或者在生成规则里强制要求所有交互组件必须包含状态处理。
| 问题类型 | 表现 | 排查方法 | 预防措施 |
|---|---|---|---|
| 组件路径错误 | 渲染时报模块找不到 | 检查 import 路径 | 生成后加静态检查 |
| 样式冲突 | 集成后样式错乱 | 对比隔离环境和集成环境 | 类名加统一前缀 |
| 断点缺失 | 小屏幕溢出 | 多视口截图比对 | 生成时注入响应式规则 |
| 状态未处理 | 交互无反馈 | 人工检查交互组件 | 生成规则强制状态覆盖 |
4.2 Agent 陷入“改一个坏一个”的循环怎么破
这是闭环系统最让人头疼的问题。Agent 发现标题字体不对,改了字体权重,结果行高变了,导致下方内容偏移,又产生新的差异。然后它去修行高,行高改完间距又不对了。来回折腾好几轮,差异率不降反升。
我分析下来,根本原因是Agent 缺乏对样式属性之间关联性的理解。字体权重和行高是有关联的,间距和容器高度是有关联的,单独改一个属性很容易破坏另一个。解决思路有两个方向。
一个方向是给 Agent 提供属性关联规则。在生成约束里明确告诉它:修改字体相关属性时,必须同时检查行高和字间距;修改容器内边距时,必须同时检查子元素的尺寸约束。这些规则可以写在系统提示里,也可以做成一个规则引擎,在 Agent 执行修正前做一次校验。
另一个方向是限制单次修正的范围。不要让 Agent 自由地改任何属性,而是给它一个“修正窗口”,每次只允许修改一个区域内的属性,且修改后必须重新渲染验证。如果差异率没有改善,就回退这次修改,换一个策略。这个方式收敛慢一些,但稳定性好很多。
我实际用的是两个方向结合:规则引擎做前置校验,修正窗口做后置验证。跑下来,震荡的情况减少了大概七成。剩下的三成主要是设计稿本身存在歧义,比如某个间距在设计稿里是 23.5px,但代码里只能取整,这种差异是不可避免的,需要人工决策。
4.3 设计稿频繁变更时的增量处理策略
实际项目里设计稿不是一成不变的,今天改个间距,明天换个图标,后天加个页面。如果每次变更都全量重新生成,成本太高,而且会覆盖掉人工对生成代码的微调。
我的策略是基于节点 ID 的增量更新。每次拉取设计数据时,和上一次的快照做对比,找出新增、修改、删除的节点。只对这些节点重新生成代码,其他部分保持不变。节点 ID 是 Figma 分配的,只要设计师不是删了重画,ID 就不会变。
增量更新的难点在于依赖关系的处理。如果一个容器的布局属性变了,它所有子节点的位置都可能受影响,需要重新生成。所以增量分析不能只看节点自身,还要看它的父级和兄弟节点。我的做法是:如果一个节点被修改,把它和它的所有后代节点都标记为“需要重新生成”;如果它的父级布局属性变了,把它父级下的所有子节点都标记为“需要重新生成”。
人工微调的保护也很重要。生成代码之后,我会在代码里插入特殊的注释标记,比如/* @generated */和/* @manual */。增量更新时,只替换@generated标记之间的内容,@manual标记的内容原样保留。这样设计师改设计稿和工程师改代码可以并行,不会互相覆盖。
实操心得:增量更新一定要有回滚机制。有时候设计稿的变更会导致生成代码大面积报错,这时候需要快速回退到上一个可用版本。我的做法是每次生成前把当前代码目录打包备份,出问题了直接解压覆盖。备份文件保留最近 10 个版本,再老的自动清理。
5. 这套闭环方案的实际影响范围
5.1 对前端工程师日常工作的改变
最直接的变化是重复性劳动大幅减少。以前一个中等复杂度的页面,从设计稿到可交互的代码,大概需要 2 到 3 天。现在用闭环方案,生成加修正大概 2 到 3 小时,剩下的时间主要花在业务逻辑对接和边界情况处理上。这个效率提升不是线性的,页面越复杂、组件复用率越高,提升越明显。
但工作内容也变了。以前前端工程师的核心竞争力是“还原度”,谁能把设计稿还原得一模一样谁就厉害。现在还原度这件事被 Agent 接管了,人的价值转移到定义规则和验收结果上。你需要理解设计系统的运作方式,知道哪些属性可以自动映射、哪些需要人工干预,还要能判断生成结果的质量。这其实对工程师的设计素养提出了更高要求。
另一个变化是协作节奏。以前设计和前端是串行的:设计定稿,前端开发,前端开发完了设计验收。现在可以并行:设计在 Figma 里改,Agent 实时生成代码,前端工程师同步看到变更。设计验收和代码验收可以合并成一个环节,因为两边看的是同一个东西。这个节奏变化对团队的工具链和沟通方式都有影响,需要一段时间适应。
5.2 对设计师工作方式的倒逼
设计师这边的影响可能更大。以前设计师画图的时候不需要考虑代码实现,想怎么画就怎么画。现在如果设计稿要进入闭环流程,就必须遵守一些约束:用自动布局、用组件实例、用设计令牌、命名规范。这些约束在短期内会增加设计师的工作量,但长期来看是好事,因为它让设计稿从“一张图”变成了“一份可执行的规格说明”。
我观察到的一个有趣现象是,当设计师知道自己的设计稿会被 Agent 直接转成代码时,他们会更自觉地使用设计系统的组件,而不是随手画一个看起来差不多的东西。因为随手画的组件在代码生成时会走模型方案,结果不稳定;而用系统组件走模板方案,结果可控。这种“用脚投票”的机制,反过来推动了设计系统的覆盖率提升。
还有一个变化是设计评审的重点转移。以前评审主要看视觉效果和交互流程,现在还要看“这个设计能不能被自动生成”。比如设计师用了一个很复杂的层叠效果,视觉上很好看,但代码生成时很难用标准 CSS 实现,Agent 可能会生成一堆绝对定位的代码,后期没法维护。这种设计在评审阶段就会被质疑,设计师需要提前考虑实现成本。
5.3 对团队工具链和流程的冲击
闭环方案落地不是装一个工具那么简单,它牵扯到整个工具链的调整。
版本管理需要重新设计。设计稿的版本和代码的版本怎么对应?设计稿改了但代码还没生成,这时候代码仓库里是什么状态?我的做法是给每次生成打一个 tag,tag 里包含设计稿的版本号和生成时间。代码仓库里维护一个design-version.json文件,记录当前代码对应的设计稿版本。这样出问题的时候可以快速定位是哪个版本的设计稿导致的。
CI/CD 流程需要增加设计验证环节。传统的 CI 只跑单元测试和构建,现在还要加一步:拉取最新设计稿,生成代码,渲染比对,差异率超标就阻断合并。这个环节会增加 CI 的时间,但能防止设计稿和代码脱节。我一般把这个环节放在 nightly build 里,不阻塞日常开发,但每天会出一份差异报告。
权限管理也需要调整。以前设计稿的编辑权限和代码的提交权限是分开的,现在闭环系统需要同时访问两边。我的做法是给闭环系统一个独立的服务账号,设计侧只读,代码侧只写生成目录,其他目录没有权限。这样即使系统出问题,也不会影响人工维护的代码。
| 影响维度 | 传统模式 | 闭环模式 | 需要调整的地方 |
|---|---|---|---|
| 版本管理 | 设计稿和代码独立版本 | 版本需要对应 | 增加版本映射文件 |
| CI/CD | 只跑代码测试 | 增加设计验证 | 调整流水线配置 |
| 权限 | 设计和代码权限分离 | 系统需要跨端访问 | 增加服务账号 |
| 评审 | 看视觉效果 | 兼顾可实现性 | 更新评审清单 |
6. 我踩过的坑和最后分享的几个技巧
6.1 不要试图一步到位:从单页面试点开始
我一开始就想做一个全自动的闭环系统,结果折腾了两周发现根本跑不通。问题出在设计稿的多样性上。不同设计师有不同的画图习惯,有的用自动布局,有的用绝对定位;有的组件命名规范,有的随手写。一个通用的闭环系统要处理所有这些情况,复杂度是指数级上升的。
后来我换了个思路:先选一个设计规范执行得最好的页面做试点。这个页面的设计师愿意配合调整命名和布局方式,前端也愿意花时间维护组件映射表。试点跑通之后,再逐步扩展到其他页面。每扩展一个页面,就补充一批映射规则和过滤规则。这个过程很慢,但每一步都是稳的。
我的建议是:第一个月只做 3 到 5 个页面,把闭环的每个环节都跑顺,把规则库建起来。不要急着推广,推广之前先确保规则库能覆盖 80% 的常见场景。剩下的 20% 长尾场景,人工处理就好,不要为了自动化而自动化。
6.2 差异报告要给人看,不能只给机器看
我早期的差异报告就是一堆数字和坐标,Agent 能看懂,但人看不懂。结果出了问题的时候,工程师不知道从哪里下手排查。后来我把报告改成了“人机双读”的格式:每个差异区域配一张裁剪后的对比图,左边设计稿,右边渲染结果,中间是差异高亮。下面用自然语言描述差异内容和建议修正方向。
这个改动看起来只是展示层的优化,但实际影响很大。工程师排查问题的速度提升了至少一倍,而且非技术角色(比如产品经理)也能看懂报告,参与讨论。有时候产品经理会指出“这个差异不是 bug,是设计稿本身有问题”,这种反馈在纯数字报告里是看不到的。
6.3 保留人工干预的入口,不要追求全自动
全自动闭环听起来很美好,但实际运行中总有一些情况是 Agent 处理不了的。比如设计稿里有一个复杂的插画,Agent 生成的代码可能是一个占位图,需要人工替换成实际的图片资源。又比如某个交互效果需要 JavaScript 逻辑,Agent 只能生成静态样式,需要人工补充事件处理。
我的做法是在生成代码里预留“人工干预标记”。Agent 遇到不确定的情况时,不强行生成,而是插入一个带注释的占位符,比如/* @todo: 需要人工处理 - 复杂插画替换 */。工程师看到这个标记就知道这里需要手动处理。同时,差异报告里也会把这些标记列出来,作为“待人工处理项”单独展示。
这个策略的核心思想是:Agent 做它擅长的部分,人做人擅长的部分,两者通过明确的接口协作。追求 100% 自动化往往会导致系统过于复杂,维护成本超过收益。80% 自动化加 20% 人工干预,可能是更务实的平衡点。
最后分享一个提高生成质量的小技巧:在代码生成之前,先让模型对设计稿做一次“意图描述”。比如让它用自然语言描述“这个页面是一个电商详情页,顶部有导航栏,中间是商品图和价格信息,底部是加入购物车按钮”。这个描述不直接用于生成代码,但可以作为生成时的上下文,帮助模型理解每个区域的功能定位。实测下来,加了这一步之后,生成的代码在语义结构上更合理,后续人工调整的工作量也少了一些。