編寫良好的規格說明
你很少會從空白頁開始編寫規格說明。你先用通俗語言描述變更,/opsx:propose 起草需求和情境,然後由你把它們打磨好。本頁關注最後這一步——什麼樣的規格說明才算“好”,以及如何引導 AI 寫出這樣的內容。
本文與審查變更相輔相成:審查是發現草稿中的薄弱之處,編寫則是瞭解優質規格說明由什麼構成。
規格說明描述行為,而非程式碼
Section titled “規格說明描述行為,而非程式碼”規格說明應描述系統做什麼,並且任何人都能檢查,而不是描述系統如何建置。它由需求(對行為的陳述)和情境(證明需求成立的具體範例)組成。
### Requirement: Session TimeoutThe system SHALL expire a session after 30 minutes of inactivity.
#### Scenario: Idle timeout- GIVEN an authenticated session- WHEN 30 minutes pass with no activity- THEN the session is invalidated and the user must re-authenticate將實作方式——佇列、庫、表結構——放在 design.md 或程式碼中。如果把行為和實作混在同一條需求裡,這條需求就無法測試,並且程式碼一旦變化,它很快就會過時。
優質需求的特徵
Section titled “優質需求的特徵”一條優質需求只描述一種行為,並且表述清楚到可以交給別人測試。
-
一句話,一個
SHALL/MUST。 如果一條需求包含三項“還要”內容,那實際是三條需求。應將它們拆開。 -
可觀察。 不看程式碼的人也應該能夠判斷需求是否滿足。“上傳內容超過 10 MB 時,系統 SHALL 顯示錯誤橫幅”是可觀察的;“系統 SHALL 妥善處理大型上傳”則不是。
-
嚴格程度恰當。 OpenSpec 使用 RFC 2119 關鍵詞,各關鍵詞含義不同:
關鍵詞 含義 MUST/SHALL強制要求,不容協商。 SHOULD強烈建議,但有理由時允許例外。 MAY確實可選。 預設使用
MUST/SHALL。只有在確實表示“除非有充分理由不這樣做”時才使用SHOULD。
檢驗一條需求的方法是:一個從未看過程式碼的測試人員能否判斷它是否透過? 如果不能,就需要把需求寫得更明確。
優質情境的特徵
Section titled “優質情境的特徵”情境能體現需求的價值。每個情境都是一個具體的 GIVEN / WHEN / THEN,並且可以轉化為自動化測試。
- 情境要驗證對應需求。 只換一種說法重述需求的情境毫無測試價值。應描述一種具體情形及其具體結果。
- 覆蓋重要情形,而不只是正常流程。 成功登入很容易想到。空輸入、過期令牌、再次點選、出錯情形——這些才是 bug 常見之處,也是情境最有價值的地方。
- 在標題中說明所測情形。 “Scenario: Rejects an expired token”能讓審查者一眼看出測試覆蓋範圍;“Scenario: Test 2”則不能。
一個實用習慣:批准之前,先問自己最不希望看到哪種情形出錯?——並確保有一個情境明確描述了它。
選擇正確的差異型別
Section titled “選擇正確的差異型別”變更透過三種章節型別描述對規格說明的修改。正確選擇可確保歸檔後的規格說明如實反映實際情況:
## ADDED Requirements——新增之前不存在的行為。## MODIFIED Requirements——修改已有行為。應寫出完整的新版本;簡要說明變化內容有助於審查者理解。## REMOVED Requirements——刪除即將廢止的行為,並說明原因。
歸檔時,ADDED 內容會追加到主規格說明中,MODIFIED 內容會替換舊版本,REMOVED 內容則會從主規格說明中移除。刪除某項能力的最後一條需求,就表示要廢棄該能力:歸檔會刪除 openspec/specs/<capability>/spec.md,而不是留下空檔案。因為這是歸檔過程中唯一會刪除檔案的步驟,所以必須明確請求:在變更的 .openspec.yaml 中新增 retire_capabilities: true,並保留該檔案已有的 schema: 設定。未設定此項時,歸檔會中止並說明原因。
廢棄操作會刪除整個檔案;因此,如果規格說明中除了標題、## Purpose 和需求塊之外還包含其他內容(例如 ## Notes 章節或需求下方的註釋),操作也會被拒絕。中止訊息會指出這些行;你可以將其移至 ## Purpose 或某項需求中,也可以手動刪除規格說明。如果規格說明位於呼叫者當前檢出的儲存庫中,歸檔輸出還會說明如何使用 git checkout 恢復已提交的檔案;如果是所選儲存庫,則會提供針對該檢出範圍的恢復說明。
如果把一項真實變更標為 ADDED,就會留下兩條互相競爭的需求;如果把新行為描述為 MODIFIED,則沒有舊內容可供替換。拿不準時,先開啟當前規格說明,確認該需求是否已經存在。
還有一種章節值得了解。如果差異建立了一個此前不存在的能力,應使用 ## Purpose 開頭,並用一兩句話說明該能力的用途。歸檔時,這段內容會成為新建主規格說明的 Purpose;如果省略,則會留下 TBD 佔位符,需要手動補充。現有規格說明已經有 Purpose,因此其中差異檔案寫的 Purpose 會被忽略——如需修改它,請直接編輯 openspec/specs/<capability-path>/spec.md。這裡的 <capability-path> 是相對於 specs/ 的目錄,例如扁平專案中的 user-auth,或按領域組織的專案中的 identity/user-auth。
合理控制變更規模
Section titled “合理控制變更規模”最常見的編寫錯誤並不是需求措辭不佳,而是試圖在一個變更中塞進三項變更。
優質變更只有一個意圖,可以用一句話說清楚。 “新增深色模式切換開關。”“對登入端點限流。”“將會話儲存從 cookie 遷出。”如果描述變更時需要反覆說“還要……”,就說明應該拆分。
以下跡象表明變更過大:
- 提案中的範圍像一份互不相關功能的清單。
- 審查要花一個下午,因此沒人會認真審查。
- 兩個人無法同時處理而不相互衝突。
- 一半任務可以單獨釋出。
更小的變更更易審查、更容易在一次專注的工作時段內完成,也更便於在六個月後僅剩歸檔時理解。你可以並行執行多個變更——參閱編輯與迭代和工作流程。
反過來也一樣:修復一處拼寫錯誤,不需要列三項需求並撰寫設計文件。流程的複雜程度應與風險相匹配。
如何引導 AI 寫出優質草稿
Section titled “如何引導 AI 寫出優質草稿”/opsx:propose 會起草初稿,因此產出的品質取決於你提供的資訊。你不必手動編寫需求,但需要為 AI 指明正確方向:
- 說明意圖和邊界。 “新增深色模式切換開關,首次載入時遵循作業系統設定——不要修改現有主題 API。” 範圍外內容與範圍內內容同樣重要。
- 指出你關心的情形。 “確保包含一個使用者已手動選擇主題的情境。” AI 會重點覆蓋你指出的內容。
- 然後進行編輯。 規格說明是純 Markdown。你可以明確含糊的
SHALL、刪除毫無測試價值的情境、補上遺漏的情況,也可以請 AI 幫忙:“超時需求太含糊了,請明確為 30 分鐘。”
起草、完善、重複。經過幾輪這樣的迭代,你就能得到一份值得信賴的規格說明——這正是整個流程的目標。
快速檢查清單
Section titled “快速檢查清單”- 每條需求都是一種可觀察的行為,並包含
SHALL/MUST。 - 需求中沒有混入實作細節。
- 每條需求至少有一個真正驗證其行為的情境。
- 重要的邊界和錯誤情形都有對應情境,而不僅是正常流程。
- 根據當前規格說明,正確使用 ADDED / MODIFIED / REMOVED 差異型別。
- 整個變更只有一個意圖,並且可以用一句話描述。
接下來讀什麼
Section titled “接下來讀什麼”HagiCode
HagiCode 是智慧代理程式開發工作台,結合結構化工作流程、多代理程式執行與 Hero Dungeon 介面,將想法化為交付成果。
以更聰明、更快速且更有趣的智慧代理程式工作流程,打造實用的軟體。

- Smart結構化流程將意圖轉化為從構想到交付的可執行步驟。
- Efficient多代理程式工作流程讓研究、實作與審查並行進行。
- FunHero Dungeon 讓長時間的程式協作更直覺、更有參與感。
生態站點
快速連結
社群
© 2026 HagiCode