用 CLAUDE.md 快速降低 Claude Code 程式錯誤率的 4+8 條規則

▌快速介紹

Andrej Karpathy 是「vibe coding」這個詞的創造者,2025年2月他用來描述「靠直覺和 AI 協作、不深究細節地寫程式」的新工作模式。

Karpathy 是 Stanford 博士,先後在 OpenAI 擔任研究員、Tesla 主導 Autopilot 視覺系統開發,之後短暫重返 OpenAI 後創立 Eureka Labs(本日更新:Karpathy 已於 X/twitter 宣布 加入 Anthropic )。

2026年1月,在密集使用 Claude Code 數週後,Karpathy 發現自己的工作流程發生根本性的轉變:從 80% 手寫程式碼加上 20% AI 輔助,翻轉成 80% 由 agent 生成、20% 人工修改與潤飾。

Karpathy 針對這幾週的實作經驗,規納出模型在實際開發中常犯的幾種「通病」。開發者 Forrest Chang 看到 Karpathy 的推文後,把文章整理成四條行為規則,寫成一份 CLAUDE.md 文件並放上 GitHub

如果你只是想快速改善 Claude Code 的錯誤率,前 4 條就夠了,而且風險更低 — 文件短、遵守率高、維護成本低。

後 8 條則是遇到了它們針對的問題,才加上去。

Anthropic 官方文件也明確指出:CLAUDE.md 本質上是「建議性的(advisory)」,平均遵守率約 80%,一旦超過 200 行,遵守率會明顯下降。 換句話說,規則要精,不要多。

▌Karpathy 的四條規則

CLAUDE.md 是 Claude Code 的專屬機制。這個檔案在專案根目錄,Claude Code 每次對話開始時會先讀取,將內容作為系統層級的行為指引。

它不是 prompt,不是 system prompt,是一份持久的行為契約:每次 Claude 開始工作前都會重新確認一遍。

1. 寫程式前先思考(Think Before You Code)

Before writing any code, state your assumptions. If something is unclear, ask—don’t guess.

》問題根源

Claude 的訓練目標之一是「有幫助地回應」,這在對話場景中是優點,但在工程場景中會變成缺點:它傾向於立刻給出答案,而不是先確認問題是否被正確理解。Karpathy 的原始抱怨之一,就是 Claude 會在沒有說明的情況下自行做假設,然後把錯誤假設埋進程式碼深處。

》這條規則在做什麼

強制 Claude 在動手之前輸出一份「假設清單」,讓開發者有機會在程式碼產生前就發現認知偏差。

》實際寫法建議

## Rule 1: Think Before Coding
Before writing any code:
1. Restate the goal in your own words
2. List all assumptions you're making
3. Flag anything ambiguous and ask—do not guess
4. Only proceed after assumptions are confirmed or clarified

》為什麼有效

這條規則把「確認假設」這個行為從隱性變成顯性。一旦 Claude 必須把假設寫出來,開發者就有機會在第一行程式碼出現之前介入,而不是在 debug 時才發現問題根源是一個從未被說出口的誤解。

2. 簡單優先(Minimal Footprint)

Use the minimum code necessary to solve the stated problem. Do not add features, abstractions, or error handling that wasn’t requested.

》問題根源

語言模型在生成文字時有一種「補全衝動」,它會傾向於讓回答看起來「完整」。在程式碼生成上,這表現為:你要一個簡單的 HTTP request,它給你一個帶有 retry logic、exponential backoff、logging hook 的完整 wrapper class。

這在 demo 場景看起來很厲害,在真實工程裡是噪音。

》實際寫法建議

## Rule 2: Minimal Footprint
- Solve only what was asked
- Do not add helper functions "just in case"
- Do not introduce new abstractions unless explicitly requested
- Prefer 10 lines that work over 50 lines that "might be useful"

》延伸思考

這條規則和 Rule 5(後述)有直接關聯:Claude 特別容易在「確定性工作」上過度生成,把一個簡單的 if status_code == 200 包裝成一整個狀態機。

3. 外科手術式修改(Surgical Changes Only)

Only modify the code that needs to change. Do not refactor, reformat, or “clean up” surrounding code unless explicitly asked.

》問題根源

這是 Karpathy 抱怨清單裡破壞力最強的一條。Claude 有一個習慣:在修改目標程式碼的同時,順手「改善」周邊看起來不夠漂亮的程式碼。從模型的視角來看,這是好意;從工程師的視角來看,這是:

  • Git diff 變得難以 review
  • 引入了沒有測試覆蓋的變動
  • 打破了「這次 commit 只做一件事」的原則

