AI Slop CLI——145 条规则,
无 LLM,在 CI 中运行
每个 AI 编码工具都会在第一次生成时落入同样的视觉默认值——头部用 Inter 90px、紫到蓝渐变、三张完全相同的卡片。解决方法不是问大模型「这个设计够好吗」——那是非确定性的。解决方法是一个在 CI 中跑的确定性 linter:145 条正则规则,扫描磁盘上的代码,无 LLM 调用,无 token 预算,sub-second。这就是 ux-skill 的 lint 子命令。
为什么用正则,而不是 LLM 当裁判
如果把「设计是否合格」交给另一个 LLM 判定,你会撞上三个互相放大的问题。
它是不确定的。同一个输入,裁判模型的结论会在多次运行中漂移。CI 失败变成 flaky test,贡献者学会重试而不是修复,信号崩塌。
它是昂贵的。每个 PR 推送都消耗 token。每次重试都让账单翻倍。一个每周 200 个 PR 的仓库,运行 LLM 设计评判器在 diff 上,实际是在用计算资源确认正则可以在 12 毫秒内捕获的同样问题。
它隐藏了规则。当裁判失败一个 PR,作者得到的是散文。当正则失败一个 PR,作者得到的是可以在自己代码中匹配并学习的模式。前者制造的是申诉文化,后者制造的是熟练文化。
145 条规则覆盖什么
从仓库的 data/anti-patterns.json 拉取。每条规则有一个 id、严重程度(low | medium | high | critical)、类别、带文件后缀作用域的正则、一行 why 和一行 fix。
| 类别 | 数量 | 覆盖范围 |
|---|---|---|
| 无障碍 | 28 | 缺失 alt 文本、仅颜色的状态、低对比度配对、点击目标小于 44px、无焦点样式、装饰性 SVG 无 aria-hidden。 |
| 内容 | 18 | 「John Doe」占位符、「Lorem ipsum」、「Beautiful experiences」、「Revolutionizing X」、通用图床 URL、emoji 标题。 |
| 排印 | 16 | Inter 当显示字体、90px 字号 + 1.0 行高、全大写正文、纯无衬线字栈、100 字重发丝线、无 font-feature-settings。 |
| 色彩 | 14 | 紫到蓝渐变(#7C3AED → #3B82F6 家族)、600/400 默认配对、白底霓虹光晕、三种靛色。 |
| 布局 | 14 | 三张同款卡一排、「Hero + 三栏 + CTA」模板、全宽渐变 Hero、所有元素居中对齐。 |
| 质量 | 14 | 生产组件上的 inline style、!important 覆盖、应该用 token 处却写死像素值、无用 import。 |
| 动效 | 10 | 所有元素都 fade-in-up、无 prefers-reduced-motion 分支、悬停超过 500ms、自动播放轮播。 |
| 视觉 | 4 | 扁平设计上的阴影、模糊背板无降级。 |
| 性能 | 2 | 动画 top/left/width/height 而不是 transform。 |
| 合计 | 145 | 覆盖九大类。每条规则在 指纹清单 中有完整解释。 |
本地一行运行
# 默认:在 high+critical 上 gate,扫描当前目录 $ uxskill lint [OK] Scanned 142 files in 412ms · 0 findings at threshold high # 降低到 medium $ uxskill lint --threshold medium # 扫描子目录 $ uxskill lint apps/web/src --threshold high # JSON 输出,管道给 jq $ uxskill lint --json | jq '.findings | length'
典型的失败长这样:
$ uxskill lint apps/web/src
[FAIL] 4 findings at threshold high · exit 1
high inter-as-display src/components/Hero.tsx:18
Inter 用作显示字体
fix: 给 Inter(正文)配 Geist / Satoshi / Cabinet Grotesk
high purple-to-blue-gradient src/styles/hero.css:42
默认的紫到蓝 AI 渐变
fix: 单一克制的强调色(Emerald、Electric Blue、Deep Rose)
high three-equal-card-grid src/pages/index.tsx:96
一排三张同款卡
fix: 不对称布局(bento、7-and-5、四张含一张跨列)
无 LLM 调用。200 文件 Next.js 仓库的平均耗时:冷启动 380ms,热启动 90ms。
GitHub Actions 工作流
放到 .github/workflows/ux-lint.yml,每个 PR push 都会被 linter 阻塞。Python 安装是最贵的一步,大约 6 秒;lint 本身在大多数仓库上 sub-second。
# .github/workflows/ux-lint.yml name: ux-lint on: pull_request: paths: ['**/*.{tsx,jsx,vue,css,scss,html}'] jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: { python-version: '3.11' } - run: pip install uxskill - run: uxskill lint --threshold high
pre-commit hook(在 push 之前就拦下来)
# .pre-commit-config.yaml repos: - repo: local hooks: - id: uxskill-lint name: ux-skill 反模式 lint entry: uxskill lint --threshold high --staged language: python additional_dependencies: [uxskill] files: \.(tsx|jsx|vue|css|scss|html)$ pass_filenames: true
仅扫描 staged 文件,平均运行时间在 200ms 以下。diff 在离开笔记本之前就被拦下来。
Linter 是 AI 辅助代码库中唯一的确定性表层。其他所有检查都是概率性的。
和推荐器配对
单独的 linter 是被动的——它捕获已经存在的代码中的 slop。完整的 ux-skill 循环既预防又被动:
/ux-frame—— 10 字段发现简报(forcing function)。/ux-recommend—— Python 推荐器 跑 5 个并行检索并返回一个系统。/ux-design—— 在系统上生成界面。/ux-lint—— 用 145 条正则规则给输出加门。/ux-fix—— 自动修补 linter 能解决的问题(Inter → Fraunces、靛色渐变 → 单一强调色、三卡 → 不对称)。
步骤 1-3 降低模型产出 slop 的频率。步骤 4-5 捕获漏网的。推荐器抬高地板;linter 设定天花板。
正则捕获结构性指纹,不捕获品味。
linter 永远不会捕获「这一节的节奏不对」或「这段文案太冷」。这些需要人或模型。正则能捕获的,是每一个有字面 token、模式或形状的指纹——这覆盖了 AI 默认值的大部分,因为模型每次都会伸手去拿同一件工件。
我们刻意不在 CI 里跑 LLM 裁判。如果你的标准是「看起来像设计师做的」,那是 code review,不是 lint。ux-skill 提供 /ux-critique 用于品味检查——但它在编辑器里按需运行,不在 CI 里。
跨 IDE 分发
同一个 Python 包,每一个能跑 Python 或 shell 出去的 IDE:Claude Code、Cursor、Windsurf、Copilot、Gemini Code Assist、Aider、Continue、Cline、Roo Code、Codex,以及另外七个。Windsurf 安装 · Cursor 安装。