★ 零个 em-dash:为什么这条禁令被写成了二元规则

2026-08-09

本文所有仓库信息核对日为 2026-08-09,以上游仓库最新内容为准。

taste-skill 默认 skill 的 skills/taste-skill/SKILL.md 共 1206 行,里面关于版式、动效、间距的规定绝大多数都带着”视情况""除非需求明确要求”的余地。明写”这条不可谈判”的条目很少:§6.B 的 reduced motion 是一条,§9.G 的 em-dash 禁令是另一条,而后者把”程度”这个维度删得最干净。原文给这一节起的标题是「被违反最多的那条 Tell」,正文措辞是二元的:零个。这一节最值得看的不是禁令本身,而是它在文末自己交代了为什么要写成这个形状。

一、先把条文原样摆出来

这条规则在 §9 AI TELLS 的 §9.G。原文的定性是:em-dash(被完全禁止,它是 LLM 的招牌文体拐杖,是生产测试里的 #1 视觉 Tell。紧接着连堵三个口子:没有”少量使用”的余地,没有”自然语言频率”的余地,没有”正文里可以”的余地。一个都没有。

然后是分场景的五条:

  • 标题里禁,用句号或逗号
  • eyebrow、标签、胶囊、按钮文字、图注、导航项里禁,用换行、分栏或发丝线替代
  • 正文里禁,重构句子:拆成两个句号句,或用逗号,或用括号,或用冒号
  • 引言署名里禁,用带空格的普通连字符(-)或换行加更轻的字重
  • en-dash()作分隔符时同样禁。年份区间(2018-2026)用连字符,数字区间(€40-80k)用连字符

页面上唯一被允许的破折类字符只有两个:普通连字符 -(复合词、区间、标记里的分隔线),以及数学减号(-5°C)。

判定语原文写得很干脆:输出里只要在用户可见处出现一个 ,就算未通过 Pre-Flight Check,必须重写。这条不可谈判。

注意最后那句限定:「用户可见处」(原文 anywhere visible to the user)。条文把范围划到”渲染出来给人看的字符”这一层就停了,源码注释、提交信息这类用户看不到的文本,条文里没有交代。范围就到这里,别替它往两边扩。

二、★ 它自己写出了立法理由

这一节结尾有一句话,是整条规则里信息量最大的部分。原文说明了为什么措辞要写成二元:历史上把 em-dash 限制表述成 “use sparingly”(少量使用)时,agent 会忽略它,所以这里的措辞改成二元的——零个 em-dash。

把这句话拆开看,它承认了三件事:

第一,这条规则的约束对象是模型,不是设计师。一个人类排版师看到”少用破折号”能自己拿捏分寸;模型在面对带程度副词的约束时,服从率不够。规则作者选择的不是把话说得更细,而是把程度维度直接砍掉。

第二,规则的形状是按失败率反推的,不是按排版理论推的。§9 其它条目多少还讲得出审美道理(§9.A 说不要过饱和强调色,理由是降饱和才能融入中性色;纯黑同样被禁,理由写在 §8.B:纯值会杀掉纵深),em-dash 这条给出的正当性来源却是”生产测试里它排第一”。这是一条运维性质的规则,被放进了审美文档里。

第三,误伤是写在条文表面的。“没有自然语言频率的余地”这句话摆明了:即便某处用 em-dash 在英文写作里完全合法,也照禁不误。二元规则拿准确性换服从率,这个取舍在原文里读得出来,不用猜。

理解到这一层,你才能判断这条规则该不该抄。

三、它靠什么”生效”

这里必须把性质说清楚,否则容易读成一条工程保障。

taste-skill 是一个纯 Markdown 的规则仓库,没有 src/,没有运行时,没有任何东西会在你的项目里执行这些条文。SKILL.md 是写给模型看的提示词约束,不是 lint 规则,不是 CI 检查。“禁止 em-dash”是一条指令,不是”装了这个 skill 你的输出里就不会有 em-dash”的结果。中间隔着模型会不会听话这一层,而这一层恰恰就是原文那句立法理由承认存在的那一层。

在仓库内部,这条规则的执行挂钩是 §14 FINAL PRE-FLIGHT CHECK。原文对这份清单的定性是:出码前跑这张矩阵,这是最后一道过滤,THIS IS NOT OPTIONAL. Run every box. If any box fails, the output is not done.(不可选,每个框都要跑,任何一个不过就是没做完。)我们实读这份清单共 62 个复选框,其中就有一条零 em-dash。清单末句是:若有任何一个复选框不能诚实打勾,页面就没做完,交付前先修好。

关键词是”诚实打勾”。这份清单同样是文本,勾是模型自己打的。所以完整的链路是:一条二元指令,交给一份自查清单,由被约束的那一方自己执行。这个链路能提高概率,不能给你结果。

四、为什么恰好是这条能写成二元

62 个复选框里的条目并不是同一类东西,把它们摆在一起就能看出这条规则为什么特别。

一类是能机械判定的。零 em-dash 是最典型的:字符出现与否,一个 grep 就能给出确定答案,不需要理解上下文。同一份清单里还有一条 EYEBROW COUNT,原文明写是机械计数:count ≤ ceil(sectionCount / 3),hero 算 1。§9.F 里”中点(·)要定量配给,元信息条里每行最多 1 个”也是这一类。跑马灯每页最多一条、导航单行且高度不超过 80px,同样能数。

另一类只能靠判断。§9.F 里禁止 “From the field”、“Field notes”、“Currently on the bench” 这类诗意标签,理由是读起来是表演式匠人腔;禁止”不要 ‘We respect the French ones’ 式假谦虚的行业内部梗”;要求”内容密度合理""代码在视觉上要干净、有记忆点”。这些条目你没法写成二元,因为判定本身就需要品味。

这就给出了一条可以带走的判断依据:二元表述只在规则可机械判定时才划算。可机械判定的规则写成二元,代价是偶尔误伤一个合法用法,收益是服从率上去了、而且事后可验证;不可机械判定的规则写成二元,只会逼模型在灰色地带里瞎猜,还没法复查。你往自己的提示词里加硬禁令的时候,先问这一句:这条我事后能不能用一行命令查出来。查得出来,就写死;查不出来,写死也没意义。

五、同一份文档里,不是每条禁令都不可谈判

顺着上一节再往下看一层,会发现 §9 内部对”余地”的处理并不统一,而且是明写在条文里的。

§9.B 版式那条写的是避免把 Inter 当默认,后面直接跟了一句「见 §4.1,有 override 路径」。也就是说,这条禁令承认存在合法的例外走法,并且给你指了门在哪。而 §9.G 结尾写的是”这条不可谈判”,全文没有给出任何 override 入口。

同一节里,一条禁令留了 override 路径,另一条明标不可谈判,两者的处理不一致。以仓库当前状态为准,我们只陈述这个差异。

对使用者来说,这个差异有实际意义:当你想在某个具体场景偏离规则时,先看这条规则本身有没有给出偏离路径。写了 override 的,按它指的路径走;写了不可谈判的,你要么整条不用,要么就照做——在这个文档的口径里,没有”我这次少用几个”这个中间态。

六、抄进中文项目之前,先看两件事

第一件:这条规则的原始语境是英文界面文案。 条文里举的例子(2018-2026€40-80k、引言署名)都是英文排版场景。你的产出如果是中文正文,破折号在你的语言里承担的功能和英文 em-dash 并不重合,直接照搬这条禁令等于替中文读者改掉了一种正常标点。要不要禁,取决于你在意的是”AI 味”还是”排版规范”,这两件事在中文语境里未必指向同一个结论。

第二件:如果你打算把它做成脚本,先确认码点。 中文全角破折号在常见输入法下打出来往往就是两个 em-dash 字符连排,也就是这条规则要禁的那个码点本身。一条照抄过来的检查规则,很可能会把你正文里所有正常的中文破折号一起判成失败。落脚本之前,自己在项目里实际取一段样本确认是哪个码点,别照着别人的正则改。

顺带说一句,这条规则真正值得学的部分是”把可机械校验的约束落到机械校验里”这个动作本身。skill 只能把它写成提示词,因为 skill 就是一堆 Markdown,没有别的执行位置可挂。你有构建链,你可以把它挂在真正会拦住提交的地方。那才是把”指令”变成”结果”的唯一途径。

七、收尾

§9.G 是全份 SKILL.md 里最短、最硬、也最坦白的一节。它禁的是一个字符,交代的却是整套规则的工作方式:作者观察到模型在模糊约束下不服从,于是把这条约束的程度维度删掉;删掉之后需要一个判定点,于是挂到 Pre-Flight 的复选框上;而复选框仍然由模型自己勾。

看懂这条链路,你对 taste-skill 里所有硬禁令的期待值就该校准了:它们提高概率,不给保证。真要保证,得你自己动手加一道拦得住的检查。


本文依据 taste-skill 官方仓库(github.com/Leonxlnx/taste-skill)的 README、CHANGELOG、 skills/ 下的 SKILL.md 与 .claude-plugin/ 清单整理,核对日 2026-08-09。 本文内容为仓库文档口径,我们没有安装或运行过其中任何一个 skill, 文中所有规则均为写给模型的提示词约束,不构成对输出结果的保证。 skill 内容随上游更新而变动,默认 skill 当前自标为 v2 (experimental) 且仍在迭代,请以仓库最新内容为准。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。