语义规范体系:YAML里写的不是颜色值是语义令牌

1 评论 782 浏览 0 收藏 19 分钟

设计规范正经历从文档到代码的范式转变,而语义翻译成为关键突破口。本文深度解析Schema-As-Code方法论,揭示如何通过YAML语义契约实现设计意图的机器可读化,构建包含四大命名空间、三种语义域和不可变边界的完整体系,彻底解决AI生成内容时的语义失控问题。

本文是阶段二《设计师作为”语义翻译者”》的语义规范体系专题。阶段二论证了设计规范从文档转向代码的必要性:传统规范给”人”看,机器无法读取,AI生成内容时不受约束。核心方案是Schema-As-Code——将设计意图翻译成YAML语义契约,让机器在生成前读取并执行约束。

需要首先澄清:YAML里写的不是颜色值,不是文案,是语义令牌。这不是”技术实现”,是”语义翻译”。

本文在此基础上回答”代码格式的规范体系长什么样”:YAML格式标准、语义令牌命名空间、语义域分类、契约库管理,以及到Prompt前缀/Checklist/CI规则的编译输出机制。

阶段一:组件语义快照与模式诊断:AI 生成界面的第一道检查

方法论总纲与开源仓库:把设计规范写成代码格式,是所有 AI 工具的上游约束方法论

一、引言:YAML 里到底写的是什么?

我第一次给别人看我的 YAML 契约时,对方看了一眼说:”这不就是 Design Token 吗?把颜色、字体写成代码格式。”

我说不是。他反问:”那你写的 color_token: status.critical 和 Design Token 的 color: #EF4444 有什么区别?”

这个问题让我意识到:如果我不先讲清楚“语义令牌”和“Design Token”的区别,所有人都会把 Schema-As-Code 理解成“另一种 Design Token 写法”,然后整个方法论就被矮化了。

所以这篇文章必须放在 YAML 格式之前——先理解语义规范体系,再看 YAML 怎么写,顺序不能反。

二、Design Token vs 语义令牌:两个完全不同的东西

Design Token 解决什么问题?

Design Token 管的是”视觉层的一致性”:

# Design Token(Figma / Tokens Studio / Style Dictionary)

color:

primary: “#1677FF”

danger: “#EF4444”

warning: “#F59E0B”

font:

family: “Inter”

size: 14px

Design Token 回答的问题:”这个按钮用什么颜色、什么字体?”

它的作用是:让设计稿和代码里的颜色值保持一致,设计系统更新时,改一处全局生效。

语义令牌解决什么问题?

语义令牌管的是”语义层的一致性”:

# 语义令牌(Schema-As-Code)

semantic_tokens:

error_severity:

fatal:

visual_mapping:

color_token: “status.critical” # ← 不是 #EF4444,是 “致命状态”

motion_token: “pulse.red.urgent” # ← 不是 pulse 2s,是 “紧急脉冲”

icon_token: “alert.octagon” # ← 不是 warning.svg,是 “八边形警告”

语义令牌回答的问题:”这个错误在这个场景下代表什么后果?用户应该怎么理解?”

核心区别:一层 vs 两层

关键洞察:Design Token 是“视觉字典”,语义令牌是“语义字典”。两者互补,不是替代。

用户看到的界面

Design Token(管颜色、字体、间距)

语义令牌(管颜色代表什么、文案传递什么)

机器理解的规则

没有语义令牌,AI 知道“用红色”,但不知道“红色代表致命”。

三、语义令牌的四大命名空间

我设计语义令牌时,把常见的语义场景归纳为四大类,每类一个命名空间:

1. status.* —— 状态级别

回答的问题:“这件事有多严重?”

为什么不是直接写颜色?

因为同一个 status.critical 在不同设计系统里可以映射到不同的色值:

  • 设计系统 A:#EF4444(Tailwind 红)
  • 设计系统 B:#F5222D(Ant Design 红)
  • 设计系统 C:#FF4D4F(DevUI 红)

语义令牌不关心具体色值,只关心语义映射关系。 设计系统更新时,改映射表,语义令牌不变。

2. phase.* —— 认知阶段

回答的问题:“AI 现在处于什么阶段?用户在等什么?”

为什么需要阶段令牌?

Perplexity 的 “Searching…” “Reading…” “Wrapping up…” 让用户困惑——不知道 AI 是在查资料还是开始编答案。

有了 phase.*,系统可以显化认知阶段:”现在处于检索阶段,已找到 5 个来源,其中 4 个一致。”用户知道”这是查出来的,不是猜出来的”。

