Vercel News

Teaching agents product design at Vercel

8.5内容质量

TL;DR · AI 摘要

Vercel 通过 product-design 技能系统,使 AI 代理能理解产品设计原则,提升代码质量与一致性。

核心要点

  • Vercel 使用 product-design 技能系统,使 AI 代理能理解产品设计原则。
  • 该系统包含技能、自动校验和审查循环三个部分。
  • product-design 技能结构包含 references 和 exemplars 目录,用于存储设计决策和示例。

结构提纲

按章节快速跳转。

  1. AI 代理可以快速生成 UI,但难以理解设计原则背后的原因。

  2. ·Vercelproduct-design 系统

    Vercel 通过 product-design 系统,使 AI 代理能理解产品设计原则。

  3. product-design 技能结构包含 references 和 exemplars 目录,用于存储设计决策和示例。

  4. SKILL.md 解析请求模式,确保审查不变成修改,避免不必要的设计变更。

思维导图

用一张图看清主题之间的关系。

查看大纲文本(无障碍 / 无 JS 友好)
  • Vercel 的 product-design 系统
    • 系统组成
      • product-design 技能
      • 自动校验
      • 审查循环
    • 技能结构
      • references 目录
      • exemplars 目录
    • 技能路由机制
      • 解析请求模式
      • 避免不必要的设计变更

金句 / Highlights

值得收藏与分享的关键句。

  • Vercel 通过 product-design 技能系统,使 AI 代理能理解产品设计原则,提升代码质量与一致性。

    引言

    ⬇︎ 下载 PNG𝕏 分享到 X
  • product-design 技能结构包含 references 和 exemplars 目录,用于存储设计决策和示例。

    product-design 技能结构

    ⬇︎ 下载 PNG𝕏 分享到 X
  • SKILL.md 解析请求模式,确保审查不变成修改,避免不必要的设计变更。

    技能路由机制

    ⬇︎ 下载 PNG𝕏 分享到 X
#AI 代理#产品设计#Vercel#代码校验
打开原文

在 Vercel 教授代理产品设计 - Vercel

编码代理可以快速生成可用的用户界面,但更困难的是另一种形状。它们可以复制你的产品的风格,匹配其模式,并尝试遵循其惯例。但它们无法理解这些模式存在的原因。代码向代理展示了已发布的成果,但无法解释为什么某个组件、措辞或交互成为你的标准。这种推理存在于设计评审、PR 评论、Slack 线程以及当时在场的人中。对于代理来说,不在代码库中的上下文是不存在的。

Vercel 是一个以代理为中心的团队。我们将已接受的产品决策视为代码,将其保存在仓库中,对其变更进行评审,并让所有在此工作的代理都能使用这些决策。

我们通过产品设计技能来实现这一点。这是一个包含三个部分的系统:

  • 一种代理技能,为需要产品或代码库判断的决策提供背景信息。
  • 自动执行明确规则的 linters。
  • 一个评审循环,从 Slack、Figma 和 GitHub 收集证据,然后准备指南更新供评审。

任何团队都可以围绕自己的标准构建相同的结构。

产品设计技能内部

该技能与它所管理的代码一起存在于仓库中。以下是其结构的简化视图:

code
repository/
├── AGENTS.md
├── .agents/
│   └── skills/
│       └── product-design/
│           ├── AGENTS.md
│           ├── SKILL.md
│           ├── references/
│           │   ├── product-judgment.md
│           │   ├── interface-quality.md
│           │   ├── resilience.md
│           │   ├── surfaces.md
│           │   ├── surfaces-{surface}.md
│           │   ├── copy.md
│           │   ├── rules.md
│           │   ├── glossary.md
│           │   ├── patterns.md
│           │   └── coverage-gaps.md
│           └── exemplars/
│               └── pr-{name}.md
└── tooling/
└── scripts/
└── evals/
├── fixtures.json
├── rules-checklist.json
└── <fixture>/
├── before/
└── after/

