我们的智能体如何借助 design.md 构建符合品牌风格的页面

Vercel Blog 2026-09-01T11:45:09.294193

在整个 Vercel,我们都会用编码智能体(coding agent)来设计和构建页面,而这些页面必须看起来、用起来都像 Vercel 自己的作品。字体、颜色、版式,都需要具备我们手工发布页面时同样的判断力。

我们最近写了一篇关于 product-design 的文章,那是我们用来教智能体在我们代码库中工作时如何做设计的技能。这个技能就放在各个仓库里,和它所管理的代码待在一起,告诉智能体如何找到并理解我们的设计系统,以及它们正在构建的产品对应的规范。当智能体在我们的代码库里工作时,这套方案相当好使——技能需要的一切都近在眼前。

但如果是报告、提案,或者那些一次性页面呢?它们同样得长得像 Vercel,可制作它们的工具根本读不到这些文件。我们的答案是 design.md:一个公开文件,任何智能体都能加载。

我们是怎么构建 design.md 的

product-design 之所以好用,是因为设计系统和产品规范就摆在仓库里,智能体随取随读。我们需要让仓库之外的智能体和工具也能触达同样的知识,这样最终产出的页面,仍然得像我们自己设计的一样。这就定了两个要求:

我们一开始尝试了最直接的办法:把 product-design 原封不动移植成一份公开提示词,把技能引用的所有参考文件压缩成一个文件,让智能体通过 URL 直接读取。

但问题也随之而来:提示词虽然把我们的视觉语言描述得足够清楚,可每个读到它的模型都会产生各自的理解。同一份指引,最终生成出来的页面却五花八门。

一部分原因在于,设计语言本来就是主观的。像「保持布局干净」这种话,基本等于什么都没说——「干净」到底指什么?更关键的问题是,这份提示词还丢掉了其他很多东西。

在我们的代码库里,智能体(agent)会读取产品设计文件(product-design),文件周围就是真实的组件和已经上线的示例。但公开的提示词里没有这些信息,每个模型都只能靠文字描述来重建我们的风格。所以我们需要把环境提供的这些内容提炼成单独一个文件;而要判断我们是否越来越接近目标,唯一办法就是看生成出来的页面。我们先把端口的事放到一边,从头开始写一个新文件,这次用一组可重复的评估提示词来测试每次改动。

我们写了七个这样的提示词,全部来自真实使用场景,并配上了模拟输入:使用与性能报告(Usage and performance report)、续约提案(Renewal proposal)、基准对比报告(Benchmark report)、交互式规划页面(Interactive planning page)、自建还是外购简报(Build-versus-buy brief)、安全治理简报(Security governance brief)、演示文稿(Presentation deck)。

提示词固定不变,只有文件在改,所以输出上的任何差异都能追溯到这份指南上。

第一次对比

这些评估让我们既能衡量文件实际起到的作用,也能看出不同智能体是怎么理解它的。第一次测试,我们想确认 design.md 是否真的会改变模型的产出。我们在相同环境、相同模型上,把续约提案评估跑了两遍:一遍不加载 design.md,一遍加载;两次运行的提示词、数据和视口完全一致。

没有 design.md 时,模型生成的是通用的 SaaS 仪表盘;有了它,页面会先展示续约建议本身,把商业证据汇总到一个网格里,把同行数据放到同一把刻度尺上以便真正比较,同时保留支撑细节,又不让细节和概览抢注意力。这让我们得出结论:这个文件不仅像最初发现的那样改变了样式,还改变了页面的结构和层级。这给了我们足够的信号,可以继续按这种方式一条一条地构建指南。

让系统运转的三个部分

随着我们不断测试和重建 design.md,它的范围也演变成一个由三部分组成的系统,让整个系统运转起来:design.md 提供指导,告诉智能体如何界定读者的任务、如何组织证据、如何选择页面构图。

一个公开样式表定义了一套界限明确、有文档记录的类名和 token(即设计变量);而评估循环则把反复出现的人类反馈,转化成更完善的规范和可自动化的检查。这三层机制各自覆盖了打造高质量、符合 Vercel 品牌调性的页面所需的某一部分工作。

最终沉淀在 design.md 里的判断,会这样指导 agent(智能体):

design.md 还会给那些反复出现的「AI 生成设计」套路命名——这些是我们绝不希望看到的。一旦这些模式有了名字,agent 就能更可靠地识别并避开它们。