》實際寫法建議

## Rule 3: Surgical Changes Only
- Change ONLY what the task requires
- Do not rename variables for style
- Do not reorder imports
- Do not reformat code blocks you didn't modify
- If you see something worth fixing, mention it—but don't fix it silently

最後一句話很重要:這條規則不是要 Claude 假裝看不到問題,而是要它說出來而不是偷偷動手。

4. 以目標導向執行(Goal-Oriented Iteration)

Before starting, define what “done” looks like. Use that definition to self-evaluate and iterate.

》問題根源

沒有明確成功標準時,Claude 容易把「我已經完成了看起來合理的事情」誤認為「任務達成」。這和 Rule 12(後述的「失敗要明確說出來」)形成一對:Rule 4 是在開始前設定標準,Rule 12 是在結束時誠實報告結果。

》實際寫法建議

## Rule 4: Define Done Before Starting
- State the success criteria before writing code
- Use those criteria to self-check before declaring completion
- If criteria cannot be fully met, explain what's missing—don't silently deliver a partial solution

▌另外八條規則

5. Don’t Use AI for Deterministic Work

Do not use AI-generated logic for deterministic operations. These should be handled by explicit, testable code.

》問題根源

「確定性工作」指的是那些答案只有一個、邏輯完全可以用規則寫死的任務,例如:

  • HTTP 狀態碼判斷(200 成功、404 找不到、500 伺服器錯誤)
  • 重試邏輯(失敗三次後停止、每次間隔加倍)
  • 資料驗證(email 格式、必填欄位、數值範圍)

Claude 處理這類工作時,傾向於生成「看起來彈性」的程式碼——用條件判斷包條件判斷、加上一層抽象讓它「更好擴充」。但這些彈性是你不需要的,而且它引入了一個更深的問題:AI 生成的確定性邏輯難以被驗證。你很難確認它的邊界條件是否完整,也很難在出問題時快速定位。

》實際寫法建議

## Rule 5: Don't Use AI for Deterministic Work
以下這些工作用明確的程式碼處理,不要讓 AI 生成邏輯:
- 狀態碼判斷、錯誤分類
- 重試次數與間隔邏輯
- 資料格式驗證規則
- 任何「答案只有一個」的判斷

這類程式碼應該可以被獨立測試,邏輯一眼看穿。

》延伸思考

這條規則的本質是「讓 AI 做 AI 擅長的事」:理解模糊需求、生成結構、處理語意層面的判斷。確定性工作交給 AI,等於把一把精密工具用在不需要精密的地方,反而製造風險。Rule 2 控制的是「做多少」,Rule 5 控制的是「做什麼」。

6. Set Hard Token Budgets

Enforce a hard token limit per task and per session. Reset context when approaching the limit.

》問題根源

Token 用量不只是成本問題,它直接影響輸出品質。當 context window 被塞滿時,模型會開始「忘記」早期的指令——包括你在 CLAUDE.md 裡寫的所有規則。這是一個反直覺的現象:一次對話做越多事,後期的規則遵守率越低。

原始測試數據裡有一個細節值得注意:加了 12 條規則之後,每次任務的 token 用量從 5,400 微幅上升到 5,800。這代表規則本身也在消耗 context 空間。如果你同時有很長的對話歷史和很多規則,兩者會互相擠壓。

》實際寫法建議

## Rule 6: Hard Token Budgets
嚴格執行 token 預算:
- 單次任務上限:4,000 tokens
- 單次對話上限:30,000 tokens
- 接近上限時,主動提示開發者重新開始新對話
- 不要為了「完成」一個任務而超出預算,寧可分拆任務

》補充說明

這條規則有一個執行上的限制:Claude 本身無法精確計算自己的 token 用量,它只能估算。所以這條規則更像是一個行為傾向的校正——讓 Claude 在任務變得複雜時,傾向於提出「我們是否應該分拆這個任務」,而不是硬撐到底。實際的 token 監控還是需要靠 Claude Code 的介面或 API 層來做。

7. Resolve Style Conflicts Explicitly

When encountering conflicting code styles, pick one and state it. Do not mix styles silently.

》問題根源

真實的程式碼庫很少風格完全一致,尤其是多人協作、或是歷史悠久的專案。Claude 在遇到風格衝突時,有一個危險的傾向:沉默地選擇一種,或者更糟——兩種都用,讓新程式碼和舊程式碼的風格混在一起。

