title: Specsmaxxing:當你發現寫規格比寫程式碼更有效
你的 Claude Code 正在無人的角落裡,幫你「發揮創意」——亂改資料庫結構、把分頁邏輯從 offset 改成 cursor、把 N+1 query 默默修掉。你提出的每個修改要求,它都乖巧地回一句「你說得對,我來修正」,然後任務越做越大,到最後你根本不知道它在做什麼。
這不是什麼科幻情節。這是在 vibe coding 時代,每個開發者遲早會遇到的事。你以為你只是在用 AI 加速開發,但實際上你正在經歷作者所說的「AI 精神病」——一種讓你的 agent 在缺乏明確指令時自行其是的集體現象。
從 vibe coding 到 Peak Slop
2026 年三月,一個有趣的趨勢曲線引起了開發社群的討論。「Slop」這個詞——用來描述 AI 未經審查就亂噴的產出——在 Google Trends 上出現了一個戲劇性的峰值。那是 AI 輔助開發大爆發的一個高點,程式碼量前所未有的多,但品質也前所未有的參差不齊。
原文作者在一家新創公司擔任技術長,他親眼見證了這個過程:AI agent 能在短短幾個小時內生出整組 CRUD API、串接外部服務、甚至自動補上單元測試。但問題是,這些程式碼往往「只對了一半」——功能能用,但邊界條件沒處理、錯誤訊息寫得奇怪、資料庫索引亂上加。
「Peak Slop 已經過去了,」作者在他的 PR review 留言中觀察到,他那幾個月收到的 code review 中出現「slop」這個詞的次數已經顯著下降。根據他在文章中的截圖記錄,3 月 11 日前後是 slop 的最高峰,之後逐漸平緩——這不代表開發者變得更少用 AI,而是代表他們學會了如何有效控制。
關鍵在於:你怎麼跟你的 AI agent 溝通期望?
對話式開發的極限
如果你用過 Claude Code 或任何 AI 編碼工具,你一定經歷過這種模式:你提一個需求,AI 產出一段程式碼,你看一看,要求修改,它改好,你再要求微調,直到滿意為止。
這個流程感覺很自然,就像在跟一個超級聽話的同事合作。但它有一個根本問題:你不是在定義規格,你是在逐步引導。 每次對話都是一次新鮮的上下文,你的要求、你的決策邏輯、你的設計取捨,全都隨著聊天視窗滾動而流失。
更糟的是,當你切換機器、重開 session、或把專案交給其他人時,所有這些未成文的默契全部歸零。agent 重新醒來,什麼都不知道,只能從頭開始猜測你的意圖。
這種現象作者稱之為「AI 精神病」(AI psychosis)——agent 在缺乏明確規格時,自行判斷「這樣做應該可以」,然後創造出一個你從未要求過、也未必符合設計意圖的解決方案。這不是 agent 的錯,而是它根本不知道你要什麼。
回到原點:沒有人喜歡寫規格
真正諷刺的是,解決方案其實老得不能再老。
早在 1990 年代,軟體工程界的先驅們就在提倡「規格驅動開發」(Spec-Driven Development)。寫需求文件、定義驗收標準、在實作之前先釐清要做什麼。這些做法在敏捷開發的浪潮中被邊緣化了——因為「可運作的軟體重於詳盡的文件」,人們從一個極端跑到了另一個極端。
但現在,情況完全不一樣了。
過去寫規格的成本是:你花費 X 小時寫規格,然後花費 Y 小時實作,規格帶來的回報是減少溝通成本和重工。但當 AI 可以幫你實作時,規格投資的回報率發生了質變:同樣花 X 小時寫規格,現在 AI 可以在數分鐘內把規格轉為實作,而規格防止的 bug 和浪費的時間,則成倍增加。
所以作者做出了一個乍看荒謬、但細想非常合理的選擇:把大量時間花在寫規格上。 他稱自己陷入了「Specsmaxxing」——一種規格極大化的狀態。
YAML 規格:從需求到驗收的鏈結
作者嘗試過各種規格格式:README.md、AGENTS.md、testing-guide.md、architecture.md、PRD.md,甚至還有一個叫 md.md 的文件用來教 agent 如何寫 markdown。這些非結構化的規格確實有用,比起「只靠提示詞」進步太多了。
但真正的突破來自一個意外的發現。
某天,作者注意到一個勤奮的 sub-agent 做了一件他沒有要求的事情:它自動把需求編號(AUTH-1、AUTH-2、AUTH-3),然後在程式碼中用註解引用了這些編號。
feature:
name: imaginary-api-endpoint
product: api
description: Example feature spec for REST API
components:
- id: AUTH-1
description: 接受 Authorization: Bearer <token> 標頭
status: completed
- id: AUTH-2
description: Token 為 user-scoped,可存取該使用者的任何資源
status: completed
- id: AUTH-3
description: 拒絕未授權請求,回傳 401
status: completed
然後在程式碼中:
// AUTH-1
const authHeader = req.headers["authorization"];
// AUTH-2
const isAuthorized = verifyBearerToken(authHeader);
// AUTH-3
if (!isValid) return res.status(401).json({ error: "Unauthorized" });
這個做法打破了規格與程式碼之間的孤立。現在,規格與實作之間有了雙向連結。當你修改規格時,你知道哪些程式碼需要跟著改。當你 review PR 時,你可以快速定位到「這段程式碼是為了滿足哪個需求」。當你想知道某個 feature 的實作進度時,你不需要手動比對——你的規格本身就是進度儀表板。
這個機制作者稱為 ACID(Acceptance Criteria ID,驗收標準 ID),並圍繞它打造了一個開源工具鏈。
用 feature.yaml 取代 markdown
作者認為,非結構化的 markdown 規格有幾個致命缺點:
- 沒有可參照的 ID——你無法在程式碼中引用「規格第三段第二句」
- 無法自動化——CI/CD 不知道哪些需求已滿足、哪些還沒
- 難以同步——當 feature 分支的規格和主線不同時,你用眼睛對比兩份文檔太痛苦了
為了解決這些問題,他設計了 feature.yaml 格式。這不是什麼複雜的規範語言——只是一個結構化的需求清單,每個需求都有一個唯一的 ID:
feature:
name: user-authentication
product: api
description: 使用者認證功能
components:
- id: AUTH-1
description: 支援 JWT token 驗證
status: completed
- id: AUTH-2
description: Token 過期後自動 refresh
status: in_progress
- id: AUTH-3
description: 支援 OAuth 2.0 第三方登入
status: todo
每個需求都可以標記狀態:todo、in_progress、completed。一個 CLI 工具可以掃描程式碼庫中的 ACID 引用,自動比對哪些需求在程式碼中有對應實現,哪些還沒有。
這種「驗收覆蓋率」(acceptance coverage)的概念與傳統的測試覆蓋率不同——測試覆蓋率告訴你「程式碼有沒有被測到」,而驗收覆蓋率告訴你「需求有沒有被實現」。後者才是產品開發真正關心的指標。
開源工具鏈:Acai.sh
基於這個設計,作者打造了一個名為 Acai.sh 的開源工具鏈,包含三個主要組件:
1. feature.yaml 格式模板:一個簡單且靈活的規格格式,讓每個需求都可被 ACID 引用。
2. 輕量 CLI:可整合進 CI/CD pipeline,也支援在 agent 中直接使用。透過 npm 或 GitHub Release 安裝。
3. Web 儀表板:以 Elixir + Phoenix + Postgres 打造,提供 REST API 和可視化介面。你可以看到每個 feature 在不同實作分支上的完成進度——從多個視角呈現一個矩陣,橫軸是 feature 列表,縱軸是實作環境/分支,交叉點的百分比就是該 feature 在該環境中的完成度。
對於專注於編碼、不喜歡開太多後台頁面的開發者來說,最吸引人的可能是它的輕量使用方式:在 feature.yaml 中定義需求,用 CLI 在 git hooks 或 CI 中自動檢查驗收覆蓋率,然後讓 agent 根據 ACID 標籤來驅動開發流程。
值得一提的是,作者打算將託管版本長期免費開放(除非流量暴漲到無法負擔),原始碼以 Apache 2.0 授權釋出。對團隊來說,這意味著你完全可以 self-host,不需要擔心 vendor lock-in。
超長 agent session 的挑戰與解法
讀到這裡你可能會想:這不就是傳統的 specs 加上一個翻新包裝嗎?為什麼現在突然變得重要?
關鍵在於:AI agent 的工作方式跟人類工程師完全不同。
一個人類工程師可以記住他在過去一週做過的決策,知道哪些需求已經被滿足、哪些還需要調整。但一個 AI agent 每次回覆的上下文範圍有限。當它的任務時間超過幾十分鐘、或者程式碼庫大到上下文裝不下時,它就會開始「遺忘」——做出與先前的設計決策不一致的修改。
作者分享了他打破「vibe coding 音障」的經驗:他讓一個 agent 在無人監督的情況下連續運行了 1.5 小時。這在今天聽起來像是很普通的操作,但考慮到上下文視窗的限制和 agent 逐漸偏離軌道的傾向,這其實是一個嚴峻的挑戰。
解決這個問題的方法正是結構化規格。當 agent 在執行過程中發現它需要判斷「這個 edge case 要怎麼處理」時,它不需要靠記憶或猜測——它可以直接查閱 feature.yaml 中對應的 ACID 需求。
更重要的是,當規格以結構化格式存在時,不同 agent 之間可以共享相同的需求參照。你在分支 A 用 Claude Code 完成的 AUTH-1 需求,切換到分支 B 用其他工具時,ACID 標籤依然能正確對應。規格不再只是人類閱讀的「文件」,而是 agent 和人類之間共用的合約。
Spec-driven 開發的實戰心法
從作者的經驗中,可以整理出幾個實際可行的做法:
從 README 開始。 如果你還什麼結構都沒有,先寫一份 decent 的 README.md 和 AGENTS.md。這是成本最低、回報最高的起點。很多開發團隊跳過這一步直接玩 feature.yaml,反而會覺得負擔太重。
聚焦在真正重要的需求上。 不要把 UI 微調、按鈕顏色、字體大小這些細節寫進規格。規格應該涵蓋功能性行為和關鍵限制條件——那些「如果做錯會出事」的部分。把 nitpicky 的事情留給對話解決就好。
用 ACID 在程式碼中建立錨點。 不需要一次把所有程式碼都標上 ACID。先從新的 feature 開始,養成習慣後再回頭補舊的。每次寫一段實作時順手加上對應的 ACID 註解,這是邊際成本最低的做法。
把驗收覆蓋率納入 CI。 設定一個門檻——例如合併到主線之前,所有 critical 需求的 ACID 必須被實作覆蓋。這比傳統的測試覆蓋率檢查更具產品意義,因為它強制團隊在交付之前確認「需求實現了」。
不要把規格當作文書工作。 這是最重要的心態轉變。在 vibe coding 時代,寫規格不是為了滿足流程要求,而是為了讓你的 AI agent 知道什麼該做、什麼不該做。一份好的 feature.yaml 可以讓 agent 的產出從「可能對」變成「就是對」。
在台灣開發圈如何落地
對於台灣的開發團隊來說,Acai.sh 這樣的方法論其實特別適合。台灣的軟體公司多數屬於中小型團隊,沒有大型企業那種龐大的需求管理系統。你可能沒有人力養一個 PM 團隊來寫 PRD,也可能沒有預算導入 Jira + Confluence + 一堆附加元件。
但你可以做的事很簡單:在本地維護一個 feature.yaml,讓你的 AI coding agent 在每次任務開始時先讀它。不需要華麗的 dashboard,不需要自動化的 CI 鏈路——只需要一個檔案和一個約定。
以一個五人團隊開發一個 SaaS 產品為例:每週一期 sprint,每個 story 對應一個 feature.yaml。在 sprint planning 時把需求寫進去,agent 就照著做,code review 時對照 ACID 檢查。不需要開 30 個 confluence pages,不需要 10 個 Jira subtasks,一切都在版本控制裡。
從實驗到習慣
回到最開始的問題。當你打開 Claude Code,輸入「幫我加一個使用者認證功能」,你其實不是在提需求——你是在賭博。你在賭 AI 的理解跟你一模一樣,賭它會做出你心中想像的設計,賭它不會擅自加上一些你不需要的東西。
Acai.sh 的作者用了一個很妙的比喻:規格就像是飛機飛行時同步設計建造的藍圖。你無法降落之後再設計——因為你正在飛。同樣的,你也無法等 agent 寫完所有程式碼再來驗收——因為到那個時候,context window 已經滿了,agent 已經偏離軌道了,你已經浪費了無數次 API 調用。
規格的作用不是增加負擔,而是建立一個共用的參照框架。對人類而言,它讓 team members 知道彼此在做什麼。對 AI 而言,它讓 agent 知道你到底是什麼意思——不是隨便「發揮創意」,而是照著計畫精準執行。
這不是回歸瀑布式開發,而是在 AI 時代重新解釋「寫下來」這件事的價值。當所有人都忙著用 prompt engineering 來馴服 AI 時,或許真正的解法就藏在那些你早就知道、但一直懶得做的事裡——把需求寫清楚。
而最諷刺的是,現在 AI 會讀規格了,你卻不願意寫。