一个 70 行的 Markdown 文件,108K GitHub Star,两万开发者在一周内装进自己的项目。
2026 年 1 月,Andrej Karpathy(前特斯拉 AI 总监、OpenAI 创始成员)发了一条帖子,吐槽 LLM 写代码时的「坏毛病」。这条帖子引发了一场蔓延整个开发者社区的现象——开发者 forrestchang 把他的观察提炼成 4 条行为原则,写成一个 CLAUDE.md 文件,发布在 GitHub。不到四个月,收获 108K Star、10.7K Fork。
为什么一条 70 行的规则文件能火到这个程度?因为它恰好击中了每个用过 AI 编程助手的人的隐性痛点:AI 写代码太快、太自信、太爱把事情搞复杂。
为什么你需要一套 AI 编程规则?
场景一:AI 默默做了错误假设。你让它「加一个导出功能」,它批量导出所有用户数据,连哪些字段可以导出、文件存哪都没问。代码跑通了,但不符合你的安全策略。
场景二:AI 把简单事情复杂化。你让它「加个折扣计算」,它给你搭了一个策略模式 + 抽象工厂 + 配置层的架子,500 行代码实现了本应 5 行搞定的功能。
场景三:AI 顺手改了不该改的东西。你让它「修复空邮箱报错」,它顺手把你的双引号改成单引号、加了类型注解、重构了旁边的校验逻辑。Code Review 时你盯着 30 行的 diff 发呆。
这不是工具的问题——这是 LLM 的基本行为模式:模型倾向于做出假设、倾向过度设计、倾向改动多于所需。Karpathy 的四原则,就是针对这些系统性缺陷的行为约束。
原则一:先想再写(Think Before Coding)
核心思想:不要假设,不要隐藏困惑。把取舍摆到台面上。
问题场景
Karpathy 的原话是:「模型会为你做错误假设,然后顺着这些假设一直跑下去。它们不管理自己的困惑,不寻求澄清,不呈现矛盾,不在该 push back 的时候 push back。」
举个具体例子。你让 AI「实现一个用户数据导出功能」,典型的 LLM 行为是这样的:
def export_users(format='json'):
"""Export all users to a file."""
users = User.query.all()
if format == 'json':
with open('users.json', 'w') as f:
json.dump([u.to_dict() for u in users], f)
elif format == 'csv':
with open('users.csv', 'w') as f:
writer = csv.DictWriter(f, fieldnames=['id', 'email', 'name'])
writer.writeheader()
writer.writerows([u.to_dict() for u in users])
return f"Exported {len(users)} users"
代码看起来没问题,但隐藏了四个假设:假设导出所有用户(没考虑分页和隐私)、假设文件位置、假设导出字段、假设 CSV 列名。如果数据量 100 万行、或包含敏感字段,这段代码就是生产事故。
正确的做法
AI 应该在动手之前说:「我需要澄清几个问题再开始:导出全部用户还是筛选结果?文件放本地还是提供下载 API?哪些字段可以包含?」先把假设列出来,让开发者做决策。
如何应用在 CLAUDE.md 中写入:
先想再写
这条原则的适用范围不仅是代码——任何需要 AI 做决策的任务,都应该先呈现假设。在不确定的时候问一句,比事后修 bug 节省 10 倍时间。
原则二:简单优先(Simplicity First)
核心思想:用最少的代码解决当前问题。不多写一行推测性的东西。
问题场景
这是 LLM 最典型的「过度工程」行为。你让它「加一个计算折扣的函数」,它给了你一个包含策略模式、抽象基类、配置对象的解决方案:
from abc import ABC, abstractmethod
from dataclasses import dataclass
class DiscountStrategy(ABC):
@abstractmethod
def calculate(self, amount: float) -> float: pass
class PercentageDiscount(DiscountStrategy):
def init(self, percentage: float):
self.percentage = percentage
def calculate(self, amount: float) -> float:
return amount * (self.percentage / 100)
... 更多类定义
30 行设置代码,实际要的功能只是 amount * (percent / 100)。
Karpathy 指出:LLM 非常喜欢把代码搞复杂、膨胀抽象层、不清理死代码。1000 行能解决的问题,它倾向于写 2000 行。
正确的做法
def calculate_discount(amount: float, percent: float) -> float:
"""计算折扣金额。percent 取值 0-100。"""
return amount * (percent / 100)
等真的需要多种折扣类型时,再重构。在那之前——不加一行不必要的代码。
如何应用在 CLAUDE.md 中写入:
简单优先
自测问题:「资深工程师会觉得这个过于复杂吗?」如果答案是「是」,就简化。
原则三:手术式修改(Surgical Changes)
核心思想:只动必须动的。只清理自己留下的脏东西。
问题场景
这是 Code Review 中最让开发者崩溃的行为。你让 AI「修复空邮箱导致验证器崩溃的 bug」,它返回的 diff 是这样的:
- def validate_user(user_data):
- def validate_user(user_data: dict) -> bool:
email = user_data.get('email', '').strip()
if not email: raise ValueError("Email required")
if '@' not in user_data['email']:
if '@' not in email or '.' not in email.split('@')[1]: raise ValueError("Invalid email")
username = user_data.get('username', '').strip()
raise ValueError("Username too short") return True
修复空邮箱的 bug 只需要改 3 行,但 AI 顺手「优化」了邮箱校验逻辑、加了用户名校验(没人要的)、加了类型注解和 docstring。这些改动本身不是错,但让 Code Review 的成本从 30 秒变成了 10 分钟。
正确的做法
只改跟 bug 直接相关的行:
if not user_data.get('email'):
email = user_data.get('email', '')
if not email or not email.strip(): raise ValueError("Email required")
if '@' not in user_data['email']:
if '@' not in email: raise ValueError("Invalid email")
每一行改动都可溯源到用户需求。这就是「手术式修改」的含义。
如何应用在 CLAUDE.md 中写入:
手术式修改
改动造成的孤儿(import/变量/函数)必须清理。
检验标准:每一行改动都应能直接溯源到用户需求。
这条原则在多人协作项目中尤其重要——你期望的不仅是 AI 写出好代码,更是不制造多余的 Review 负担。
原则四:目标驱动执行(Goal-Driven Execution)
核心思想:定义清晰的成功标准,闭环直到验证通过。
问题场景
开发者常说:「把这个功能修好」「优化一下」「重构这个模块」。这些模糊指令在 AI 面前是灾难——AI 会按自己理解的最佳方式执行,然后告诉你「搞定了」,但实际可能完全不是你想要的。
典型例子:你在对话框中问「排序在分数相同时会乱」,AI 直接改了排序逻辑但没有确认 bug 是否存在、没有写测试验证。
正确的做法
AI 应该先写复现测试:
def test_sort_with_duplicate_scores():
scores = [
{'name': 'Alice', 'score': 100},
{'name': 'Bob', 'score': 100},
]
result = sort_scores(scores)
assert result[0]['score'] == 100
assert result[1]['score'] == 100
先确认:这个测试能复现 bug 吗?
再修复:用稳定排序键
最后验证:测试通过了
Karpathy 的洞察很关键:模糊的指令让 AI 无法独立完成任务,清晰的成功标准让它能闭环。
如何应用在 CLAUDE.md 中写入:
目标驱动执行
把模糊任务转为可验证目标:
多步骤任务写简短计划:
批评与局限
Karpathy 的四原则并非万能药。一些开发者在实践后发现:
过度强调简化有时会导致过早错误的实现——当项目确实需要抽象层时,原则二可能会误判。
对产品协作场景覆盖不足——原则一鼓励「问清楚再动手」,但在团队协作中,AI 需要的不只是问清楚,还要理解产品上下文和渐进式的交付节奏。
静态规则 vs 动态上下文——CLAUDE.md 是静态的,而开发场景是动态的。一个好的 AI 编程助手应该在遵循规则的同时,也能判断「什么时候该打破规则」。
尽管如此,对于一个 70 行的配置文件来说,这些局限并不减损它的核心价值——它提供了一个最低成本的 AI 行为基线,让开发者不再需要重复纠正 AI 的「坏习惯」。
常见问题
Q:CLAUDE.md 和 Cursor 的 rules 有什么区别?
CLAUDE.md 是 Claude Code 原生支持的配置文件。Cursor 使用自己的 .cursor/rules/ 目录。两者逻辑相同——都是给 AI 提供持久化的行为指令。目前已经有社区开发者将 Karpathy 四原则转成了 Cursor 版本。 Q:这条规则适用于 Copilot 吗?
Copilot 目前不支持 CLAUDE.md,但类似的行为约束可以通过 GitHub Copilot 的指令功能实现。四原则的思想不限于某个具体工具。 Q:四原则会降低 AI 编码速度吗?
会,但这种「降低」是刻意的。Karpathy 的原则权衡了速度和质量:前几次对话会慢一些(因为 AI 会提问、会简化、会等待确认),但避免了后续无休止的修 bug 和重构。长期来看,总时间是节约的。
Q:四原则之间有冲突怎么办?
比如「简单优先」和「目标驱动」在特定场景下可能需要平衡。建议优先级是:先想再写 > 目标驱动 > 简单优先 > 手术式修改。当然,最终决策权在开发者。
结语
Andrej Karpathy 的 CLAUDE.md 四原则,本质上是用了 70 行 Markdown 解决了一个被低估的问题——AI 编程工具的能力已经足够强,但缺乏一套行为约束让它和人类开发者高效协作。
108K Star 的投票说明了一切:开发者需要的不只是更强的 AI,而是更可控的 AI。
你的 CLAUDE.md 文件写好了吗?