3. boundary.* —— 边界强度

回答的问题:“系统拒绝用户时,权利边界在哪里?”

为什么需要边界令牌?

Claude 的 “I can’t help with that” 和 “Claude has ended this chat” 在界面上都是”拒绝”——用户不知道对话还在不在、数据丢没丢。

有了 boundary.*,系统区分:软性拒绝(继续聊)vs 强制终止(开新会话)。用户明确知道自己的权利状态。

4. action.* —— 操作性质

回答的问题:“用户点击这个按钮后,后果是什么?”

为什么需要操作令牌?

AI 生成”删除账户”按钮时,默认给蓝色实心”确认”——因为 Prompt 里只说”生成一个删除按钮”,没有说”这是不可逆操作”。

有了 action.destructive,系统知道:这个按钮后果是破坏性的,必须红色空心、必须二次确认、必须输入账户名验证。

四、语义域:组件在什么场景下?

语义令牌定义了”是什么”,但同一个组件在不同场景下,语义可能完全不同。

我设计了三个语义域(Semantic Domain):

observational —— 观察型

特征:用户被动接收信息,不需要操作。

典型组件:错误提示、状态通知、告警卡片。

约束

  • 禁止要求用户输入
  • 必须提供明确的退出路径
  • 文案必须说明后果(不能只说“出错了”)

transactional —— 交易型

特征:用户主动触发操作,系统必须反馈结果。

典型组件:提交按钮、表单、确认弹窗。

约束

  • 必须提供操作结果反馈
  • 成功/失败状态必须明确
  • 不可逆操作必须有二次确认

conversational —— 对话型

特征:用户和系统双向对话,上下文持续累积。

典型组件:聊天界面、问答系统、AI 助手。

约束

  • 必须保留对话上下文
  • 边界动作必须说明会话状态
  • 拒绝时必须提供替代建议

为什么需要语义域?

同一个 Alert 组件:

  • 在 observational 域(系统故障)→ 用户被动看,不能要求输入
  • 在 transactional 域(表单验证)→ 用户主动填,必须给反馈
  • 在 conversational 域(对话中断)→ 上下文要保留,不能说断就断

没有语义域,系统不知道“这个组件在用户流程中扮演什么角色”,约束就会错位。

五、不可变边界:红线

语义令牌定义”应该是什么”,不可变边界定义”绝对不能是什么”。

我把它理解为”语义红线”——一旦触碰,系统必须阻断。

示例:ERR-001 的不可变边界

immutable_boundaries:

– boundary_type: “safety”

rule: “禁止直接执行删除操作而不显示二次确认”

violation_action: “block”

– boundary_type: “clarity”

rule: “禁止在错误状态文案中使用模糊词汇(如’出错了’、’Something went wrong’)”

violation_action: “block”

– boundary_type: “consistency”

rule: “禁止将不同严重级别的错误使用相同视觉表达”

violation_action: “block”

为什么叫”不可变”?

这些边界不是”建议”,是”强制规则”:

  • block:一旦触发,直接阻断生成,返回修改建议
  • warn:触发后警告,但允许人工确认后放行
  • escalate:触发后升级人工审核

与语义令牌的区别:

  • 语义令牌 = “ fatal 应该用什么颜色”(推荐性映射)
  • 不可变边界 = “fatal 绝对不能和 retryable 用同一种颜色”(强制性约束)

六、完整示例:ERR-001 的语义规范拆解

把上面的概念串起来,看 ERR-001 是怎么从”语义规范”翻译成”YAML 契约”的:

语义规范层(设计师的意图)

设计意图:

– 错误状态必须按后果严重程度分级

– 用户必须知道”多严重”和”该做什么”

– 系统绝对不能让不同级别的错误长得一样

语义规范:

– 状态级别:fatal / transient / retryable / degraded(status.*)

– 语义域:observational(用户被动接收)

– 不可变边界:不同级别不能用相同颜色

语义令牌层(机器可读的标识)

# 语义令牌映射

status.critical → 致命错误 → 红色脉冲

status.neutral → 可恢复错误 → 灰色加载

status.warning → 限流提示 → 黄色倒计时

status.info → 部分可用 → 蓝色提示

YAML 契约层(可执行的规则)

intent_id: “ERR-001”

semantic_domain: “observational”

semantic_tokens:

error_severity:

fatal:

description: “系统级故障,对话上下文可能丢失”

visual_mapping:

color_token: “status.critical” # ← 语义令牌

