如果你在用 Claude Code、Cursor、Copilot 写代码,大概率被 AI "自作聪明"坑过。
Andrej Karpathy 在 X 上吐槽了这件事,然后有人把他的吐槽做成了解决方案。
这篇文章讲清楚:他吐了什么槽、解决方案长什么样、你今天就能抄走用。
先认识下吐槽的人
如果你是 AI 圈外的开发者,Karpathy 这个名字可能听着耳熟但说不准是谁。先花 30 秒介绍一下:
- 前 OpenAI 创始团队成员
- 前特斯拉 AI 高级总监,Autopilot 的掌舵人
- 斯坦福 CS231n(深度学习视觉课)讲师,很多人入门 AI 就是看他的课
- AI 教育圈公认最会"讲人话"的大神,B 站也有他的课程搬运
他最近在 X 上发了一条观察,吐槽大语言模型写代码时的几个典型毛病。这条推文本身没什么特别------谁都吐过类似的槽。但有意思的是:
一位叫 forrestchang 的开发者把这条吐槽,做成了一份 CLAUDE.md 文件,放到 GitHub 上。
结果这份文件,收获了 73k Star。

一份 markdown 文件,没有代码,没有脚本,比很多精心打磨的开源项目还火。
为什么?因为它解决的真的是所有 AI 编程用户的共同痛点。下面我把 Karpathy 的原话、这份 CLAUDE.md 的 4 条规则、以及你怎么用,一次讲清楚。
Karpathy 的原话:LLM 写代码的三宗罪
先看 Karpathy 原帖的三段核心吐槽(我翻译成大白话):
罪状一:瞎假设 + 不求证
"模型会替你做错误的假设,然后一路狂奔也不检查。它们不管理自己的困惑、不寻求澄清、不暴露不一致、不呈现权衡、该反驳的时候也不反驳。"
翻译过来就是:
你告诉它"做个用户登录",它不会问"用 JWT 还是 Session?用户密码怎么存?要不要记住登录?"------它会默默替你选一个,然后写 500 行代码,最后你发现选错了,全部推翻重来。
你说"这里有点问题,好像不太对",一个好的工程师会说"你是指 X 还是 Y?我倾向 X,因为......",而 LLM 经常就直接改,结果越改越离谱。
罪状二:过度工程上瘾
"它们特别喜欢把代码和 API 搞复杂,堆叠臃肿的抽象......不清理死代码......100 行能解决的事,它实现成了 1000 行的庞然大物。"
翻译过来就是:
你说"写个读取配置的函数",它给你整出来:
- 一个
ConfigLoader抽象类 - 三个具体实现
JSONConfigLoader、YAMLConfigLoader、TOMLConfigLoader - 一个
ConfigLoaderFactory - 一个
ConfigLoaderRegistry - 再加上完整的错误处理、日志、缓存......
你:"我只是想读一个 .env 文件啊?"
罪状三:顺手改不该改的东西
"它们有时候会修改或删除自己并没有充分理解的注释和代码,哪怕这些跟当前任务完全无关。"
翻译过来就是:
你让它在某个函数里加一行日志。提交 PR 时你一看 diff:
- ✅ 加了日志(你要的)
- ❓ 顺手把附近一个函数的参数顺序改了
- ❓ 删掉了一段"看起来没用"的注释(其实是团队的重要约定)
- ❓ 把一个
const改成了let(毫无理由) - ❓ 甚至格式化了整个文件
这种"顺便优化"是 code review 里最让人头疼的事,因为你得一行行过,生怕它漏看哪里偷偷改了东西。
痛吗?痛就对了
上面这三条,只要你真用 AI 写过几周代码,一定全部中过枪。
我自己最痛的一次:让 Claude 改一个 API 的返回格式,它改完顺手把请求参数校验逻辑"优化"了------实际上是把原来的校验函数删了,换成了一个更"优雅"但漏了一个边界情况的新函数。等到上线后用户反馈才发现。
这不是 Claude 蠢,这是它被训练得"太勤快" ------训练数据里那些"好代码"都是在重构里抽象出来的,所以它本能地想把你的代码也"优化"到那个样子。但问题是:
你只让它做 A,它顺手做了 A、B、C、D。多出来的 B、C、D 就是定时炸弹。
Karpathy 的洞察就在于:他把这种"AI 勤快病"总结清楚了,而 forrestchang 把它做成了可以直接贴给 AI 的规则。
解决方案:四条规则,一份文件
forrestchang 做的这份 CLAUDE.md,本质是把 Karpathy 的观察翻译成 AI 能理解、能执行的指令。它一共四条规则,每条都精准对应 Karpathy 吐槽的一个毛病:
| 规则 | 解决的毛病 |
|---|---|
| Think Before Coding(先想再写) | 瞎假设、藏着困惑、不讲权衡 |
| Simplicity First(简洁优先) | 过度工程、臃肿抽象 |
| Surgical Changes(外科手术式修改) | 顺手动不该动的代码 |
| Goal-Driven Execution(目标驱动执行) | 靠验证标准而不是指令细节 |
下面逐条讲。
规则一:Think Before Coding(先想再写)
核心要求
不要假设。不要藏着困惑。把权衡摆出来。
具体做法(这些会直接写进 CLAUDE.md 让 AI 遵守):
- 明确说出假设 ------ 如果不确定,先问,别猜
- 呈现多种解读 ------ 需求有歧义时不要默默选一个
- 该反驳就反驳 ------ 有更简单的方案就直说
- 困惑了就停 ------ 说清楚哪里不懂,要求澄清
实际效果对比
规则生效前(AI 常见行为):
vbnet
用户: "给这个用户模块加个权限校验"
AI: "好的,我会实现一个完整的 RBAC 权限系统..."
[开始写 800 行代码,包含角色表、权限表、中间件、装饰器]
规则生效后:
vbnet
用户: "给这个用户模块加个权限校验"
AI: "开始实现前我想确认几点:
1. 你是想要简单的"登录即有权限"的检查,还是需要细粒度的角色/权限控制?
2. 看到你的代码里已经有 requireAuth 中间件,是基于这个扩展,
还是要重新设计?
3. 如果只是单个接口,我建议最小化改动,只在这个接口上加一行检查。
倾向哪种?"
区别一目了然:第一种你会得到一堆没人要的代码;第二种你用 30 秒澄清,省下 2 小时返工。
规则二:Simplicity First(简洁优先)
核心要求
能解决问题的最少代码。不搞投机性设计。
具体禁令:
- ❌ 不做没被要求的功能
- ❌ 不为一次性代码做抽象
- ❌ 不搞没要求的"灵活性"和"可配置性"
- ❌ 不处理不可能发生的错误
- ✅ 200 行能压成 50 行,就压
判断标准
资深工程师看到会不会说"这太复杂了"?会 → 简化。
这个标准非常关键,因为它不是死规则,而是一个可以让 AI 自我校验的启发式问题。
一个真实例子
我让 Claude 写一个"把字符串转成 slug"的函数(比如把 "Hello World!" 转成 "hello-world")。
没有这条规则时,它的输出:
python
from typing import Optional, List
import re
import unicodedata
class SlugConfig:
def __init__(
self,
separator: str = "-",
lowercase: bool = True,
max_length: Optional[int] = None,
allowed_chars: Optional[str] = None,
replacement_map: Optional[dict] = None,
):
# ... 30 行初始化
pass
class SlugGenerator:
def __init__(self, config: SlugConfig):
# ...
def generate(self, text: str) -> str:
# ... 50 行
def batch_generate(self, texts: List[str]) -> List[str]:
# ... 你没要这个
# 外加单元测试类、异常类......
加了简洁优先规则后:
python
import re
def slugify(text: str) -> str:
return re.sub(r'[^a-z0-9]+', '-', text.lower()).strip('-')
两行代码,功能完全一样 。这就是"简洁优先"的力量------它不是让 AI 偷懒,而是让 AI 停止为想象中的需求做准备。
规则三:Surgical Changes(外科手术式修改)
核心要求
只碰必须碰的。只清理你自己弄出的烂摊子。
具体做法:
修改现有代码时:
- ❌ 不"顺手改善"相邻的代码、注释、格式
- ❌ 不重构没坏的东西
- ✅ 匹配现有风格,哪怕你不喜欢
- ✅ 发现无关的死代码 → 只提一下,不要删
你的改动产生孤儿代码时:
- ✅ 删除因你的修改而变得无用的 import、变量、函数
- ❌ 不要删除预先存在的死代码,除非被要求
判断标准
每一行改动,都必须能直接追溯到用户的某个请求。
这条规则听起来简单,但对 AI 是最难遵守的一条------因为它的训练数据让它天然觉得"看到能改进的就应该改进"。
为什么这条这么重要
因为顺手改的代码是 code review 的噩梦:
- 你以为在 review 一个改动,结果发现要 review 5 个改动
- 每个"顺手改"都可能引入 bug,而且最难排查
- 团队代码风格被不断"微调",一致性崩坏
- 任务复杂度会指数级增长:一次改 5 个地方 → 5 个地方都可能出问题 → 排查时间 x 5
加上这条规则后,AI 提交的 diff 会变得非常"干净"------你能一眼看完、一眼 review、一眼合并。
规则四:Goal-Driven Execution(目标驱动执行)
这条是全篇最有价值的洞察,也是 Karpathy 原帖的灵魂。
Karpathy 的原话
"LLM 特别擅长围绕明确目标不断迭代。不要告诉它做什么,给它成功标准,看着它自己跑。"
翻译成实操
把命令式指令 → 转化为可验证的目标。
| ❌ 别这样说 | ✅ 改成这样 |
|---|---|
| "加个校验" | "为非法输入写测试,让测试通过" |
| "修这个 bug" | "写一个能复现 bug 的测试,然后让它通过" |
| "重构这个模块" | "确保重构前后所有测试都通过" |
| "优化性能" | "把这个函数的耗时从 X ms 降到 Y ms 以内" |
为什么这个转变这么关键
命令式的问题:"加个校验"------ 加什么?加多严?加到哪一层?AI 得猜,你也得不停澄清。
目标式的好处 :"为非法输入写测试让它通过"------AI 可以自己循环:
- 写测试(定义什么叫"对")
- 写实现
- 跑测试
- 没过 → 改
- 过了 → 完成
整个过程不需要你干预。AI 自己就能判断成功与否。
多步任务的模板
对于复杂任务,用这个模板:
ini
1. [步骤] → 验证:[检查项]
2. [步骤] → 验证:[检查项]
3. [步骤] → 验证:[检查项]
比如"实现用户注册":
markdown
1. 写 API 接口 → 验证:curl 能拿到 200
2. 加入参数校验 → 验证:非法邮箱返回 400
3. 密码加密存储 → 验证:数据库里看不到明文
4. 发送确认邮件 → 验证:测试邮箱能收到
每一步都有验证,AI 就能独立推进。没有验证的任务("让它工作")需要你不断澄清。
这条规则的哲学意义
这其实不只是一条 coding 规则------它是和 AI 协作的根本范式转变:
旧范式:我是老板,AI 是员工,我给指令,它执行。
新范式:我是产品经理,AI 是整个工程团队。我定义成功标准(验收条件),它自己组织、执行、迭代。
这个转变一旦理解,你和 AI 的协作效率会整体跃升一个台阶------不只是写代码,写文章、做分析、跑数据都适用。
怎么用?两种方式
方式一:Claude Code 插件(推荐)
在 Claude Code 里执行:
bash
/plugin marketplace add forrestchang/andrej-karpathy-skills
bash
/plugin install andrej-karpathy-skills@karpathy-skills
装完后,这份规则对你所有的项目生效。
方式二:直接下载 CLAUDE.md(逐项目)
新项目:
objectivec
curl -o CLAUDE.md https://raw.githubusercontent.com/forrestchang/andrej-karpathy-skills/main/CLAUDE.md
已有 CLAUDE.md 的项目,追加到现有文件末尾:
bash
echo "" >> CLAUDE.md
curl https://raw.githubusercontent.com/forrestchang/andrej-karpathy-skills/main/CLAUDE.md >> CLAUDE.md
如何验证起作用了?
作者给了四个观察指标:
- diff 里的废话变少 ------ 只出现你请求涉及的改动
- 少因过度复杂而重写 ------ 第一次就写得简洁
- 澄清问题提在实现之前 ------ 不是等你发现错了才问
- PR 干净整洁 ------ 没有顺手的"改进"
装上一周后回头看看你的 commit history,如果这四个指标都改善了,说明规则在起效。
一个重要的 Tradeoff 提醒
作者在 README 末尾特别提到:
这份规则偏谨慎,牺牲速度换可靠性。对于简单任务(改错字、显而易见的一行改动),用你的判断力,不是每次改动都需要完整流程。
目标是减少复杂工作上的昂贵错误,而不是拖慢简单任务。
我的实际使用体验也是如此------装上之后,AI 会稍微"慢"一点,会问更多问题。
对于 prototype、一次性脚本、学习项目 :可能会觉得有点烦 对于生产代码、团队协作、长期维护的项目:价值巨大
建议:在你的主力工作项目里装,在玩具项目里别装。
我自己的几条延伸思考
读完这个项目,我有三个更深的感悟,分享一下:
1. "AI 勤快病"的根源是训练数据的偏见
AI 之所以爱过度工程,是因为它训练数据里的"优秀代码"大多是经过多次迭代、抽象、重构的成熟代码------GitHub 上那些高 Star 项目、设计模式教科书的例子。
它看多了这些,就以为"代码就应该长这样"。
但真实工作中,大部分代码的寿命只有几周、几个月,不需要任何抽象 。这份 CLAUDE.md 本质上是在纠正 AI 的训练偏见。
2. Prompt Engineering 的范式正在变
三年前我们研究 prompt,重点是"怎么说才能让 AI 听懂"------咒语、few-shot、thought chain。
但 andrej-karpathy-skills 代表的是新范式:"怎么给 AI 定边界"。
从"教它怎么做"→ "告诉它不该做什么 "和"什么样算做完了"。
这个转变背后,是 AI 能力已经足够强,短板不在理解力,而在自律。
3. 73k Star 说明了什么
一份没有代码、只有 4 条规则的 markdown 文件,能收获 73k Star------这背后揭示了几件事:
- AI 工具的痛点正在从"能用"转向"好用" ------能力已经不是问题,用得舒服才是
- "认知工具"可能比"代码工具"更有价值 ------帮人想清楚问题比帮人写代码更稀缺
- 内容即产品 ------在 AI 时代,一份好的文档、一套好的规则,本身就可以是产品
结语
Karpathy 的这条观察之所以引发这么大共鸣,是因为它说出了所有 AI 编程用户心里的一个声音:
"我不需要 AI 更聪明,我需要它更克制。"
andrej-karpathy-skills 这份 CLAUDE.md 就是这句话的具象化。四条规则,没有任何黑科技,全是经验之谈。但经验之谈才是最稀缺的------因为经验是用踩坑换来的。
如果你在用 Claude Code,花 30 秒装一下这份规则。一周后你会回来给这篇文章点赞的。
参考资料