仓库中的产品设计技能结构。

  • 仓库中的 AGENTS.md 告诉编码代理何时加载该技能。技能本地的 AGENTS.md 定义加载顺序、验证和治理。SKILL.md 负责运行时工作流程。
  • references/ 存储产品判断、界面质量、韧性、文案、规范产品名称、交互模式和特定表面的决策。
  • exemplars/ 记录了值得重复的已发布拉取请求中的决策,以及需要避免的错误。coverage-gaps.md 列出了我们尚未有标准的领域。
  • copywriting-eval/ 测试文案和界面语言行为。它不评估更广泛的产品设计工作流程。

技能的路由方式

SKILL.md 首先确定请求模式:形状、实现、评审、文案或加固。这防止了审计变成编辑,文案检查扩展成重新设计。它跳过仅后端工作、遥测、控制台错误、生成的文件和没有已发布用户界面影响的测试。

该技能路由到规范来源,而不是复制它们。组件 API、设计系统规则、无障碍标准和交互指导仍由其所有者管理。

路由特定于任务和界面。材质变化首先加载产品判断和界面质量。复制、组件、布局、交互、可访问性和弹性工作每个路由到聚焦的参考。模态加载破坏性操作模式和规范动词。设置表单加载标签、验证、逐步披露和可访问名称指导。

你可以使用这个简化的结构作为起点,并用自己的路径和标准替换:

SKILL.md

code
1
---
2
name
:
product
-
design
3
description
:
>
-
4
产品设计和用户面向产品实现的单一入口点,在 apps/vercel-site 中使用。每当工作内容改变用户所看到、理解、选择或执行的内容时使用:
塑造需求和流程;构建或重新设计页面和组件;审查 URL、截图、差异或 Vercel Agent 的发现结果;改进产品文案、信息架构、组件选择、
5
Geist 合规性、层级、布局、交互、可访问性、响应式行为、加载、空状态、错误状态、权限状态、计费状态或破坏性状态。在设计、用户体验、用户界面、可用性、流程、引导、设置、
6
仪表板、构建、改进、修复、审核、审查、润色、简化或生产就绪请求时触发。当后端行为改变用户可见结果时也使用。不用于仅限后端且无用户可见影响的工作、无已发布 UI 影响的测试、仅限遥测的工作、文档或营销内容。
7
---
8
9
#
Vercel 产品设计
10
11
为用户、产品和 Vercel 创建正确的界面。仅凭工作代码是不够的:选择正确的交互方式,明确范围和后果,覆盖超出理想路径的现实情况,并验证渲染结果。
12
13
##
操作契约
14
15
-
**
从任务出发,而不是像素。
**
确定谁在执行操作、他们试图完成什么、涉及的产品对象以及系统将发生的变化。
16
-
**
在输出之前定义结果。
**
在选择表面或组件之前,确定当前用户问题、期望行为、成功信号和非目标。
17
-
**
使用证据,而不是个人喜好。
**
将决策追溯到产品行为、规范仓库的指导、已接受的设计决策或已验证的相邻模式。
18
-
**
将事实与决策分开。
**
明确标记假设和未解决的产品选择;不要将它们隐藏在实现细节中。
19
-
**
将已发布的代码视为证据,而非自动的先例。
**
它证明了什么存在,但不能证明其正确性。将其与当前组件、产品行为和明确指导进行核对。
20
-
**
选择最小的连贯干预。
**
在添加 UI 之前,考虑更好的默认值、行为或重用。不要通过创建不相关的设置或抽象来解决一个任务。
21
-
**
在装饰之前做出决定。
**
在样式或重写文案之前,解决信息架构、组件语义、交互和状态行为。
22
-
**
设计所有可到达的状态。
**
只包括产品实际可以进入的状态,但不要只停留在已填充的成功案例上。
23
-
**
验证真实界面。
**
通过源代码检查确定行为;通过渲染的界面确定视觉和交互质量。不要仅凭代码声称视觉验证。
24
-
**
保持一个面向用户的入口点。
**
调用
`product-design`
;在内部路由到下面的规范来源。
25
26
##
请求模式
27
28
在采取行动之前,从用户的动词和工件中确定模式。
29
30
| 模式      | 典型请求                                                                    | 必需行为                                                                                                                                                      |
31