我们之所以专门做样式表,是因为 agent 老是自行发明字体、间距和布局。干脆把这些决定权完全从模型手里拿掉。样式表把我们设计系统的基础组件——比如标题、表格、数据条、图表样式——打包成 CSS,任何页面都能通过公开 URL 直接引用。然后 design.md 把这些类名和 token 文档化,agent 构建页面时直接用这些名字写 HTML,而不是自己重新造一遍。

这么做还有一个额外好处:agent 实际上完全不用读样式表本身。样式表是在浏览器渲染页面时才加载的,所以这部分代码根本不会进入模型的上下文,省下来的空间正好可以放更多设计指导。

最后,评估循环是让另外两样东西真正发挥作用的关键。确定性检查用来捕捉机械性故障,比如表格没有适配可用宽度;而像层级、构图、页面到底有没有给读者他想要的东西,这些没法自动化的主观部分,就需要人来把关。

规范是怎么写进 design.md 的

design.md 里每一行规范,都是通过评估循环挣来的。

我们先用固定场景生成页面,检查返回的产物,把认可的修正沉淀下来,再重新跑一遍场景,看看每个改动是否真的落地——因为某个改动可能对一个页面有帮助,却悄悄损害了另一个页面。没有哪个改动可以绕过这套流程。

场景与轮次

七个提示词中的每一个都成为一个“场景”,也就是说,提示词、模拟输入和渲染设置都会被固定下来。比如“续约建议”这个场景,始终使用相同的模拟客户数据和视口设置,不同运行之间唯一变化的只有 design.md。

一轮(round)就是用当前版本的 design.md 把每个场景都重新生成一个新页面。完整的一轮会在 Claude Opus 4.8 和 Codex with GPT-5.5 两个模型上跑完全部七个场景。如果想有针对性地排查某个问题,比如一个只影响表格的规则改动,我们可以只重跑受影响的场景,或者只跑单个模型,这样迭代周期就能控制得很短。

同时生成七个页面,也方便把它们放在一起横向对比。最明显的一点是:design.md 并没有把所有页面推向同一个模板。交互式规划页面把控件放在最显眼的位置,因为用户打开这个页面就是为了改数字、看变化;而续约建议页面则把推荐结论放在最前面,后面跟着商业对比信息,因为阅读者要做的是“要不要续约”的判断。每个页面都使用同一套 Vercel 字体、配色和间距,但整体结构都围绕访客来这个页面的目的来组织。

评审每一轮结果

为了评审每一轮生成的页面,我们做了一个本地应用,用来显示整页渲染效果,并进行盲测式的 A/B 对比。这个应用后来演变成了我们的评估工具(eval harness),负责跑每个场景并保存结果。

每次运行的记录都会保存提示词、输入、模型配置、使用的 design.md 版本、截图,以及评审者留下的所有反馈。评审者会把每一条修正意见对应到产生该问题的具体那次运行上。

把修正变成规则和检查

评审者记录的每一条修正,都会被放进一个既能稳定生效、范围又尽可能小的地方。

需要主观判断的改动,以文字形式写进 design.md;可复用的机制放进样式表;凡是能靠代码机械检查的,就做成确定性校验。测试框架自身的问题留在框架里解决;如果只有某一个模型用其他模型没有的方式翻车,那就先不写进规则,等它重复出现再说。

拿早期一个续费方案来说。它生成出来的商务条款表格被压得和正文一样宽,可页面上明明有足够空间,让表格再宽出一倍。人工评审时我们指出,证据表格应该占满可用宽度。但翻看此前的输出,发现这个毛病反复出现。于是这条修正被写进了两个地方:一是 design.md 里的一条规则,明确预期的行为;二是代码里的一个确定性校验,下次再出现同样的布局问题时能直接抓出来。这个改动落地后,后续续费方案提示词生成的页面,表格宽度就正常了。

为了验证这类修正,我们在把它编码进规则之后,重新跑了受影响的场景。到里程碑节点还会更进一步:做盲测 A/B 对比,用更新后的 design.md 和旧版文件分别生成页面,据此决定每处改动是保留、修改还是回退。

衡量是否有效

构建这份文件总共跑了 200 多次,算上完整轮次、定向检查、试运行,以及所有走不通的死路。除了人工评审,每一轮还会有一个模型评判员写点评,每一轮的反馈都会用来改进下一轮生成。

