設計工程師的 Agent 技術堆疊
設計工程師需要的 agent 堆疊,與純工程師截然不同。 標準 agent 基礎架構針對正確性最佳化:測試通過、型別檢查無誤、lint 規則成立。但從來沒有人為設計品質建立過同等的基礎架構——確保 agent 產出的成果看起來經過深思熟慮,而非僅僅能用。設計工程師的 agent 堆疊包含六大元件:字型 hook、色彩系統 hook、版面驗證、Lighthouse 閘門、無障礙 lint,以及視覺回歸測試。它們共同將工藝編碼進流程之中。
這個缺口在每個 AI 生成的介面中都清晰可見。間距不一致、字級偏離了既定的級距系統、寫死的十六進位色值繞過了 token 體系。版面位移在行動裝置上浮現,因為沒有人在 agent 修改 CSS 之後檢查 CLS。agent 通過了每一項測試、滿足了每一項型別檢查,產出了程式碼審查者會核准的結果——因為程式碼審查者評估的是邏輯,不是視覺一致性。設計工程師一眼就能發現問題。但 agent 基礎架構什麼都沒察覺,因為從來沒人告訴它該看什麼。
工程師的 agent 基礎架構已經快速成熟。Hook 會阻擋危險的 git 指令。證據閘門在標記工作完成前要求提出證明。品質迴圈強制要求重新逐行閱讀。工程品質可以分解為可驗證的屬性(正確性、效能、安全性、型別安全),每個屬性都對應到一個能產出二元結果的工具。
設計品質同樣可以分解。品味是一個技術系統,包含四個可編碼的元件:約束、評估準則、模式辨識與一致性。前三者可以直接映射到自動化基礎架構。一致性需要人的判斷,但前三者已經涵蓋了足夠的範圍,能夠防止 agent 最常產生的設計缺陷。字型違規、色彩偏移、版面不穩定、效能退化、無障礙失敗——全都是機器可偵測的。設計工程師的 agent 堆疊就是用來偵測這些問題的。
設計工程師對 Agent 的需求
純工程師問的是:程式碼能不能運作?設計工程師還要追問六個問題,每個問題針對視覺品質的不同面向。
視覺一致性。 間距值遵循 8 點網格或既定的間距級距。對齊尊重垂直節奏。元素之間的比例關係在不同視窗尺寸下保持穩定。當 agent 新增一個卡片元件,用的是 margin-top: 13px 而非 var(--space-md),它就引入了任何測試都抓不到的視覺雜訊。
字型紀律。 程式碼庫中每個字級都對應到字型級距中的一個階層。不容許任何隨意的尺寸,不容許任何繞過自訂屬性的行內覆寫。字重使用遵循既定層級:700 用於標題、400 用於內文、300 用於後設資料。當 agent 將副標題設為 font-size: 19px,它就發明了一個級距中不存在的階層,視覺層級隨之崩塌。
色彩系統合規。 每個色彩值都引用設計 token。:root 和設計 token 定義之外不允許寫死的十六進位值。對比度至少符合 WCAG AA,盡可能達到 AAA。我網站上的零色彩系統使用四個透明度層級搭配絕對黑色,每個層級都通過 AAA。當 agent 引入 color: #cccccc,它就繞過了 token 系統,創造了一個未經任何人驗證的對比關係。
效能意識。 不允許累積版面位移(Cumulative Layout Shift)。首次內容繪製(First Contentful Paint)維持在預算之內。總阻塞時間(Total Blocking Time)不得退化。Agent 必須理解視覺變更帶有效能後果。一個在每次捲動事件中觸發版面重新計算的 CSS 變更就是效能缺陷,無論它看起來如何。
無障礙。 語義化 HTML 結構、正確的標題層級、必要時加上 ARIA 屬性而非濫用、色彩對比驗證、焦點指示器、螢幕閱讀器相容性。Lighthouse 稽核能捕捉可量測的子集,但 agent 還必須維護自動化工具可能遺漏的結構語義。
品味。 最難編碼的面向。元素之間的一致性、裝飾的節制、刻意留白而非意外的空洞。品味是區分「遵循每條規則但感覺不對」與「遵循每條規則且感覺到位」的品質。自動化檢查能捕捉違規。品味層捕捉的是那些沒有違規、但仍欠缺考量的問題。
設計工程師堆疊的六大元件
每個元件都對應到我在 agent 生成輸出中觀察到的特定失敗模式。這些元件並非理論推演,每一個之所以存在,都是因為某件事出了錯——與我95 個 hook 基礎架構中每個 hook 的誕生故事如出一轍。
1. 字型 Hook
字型 hook 驗證提交中的每個 font-size 宣告都引用了字型級距中的 CSS 自訂屬性。Hook 會掃描變更檔案,找出未對應到任何已定義階層的原始像素或 rem 值。
#!/bin/bash
INPUT=$(cat)
DIFF=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
# Catch font-size declarations that bypass the type scale
if echo "$DIFF" | grep -qE 'font-size:\s*[0-9]+(px|rem|em)'; then
cat << EOF
{"decision": "block", "reason": "Font size must use a --font-size-* token"}
EOF
fi
這個 hook 很直接。更精緻的版本會解析數值,檢查像素等效值是否對應到 13 階級距中的任何一階。重點不在精巧,而在於 agent 無法在基礎架構不發出警示的情況下引入任何隨意的字級。Bringhurst 關於和諧字型關係的原則之所以成立,並非因為 agent 理解和諧,而是因為 hook 強制執行了體現和諧的級距。1
字重值得獨立驗證。我的系統使用三種字重:700、400 和 300。當 agent 將卡片標題設為 font-weight: 600,它就引入了一個與既定層級矛盾的字重。字型 hook 會在它進入正式環境之前捕捉到這個偏差。
2. 色彩系統 Hook
色彩偏移是 agent 生成 CSS 中最常見的設計缺陷。Agent 知道深色背景上的文字應該是白色,但它不知道 #ffffff 應該是 var(--color-text-primary),也不知道 65% 透明度的次要文字是 var(--color-text-secondary) 而非 rgba(255,255,255,0.60)。
色彩 hook 掃描 :root 和設計 token 定義之外的寫死色彩值:
# Block hardcoded colors outside token definitions
if echo "$DIFF" | grep -vE '^\+.*:root' | \
grep -qE '#[0-9a-fA-F]{3,8}|rgba?\('; then
cat << EOF
{"decision": "block", "reason": "Use color tokens, not hardcoded values"}
EOF
fi
零色彩設計系統——驅動整個網站視覺識別的同一種粗獷主義約束——使得強制執行變得簡單明瞭,因為調色盤恰好只有十個 token。任何不匹配這些 token 的色彩值,就定義而言都是錯的。更寬泛的調色盤需要更細緻的驗證。基於約束的方法簡化了 hook,因為約束簡化了設計。
3. 版面驗證
版面驗證捕捉兩類失敗:由 CSS 變更引入的累積版面位移,以及響應式斷點退化。
CLS 偵測需要測量變更前後的頁面狀態。預提交 hook 無法執行瀏覽器,但 CI 流水線可以。基礎架構在無頭 Chrome 中對暫存部署執行 Lighthouse,將 CLS 值與前一次建置比較,若差值超過 0.01 即阻擋合併。Google 認為 CLS 低於 0.1 為「良好」。我的門檻嚴格 10 倍,因為我見過 0.493 的 CLS 是什麼樣子,絕不容許退化。
響應式驗證需要在已定義的斷點檢查版面。視覺回歸工具在 375px(手機)、768px(平板)和 1440px(桌面)擷取螢幕截圖,然後與基準圖像比較。在 375px 出現的 5 像素標題位移,在 1440px 看起來可能毫無問題,卻會在手機端比較中浮現。修改了 max-width 屬性卻未測試響應式行為的 agent,會被自動測試響應式行為的基礎架構捕獲。
4. Lighthouse 閘門
Lighthouse 閘門在每次合併至主分支之前執行完整稽核。閘門強制執行四項門檻:
| 類別 | 門檻 |
|---|---|
| 效能 | 100 |
| 無障礙 | 100 |
| 最佳實務 | 100 |
| SEO | 100 |
這些門檻並非理想目標,而是反映了目前正式環境的分數。任何讓任一分數低於 100 的提交都會被阻擋。閘門在 CI 中使用 lighthouse-ci 執行,結果會作為狀態檢查回饋至 pull request。
# lighthouse-ci configuration
assertions:
performance: ["error", { minScore: 1 }]
accessibility: ["error", { minScore: 1 }]
best-practices: ["error", { minScore: 1 }]
seo: ["error", { minScore: 1 }]
cumulative-layout-shift: ["error", { maxNumericValue: 0.01 }]
Lighthouse 閘門能捕捉人類審查者不會注意到的效能退化。當 agent 加入一張未最佳化的圖片、一個阻塞渲染的腳本,或一個觸發無樣式內容閃爍的 CSS 檔案,閘門會在變更進入正式環境之前將其阻擋。閘門不需要理解變更為何導致退化,它只需要阻擋退化,讓 agent 在下一次嘗試時從上下文中獲得失敗原因。
5. 無障礙 Lint
無障礙驗證分為兩層:靜態分析與執行階段評估。
靜態分析針對渲染後的 HTML 執行 axe-core。WCAG 2.1 AA 規則集能捕捉缺失的替代文字、不正確的標題層級、不足的色彩對比、缺失的表單標籤,以及 ARIA 誤用。檢查在與 Lighthouse 閘門相同的無頭 Chrome 實例中執行,額外開銷微乎其微。
// axe-core integration in CI
const { AxeBuilder } = require('@axe-core/playwright');
const results = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21aa'])
.analyze();
if (results.violations.length > 0) {
process.exit(1); // Block the merge
}
執行階段層捕捉靜態分析遺漏的問題:HTMX 置換後的焦點管理、動態內容的鍵盤導航、狀態變更的螢幕閱讀器播報。這些檢查需要腳本化互動,不僅僅是 DOM 檢查。無建置方法讓頁面保持足夠簡潔,使無障礙涵蓋範圍維持在可管理的程度。
無障礙 lint 是大多數工程師已經理解的元件。設計工程師的附加價值不在工具本身,而在門檻:零違規,而非「可接受的」違規。同樣的理念驅動著 100/100/100/100 的 Lighthouse 分數:以完美為基準線,而非遠方的願景。
6. 視覺回歸測試
視覺回歸測試將當前建置的螢幕截圖與已核准的基準進行比對。比對使用感知差異演算法,偵測人類會注意到的變化,同時忽略人類不會注意到的差異(次像素渲染差異、反鋸齒變化)。
Percy、Chromatic 和 BackstopJS 等工具可以自動化比對流程。流水線在每個已定義的斷點擷取螢幕截圖,對基準執行感知差異比對,並標記差異超過門檻的頁面。頁尾 0.1% 的像素差異是雜訊;主視覺區域 2% 的位移則是退化。
視覺回歸是「頁面看起來對不對?」最接近的自動化近似。感知差異演算法無法評估版面變更是改進還是退化,只能判斷變更是否發生。人類審查被標記的差異,決定核准或駁回。自動化的價值在於覆蓋率:在每次提交中、每個斷點測試每個頁面,這是人類不可能手動完成的任務。
堆疊如何對應我的基礎架構
六大元件與本站設計工程內容中已記錄的各項決策環環相扣。
字型 hook 強制執行 13 階字型級距——一套以內容為驅動的遞進體系,級距以 CSS 自訂屬性存在,hook 確保這些屬性是程式碼庫中唯一的字級來源。色彩系統 hook 強制執行零色彩設計系統:十個 token、四個透明度層級、無品牌色、不可選擇。Lighthouse 閘門維護 100/100/100/100 分數,防止任何提交撤銷達成這些數字所需的 CSS 提取和阻塞渲染消除工作。
無建置方法簡化了整個堆疊。無需調和 source map、無需處理 tree-shaking 的模糊地帶、撰寫的 CSS 與發佈的 CSS 之間沒有轉譯層。Agent 寫的就是最終發佈的,因此 hook 驗證的就是使用者看到的。
證據閘門以相同方式適用於設計審查和工程審查。「字型看起來沒問題」不是證據。「差異中每個 font-size 宣告都對應到一個 --font-size-* token,已由字型 hook 驗證」才是證據。設計系統提供 hook 所強制執行的 token。沒有 token,就沒有驗證依據;沒有 hook,token 就只是建議。Nathan Curtis 精準指出了這個動態:一個缺乏治理的系統,最終會退化為無人閱讀的文件。2
品味層
六大元件捕捉的是違規。字型 hook 捕捉錯誤的字級。色彩 hook 捕捉寫死的色值。版面驗證捕捉 CLS。Lighthouse 閘門捕捉效能退化。無障礙 lint 捕捉 WCAG 違規。視覺回歸捕捉非預期的變更。
但它們都無法捕捉那些遵循了每條規則、卻仍然感覺不對的輸出。
一個卡片元件,字級正確、token 完備、CLS 為零、Lighthouse 滿分、WCAG 完全合規、視覺回歸無異常——但間距讓標題擠壓了圖片、行長拉到影響閱讀性、hover 狀態生硬而非深思熟慮。每項自動化檢查都通過了。卡片是正確的,卻不是好的。
品味運作在規則層之上。約束捕捉違反規則的問題。評估準則捕捉未通過指標的問題。模式辨識捕捉第二次審視才會發現的問題。一致性捕捉唯有全系統視角才能揭露的問題。六個自動化元件處理約束與評估準則。模式辨識和一致性需要品質迴圈:對作品進行強制性的第二次(第三次、第四次)檢視,每次檢查的不是規則是否成立,而是結果是否值得發佈。
品質迴圈是設計工程師證明「工程師」這個頭銜的地方。發佈通過測試的程式碼只是最低標準。發佈通過自動化檢查且經得起品質迴圈檢驗的介面,維護的是機器尚無法評估的標準。Pride Check 提出五個問題,最後一個(「我有沒有讓它變得更好?」)沒有自動化的等效方案。Steve 準則同樣如此:Blake 會在這上面簽名嗎?
複合效應
每個元件防止的是特定類別的設計缺陷。六者結合,產生的複合效應超越個別檢查的總和。
缺乏這套堆疊的 agent 工作階段,產出會逐漸偏移。字級在級距之外累積、色彩值被寫死而非 token 化、效能因微小增量逐步退化——沒有任何單次提交觸發警報,卻在數週間不斷累積。這種偏移在任何單一差異中都不可見,在全貌中卻顯而易見。
配備了這套堆疊的 agent 工作階段無法偏移。Hook 阻擋每一個偏離字型級距的行為。色彩系統拒絕每一個寫死的值。Lighthouse 閘門捕捉每一次效能退化。Agent 繼承了設計工程師的標準,並非因為 agent 理解這些標準,而是因為基礎架構強制執行了它們。Agent 不需要品味,agent 需要的是約束——而約束體現了品味。
Jony Ive 曾將 Apple 的設計流程描述為「無情的精煉」:在固定原則上反覆迭代所達成的品質,而非透過新奇性來追求創新。3 設計工程師的 agent 堆疊將同樣的理念操作化。原則被固定在 token、級距和門檻中。精煉是無情的,因為自動化在每次提交時都會執行。
將標準編碼進 agent 堆疊的設計工程師,做的不僅僅是在自主生成期間維護品質,而是讓品質可擴展。每一次工作階段、每一個 agent、每一次提交都繼承相同的約束。人類仍然評估一致性、仍然執行品質迴圈、仍然追問產出是否值得發佈。但人類不再需要捕捉字級違規、寫死色值或 CLS 退化。堆疊已經率先攔截了這些。人類的注意力完全投入在機器無法回答的問題上。
常見問題
必須從六個元件全部開始嗎?
不必。從解決最常見失敗模式的元件開始即可。字型 hook 和色彩系統 hook 提供最高回報,因為它們捕捉的是 agent 最常產生的設計缺陷。接下來加入 Lighthouse 閘門和無障礙 lint。視覺回歸和版面驗證是基礎架構最重的元件,適合放在採用序列的後期。
這套堆疊能配合建置工具使用嗎?
這套堆疊適用於任何前端架構。無建置方法簡化了實作,因為撰寫的程式碼與發佈的程式碼之間沒有轉換層。使用建置工具時,hook 必須驗證原始檔案,而 Lighthouse 和視覺回歸則驗證建置後的輸出。元件維持不變,只是整合點有所改變。
Agent 能否在沒有堆疊的情況下學會品味?
目前的語言模型不具備品味。模型產出的是統計上最可能的結果,而統計上最可能的結果趨向訓練資料的中位數。這套堆疊並非教導 agent 品味,而是約束 agent,讓流水線在缺乏品味的輸出發佈之前就將其拒絕。這個區別很重要:將品味編碼為基礎架構,比期望模型從 prompt 中內化品味要可靠得多。
視覺回歸測試如何處理刻意的變更?
刻意的變更會產生預期的視覺差異。工作流程標記這些差異,由人類審查並核准,更新基準。視覺回歸的價值不在於阻止變更,而在於揭露非預期的變更。當 agent 修改了按鈕顏色,同時也讓卡片版面偏移了 3 像素。顏色變更是刻意的,版面位移則不是——視覺回歸測試會捕捉到這個副作用。
參考資料
-
Robert Bringhurst, The Elements of Typographic Style, Hartley & Marks, 4th edition, 2012. Bringhurst establishes that typographic harmony follows mathematical ratios derived from musical intervals. ↩
-
Nathan Curtis, “Governance and Evolution,” Medium, 2019. Curtis documents the governance failure mode in unmanaged design systems, where tokens and guidelines exist but compliance degrades without enforcement mechanisms. ↩
-
Ian Parker, “The Shape of Things to Come,” The New Yorker, February 23, 2015. Ive describes Apple’s design process as iterative refinement within fixed constraints rather than open-ended exploration. ↩