
最近這一年我身邊用 AI 寫代碼的團隊越來越多了但一個尷尬的現象也隨之出現代碼量上去了安全感沒上去。功能確實能跑但沒人能說清楚某一行代碼為什么這么寫、當時基于什么需求、有沒有替代方案。說白了AI 編碼最大的問題不是寫不出代碼而是寫出來的代碼不可追溯、不可驗證、不可維護。我自己在幾個項目里反復折騰后慢慢摸索出一套組合拳用 SDDSpecification-Driven Development作為頂層方法論搭配 OpenSpec 和 SuperPowers 兩個框架落地。這套方案不是懸在空中的理論而是能讓 AI 按需產出、每行代碼都有據可查的實操路徑。這篇文章就把我的實踐過程、踩過的坑和具體玩法一次性講清楚。1. 先捋清楚當前 AI 編碼到底亂在哪1.1 我觀察到的三種典型亂象你如果讓 AI 直接寫一個稍微復雜一點的功能最常見的現象就是“看起來都對跑起來就炸”。我遇到過最典型的一次讓 AI 實現一個訂單超時自動關閉的邏輯它很貼心地寫了個定時任務但定時任務的觸發頻率是每 5 分鐘一次而業務要求是訂單創建后 30 分鐘關閉中間沒有任何掃描 offset 的概念。結果就是大量訂單在 35 分鐘、40 分鐘甚至更晚才被關閉線上監控直接報錯。這種問題不是偶發而是普遍存在。第二種亂象是 AI 會把上一段對話里的上下文錯誤地帶到下一段。你在同一個會話里先讓它寫了一個 Python 的 FastAPI 接口又讓它寫一個 Java 的 Spring 服務它可能就會把 Python 風格的命名規范帶進 Java 代碼里甚至把 FastAPI 的依賴注入方式硬套到 Spring 上。我見過最離譜的一次AI 在一個 Java 項目里生成了 Python 風格的路徑拼接邏輯編譯能過測試直接掛。第三種亂象更隱蔽AI 生成的代碼沒有任何“來路說明”。它不會告訴你這個常量值為什么是 30 而不是 60不會告訴你這個邊界條件是從哪個需求文檔里推導出來的也不會告訴你它順手幫你改掉的那個方法簽名是為了什么。等代碼 review 的時候你問它“為什么這里要加鎖”它可能回你一句“這是常見實踐”。這種沒有決策記錄、沒有需求關聯的代碼維護成本極高甚至比沒人維護的遺留系統還難搞。1.2 亂象的根源缺規范、缺上下文、缺審計總結下來AI 編碼亂象的根源逃不出三個詞缺規范、缺上下文、缺審計。缺規范指的是沒有給 AI 一套清晰的、可執行的約束條件。大多數時候我們只給了 AI 一個“需求”而不是一份“規格”。需求是模糊的規格是清晰的。你讓 AI“優化一下登錄邏輯”它能給你找出幾十種“優化”方式但你沒有告訴它優化的邊界是“保持接口兼容”還是“允許破壞性變更”它自然就會自由發揮。缺上下文則是因為 AI 的上下文窗口雖然越來越大但項目相關的信息散布在需求文檔、設計文檔、代碼注釋、歷史提交記錄里AI 很難全部拿到。你不能指望 AI 自己把整個 git 歷史翻一遍來理解你的項目它只會基于當前會話里能看見的內容作答。一旦你給的信息不完整它就會用自己的“常識”補齊而這些常識往往和你的業務場景對不上。缺審計就更直接了。如果你沒有一個機制去記錄“這個決策是誰在什么時間基于什么原因做出的”那 AI 產出的每一行代碼就都是無根之木。出了問題只能從頭排查而 AI 如果再來“優化”一次可能又把之前踩過的坑重新踩一遍。1.3 SDD 為什么能成為破局抓手我接觸 SDD 是在一次內部技術分享上當時聽到的概念很簡單先寫規格再寫代碼。看代碼的人應該能通過規格文件理解代碼為什么存在改代碼的人應該能通過規格文件判斷改動會不會破壞契約。這聽起來像傳統軟件工程里的“設計先行”但 SDD 和傳統設計文檔最大的區別是SDD 的規格文件是活文檔是和代碼同步演化的。它不是一個評審完就丟進 wiki 里的 PDF而是整個開發流程中的“單一事實來源”。在 AI 編碼的場景下這個特性格外重要因為 AI 不會自己主動去翻需求文檔但如果你把規格文件放在項目根目錄并且在規則里強制要求 AI 每次修改代碼前先讀對應的規格文件它就能做到“帶著約束寫代碼”。后來我又接觸到 OpenSpec 和 SuperPowers 這兩個框架發現它們剛好從兩個維度補上了 SDD 落地的關鍵缺口OpenSpec 負責把“規格”這個東西變成標準化的、可版本化的文件結構讓 AI 好讀、好理解、好引用SuperPowers 負責在 AI 執行編碼時注入一套行為準則從流程層面強制 AI 走“先理解規格、再動手實現、最后記錄決策”的路徑。兩者合在一起就是我標題里說的“雙框架”。2. OpenSpec 和 SuperPowers 在雙框架里的分工2.1 OpenSpec把需求變成機器可讀的規格先說 OpenSpec。我理解它的核心價值不是“幫你寫文檔”而是“幫你把需求結構化”讓規格文件成為 AI 編碼時的硬約束。它定義了一套推薦的目錄結構和文件組織方式你在項目里跑起來之后大概是這個形態repo/ ├── specs/ │ ├── 001-order-timeout-close/ │ │ ├── spec.md │ │ ├── decisions.md │ │ └── acceptance.md │ ├── 002-login-captcha/ │ │ ├── spec.md │ │ ├── decisions.md │ │ └── acceptance.md ├── src/ ├── tests/ ├── .superpowers/ │ ├── rules.md │ └── workflow/ └── AGENTS.md每個業務功能一個目錄里面至少包含三份文件spec.md 描述需求背景、功能范圍、約束條件和驗收標準decisions.md 記錄實現過程中所有關鍵決策及原因acceptance.md 明確驗收場景和測試流程。以“登錄接口增加驗證碼校驗”為例OpenSpec 風格下的 spec.md 長這樣# Spec: 登錄接口驗證碼校驗 ## Context - 現有登錄接口無驗證碼存在暴力破解風險 - 需要在保持響應結構兼容的前提下增加驗證碼 ## Requirements 1. 用戶在登錄前必須先獲取驗證碼 2. 登錄請求必須攜帶驗證碼及會話標識 3. 驗證碼有效期 5 分鐘失敗次數超過 5 次后刷新 ## Constraints - 不改變現有 HTTP 狀態碼約定 - 不引入新的第三方依賴 ## Acceptance Criteria - 無驗證碼請求返回 400 - 驗證碼錯誤返回 4001 - 同一會話連續 5 次驗證失敗后舊驗證碼立即失效這份文件的語氣很關鍵它不是在描述“怎么做”而是在描述“要滿足什么條件”。AI 讀到這種文件時會把它當成契約而不是參考資料這能極大減少自由發揮空間。2.2 SuperPowers給 AI 配上編碼行為準則SuperPowers 的定位和 OpenSpec 完全不同。OpenSpec 定義的是“做什么”SuperPowers 定義的是“怎么做”。我第一次看到 SuperPowers 這個名字時以為它是一堆現成的代碼生成模板后來才意識到它更像一套“給 AI 用的行為準則注入器”。你可以把它理解為一個規則包把 AI 編程時需要遵守的流程、約束、檢查清單、輸出格式統一寫進規則文件然后讓 AI 編碼助手在每次會話開始時自動加載這些規則。比如我的一套基礎規則大概是這樣的# .superpowers/rules.md ## 全局規則 - 每次修改代碼前必須先讀取 specs/ 下對應功能的 spec.md - 若 spec.md 缺失暫停編碼并提示用戶先補充規格 ## 編碼規則 - 所有函數必須包含 docstring注明關聯的 spec 編號 - 禁止在代碼中硬編碼業務常量常量必須提取到配置文件中 - 如果有多種實現方案優先選擇 spec.md 中約束較少的方案 ## 提交規則 - git commit message 必須以 spec 編號開頭例如 001: 實現訂單超時關閉任務 - 提交前必須運行 tests/ 下的全量測試 - 提交后自動觸發 DECISIONS.md 更新這套規則文件的核心作用是把“人靠自覺”變成“流程強制”。以前我要求團隊成員在代碼里寫注釋總有人忘現在讓 AI 在規則驅動下寫代碼它每一行都會主動關聯 spec 編號因為規則文件里寫得清清楚楚。2.3 兩個框架如何銜接成一條完整鏈路OpenSpec 和 SuperPowers 之間不是“二選一”的關系而是前后銜接、互相強化。我這里列一下我自己項目的運轉流程需求方提出需求后先由人工或者 AI 輔助人工把需求整理成 OpenSpec 規格文件放入 specs/ 目錄然后在 SuperPowers 的 rules.md 里聲明“所有編碼工作必須先讀取相關 spec”AI 編碼助手啟動后會自動加載 rules.md接著按規則找到 specs/ 下的對應文件再開始寫代碼寫完代碼后AI 會按照規則里的“提交規則”檢查一遍確保代碼注釋、提交信息、測試結果都滿足要求最后如果實現過程中有任何偏離 spec 的地方AI 必須把決策記錄到 decisions.md 里而不是悄悄改代碼。這套鏈路跑通之后最大的感受是“安全感回來了”。任何一行代碼你都能往前追到 spec再往前追到需求再往前追到當時的決策記錄。AI 不再是懸浮在項目之上的“黑盒寫手”而是一個真正參與項目流程的協作者。3. 完整實操從需求到可追溯代碼3.1 環境初始化把兩個框架請進項目這套組合拳不需要安裝特別復雜的服務核心就是把文件結構和規則配置準備好。我通常用下面的命令初始化一個項目目錄mkdir -p specs mkdir -p .superpowers/workflow touch AGENTS.md touch .superpowers/rules.md然后在 AGENTS.md 里寫入“項目級引導說明”讓 AI 編碼助手在進入項目時能第一時間讀到這里。我的 AGENTS.md 通常非常簡單# AGENTS.md 本倉庫采用 SDD 規范驅動開發任何編碼任務開始前請按以下順序執行 1. 閱讀 .superpowers/rules.md 2. 在 specs/ 目錄下找到對應功能規格文件 3. 如果規格文件不存在先詢問用戶是否需要創建 4. 完成編碼后根據規則提示運行測試并更新決策記錄這里的關鍵是AGENTS.md 是 AI 編碼工具Cursor、Copilot CLI、Windsurf 等默認會優先讀取的入口文件。你不需要每次對話都重復一遍“記得先讀規范”只要把它寫進 AGENTS.mdAI 就會自動遵循。3.2 用 OpenSpec 寫一份合格的需求規格很多人第一次寫 OpenSpec 規格時會犯一個錯誤寫得太像技術方案。比如“點擊按鈕后調用 /captcha 接口拿到返回的 base64 圖片和 captchaId”這是實現方案不是規格。一份合格的規格應該描述“問題是什么、約束是什么、怎樣算完成”把“怎么做”留給編碼者在 AI 場景里就是留給 AI。我通常用四個問題來引導自己這個功能解決什么問題在什么場景下生效有什么是不能碰的用什么標準來判斷做完了以驗證碼需求為例我把上面四個問題的答案填進 spec.md 后它變成了“Context Requirements Constraints Acceptance Criteria”的結構。這里面最容易被忽略的部分是 Constraints。因為 AI 很容易“過度設計”如果你不寫清楚“不引入新的第三方依賴”“不改變現有狀態碼約定”它可能會給你引一個驗證碼庫然后把接口文檔也改了。寫完 spec.md 之后我還會在同一個目錄下創建空的 decisions.md 和 acceptance.md。decisions.md 是一份運行日志在開發過程中逐步補充acceptance.md 是對照驗收標準的測試清單可以手寫也可以讓 AI 在生成實現代碼時同步生成。3.3 用 SuperPowers 約束 AI 編碼行為SuperPowers 落地的關鍵是把規則寫得“可執行、可檢查”。不要寫“注意代碼質量”這種廢話而要寫“函數必須有 docstring且 docstring 第一行包含 spec 編號”這種能被程序或人工精確判斷的規則。我自己用的規則文件分三層。第一層是全局規則約束所有文件第二層是任務規則針對某類任務比如“接口開發”“數據庫變更”“測試編寫”做細化第三層是提交規則約束 git commit 和合并請求的格式。這里給出一個更完整的 rules.md 示例片段# .superpowers/rules.yaml global: - 所有代碼修改必須引用 spec 編號格式為 spec#001 - 禁止修改 specs/ 以外的需求文件 - 若在實現過程中發現規格不合理先停止編碼記錄問題 task: api: - 接口參數校驗必須放在業務邏輯之前 - 新增接口必須同步生成對應的測試用例 database: - 禁止使用裸 SQL 拼接用戶輸入 - 表結構變更必須包含回滾腳本 commit: - 提交信息必須匹配 ^\\d{3}: .$ - 提交前運行 npm test 或 pytest如果你用 Cursor 或類似工具可以把 rules.yaml 的路徑配置到工具的額外指令里如果是 CLI Agent可以直接在 AGENTS.md 里寫“啟動時自動加載 .superpowers/rules.yaml”。實際操作中我建議把規則文件同時放到項目根目錄和用戶配置目錄防止某些工具不認項目內文件。3.4 讓 AI 按規格生成代碼并留痕一切準備就緒后真正的編碼過程反而變得很“機械”。我會把任務描述寫成這樣的 prompt請根據 specs/002-login-captcha/spec.md 實現登錄驗證碼功能。 要求 1. 先讀取 spec.md列出你理解的驗收標準 2. 按 .superpowers/rules.yaml 中的規則編碼 3. 編碼完成后運行測試并反饋結果 4. 如果實現過程與 spec 存在偏差將決策記錄寫入 decisions.md這里有個細節值得強調讓 AI 先復述驗收標準再開始寫代碼。這個步驟能有效防止它一上來就悶頭寫。我試過很多次只要 AI 先輸出“我理解的驗收標準是……”后面跑偏的概率會大幅下降。原因是它把 spec 里的關鍵信息提前加載到了上下文的前置位置后續生成代碼時會更容易保持一致性。代碼生成過程中我還會時不時人工打斷問一句“你剛剛那個常量值是從哪個需求推導的”如果 AI 答不上來說明它沒有真正基于 spec 編碼而是在憑直覺寫。這時我會回到規則文件加強“常量值必須來源于 spec 或配置文件”的約束。3.5 驗證與驗收確保每一行都有據可查編碼完成不等于功能完成在 SDD 流程里驗證和驗收是最后一道關卡。我的做法是讓 AI 先生成一份“驗證報告”內容必須包含測試命令、測試結果、覆蓋的驗收標準編號和未覆蓋項的原因。真實場景下我見過最舒服的一次驗證輸出是這樣的## 驗證報告spec#002 登錄驗證碼 ### 測試命令 pytest tests/test_login_captcha.py -v ### 測試結果 7 passed, 0 failed ### 驗收標準覆蓋 - AC-1: 無驗證碼請求返回 400 ? - AC-2: 驗證碼錯誤返回 4001 ? - AC-3: 連續失敗 5 次后舊驗證碼失效 ? ### 未覆蓋項 - 無本次實現覆蓋全部驗收標準有了這份報告review 代碼的人可以在幾分鐘內判斷“代碼是否達到規格要求”。如果你還配置了 CI還可以讓 CI 自動執行 acceptance.md 里的測試清單并把結果回寫到 spec 目錄這樣追溯鏈路就完整了。4. 沒有 OpenSpec 和有 OpenSpec 到底差在哪4.1 對比實驗同一個需求兩種做法為了驗證這套流程到底有沒有用我在自己的一個開源示例項目里做過一次對比實驗。需求是“實現一個帶緩存的用戶信息查詢接口緩存時間 10 分鐘”。第一次我不給 AI 提供任何規格文件只在 prompt 里說“實現用戶信息查詢接口帶緩存”。AI 很快寫完了代碼用的是全局靜態 Map 做緩存沒有過期策略也沒有考慮并發問題。代碼能跑但顯然不符合“10 分鐘過期”的隱含要求更別提線程安全性了。第二次我先用 OpenSpec 寫好了 spec.md里面明確寫了“查詢用戶信息時先查緩存、緩存命中則直接返回、緩存 miss 時查數據庫并寫入緩存、TTL 為 600 秒且首次訪問創建、并發請求下不能重復查數據庫”。然后讓 AI 基于 spec 實現結果它自動選擇了 Caffeine 作為本地緩存庫并設計了一個合理的過期刷新策略還附上了測試用例。兩次結果高下立判。區別不在于 AI 能力提升了而在于第二次我給了 AI 一份“可執行的邊界說明書”。4.2 效果差異背后的原因拆解為什么同樣的 AI 模型在有無 OpenSpec 的情況下表現差距這么大我覺得核心原因有三個。第一AI 是“依據輸入做生成”的系統。你輸入模糊它就輸出模糊你輸入精確它就盡量輸出精確。OpenSpec 提供的結構化 spec 本質上是一種高質量的輸入它把模糊需求轉換成了 AI 更容易理解的格式。第二spec.md 里的 Constraints 和 Acceptance Criteria 構成了一種“過濾機制”。AI 生成候選代碼時會基于這些約束剔除明顯不合規的方案。比如你在 Constraints 里寫“不引入第三方依賴”AI 就會優先用 JDK 自帶的并發工具實現緩存而不是引入 Caffeine。不是因為它更聰明而是因為它被明確限制了。第三也是我認為最重要的一點OpenSpec 讓“追溯”變得容易了。當你發現緩存實現有問題時你能立刻回到 spec.md 去看當時的約束是不是漏了一條當你需要修改功能時你能通過 spec 編號直接找到所有關聯代碼。這種“代碼和需求可互相定位”的能力是裸 prompt 永遠給不了你的。5. 常見問題與排查技巧實錄5.1 典型問題速查表現象可能原因排查方法 / 解決建議AI 生成的代碼和 spec 明顯不符規則文件未加載檢查 AGENTS.md 和 .superpowers/rules.md 是否在項目根目錄確認工具是否讀取了項目內規則AI 在實現時悄悄改了 spec 外的代碼規則中缺少“禁止修改范圍”約束在 rules.md 中增加“只允許修改 specs/xxxx/ 關聯文件列表其他文件改動需明確授權”spec 文件更新后 AI 仍然按舊 spec 編碼上下文里舊 spec 占主導新會話中先讓 AI 重新讀取 spec 文件或把 spec 文件的關鍵結論寫進 AGENTS.mddecisions.md 沒有自動更新SuperPowers 規則未定義“何時更新”在規則中寫明“每次編碼完成后如果出現偏離 spec 的決策必須追加到 decisions.md否則禁止提交”測試用例與驗收標準不對應缺少驗收標準映射在 acceptance.md 中為每條驗收標準編號并要求 AI 生成代碼時在測試用例中標注對應的 AC 編號多個 AI 編碼工具規則沖突不同工具讀取的規則文件不同統一在項目根目錄維護 AGENTS.md并在其中引用其他規則文件的路徑保證所有工具走同一入口5.2 我踩過的三個大坑第一個坑是“規則寫得太大而全”。我最開始照著網上別人分享的superpowers配置塞了上百條規則進去結果 AI 每次編碼前光解析規則就要很久而且規則之間互相矛盾AI 反而不知道該聽哪條。后來我砍到只剩 20 多條核心規則效果反而好了很多。現在我的原則是一條規則如果不能被明確檢查就不寫。第二個坑是“spec 文件變成一次性文檔”。有些同事寫 spec 只是為了應付流程需求一變就另開一個新 spec舊 spec 里全是過時的內容。這樣做的后果是 AI 在新會話里讀到舊 spec 后會被錯誤信息帶偏。我現在強制要求需求變更時只能修改舊 spec并在文件頭部加一段 Change Log不能新建文件除非舊 spec 已經被完全棄用。第三個坑是“過度依賴 AI 記錄決策”。一開始我以為只要給 AI 規定了“必須更新 decisions.md”它就能自動記錄所有關鍵決策。實際試下來發現AI 只會記錄它主動做出的決策如果你在 prompt 里給了它有歧義的約束它可能不會把“我不確定”寫進 decisions.md而是直接選一個默認行為。所以我的補救措施是在規則里增加一條“如果發現需求有歧義必須在 decisions.md 中記錄‘由于 XX 不確定本次采用 XX 方式’否則視為未完成”。這三個坑讓我意識到SDD OpenSpec SuperPowers 這套組合不是“裝完就萬事大吉”它需要人為維護規則的質量和 spec 的準確性。但長遠來看這種維護是值得的因為每一條被記錄下來的決策、每一份和代碼同步演化的規格都會在未來的某次維護中替你省下大量排查時間。我在實際使用這套流程半年之后最大的變化是我敢讓 AI 獨立完成更多任務了。以前讓 AI 改一個老模塊的代碼我總擔心它把別的地方改壞現在只要它遵循“先讀 spec、再實現、再記錄決策”這條路徑我就敢在它提交后直接看 diff 和驗證報告因為每個改動都能向前追溯到需求和約束。如果你也在被 AI 編碼的不可控性折磨可以按這篇文章的結構先把 OpenSpec 和 SuperPowers 搭起來哪怕只做一個功能需求也能明顯感受到“可追溯代碼”帶來的安心感。