| --------- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 42 | Shape | "设计这个流程", "这个应该如何运作?", 未确定 UI 的功能简要说明 | 明确问题并提供证据,比较材料替代方案,然后定义流程、状态、验收标准、风险和开放决策。除非被要求,否则不要进行编辑。 | 43 | Implement | "构建", "修复", "改进", "使其合规", 或 "对所有内容运行产品设计" | 解决材料产品决策,然后在范围内实施最小的连贯端到端更改。不要吸收不相关的审查发现。 | 44 | Review | "审计", "批评", "哪里错了?", 代码审查 | 检查源代码和渲染证据,然后报告优先级发现。除非被要求,否则不要进行编辑。 | 45 | Copy | "修复文案", "重写这些错误" | 编辑面向用户的语言、可访问名称和直接所需的 JSX。报告结构性障碍,但不要在不扩大范围的情况下静默处理。 | 46 | Harden | "润色", "生产就绪", "处理边缘情况" | 在修复状态、弹性、响应性、可访问性和完成缺陷的同时,保持已确定的产品方向。 | 47 48 当意图不明确时,请使用动词支持的最狭窄模式。URL、截图、路由或组件标识范围;它本身并不授权编辑。 49 50 材料决策会改变用户的任务、默认值、范围、后果、导航、交互表面或可到达状态。文案机制、标记替换和已建立的组件替换通常不是材料。 51 52 ## 决策权限 53 54 按以下顺序解决冲突: 55 56 1. 用户的明确目标和约束。 57 2. 验证过的用户/产品证据和系统真相。 58 3. 仓库规范指导: AGENTS.md 、Geist 组件 API、 packages/geist/STYLE_GUIDE.md 和路由技能。 59 4. 已接受的产品/设计决策和具有稳定证据的示例。 60 5. 同一产品区域中已验证的相邻已发布模式。 61 6. 通用界面启发式方法。 62 63 ## 工作流程 64 65 ###

  1. 设置范围和模式

66 67 在工作计划或审查笔记中命名目标表面和请求模式。 68 69 ###

  1. 加载产品上下文

70 71 在提出 UI 之前,阅读适用的 AGENTS.md 链、提供的简要说明和设计,以及确定突变、权限、验证、错误和副作用的产品逻辑。 72 73 ###

  1. 建模产品决策

74 75 对于 Shape、Implement、Harden、完整 Review 或任何材料产品/流程更改,请阅读 product-judgment.md 并编写一个涵盖用户、任务、当前行为、期望结果、成功信号、非目标、对象、范围、操作、后果、可逆性、权限和开放决策的简洁内部简要说明。 76 77 ###

  1. 映射表面和状态

78 79

库存入口点、可见区域、覆盖层、过渡效果、退出路径和返回路径。地图中仅包含可到达的状态,包括加载、空、稀疏、已填充、验证、错误、权限、禁用、乐观、过时、破坏性和响应式变体。 80 81 ###

  1. 加载路由引用

82 83 | 需求 | 加载 | 84 | ---- | ---- | 85 | 产品/流程/组件决策 | product-judgment.md + component-guide | 86 | 实现、材质视觉变化或全面审查 | interface-quality.md | 87 | 复制或可访问名称 | copy.md + surfaces.md 路由 | 88 | 布局、字体、颜色、间距、Geist APIs | design-guidelines + packages/geist/STYLE_GUIDE.md | 89 | 键盘、焦点、表单、触摸、动画、URL状态、性能 | web-interface-guidelines | 90 | 溢出、本地化、极端数据、网络/错误恢复能力 | resilience.md | 91 92 ###

  1. 决策,然后实现

93 94 对于每一个非机械性变更,能够回答:这个变更解决了什么用户问题?为什么这个组件是合适的?界面必须传达什么后果?哪些证据支持这个决策?最小的连贯变更是什么? 95 96 ###

  1. 验证