跑了这么多轮之后,我们想弄清楚一件事:写进规则的那些修正,到底有没有真的挡住它们原本要防的失败。于是我们挑了三个桌面端场景,每个场景都让 Codex 搭配 GPT-5.5 生成两遍页面——一次加载 design.md,一次不加载。每次生成只保留第一次产出,不重试。然后我们对全部六个页面跑确定性校验,统计每组里已知失败(比如表格无视可用宽度)出现了多少次。加载 design.md 生成的页面里,这类失败出现了 39 次。

页面离开 design.md 之后,效果如何

没有 design.md 时生成的页面,在测试中有 91 个问题;而用了它之后只有 39 个,少了 57%。不过这个数字有两个前提:这些检查只能抓到我们已经见过、并且写进规则里的问题,所以这次测试并不能说明页面整体设计得好不好;另外,6 个页面的样本量也太小,不足以证明质量或可靠性,而且无论是用了还是没用这个文件,每个页面都至少还有一个严重到无法上线的问题。但这个测试真正有价值的地方在于:一旦我们把某个问题命名并用规则固化下来,这个问题往往就不会再出现。

design.md 如何保持更新

这个 eval 循环让文件得以发布,但真正让它不过时的,是实际使用。在我们的 Slack 里,这体现在 @design-agent 上——一个基于 eve 构建的智能体。我们用它可以做设计评审、文案备选、图标推荐,也可以让它把粘贴的数据做成报告页面。不需要写 prompt 或翻找源文件,只要在讨论串里 @ 它就行。对网站制作请求,它会加载最新的 design.md,依据已发布的样式表来构建页面,然后把整页截图和部署链接发回讨论串。

和我们固定的测试场景不同,这些讨论串记录的是真实的请求、真实的输出,以及随后给出的反馈或调整意见,能让我们看到这套指引在实际使用中表现如何。每周我们都会把所有这些反馈汇到一起,包括 Slack 讨论串、GitHub 评审和 Figma 里的评论。自动化工具会把反复出现的评论分组,每个反复被提的问题就会变成一条修改建议。然后由人来逐条审查,确认系统是否已经覆盖了这个问题,并决定把修改放在哪里:是 @design-agent、产品设计技能、design.md、样式表,还是某个确定性检查。

此外,如果有人开始请求我们从未测试过的新页面类型,这个请求就会变成一个新的 eval 场景。为了判断这些措施到底有没有用,我们会统计每类问题在相似工作中出现的频率。一旦修复被固化下来,这个频率就应该开始下降;如果没有下降,说明修复方式有问题。

规则可能含糊不清、需要时未加载、样式表缺少能表达它的原语,或者它需要的是可确定的检查而不是一段描述文字。

构建你自己的闭环

你可以自己搭建同样的循环,从一个反复出现的产物和一次人工对比开始。

1. 挑一个反复出现的产物

选一个最近的任务,要有真实读者和真实输入,比如提案、绩效报告、基准测试或微型站点。避免“做得符合品牌调性”这类宽泛目标。在生成任何内容之前,先写下一条简短的评分标准。好的标准应该检查:给定的事实是否保留、读者的决策是否清晰、你反复手工修正的那个问题是否真的解决了。

2. 先保存基线

不要加入任何新的设计上下文,先照常生成一次页面,并保存提示词、输入、配置和截图。即使第一次输出看起来粗糙也留着,除非是工具本身出了问题。没有“之前”的版本,你就无法判断新上下文是否起了作用。

3. 从最近的十次修正入手

收集你在设计评审、拉取请求或 Slack 里反复给出的反馈,把每一条修正都改写成可观察的形式。也就是说,把“让表格显得没那么挤”改成“让证据表使用完整的可用宽度”,因为只有后者可以被检查。把这些决定放进一个文件里,分节记录:适用范围、读者与任务、可观察的决策、可用的原语。这个文件就是你的第一个 design.md

4. 约束可重复的机制

如果你的输出总是自己发明排版、间距或布局,就发布一份样式表,并明确写出智能体可以使用的类和标记。把判断留给人写,把可重复的机制推进 CSS 或确定性检查里。

5. 跑一次对照比较

用相同的输入、模型和视口再生成一次页面,但这次加载你的文件。把新输出与基线随机混合,在不知道哪个是哪个的情况下按你的评分标准分别打分。你不必一开始就搭好 runner 或模型裁判,一次简单试跑就能暴露出那些大而明显的失败。

要衡量可靠性,可以跑多次独立的首次尝试试验(参见 Anthropic 的 agent 评估指南),然后汇报结果稳定的频率。
6. 把修正规则编码下来

查看原文