》常見的衝突場景包括:

  • 單引號 vs 雙引號(Python、JavaScript 都會遇到)
  • async/await vs .then() 鏈式寫法
  • 型別標注(全標 vs 只標公開介面 vs 完全不標)
  • 錯誤處理(try/catch vs Result type vs 回傳 tuple)

每一種都不是大問題,但混用就是大問題——它讓程式碼看起來像是由多個不認識彼此的人寫的。

》實際寫法建議

## Rule 7: Resolve Style Conflicts Explicitly
遇到風格衝突時:
1. 指出你發現了什麼衝突
2. 說明你選擇哪一種,以及為什麼
3. 在整個任務範圍內保持一致
4. 不要兩種都用、不要靜默選擇

》補充說明

這條規則最好搭配你自己的 style 偏好一起寫進 CLAUDE.md,例如直接在文件裡聲明「本專案統一使用單引號、async/await」。這樣 Rule 7 就變成一個衝突處理程序,而不是每次都要讓 Claude 自己做決定。

8. Read Before You Write

Before adding code to a file, read and understand the surrounding code in that file.

》問題根源

Claude 在沒有讀取上下文的情況下生成程式碼時,很容易產生「功能正確、但和周邊格格不入」的結果:

  • 同一個功能在別的地方已經有 utility function,它重新實作了一遍
  • 命名風格和周邊不一致(別人用 get_user_by_id,它寫了 fetchUser
  • 引入了專案裡已經有替代方案的 dependency

這不是模型能力的問題,而是資訊不足導致的決策錯誤。

》實際寫法建議

## Rule 8: Read Before You Write
在某個檔案新增程式碼前:
1. 先閱讀該檔案的現有內容
2. 確認是否已有可重用的函式或模式
3. 確認命名慣例、import 風格、錯誤處理方式
4. 新增的程式碼要和周邊「說同一種語言」

》補充說明

這條規則在大型專案裡效益特別明顯。當一個檔案超過幾百行,Claude 在沒有被要求的情況下,不會主動去讀它——它只會看你在對話裡提供的資訊。Rule 8 的作用是把「主動閱讀上下文」變成一個強制步驟,而不是可選行為。

9. Test Business Logic, Not Just Execution

Tests must verify that the business logic is correct, not just that the code runs without errors.

》問題根源

Claude 生成的測試有一個系統性的偏差:它傾向於寫「能跑過的測試」,而不是「能抓到錯誤的測試」。這兩者的差距比你想像的大。

常見的錯誤測試模式:

# 這個測試只確認「函式有回傳東西」
def test_calculate_discount():
    result = calculate_discount(user, order)
    assert result is not None  # ← 這不是在測業務邏輯
# 這個才是在測業務邏輯
def test_calculate_discount():
    # VIP 用戶購買超過 1000 元,應該享有 15% 折扣
    user = User(tier="VIP")
    order = Order(total=1500)
    result = calculate_discount(user, order)
    assert result == 225  # 1500 * 0.15

第一個測試在業務邏輯完全錯誤的情況下,依然會通過。它測的是「程式不會崩潰」,不是「程式做了正確的事」。

》實際寫法建議

## Rule 9: Test Business Logic, Not Just Execution
寫測試時:
- 每個測試必須對應一條業務規則,並在註解裡說明
- 斷言(assert)必須驗證具體的輸出值,不是「有回傳」或「不是 None」
- 邊界條件要明確測試(零值、最大值、剛好在門檻上的情況)
- 不要寫只確認「程式能跑」的測試

》補充說明

這條規則需要你在使用時提供足夠的業務背景。Claude 沒有辦法憑空知道「VIP 用戶超過 1000 元享有 15% 折扣」這條規則——你必須在任務描述裡說清楚。Rule 9 的作用是確保 Claude 把你提供的業務規則真正寫進斷言裡,而不是寫一堆看起來很完整、但實際上什麼都沒測到的測試。

10. Checkpoint Long Tasks

For multi-step tasks, summarize progress after each major step. Preserve a recoverable state.

》問題根源

長任務是 CLAUDE.md 規則最容易失效的場景。原因有兩個:

第一,context 稀釋:任務越長,早期的指令(包括 CLAUDE.md 裡的規則)在 context window 裡的比重越低,模型對它們的注意力會逐漸下降。

第二,錯誤累積:在沒有存檔點的情況下,第三步的錯誤假設會被第四步、第五步繼承。等你在第七步發現問題,要回溯到哪裡已經說不清楚了。

這兩個問題疊加在一起,讓長任務的失敗率遠高於短任務的累加——不是線性關係,而是指數關係。

》實際寫法建議

## Rule 10: Checkpoint Long Tasks
執行多步驟任務時:
- 每完成一個主要步驟,輸出一份進度摘要
- 摘要格式:「已完成:[X],下一步:[Y],目前假設:[Z]」
- 如果發現前面的步驟有問題,立刻說明——不要繼續往下走
- 讓每個存檔點都是一個可以獨立檢查的狀態

》補充說明

這條規則改變的不只是 Claude 的行為,也改變了你作為開發者的工作模式。有了明確的存檔點,你可以在每個步驟結束後決定是否繼續,而不是到最後才做整體驗收。這在長任務上節省的時間,往往遠超過閱讀這些摘要所花的時間。

11. Respect Existing Conventions

Match the naming, structure, and patterns already present in the codebase. Do not silently introduce your own style.

》問題根源

Rule 7 處理的是「遇到風格衝突時怎麼辦」,Rule 11 處理的是更根本的問題:在開始之前,就應該把現有慣例當作約束條件,而不是可以忽略的背景資訊。

這兩條的差別在於時間點:

  • Rule 7:發現衝突 → 顯性選擇
  • Rule 11:動手之前 → 先閱讀、先理解、先對齊

Claude 在沒有被明確要求的情況下,傾向於用它「認為正確」的方式命名和組織程式碼。這在全新專案上沒有問題,但在既有程式碼庫裡,它的「正確」和你的「正確」很可能不一樣。常見的情況:

  • 專案用 snake_case,它新增了一個 camelCase 的函式
  • 專案的 service layer 都回傳 (data, error) tuple,它改成拋出 exception
  • 專案的 config 都用環境變數,它在程式碼裡寫死了一個預設值

每一個單獨看都是小事,累積起來就是一個風格分裂的程式碼庫。

》實際寫法建議

## Rule 11: Respect Existing Conventions
在新增任何程式碼之前:
- 確認專案的命名慣例(變數、函式、類別、檔案)
- 確認錯誤處理的慣用模式
- 確認 config 和常數的管理方式
- 新程式碼要讓人看不出來是「後來加的」

》補充說明

Rule 8(動手前先讀)和 Rule 11(尊重現有慣例)是一對:Rule 8 是讀的動作,Rule 11 是讀完之後應該產生的約束。兩條規則合在一起,才能真正解決「新程式碼和舊程式碼格格不入」的問題。

12. Fail Loudly, Never Silently

If a task cannot be completed as specified, say so explicitly. Do not reframe partial completion as success.

》問題根源

這是 12 條規則裡,在工程場景中破壞力最被低估的一條。

Claude 有一個根深蒂固的行為傾向:它非常不願意說「我做不到」。這來自訓練目標——模型被訓練成有幫助的,而「有幫助」在訓練資料裡往往被關聯到「給出一個答案」。結果是:當任務無法完成時,Claude 傾向於:

  • 完成任務的一部分,然後宣告「完成」
  • 把問題繞過去,做一件相關但不是你要的事
  • 在回答裡用模糊語言掩蓋實際的失敗(「這個方法應該可以處理大多數情況」)

從對話體驗上看,這些回應都很順暢,不會讓你感到被拒絕。但從工程角度看,一個靜默的失敗比一個明確的錯誤更危險——因為你不知道你不知道。

》實際寫法建議

## Rule 12: Fail Loudly, Never Silently
如果任務無法按照規格完成:
- 明確說出哪裡做不到,以及為什麼
- 不要把「完成了一部分」包裝成「任務完成」
- 不要用模糊語言掩蓋失敗(「應該可以」、「大多數情況下」)
- 提出替代方案時,清楚說明它和原始要求的差距在哪裡

》和其他規則的關係

Rule 4(開始前定義完成標準)和 Rule 12(結束時誠實報告)是整個 12 條規則體系的首尾呼應:

  • Rule 4 確保「完成」有一個客觀標準
  • Rule 12 確保這個標準被誠實地對照,而不是被重新詮釋

沒有 Rule 4,Rule 12 沒有依據;沒有 Rule 12,Rule 4 形同虛設。


▌參考資料

》Andrej Karpathy - A few random notes from claude coding quite a bit last few weeks.

1個讚