跳到內容

AI 工作流程

這個專案是用 Claude Code 打造的。大多數「用 AI 打造」的聲明到標籤就止步了。以下是完整的面貌:AI 知道什麼、工作階段如何運作、實際的提示詞撰寫是什麼樣子,以及人類在哪裡劃下界線。無論你自己正在用 AI 開發,或只是好奇它實際上長什麼樣子,這篇文章就是為你而寫的。

Claude Code 有一個持久記憶檔案,能在不同工作階段之間延續上下文。它不會每次對話都重新探索整個程式碼庫,而是從我們上次結束的地方接續。以下是其中的內容(已脫敏):

  • 應用程式名稱、原始碼位置、授權條款、應用程式識別碼
  • 分支關係:上游是 Francisco Salgueiro 的 En Croissant,我們獨立維護自己的分支
  • 分支存在的原因:上游維護者婉拒了 TTS 功能,這完全合理——同一個專案有不同的願景
  • 僅限 pnpm——npm 會破壞 vanillaExtract(執行時白屏,沒有錯誤訊息,什麼都沒有)
  • 需要 Node.js 22+(Vite 7 需要 crypto.hash
  • 提交前務必執行 pnpm format && pnpm lint:fix
  • 覆寫二進位檔前先關閉應用程式(「Text file busy」)
  • 搬移原始碼目錄後,執行 cargo clean 以清除過期的路徑參照
  • 哪些檔案擁有哪些功能(atoms 在 atoms.ts、棋譜樹導覽在 tree.ts、TTS 引擎在 tts.ts
  • 為什麼所有 TTS atoms 都需要 getOnInit: true(在 React 訂閱之前透過 store.get() 進行命令式讀取)
  • 音訊快取如何運作(provider:voiceId:lang:text 鍵值)
  • chessground 座標修正是在 CSS 端,而非分支該函式庫
  • 資料佈局:什麼放在哪裡、什麼是符號連結、什麼在應用程式重啟後仍然保留

記憶檔案不包含 API 金鑰、密碼或憑證。它會參照這些資料的儲存位置(localStorage atom 名稱),但絕不包含其值。AI 生成的程式碼會從設定中讀取金鑰——它永遠不會看到或處理實際的機密資訊。

除了記憶檔案之外,Claude Code 還遵循內建於其系統中的規則:

  • 不要過度工程化。 只做直接被要求的變更。修一個 bug 不需要順便整理周圍的程式碼。三行相似的程式碼勝過一個過早的抽象。
  • 不要猜測 URL。 絕不捏造連結或端點。
  • 編輯前先閱讀。 絕不對未讀過的程式碼提出修改建議。
  • 偏好編輯而非新建。 除非絕對必要,不要建立新檔案。
  • 禁止安全漏洞。 注意注入攻擊、XSS 和 OWASP 前十大問題。
  • 不確定時就問。 如果指令含糊不清,寧可詢問而非猜測。
  • 三思而後行。 破壞性操作(force push、reset —hard、刪除檔案)需要人類明確批准。

一次有用的 AI 互動和一次令人沮喪的互動之間的差異,幾乎總是取決於提示詞。

明確說明你想要什麼。 不是「修那個 bug」,而是「TTS 快取鍵沒有包含供應商名稱,所以從 ElevenLabs 切換到 Google 時會播放快取的 ElevenLabs 音訊,而不是產生新的音訊。」

提供 AI 沒有的上下文。 AI 可以讀你的程式碼,但讀不了你的心。「使用者回報棋盤上的座標是反的」不如「chessgroundBaseOverride.css 中的 CSS 把行列搞反了——Francisco 的原始版本就是反的」來得有用。

說明你的限制條件。「不要建立新檔案」、「使用現有的 atom 模式」或「這必須在沒有 API 金鑰的情況下運作」,能告訴 AI 護欄在哪裡。

說明你不想要什麼。「不要為不可能發生的情況加上錯誤處理」或「不要重構周圍的程式碼」可以防止過度工程化——這是 AI 最常見的失敗模式。

模式是:意圖 + 上下文 + 限制條件。掌握這個模式,AI 就會變得顯著更好用。

計畫模式:用一個 Claude 來提示另一個 Claude

Section titled “計畫模式:用一個 Claude 來提示另一個 Claude”

Claude Code 有一個「計畫模式」,將思考與執行分開。在計畫模式中,AI 讀取檔案、探索程式碼庫,並產出一份計畫——但不寫任何程式碼。你審閱計畫、調整它,然後切換到實作模式,讓 AI 執行。

為什麼這樣做有效?因為任何程式設計任務中最困難的部分不是寫程式碼。而是搞清楚該寫什麼程式碼——該改哪些檔案、該遵循什麼模式、存在哪些邊界情況。計畫模式在寫下任何一行程式碼之前,就把全部注意力集中在這個問題上。

來自這個專案的例子:當我們重新調整「說明」選單以加入語言選擇器時,計畫模式的對話探索了 Tauri 選單的運作方式、已存在哪些 atoms、文件檢視器如何解析資源路徑,以及確認對話框的 API 長什麼樣子。等到我們切換到實作模式時,AI 已經有了一張完整的變更地圖。沒有任何錯誤起步。

你本質上是讓 AI 的一個實例擔任資深架構師,另一個擔任開發者。同一個模型,不同的角色。

一個典型的工作階段看起來像這樣:

  1. 人類陳述意圖。「在 KittenTTS 段落加上快取注意事項。」「移除 PostHog 遙測。」「品質評分是錯的,這是正確的內容。」

  2. AI 讀取相關檔案。 它不會猜測檔案裡有什麼。它會讀取它、理解當前狀態,然後提出修改建議。當多個檔案相互獨立時,會平行讀取。

  3. AI 進行修改。 對現有檔案進行針對性的編輯。不是重寫——而是保留周圍一切的精準修改。

  4. 人類審閱。 每一次編輯在寫入磁碟前都會展示。人類批准、拒絕或重新引導。「不,那太委婉了——直說它真的很爛。」「把那個段落往上移。」「那不是我的意思。」

  5. 被告知時才提交。 AI 絕不會主動提交。人類說「commit」或「commit and push」。提交訊息包含 Co-Authored-By: Claude Opus 4.6——永遠標明歸屬,絕不隱藏。

每一次 AI 對話都有一個上下文視窗——它一次能在記憶中保存的文字總量。當對話變得夠長時,較舊的訊息會被壓縮以騰出空間。

兩個策略:保持對話聚焦(每次對話一個任務),以及使用存檔點(Claude Code 會將對話記錄儲存為 JSONL 檔案,你可以從中恢復並還原完整上下文)。記憶檔案有不同的用途——它是一個跨所有對話持續存在的知識庫。

AI 的第一個建議很少是最終版本。一個典型的交流過程:

  • AI 草擬一個合理的版本
  • 人類說「太官腔了」、「更直接一點」或「那是錯的,原因如下」
  • AI 調整
  • 人類批准

品味、語調和最終決定權永遠在人類手上。AI 負責速度——讀取檔案、理解上下文、在它能保持在記憶中的程式碼庫裡進行精準編輯。人類負責判斷——要建什麼、感覺應該如何、何時該停下來。

Claude Code 支援「技能」——儲存在 .claude/commands/ 目錄中作為 markdown 檔案的可重複使用提示詞。你可以用斜線指令來調用它們,例如 /translate-docs

這個專案使用 /translate-docs 技能來自動化將文件翻譯成多種語言。技能檔案包含完整的指示:要翻譯哪些檔案、使用什麼格式、如何處理程式碼區塊和連結、維持什麼語調。不需要每次都解釋這些,你只要輸入 /translate-docs,AI 就確切知道該做什麼。

技能編碼的是流程,而不只是資訊。你可以為任何重複性的工作流程建立技能:執行測試、部署、審閱 PR、更新變更日誌。

完整的原則文件位於儲存庫中的 .claude/01_UNIVERSAL_PRINCIPLES.md。它最初以 Robert C. Martin 的 Clean Code(2008)為基礎,再加上 AI 時代的補充。然後我們進行了一場坦誠的對話,討論哪些仍然適用、哪些已經不合時宜。

  • 揭示意圖的命名。 永遠如此。始終如此。
  • 函式只做一件事。 真正的原則是連貫性,而非大小。
  • 無副作用。 仍然是大多數 bug 的根源。
  • 註解解釋為什麼,而非是什麼。
  • 單一職責。 一個模組應該只有一個改變的理由。
  • 對介面程式設計,而非對實作。
  • 不要吞掉錯誤。 每一個錯誤都是資訊。
  • 浮現式設計: 通過所有測試、無重複、表達意圖、最小化複雜度。按照這個順序。

這些原則是正確的,但具體的規則反映了 AI 之前或特定語言的世界。我們遵循精神,而非字面:

  • DRY。 逐漸分歧的重複是危險的。但把每一個重複的模式都抽取成抽象會產生間接層,可能更糟。有時候就在這裡寫三行可讀的程式碼,比在另一個檔案裡做一個過早的抽象要好。
  • 嚴格的 TDD 儀式。 原則——交付經過測試的程式碼、知道它能運作——是不可妥協的。儀式——測試必須先於程式碼存在——是為人類打字速度慢的工作流程設計的。寫測試。確保它們通過。測試先寫還是程式碼先寫,不如兩者都存在來得重要。
  • 童軍規則。「離開時比來時更乾淨」——是的。但童軍是打掃營地,不是整座森林。修復你觸碰到的部分。不要因為改了一行程式碼就重構整個檔案的結構。
  • 基於原則的指引比規則更具擴展性。 原則允許判斷;規則則脆弱。
  • 如果代理人建造了它,代理人就能維護它。 保留對話上下文和產出物。記錄建造過程,而不只是結果。
  • 清晰勝過巧妙。 建造這個系統的工具需要能重建推理過程並正確修改。明確的結構勝過微小巧妙的抽象。
  • 這能成為基礎設施嗎? 工具為你解決問題。基礎設施讓其他人能在上面建構。相應地進行設計。

AI 是一個工具。一個非常出色的工具。但有些事情它不做:

  • 產品決策。 要建什麼功能、要砍什麼、應用程式應該有什麼感覺。「系統 TTS 品質評分應該寫『勉強堪用』因為它真的很爛」——這是基於實際聆聽後做出的人類判斷。
  • 品味。 AI 可以寫出乾淨的文字,但專案的聲音、直言不諱談論品質的決定、選擇prominently 標注 Francisco 的功勞——這些都是人類的選擇。
  • 倫理。 移除 PostHog 不是一個重構任務。而是「設定頁面說我們不收集遙測資料,但程式碼裡有一個活躍的 PostHog API 金鑰。那是謊言。修掉它。」AI 執行了。人類發現了問題並在乎這件事。
  • 西洋棋。 棋盤不在乎你的工具鏈。

因為「用 AI 打造」已經變得毫無意義。每個人都這麼說。沒有人展示出來。有趣的問題不是 AI 是否參與了——而是它如何參與的,以及人類實際貢獻了什麼。

這就是答案。人類帶來願景、品味、判斷和責任。AI 帶來速度、記憶,以及在凌晨兩點不知疲倦地閱讀 Rust 錯誤訊息的意願。

兩者都無法獨自完成這件事。兩者都被標注功勞。這就是約定。


En Parlant~ 是 Francisco Salgueiro 的 En Croissant 的分支,使用 Anthropic 的 Claude Code 打造。