97 98 1. 确认主要任务和验收标准。 99 2. 运行仓库的代码规范检查。 100 3. 检查相关紧凑和宽屏视口。 101 4. 测试每一个实质变更的可到达状态。 102 5. 验证键盘顺序、焦点移动、加载行为以及指针/触摸目标。 103 6. 测试长内容、大值、受限宽度以及本地化/RTL风险。 104 7. 加载 review-design-system 以检查结构性可见变更。 105 106 ## 产品设计标准 107 108 - 使用户的首要任务和首要操作明确无误。 109 - 除非更改它能解决一个已验证的问题,否则保留用户的心理模型和当前上下文。 110 - 明确命名重要操作的确切对象、范围和后果。 111 - 使用导航组件进行导航,使用操作组件进行操作。 112 - 选择表面持久性以匹配其重要性。 113 - 在添加模态之前优先使用内联披露。 114 - 在需要时展示高级控件,而不要让默认路径承担其复杂性。 115 - 优先使用强默认值和直接行为,而不是添加用户必须学习和维护的配置。 116 - 在使用自定义 HTML 或样式之前,优先使用语义化的 Geist 组件及其 API。 117 - 在添加容器之前,优先使用层次结构、间距和对齐方式。 118 - 通过验证和可恢复的错误来保留用户输入。 119 - 保持加载控件标签稳定;使用组件的加载/繁忙提示。 120 - 使破坏性操作与影响成比例,并在系统能够诚实地支持时提供撤销功能。 121 - 除非它能阐明结构、状态或品牌意图,否则不要添加装饰性的新奇元素、运动或复制内容。 122 123 ## 审查输出 124 125 以发现的问题为开头,按用户影响排序: 126 127 - P0: 阻止主要任务,造成严重的可访问性失败,或可能导致用户不可恢复的伤害。 128 - P1: 可能的任务失败,误导的后果,缺失的关键状态,或重大的响应式/可访问性缺陷。 129 - P2: 有意义的摩擦,不一致,弱层次结构,或可恢复性问题。 130 - P3: 次要的工艺或一致性改进。 131 132 对于每一个发现,包括:文件/行号或渲染位置、验证状态、规范来源、用户后果,以及最小的具体修复。 133 134 ## 技能完整性

135 136 - 仅在当前源代码验证和人工接受之后,才添加或更改规则。 137 - 记录范围、理由、证据、例外情况以及一个正面或反面的例子。 138 - 优先选择最具体的规则目标:规范来源、路由引用、示例、lint/eval 检查或覆盖率缺口。 139 - 保持确定性检查的机械化。将判断以文本形式保留,并附上其证据和自由度。 140 - 永远不要仅凭一张截图、一个已发布的文件或一个审查者评论,就将其提升为一个普遍适用的规则。

code

产品设计技能 SKILL.md。路由模式、操作契约和治理。

路由只是使技能有用的一部分。另一部分是技能生成结果后,如何保持这些结果的可追溯性。

### 链接到标题 使结果可追溯

复制规则具有稳定的 ID 并指向其规范来源:

rule/destructive-names-action 来源:copy.md > Actionable; verbs.md 规则:破坏性 CTA 应遵循动词 + 名词的格式。 不要使用 Confirm、OK 或单独的动词。

code

具有稳定 ID 和规范来源的示例规则格式。

当 Vercel Agent 提议一个补丁时,它会在一个安全的 Vercel Sandbox 中使用仓库的构建、测试和 linters 验证更改,然后在发布建议之前进行验证。

## 链接到标题 使用 linters 以获得更快的反馈

当 linter 可以可靠地执行规则时,我们更倾向于使用确定性检查。linters 运行速度快且成本低,因此开发人员和编码代理可以在工作过程中立即获得反馈,而无需等待后续的审查。

代码可以列出两到三个静态选项,因此 linter 可以推荐单选按钮。为破坏性操作命名正确的对象和后果需要产品上下文,因此技能会处理这些情况。

代码库中的示例包括以下规则:

- 防止嵌套模态框,这会破坏焦点管理、键盘导航和层叠。

- 对于两到三个静态选项,推荐使用单选按钮而不是下拉框,这样每个选项都保持可见。

- 要求图标按钮和表单控件具有可访问的名称,并拒绝绕过共享焦点令牌的自定义焦点环。

- 防止 className 覆盖设计系统组件的颜色、圆角或阴影,同时仍然允许布局类。

- 要求 Modal.Body,以便长内容可以正确滚动,同时保持页眉和页脚固定。

- 用主题感知的 Material 类替换原始阴影,并拒绝与 Material 内置处理方式重复的边框。

- 标记偏离 4px 网格的任意间距,并在存在标准工具类时建议使用。

每条规则都会解释为什么这种模式存在问题,并建议具体的修复方法。一些规则可以自动修复安全的迁移,例如替换过时的 Tailwind 工具类名称。

接受的决策可以采取多种形式:

- 与相关 Geist 组件旁边的可读性指导,例如 Checkbox 最佳实践。

- 产品设计技能中的代理指导。

- 当代码可以可靠地检查时,使用 linter 规则。

下面的 linter 规则展示了如何将一个产品指南编码为确定性检查:

prefer-radio-for-few-static-options.js

1 /** @type { import('eslint').Rule.RuleModule } */ 2 module . exports = { 3 meta : { 4 type : 'suggestion' , 5 docs : { 6 description : '当 Select 有 2-3 个静态选项时,建议使用 Radio 按钮' , 7 category : '设计系统' , 8 recommended : true , 9 } , 10 schema : [ ] , 11 messages : { 12 preferRadio : 13 '具有 {{ count }} 个静态选项的 Select。考虑使用 Radio 按钮 — 它们可以在不点击打开的情况下一次性显示所有选项。' , 14 } , 15 } , 16 create ( context ) { 17 return { 18 JSXElement ( node ) { 19 const opening = node . openingElement ; 20 if ( opening . name . type !== 'JSXIdentifier' ) return ; 21 if ( opening . name . name !== 'Select' ) return ; 22 const hasDynamic = node . children . some ( 23 ( child ) => 24 child . type === 'JSXExpressionContainer' && 25 child . expression . type === 'CallExpression' , 26 ) ; 27 if ( hasDynamic ) return ; 28 const optionChildren = node . children . filter ( 29 ( child ) => 30 child . type === 'JSXElement' && 31 child . openingElement . name . type === 'JSXIdentifier' && 32 child . openingElement . name . name === 'option' , 33 ) ; 34 if ( optionChildren . length < 2 || optionChildren . length > 3 ) return ; 35 context . report ( { 36 node : opening , 37 messageId : 'preferRadio' , 38 data : { count : String ( optionChildren . length ) } , 39 } ) ; 40 } , 41 } ; 42 } , 43 } ;

code

用于建议在有 2 或 3 个静态选项时使用 Radio 按钮而不是 Select 的 Lint 规则。

这些规则可以自动捕获一类错误,从而让代码审查专注于需要判断的决策。

## 链接到标题:我们如何通过评估测试指导

Lint 规则具有确定性,但代理行为可能有所不同,因此我们测试代理在之前未见过的接口上的技能。

代理编辑一个之前的状态,然后由评判者根据评分标准检查结果。

评估来自技能文档中已发布的示例。保留集隐藏了预期的编辑,测试指导是否具有泛化能力。我们还运行没有技能的测试用例,以测量技能是否改变了代理的行为。

我们分别对规则的正确性和与已发布结果的相似性进行评分。已发布的代码可能包含一个缺陷,代理应改进而不是重复。

## 链接到标题:保持指导的更新

随着组件、名称、工作流程和失败状态的变化,产品标准也在变化,每次更新都需要证据和人工审查。

我们每周的证据收集工作流程收集可能改进产品设计的设计反馈。它搜索 Slack 对话并保留指向 Figma 文件、拉取请求、审查评论和预览的链接作为证据。当证据不完整时,它会记录用于验证所需的代码或提交。

该工作流程将收集与判断分开:

- 收集者收集消息、链接和附近上下文,但不提出规则。

- 一个独立的评判者将证据分组,验证来源并记录开放问题。

- 该任务创建一个包含候选者、被拒绝的主题、后续请求和覆盖率缺口的审查包。

每个候选者都链接到其来源并保持待定状态。经验丰富的审查员的评论可以提高其优先级,但每个候选者仍然需要证据。

自动化在审查包结束。人类决定候选者是否成为代理指导、Lint 规则、示例、评估或无更改。接受的更改进入最相关的文件,并通过相关检查后合并。

## 如何将产品设计融入代码库

我们的设置反映了 Vercel 的产品、组件和评审历史,但其他团队可以根据自己的标准调整结构。

### 1. 从重复的决策开始

选择一个产品界面,其中相同的评审意见反复出现:破坏性操作、错误状态、设置表单、空白状态或导航。从已发布的代码和实际评审中收集示例,并记录决策、其重要性、例外情况和来源。

避免从“清晰”、“精致”或“直观”等宽泛的形容词开始。代理需要可观测的决策。例如,“破坏性操作使用动词 + 名词是可行的”,而“按钮应该清晰”则不够明确。

