昨天讓 AI Sub-Agent 寫一個前端模組,build 過了,TypeScript 沒報錯,頁面也跑得起來。
我看了一眼就想翻桌。
事情是這樣的
我們在做一個製造業客戶的系統,需要新增一個「製程管理」頁面。需求很明確:一個查詢列表、一個新增/編輯表單,標準的 CRUD 頁面。這種頁面我們專案裡已經有十幾個了,pattern 都是固定的。
所以我很放心地開了一個 Sub-Agent,給它 issue 描述和基本規格,讓它去寫。
二十分鐘後,Sub-Agent 回報:「完成了,build 通過,所有檔案已建立。」
好,讓我看看⋯⋯
第一眼就不對勁
打開檔案,第一個問題:假資料。
它用了一個 mockData 陣列,裡面硬編碼了三筆假的製程資料,然後 Table 就直接吃這個 array。完全沒有呼叫 API。
好吧,也許它不知道 API 怎麼接?但我們專案用 orval 自動產生 API hooks,swagger 文件都在那裡。它根本沒去看。
第二個問題:手動 state 管理。
1 | // Sub-Agent 寫的 |
我們專案有自己的 FormDrawer 元件,內建了 open/close 狀態管理,有 FormTypes interface 定義表單的 open/submit/close 行為。這些東西全部寫在 @packages/antd/components/dialog 裡面,Sub-Agent 完全忽略,自己從頭搞了一套原生的 Modal。
第三個問題:硬編碼中文。
1 | // Sub-Agent 寫的 |
我們全專案用 useTranslation 做 i18n,所有 label 都放在 locales/zhTW.json。它直接寫死中文,完全無視國際化。
更多問題陸續浮出
繼續往下看,問題越來越多:
- **沒用
useTableSearch**:我們的 Table 都搭配這個 hook 做查詢參數管理,它自己寫了一個handleSearchfunction - **沒用
useFeedback**:成功/失敗的通知用原生message.success(),不是我們封裝的 hook - **沒用
useProgramRule**:權限控制完全沒做 - 沒在
programRoutes.tsx註冊:雖然這個檔案是自動產生的,但它連對應的 route config 都沒加
每一個問題單獨看都不嚴重。但加在一起,這個模組基本上是不能用的。它跟專案裡其他頁面的 pattern 完全不一致,如果就這樣 merge 進去,後續維護的人會很痛苦。
最扎心的是:Build 是過的
對,TypeScript 完全沒報錯。ESLint 也沒意見。pnpm build 順利產出。
因為它寫的東西「語法上」完全正確——用原生 React + Ant Design 寫一個 CRUD 頁面,這有什麼錯?
錯在它跟我們專案的規範不一致。而這些規範不是 TypeScript 能檢查的,也不是 ESLint rule 能涵蓋的。
根因:Sub-Agent 不會主動讀規範
這是最關鍵的教訓。
我們的專案規範寫在 .claude/skills/ 目錄裡,包括:
- 頁面結構:主頁(Query+Table) → Table 用 FormDrawer ref → Form 實作 FormTypes
- 元件使用:哪些情境用 FormDrawer、哪些用 FormModal
- API 串接:一律用 orval 產生的 hooks,不手寫 API call
- 國際化:所有 label 走 useTranslation
- 通知:用 useFeedback hook
這些文件都在。但 Sub-Agent 不會自己去讀。
它拿到的 prompt 是:「幫我建一個製程管理頁面,需要查詢列表和新增/編輯表單。」它就照自己的理解去寫了。它的理解來自訓練資料裡見過的無數個 React + Ant Design 範例,而不是來自我們專案的特定規範。
正確的做法
後來我自己重寫了這個模組。但更重要的是,我從這次經驗整理出了一套驗收流程:
派工時就要把規範塞進去
不能假設 Sub-Agent 會自己找規範。派工的 prompt 要明確寫:
- 「先讀
.claude/skills/frontend-patterns.md」 - 「Table 要用
useTableSearchhook」 - 「表單要用
FormDrawer搭配FormTypesinterface」 - 「API 用 orval 產生的 hooks,不要手寫」
- 「所有 label 要用 useTranslation」
是的,很囉唆。但不寫就等著翻桌。
驗收 Checklist(不只看 build)
我現在驗收 Sub-Agent 的產出會逐項檢查:
- 有沒有用到專案的共用元件?(而不是自己從頭寫)
- 有沒有呼叫真正的 API?(而不是假資料)
- 國際化有沒有做?
- 權限控制有沒有做?
- 跟現有頁面的 pattern 是否一致?
- commit message 有沒有帶 issue 號?
這些全部用肉眼 review。沒有工具能自動檢查「你的 Modal 應該用 FormDrawer 而不是原生的」。
給 Sub-Agent 一個範例檔
與其寫一堆規範文字,不如直接指定:「參考 src/modules/xxx/pages/YyyPage.tsx 的寫法。」
讓它照抄一個已經符合規範的頁面,比讓它從零開始理解規範文件有效得多。
為什麼這個問題很重要
AI Coding Agent 現在很火。Claude Code、Cursor、Copilot⋯⋯每個人都在用。但我發現大部分人只看兩件事:「能不能跑」和「build 有沒有過」。
這在個人 side project 沒問題。但在團隊專案裡,code 的價值不只是「能跑」,還有「一致性」和「可維護性」。
一個用原生 React 寫的 CRUD 頁面,跟一個用團隊封裝元件寫的 CRUD 頁面,功能上可能一模一樣。但半年後有人要改需求的時候,前者會讓人想罵人。
flowchart TD
A[AI 產出 Code] --> B{Build Pass?}
B -->|No| C[修到 Pass]
C --> B
B -->|Yes| D{符合專案規範?}
D -->|No| E[重寫 / 大幅修改]
D -->|Yes| F{跟現有 Pattern 一致?}
F -->|No| E
F -->|Yes| G[可以 Merge]
大部分人在 Build Pass 那一步就停了。但真正的品質門檻在後面兩步。
一些補充想法
這不是 AI 的錯
公平地說,如果我找一個新人工程師,給他同樣的需求描述但不告訴他專案規範,他八成也會寫出類似的東西。差別只在於新人會在 code review 被打回來之後學到教訓,而 AI 下次還是會犯同樣的錯(除非你在 prompt 裡再次強調)。
Context 的成本
把所有規範塞進 prompt 是有成本的。Token 不是免費的,而且 context window 有上限。你需要判斷哪些規範是「不說就一定會錯」的,優先放進去。
我的經驗是:共用元件的使用方式 > API 串接方式 > 國際化 > 權限。因為前兩個錯了基本上要重寫,後兩個至少還能補。
可能的改善方向
長期來看,我覺得有幾個方向可以降低這個問題的嚴重性:
- 用 ESLint custom rule 強制使用特定元件(比如禁止直接用
antd的Modal,必須用FormDrawer) - 在
.claude/規範裡加更多具體的 do/don’t 範例 - 派工時自動注入專案規範(透過 skill 或 template)
- 建立自動化的 pattern consistency check
但現階段,最實際的做法還是:認真做 code review,不要被 build pass 騙了。
結語
AI 寫 code 的能力已經很強了,但「寫出能跑的 code」和「寫出符合團隊規範的 code」之間,還有一段不小的距離。
這段距離不是靠 AI 進步就能消除的——每個團隊的規範都不一樣,這本來就是 context-dependent 的東西。能消除它的,只有更好的 prompt engineering 和更嚴格的 code review。
如果你也在團隊裡用 AI Coding Agent,記得:Build Pass 只是最低門檻。真正的驗收,從打開檔案的那一刻才開始。