Claude写代码错误率从41%降到3%:Karpathy的12条CLAUDE.md规则实战全解
2026年,AI编程工具已经不是什么新鲜事物了。从Copilot到Claude Code,从Cursor到Devin,每一个都在宣称自己能帮你写更好的代码。但真正在生产环境里用过的开发者都知道:AI写代码最大的问题,不是能力不够,而是行为不可预测。
你让它改一个函数,它顺手改了三个;你让它加个测试,它把整个测试文件重写了;你让它跑一下lint,它把项目风格全改了一遍。这些"顺手"做的事,有一半是在添乱。
Andrej Karpathy在2026年1月指出了这个问题,然后Forrest Chang把它整理成了一份只有4条规则的CLAUDE.md文件。两周内,这4条规则让AI coding的错误率从40%降到了3%以下。这个项目就是multica-ai/andrej-karpathy-skills,目前已经超过14万Star,是2026年增长最快的单文件GitHub仓库。
但问题是:这4条规则解决的是2026年1月份的问题。到了5月份,Claude Code的生态已经完全不同了——agent之间开始互相打架,hook开始级联触发,skill开始加载冲突,跨session的多步骤工作流动不动就断裂。
有人在30个代码库、6周实测的基础上,把4条扩展成了12条。错误率从41%降到了3%,同时遵循率只从78%降到了76%。新增的8条规则,覆盖的是Karpathy模板根本没有触碰到的地方。
这篇文章,我们把12条规则全部拆开来讲:每条规则是什么,为什么有效,以及Karpathy原版会悄悄失效的4个地方。我会给出完整的代码示例和可复制的CLAUDE.md模板,让你直接拿去做生产级项目配置。
一、背景:为什么CLAUDE.md是AI编程里最被低估的文件
在说12条规则之前,先搞清楚一件事:CLAUDE.md是什么,为什么它比任何prompt都重要。
Claude Code会在项目根目录读取CLAUDE.md文件,把它作为项目的"宪法"。它不是一条指令,而是整个项目的上下文定义——告诉AI这个项目用什么技术栈、代码风格是什么、哪些文件绝对不能碰、遇到模糊需求应该怎么做。
Anthropic的官方文档里有这样一句话:Claude大约80%的时间会遵循CLAUDE.md的内容。注意这个"大约"——这意味着如果你写的东西太多、太乱、太长,遵循率会下降到30%甚至更低。超过200行之后,Claude开始对"这里有规则"做模式匹配,却没有真正读它们。
所以CLAUDE.md的核心哲学是:越少越好,越精准越好。
Karpathy的4条规则只用了65行,覆盖了4个最常见的失败模式:
- 先思考再写代码 — 不要默默做假设
- 简单优先 — 不要过度工程化
- 手术式修改 — 只改必须改的地方
- 目标驱动执行 — 先定义成功标准
这4条在2026年1月是够用的。但到了5月,Claude Code的工作模式从"单次代码补全"进化到了"多步骤Agent工作流",问题变了。
二、原始4条规则详解:底线在哪里
规则1:先思考再写代码(Think Before Coding)
规则原文:
Before writing code, understand the requirements, constraints, and dependencies.
If there is ambiguity, ask. Do not assume. If there's a simpler approach, advocate for it.
这条规则解决的是AI最常见的问题:默默做错误假设。
当你对AI说"帮我加一个用户认证",它可能会默认用JWT,可能默认用session,可能默认数据库里有某个表。每一个默认都是一次错误假设。正确的方式是让它在动手之前先问清楚:用什么认证协议?数据库表结构是什么?有没有现有的认证模块可以复用?
实战示例:
假设你有一个这样的请求:
帮我加一个导出CSV的功能
没有规则约束的Claude会怎么做?它可能直接写一个Python函数,把所有用户数据导出到一个users.csv文件。但实际上你的代码库里可能已经有一个export_utils.py模块,有既定的导出逻辑和错误处理。
有了规则1,Claude会这样思考:
我需要先了解:
1. 这个项目里有没有现有的导出模块?
2. CSV的字段是什么?来自哪个数据源?
3. 有没有既定的导出权限控制逻辑?
然后它会先读代码,再提问,再写代码。这个"先读再问"的过程,来自于规则1的约束。
规则2:简单优先(Simplicity First)
规则原文:
Use the minimum code that solves the problem.
No speculative features. No premature abstraction.
If a senior engineer would call it over-engineered, simplify it.
这条规则解决的是过度工程化的问题。
AI在写代码时有一个隐含的倾向:它喜欢展示能力。一个简单的请求,它可能会写出一个带工厂模式的类层次结构,加上装饰器和接口抽象。代码行数从20行变成200行,可读性反而下降了。
规则2的约束逻辑是:如果一个资深工程师看了一眼觉得"这有点过了",就简化。
实战示例:
假设你让它写一个缓存功能,它可能会这样写:
from abc import ABC, abstractmethod
from typing import TypeVar, Generic, Optional
import time
T = TypeVar('T')
class CacheInterface(ABC, Generic[T]):
@abstractmethod
def get(self, key: str) -> Optional[T]: ...
@abstractmethod
def set(self, key: str, value: T, ttl: int) -> None: ...
class InMemoryCache(CacheInterface[T]):
def __init__(self):
self._store: dict[str, tuple[T, float]] = {}
def get(self, key: str) -> Optional[T]:
if key in self._store:
value, expiry = self._store[key]
if time.time() < expiry:
return value
del self._store[key]
return None
一个简单缓存功能,用了抽象基类、泛型、TypeVar。规则2约束下的Claude会这样写:
_cache: dict[str, tuple[str, float]] = {}
def cache_get(key: str) -> str | None:
if key in _cache:
value, expiry = _cache[key]
if time.time() < expiry:
return value
del _cache[key]
return None
def cache_set(key: str, value: str, ttl: int = 300):
_cache[key] = (value, time.time() + ttl)
没有ABC,没有泛型,没有TypeVar。用最少的代码解决问题。这就是规则2的核心:不要用牛刀杀鸡。
规则3:手术式修改(Surgical Changes)
规则原文:
Change only what must be changed. Do not "conveniently improve" adjacent code.
Do not refactor code that isn't broken. Match the existing style.
这条规则解决的是连带破坏的问题。
当你让AI改一个函数时,它可能会"顺便"修改相邻的代码,甚至顺手把整个模块重构了。结果是:你原本只需要改一行,但它改了一百行,其中九十行是新引入的bug。
规则3的核心是:改一行是一行。
实战场景:
你让Claude修改一个calculate_total的函数,让它支持折扣。没有规则约束,它可能顺便重构了整个order.py文件,加上了一个新的DiscountStrategy抽象层,修改了5个调用点,改了测试文件。
有了规则3,它会这样做:
- 读取
calculate_total函数的当前实现 - 只修改函数签名,增加一个
discount参数 - 只在函数内部增加折扣计算逻辑
- 不碰任何其他文件
Git diff会显示:
- def calculate_total(items: list[Item]) -> float:
+ def calculate_total(items: list[Item], discount: float = 0.0) -> float:
total = sum(item.price * item.quantity for item in items)
+ total = total * (1 - discount)
return total
这就是"手术式"的含义——精确切开,只处理病灶。
规则4:目标驱动执行(Goal-Driven Execution)
规则原文:
Define success criteria first. Iterate until verified.
Do not specify the steps. Describe what success looks like.
这条规则解决的是过程导向vs结果导向的问题。
传统的prompt是过程导向的:"先读这个文件,然后修改那里,然后写测试。"这种prompt让AI变成了一个执行命令的机器,而不是一个解决问题的agent。
规则4的约束是:不要告诉AI怎么做,告诉它要达到什么结果。
实战示例:
❌ 过程导向的prompt(不好):
先读取 auth.py,找到 login 函数,然后在函数末尾加一个token过期检查,
如果token已过期就返回401,最后在 test_auth.py 里加一个测试用例验证过期token。
✅ 结果导向的prompt(好):
目标:已过期的JWT token必须返回401,不能被当作有效token处理。
约束:不要改变现有通过测试的行为。改动范围只限 auth.py。
验证:运行 test_auth.py,所有测试必须通过。
结果导向的prompt让Claude自己规划路径,自己决定需要修改哪些行,自己判断是否需要新增测试。它可能只改了3行,也可能重构了半个文件——但无论如何,最终结果必须满足"已过期token返回401"这个目标。
三、为什么4条规则不够:2026年5月的新问题
在30个代码库里实测了6周后,作者发现了Karpathy 4条规则的4个系统性盲区:
盲区1:长时间运行的Agent任务
Karpathy的规则瞄准的是"Claude正在写代码的那个时刻"。它们没有说明Claude跑多步骤pipeline时该怎么办。
举个例子:你让Claude做一个20个文件的重构,分6步完成。第1步到第3步没问题,第4步走错了方向,第5步和第6步在错误的基础上继续推进。等你注意到时,Claude已经在错误状态上工作了40分钟。
Karpathy的规则里没有"检查点"的概念,没有"失败要响亮"的要求,没有token预算的上限。长时间运行的pipeline会漂移,漂移到不可恢复的程度。
盲区2:多代码库一致性
"匹配既有风格"这条规则在单一代码库里是清楚的。但在有12个服务的monorepo里,每个服务可能有不同的风格——A服务用TypeScript + class,B服务用TypeScript + functional,C服务用Go。
Karpathy的规则没有告诉Claude:当代码库里有多套风格时,选择哪一套。结果是Claude会随机选一套,或者试图"平均"两套风格,结果产出了不伦不类的代码。
盲区3:测试质量
规则4说"先定义成功标准"。在AI coding的语境里,"成功标准"最容易被理解成"测试通过"。但测试通过≠功能正确。
实测中发现了这个经典陷阱:Claude给一个auth函数写了12个测试,全都能通过。但这个函数实际上坏了——它返回的是一个常量字符串,而不是从数据库查出来的真实用户数据。
测试通过的原因是:测试写的是expect(getUserName()).toBe('John'),而函数恰好返回了'John'。这是一个常量,不是真实数据。
Karpathy的规则没有一条用来判断"测试是否测了正确的东西"。结果就是测试通过,代码却藏着错误。
盲区4:生产vs原型
同一条"简单优先"规则,在生产代码上是正确的,但在原型探索阶段可能是错误的。早期原型有时候确实需要100行推测性脚手架来摸清方向。Karpathy的规则会无差别地要求简单,导致原型探索阶段被过度约束。
四、新增8条规则详解
规则5:只让模型做判断,不做路由
规则原文:
Use Claude for: classification, drafting, summarization, extraction from unstructured text.
Do NOT use Claude for: routing, retries, status-code handling, deterministic transforms.
If a status code already answers the question, plain code answers the question.
这条规则解决的是用LLM做确定性逻辑的资源浪费问题。
你让Claude来决定"503错误时是否重试"?它可以做到。但这样做的问题是:LLM的输出是有随机性的。在503的边界情况下,模型可能今天决定重试,明天决定不重试。每次调用还要花token。
确定性逻辑(if-else、分支判断、状态机)应该用普通代码写。LLM应该只用来处理需要真正"判断"的事情——比如判断一段文本的情感倾向,或者从非结构化数据里提取结构化信息。
实战示例:
❌ 用LLM做路由(浪费且不稳定):
# 不好:让AI决定如何处理HTTP状态码
async def handle_response(response):
decision = await llm.classify(
f"Status: {response.status}, Body: {response.text[:200]}",
["retry", "fail", "cache"]
)
if decision == "retry":
return await retry_request(response.url)
elif decision == "fail":
raise RequestError(response)
else:
return get_cached(response.url)
✅ 用普通代码做路由,LLM只处理需要判断的部分:
# 好:路由逻辑用普通代码,LLM只处理文本分析
async def handle_response(response):
if 500 <= response.status < 600:
return await retry_request(response.url, max_attempts=3)
elif response.status == 429:
return await handle_rate_limit(response)
elif response.status == 403:
# 只有在需要理解错误消息语义时才调用LLM
if "quota exceeded" in response.text:
raise QuotaExceededError(response)
else:
raise PermissionError(response)
else:
return response.json()
规则5的核心洞察:确定性逻辑交给代码,不确定的判断交给LLM。这是AI辅助编程里最重要的边界划分。
规则6:硬性token预算,没有例外
规则原文:
Per-task budget: 4,000 tokens.
Per-session budget: 30,000 tokens.
If a task is approaching budget, summarize and start fresh. Do not push through.
Surfacing the breach > silently overrunning.
这条规则解决的是上下文膨胀导致的能力退化问题。
一个debugging session跑了90分钟,Claude非常乐意围绕同一个8KB错误信息反复迭代。然后它逐渐忘记自己已经试过哪些修复。最后,它在第40条消息里建议的方案,是第12条消息之前就已经被拒绝过的。
Token预算本该在第12分钟就让它停下来。
实战中的token预算策略:
# 在CLAUDE.md底部加入:
## Token Budget
- Per-task limit: 4,000 output tokens. If hitting this, summarize and propose next step.
- Per-session limit: 30,000 total tokens. If approaching this, summarize progress and ask for confirmation before continuing.
- After each significant file change, verify immediately. Don't batch changes without verification.
预算规则的关键是它必须是硬的,而不是"建议"。当Claude说"让我继续分析这个问题",它应该知道如果已经接近4,000 tokens,它应该先总结当前进展,而不是继续挖坑。
规则7:暴露冲突,不要折中平均
规则原文:
If two existing patterns in the codebase contradict, don't blend them.
Pick one (the more recent / more tested), explain why, and flag the other for cleanup.
"Average" code that satisfies both rules is the worst code.
这条规则解决的是AI"讨好两边"导致的不连贯问题。
当代码库里存在两套互相矛盾的模式时,Claude会试着同时满足两边。它会写出让两套模式都能运行的代码,结果是两套模式都被破坏了——因为两边都有预期,但代码只满足了一边的假设。
实战场景:
一个代码库里存在两套错误处理模式:
# 模式A:async/await + 显式 try/catch
async def fetch_user(user_id):
try:
return await db.get_user(user_id)
except UserNotFoundError:
return None
# 模式B:全局 error boundary
# 任何未捕获异常被 app.py 里的全局 error boundary 统一处理
Claude写了一个同时使用两种模式的新函数。调用方用的是模式B(期望异常被全局处理),但函数里用try/catch吞掉了异常。结果是:异常被吞了两次,一次在函数内部,一次在全局——调试时根本不知道发生了什么。
规则7的约束:当代码库里存在矛盾的模式时,选择一个,明确说为什么,标记另一个待清理。不要写"折中"的代码。
规则8:先读再写
规则原文:
Before adding code in a file, read the file's exports, the immediate caller, and any obvious shared utilities.
If you don't understand why existing code is structured the way it is, ask before adding to it.
"Looked orthogonal to me" is the most dangerous phrase in this codebase.
这条规则是规则3(手术式修改)的加强版。规则3告诉Claude"不要碰相邻代码",但没有告诉它"要先理解相邻代码"。
实战中的陷阱:
Claude在utils.py里加了一个新函数format_timestamp:
def format_timestamp(ts: int) -> str:
return datetime.fromtimestamp(ts).strftime("%Y-%m-%d")
实际上utils.py里已经有一个format_date函数了,做的是完全一样的事情。Claude没有读到它,因为它的搜索范围只覆盖了新修改的文件,而没有覆盖"语义上相关的其他文件"。
规则8的约束是:在写任何代码之前,先读这个文件的导出列表、最近的调用方,以及任何明显的共享工具函数。如果发现已有类似实现,先复用,再扩展。
规则9:测试验证意图,不只是行为
规则原文:
Every test must encode WHY the behavior matters, not just WHAT it does.
A test like `expect(getUserName()).toBe('John')` is worthless if the function takes a hardcoded ID.
If you can't write a test that would fail when business logic changes, the function is wrong.
这条规则解决的是测试质量的问题——不是"测试是否通过",而是"测试是否测了正确的东西"。
实战示例:
❌ 只测行为,不测意图(危险):
def test_get_user():
assert get_user(1).name == "Alice"
assert get_user(2).name == "Bob"
✅ 测意图,测边界(安全):
def test_get_user_returns_correct_data():
"""
意图:这个函数必须从数据库取真实数据,不能返回假数据。
边界:用户不存在时返回None,不是抛出异常。
"""
# 给定一个已存在的用户ID
user = get_user(VALID_USER_ID)
# 那么应该返回该用户的真实姓名(不是常量)
assert user.name == DB.users[VALID_USER_ID].name
def test_get_user_not_found_returns_none():
"""不存在用户的ID必须返回None,而不是抛出异常"""
result = get_user(NON_EXISTENT_USER_ID)
assert result is None
规则9的核心洞察:测试要编码的是"为什么这个行为重要",而不是"这个函数返回什么"。一个能通过浅层测试但逻辑错误的函数,它的测试反而是危险的——因为它给你虚假的信心。
规则10:长时间任务要有检查点
规则原文:
After completing each step in a multi-step task: summarize what was done, what's verified, what's left.
Don't continue from a state you can't describe back to me.
If you lose track, stop and restate.
这条规则解决的是长时间Agent工作流的进度丢失问题。
多步骤重构、跨多个文件的功能构建、持续调试——这类任务如果没有检查点机制,一次走错就会丢掉所有进展。
实战中的检查点模板:
在每次完成多步骤任务的中间步骤后,要求Claude输出一个检查点总结:
## Checkpoint after step 3/6
✅ 已完成:
- 重构了 auth.py 的登录逻辑,增加了 token 刷新机制
- 验证:新旧 token 可以无缝切换,现有测试通过
📋 待完成:
- [ ] 修改 refresh_token endpoint,支持滑动过期
- [ ] 更新 auth middleware,处理刷新后的新 token
- [ ] 添加 refresh token 的并发安全测试
⚠️ 风险:
- refresh 逻辑和现有 rate limiter 的交互需要再验证
如果Claude在第4步之后开始跑偏,检查点总结会暴露这个问题:你可以说"checkpoint step 3显示需要验证X,现在验证了吗?"而不是等到第6步才发现整个方向都错了。
规则11:约定胜过新奇
规则原文:
If the codebase uses snake_case and you'd prefer camelCase: snake_case.
If the codebase uses class-based components and you'd prefer hooks: class-based.
Disagreement is a separate conversation. Inside the codebase, conformance > taste.
If you genuinely think the convention is harmful, surface it. Don't fork it silently.
这条规则解决的是AI引入新风格导致的一致性破坏问题。
Claude有自己的编码偏好——它可能更喜欢函数式编程,更喜欢TypeScript的泛型,更喜欢用class。但代码库里已经有一套约定好了的风格。
引入两套风格带来的伤害,比任意一套风格本身都大。
实战示例:
一个React代码库里用的是class component:
class UserProfile extends React.Component<Props, State> {
componentDidMount() {
this.loadUser();
}
render() {
return <div>{this.state.user?.name}</div>;
}
}
Claude"好心"把它改成了React hooks:
const UserProfile: React.FC<Props> = ({ userId }) => {
useEffect(() => {
loadUser();
}, []);
return <div>{user?.name}</div>;
}
结果:整个代码库的测试框架是基于componentDidMount钩子的。新代码让测试框架失效了,因为它根本不再触发那些生命周期方法。花了半天才把改动的代码找出来、回滚、重写。
规则11的约束:在代码库里,遵从性优先于个人偏好。如果真的觉得现有约定有害,先提出来讨论,不要悄悄fork。
规则12:失败要响亮,不要沉默
规则原文:
If you can't be sure something worked, say so explicitly.
"Tests pass" is wrong if you skipped any.
"Feature works" is wrong if you didn't verify the edge case I asked about.
Default to surfacing uncertainty, not hiding it.
这条规则解决的是最昂贵的失败:看起来像成功的失败。
一个函数"能工作",但返回错误数据。一个migration"完成了",但跳过了30条记录。一个测试"通过了",但只是因为assertion写错了。
实战场景:
Claude说数据库migration"成功完成"。它悄悄跳过了14%命中constraint violation的记录。跳过被写进了log,但没有被明确暴露出来。11天后,报表开始不对,才发现这个问题——而那14%的数据已经造成了不可逆的业务损失。
规则12的约束:如果某件事不能被完全确认,就明确说出来。不是"完成了",而是"完成了,但14条记录因constraint violation被跳过"。不是"测试通过",而是"测试通过,跳过了3个边界用例"。
五、完整12条CLAUDE.md模板
把以上12条规则整合在一起,得到一个完整的CLAUDE.md文件。建议控制在200行以内。
# Project Context
[简要描述项目:技术栈、架构、主要模块]
## Code Style
[描述代码风格:命名规范、格式化偏好、重要约定]
## Don't Touch
[描述绝对不能修改的文件或目录]
---
## AI Coding Rules
### Rule 1 — Think Before Coding
Before writing code, understand the requirements, constraints, and dependencies.
If there is ambiguity, ask. Do not assume.
If there's a simpler approach, advocate for it.
### Rule 2 — Simplicity First
Use the minimum code that solves the problem.
No speculative features. No premature abstraction.
If a senior engineer would call it over-engineered, simplify it.
### Rule 3 — Surgical Changes
Change only what must be changed. Do not "conveniently improve" adjacent code.
Do not refactor code that isn't broken. Match the existing style.
Run git diff before committing. Keep diffs minimal.
### Rule 4 — Goal-Driven Execution
Define success criteria first. Iterate until verified.
Do not specify the steps. Describe what success looks like.
Verification is mandatory — do not skip it.
### Rule 5 — Use the Model Only for Judgment Calls
Use Claude for: classification, drafting, summarization, extraction.
Do NOT use Claude for: routing, retries, status-code handling, deterministic transforms.
If a status code already answers the question, plain code answers it.
### Rule 6 — Token Budgets Are Not Advisory
Per-task budget: 4,000 output tokens.
Per-session budget: 30,000 total tokens.
If a task is approaching budget, summarize and propose next step. Do not push through.
### Rule 7 — Surface Conflicts, Don't Average Them
If two existing patterns in the codebase contradict, don't blend them.
Pick one (the more recent / more tested), explain why, and flag the other for cleanup.
"Average" code that satisfies both rules is the worst code.
### Rule 8 — Read Before You Write
Before adding code in a file, read the file's exports, the immediate caller, and any obvious shared utilities.
If you don't understand why existing code is structured the way it is, ask before adding to it.
"Looked orthogonal to me" is the most dangerous phrase in this codebase.
### Rule 9 — Tests Verify Intent, Not Just Behavior
Every test must encode WHY the behavior matters, not just WHAT it does.
A test like `expect(getUserName()).toBe('John')` is worthless if the function returns a hardcoded value.
If you can't write a test that would fail when business logic changes, the function is wrong.
### Rule 10 — Checkpoint After Every Significant Step
After completing each step in a multi-step task: summarize what was done, what's verified, what's left.
Don't continue from a state you can't describe back to me.
If you lose track, stop and restate.
### Rule 11 — Match the Codebase's Conventions, Even If You Disagree
snake_case vs camelCase → snake_case.
Class-based vs hooks → match existing.
Conformance > taste inside the codebase. Surface disagreement, don't fork it silently.
### Rule 12 — Fail Loud
If you can't be sure something worked, say so explicitly.
"Completed" is wrong if any records were skipped silently.
"Tests pass" is wrong if you skipped any test files.
Default to surfacing uncertainty, not hiding it.
六、数据验证:12条规则 vs 4条规则
实测数据来自30个代码库、50个代表性任务、6周跟踪:
| 指标 | Karpathy 4条 | 扩展后12条 | 变化 |
|---|---|---|---|
| 任务错误率 | 41% | 3% | ↓38pp |
| 规则遵循率 | 78% | 76% | ↓2pp |
| 静默失败率 | 28% | 2% | ↓26pp |
| Token消耗/task | 18,000 | 12,500 | ↓31% |
关键发现:新增的8条规则几乎不增加遵循负担(只降了2pp),却把错误率砍掉了38个百分点。新增规则覆盖的是原始4条根本没有触达的失败模式——它们不争夺同一个注意力预算。
超过14条规则后,遵循率会从76%掉到52%。所以12条是一个平衡点:覆盖了所有主要失败模式,同时保持了足够的遵循率。
七、Karpathy模板会悄悄失效的4个地方(总结)
长时间运行的Agent任务:没有检查点,没有token预算,没有失败暴露,pipeline会漂移到不可恢复。修复:规则6(token预算)+ 规则10(检查点)+ 规则12(失败响亮)。
多代码库一致性:当代码库里有多套风格时,Claude随机选或折中平均。修复:规则7(暴露冲突)。
测试质量:测试通过≠功能正确,AI会写出能通过浅层测试的错误代码。修复:规则9(测试验证意图)。
生产vs原型:简单优先规则在早期原型上会过度触发,阻碍探索。修复:在CLAUDE.md里对生产代码和原型目录分别应用不同规则强度。
八、实操建议:怎么把这个模板用起来
第一步:直接复制,不做修改,先跑两周
CLAUDE.md的价值在于"有"而不是"完美"。先把这个12条模板复制到项目根目录,跑两周,感受哪些地方需要调整。不要一开始就定制化——你对AI coding的痛点理解,往往是跑了两周之后才清晰的。
第二步:按项目痛点精简
12条规则里,有些是你项目里根本不会遇到的场景——比如如果你没有多代码库的monorepo,规则7的很多内容都可以简化。如果你的代码库里全是函数式风格,规则11可以大幅压缩。
精简的目标是保留所有能防止真实失败场景的规则,删除所有"理论上有用但实际用不上"的规则。
第三步:监控遵循率
CLAUDE.md不是写完就完事了。你需要在每次和Claude的交互后,观察它是否遵守了规则——特别是规则1(先问再写)、规则3(最小diff)和规则8(先读再写)。
如果发现它经常不遵守某条规则,可能的原因有两个:
- 规则写得不够明确(改成更具体的描述)
- 规则不适用于你的项目(删除或修改)
第四步:定期更新
CLAUDE.md应该是一个活的配置文件。随着项目发展,你的技术栈会变,代码风格会变,团队规模会变。CLAUDE.md也要跟着变。
建议每季度review一次CLAUDE.md,删除过时的规则,增加新痛点对应的规则。
总结
Karpathy的4条规则是一个好的起点,但它解决的是2026年1月的AI coding问题。到了今天,Claude Code已经从"单次代码补全"进化到了"多步骤Agent工作流",问题的性质变了。
12条规则的扩展,核心贡献是三条以前完全没有被覆盖的原则:
- 规则5:用LLM做判断,不做路由。这是AI辅助编程里最重要的边界划分。
- 规则6:token预算是硬的,不是建议。没有上限的上下文会无限膨胀,直到AI开始给出它在第12条消息之前就已经拒绝过的方案。
- 规则12:失败要响亮。静默失败是生产环境里最昂贵的bug。
如果你现在只用着Karpathy的4条规则,建议你把12条模板直接复制进去,跑两周,然后根据自己的实际情况做减法。你会发现的:好的CLAUDE.md不是写得越多越好,而是写得越准越好。
12条规则,76%遵循率,3%错误率。这个配置,值得每个AI编程项目拥有。