# 决策: {name} 状态: proposed | accepted | rejected 范围: 决策: 理由: 证据: 例外: 反面示例: 正面示例: 假设: 开放决策:

code

决策记录模板。

在扩展到其他界面之前,先填写与当前界面相关的字段。

### 2. 添加明确的触发器和明确的边界

在持久化仓库指令中告诉代理何时加载该技能,并定义它所涵盖的文件和界面,以及必须跳过的区域。在单独的 Next.js 评估中,代理在 56% 的情况下未能调用可用的技能。请将触发器与指导分开测试,因为加载技能失败和遵循规则失败是不同的问题。

当塑造、编辑或评审用户界面时, 加载 .agents/skills/product-design/SKILL.md。 适用范围: - 面向用户的页面和组件 - 文案、交互、可访问性、响应行为和状态 跳过: - 仅限后端且对用户不可见的工作 - 遥测、生成文件、文档和营销

code

产品设计技能的代理触发器和范围边界。

请代理报告它加载了哪些界面和参考资料,然后验证其发现是否引用了这些来源。

### 3. 将路由、规则和证据分开

使用一个简短的入口点来识别界面并加载有针对性的参考资料。围绕评审人员已经讨论的界面和决策组织细节:表单、模态框、导航、产品词汇、工作流状态和跨界面模式。

为规则分配稳定的 ID,并将其链接到示例和来源。记录已发布的示例,包括有用的决策和已知的缺陷,并在覆盖率缺口列表中保持缺失的指导可见。

# {Surface} 加载条件: 主要负责人: ## rule/{stable-id} 范围: 规则: 原因: 例外: 来源: ## 示例 反面: 正面: ## 覆盖率缺口 - {缺失的决策或证据}

code

带有稳定 ID、示例和覆盖率缺口的规则参考模板。

覆盖率缺口列表使缺失的指导变得明确。

### 4. 使用代码实现清晰的规则

如果 linter 能够可靠地识别问题,请在该位置强制执行规则。当决策需要产品或代码库上下文时,请使用代理指导。将新的标准、政策选择和未解决的产品决策与人员保持一致。

从已记录的示例和接口中未出现预期编辑的保留项构建训练用例。请分别测试检索和应用,因为代理是否加载了技能和是否遵循了规则是两个不同的问题。

不渲染的情况下,代码能否识别失败? - 不能:使用代理指导。 - 能:该规则能否避免可能的误报? - 不能:使用代理指导。 - 能:该违规行为是否有具体的修复方法? - 有:使用 linter。 - 没有:使用警告或代理指导。 需要产品或代码库上下文:使用代理指导。 建立新的标准或产品政策:需要人工决策。 对于任一路径,添加一个示例或评估,以捕获回归问题。

code

在 linter 和代理指导之间进行选择的决策树。

如果一个规则在没有大量例外的情况下无法保持可靠性,应将其移回代理指导。

### 链接到标题 5. 指定负责人和更新循环

定期审查新证据,但在更改指导或检查之前,需要人工批准。维护一个决策日志,记录发生了什么变化、原因以及支持该变化的来源。将新规则视为产品变更,对每个规则进行审查和测试,并移除那些不再有帮助的规则。

收集者提示 你是收集者。收集消息、链接、文件和附近的上下文。 只写原始工件。不要对候选对象进行评分或提出规则。 评判者提示 你是评判者。在对相关证据进行分组之前,验证覆盖范围。 将已验证的事实、推论和开放问题分开。 保留所有候选对象,不要编辑指导。 人工审查 选择:规则、参考、示例、linter 规则、评估、覆盖范围缺口或无变化。 需要稳定的证据、明确的范围和例外情况以及审批人。

code

收集者、评判者和人工审查的证据审查提示。

从一个表面和团队已经重复的决策开始。将这些决策放在代码编写和审查的地方,并让负责制定标准的人保持责任。

## 链接到标题 构建你自己的

最难的部分是选择第一个表面。每个团队都有值得编码的决策。问题是这些决策是否存在于某个人的脑海中,还是存在于代理可以找到的地方。如果你使用这种模式构建了某些东西,或者对我们的设置方式有疑问,请告诉我们。