motion_token: “pulse.red.urgent” # ← 语义令牌

icon_token: “alert.octagon” # ← 语义令牌

user_action:

– label: “刷新页面”

action: “refresh”

– label: “导出历史”

action: “export_history”

llm_constraints:

– “必须明确告知用户对话上下文可能已丢失”

transient:

description: “网络抖动,系统可自动恢复”

visual_mapping:

color_token: “status.neutral” # ← 语义令牌

motion_token: “spinner” # ← 语义令牌

icon_token: “loader” # ← 语义令牌

user_action:

– label: “等待自动恢复”

action: “wait”

llm_constraints:

– “禁止红色背景(避免情绪过载)”

immutable_boundaries:

– boundary_type: “consistency”

rule: “禁止将不同严重级别的错误使用相同视觉表达”

violation_action: “block”

三层关系:

  • 语义规范层 = 设计师的意图(人话)
  • 语义令牌层 = 机器可读的标识(机器话)
  • YAML 契约层 = 可执行的规则(代码话)

七、语义规范与 YAML 契约的关系

不是先有 YAML 格式,再往里填内容。

是先有语义规范体系,再选择 YAML 作为载体。

语义规范(理论层)

├── 语义令牌命名空间(status / phase / boundary / action)

├── 语义域分类(observational / transactional / conversational)

└── 不可变边界原则(安全 / 清晰 / 一致)

YAML 契约(实现层)

├── semantic_tokens 字段(填语义令牌)

├── context 字段(填语义域)

└── immutable_boundaries 字段(填红线)

理解了这个关系,就不会把 Schema-As-Code 当成”另一种 Design Token”,而是”设计意图的语义翻译层”。

八、Before/After:加了语义规范后,YAML 契约长什么样?

Before(没有语义规范,YAML 只写视觉值)

# 错误状态规范(没有语义层)

error:

color: “#EF4444”

bg: “solid”

icon: “warning.svg”

text: “Something went wrong”

button: “重试”

问题:

  • 前端看了知道“用红色”,但不知道“红色代表什么”
  • AI 看了知道“生成红色按钮”,但不知道“什么场景下该用什么红色”
  • 设计系统更新红色色值时,YAML 要全部改一遍

After(有了语义规范,YAML 写语义令牌)

# 错误状态规范(有语义层)

semantic_tokens:

error_severity:

fatal:

visual_mapping:

color_token: “status.critical” # ← 语义令牌,不是色值

motion_token: “pulse.red.urgent”

icon_token: “alert.octagon”

user_action: [“刷新页面”, “导出历史”]

transient:

visual_mapping:

color_token: “status.neutral” # ← 同一组件,不同语义,不同令牌

motion_token: “spinner”

icon_token: “loader”

user_action: [“等待自动恢复”]

改变:

  • 前端看了知道“fatal 用 status.critical”,去映射表查具体色值
  • AI 看了知道“fatal 必须红色脉冲 + 刷新/导出按钮”
  • 设计系统更新色值时,改映射表,YAML 完全不变

九、总结

Schema-As-Code 的 YAML 契约里写的不是颜色值、不是文案、不是 Design Token。

写的是语义令牌——机器可读的语义标识,定义“这个界面元素在这个场景下代表什么”。

四大命名空间:

  • status.* —— 状态级别(多严重)
  • phase.* —— 认知阶段(在干什么)
  • boundary.* —— 边界强度(权利在哪)
  • action.* —— 操作性质(后果是什么)

三层语义域:

  • observational —— 用户被动看
  • transactional —— 用户主动点
  • conversational —— 用户和系统聊

一条红线:

  • immutable_boundaries —— 绝对不能做什么

理解了这个语义规范体系,再看 YAML 格式,就知道每个字段填的不是视觉值,是语义映射。

本文由 @阿基拉de_Akir 原创发布于人人都是产品经理。未经作者许可,禁止转载

题图来自Unsplash,基于CC0协议

更多精彩内容,请关注人人都是产品经理微信公众号或下载App
评论
评论请登录
  1. 语义令牌的框架很漂亮,但落地时有个现实问题:设计师和前端对“语义域”的理解可能不一致,同一个Alert在不同人手里定义不同。单纯的YAML约束能否消除这种分歧,还是得靠强制的Lint规则。

    来自广东 回复
    1. 语义域还需要明确定义每个语义域的含义、适用范围、设计师约束、前端约束。 YAML 和 Lint 只是它的下游消费方式。

      来自广东 回复