Karpathy 的 4 条 LLM 编码守则与 CLAUDE.md 工程学
multica-ai/andrej-karpathy-skills 把 Andrej Karpathy 那条关于 LLM 编码的推文,落成一份 80 行的 CLAUDE.md,包含 4 条直接喂给 agent 的工作守则。
本文回答两个问题:
- 这 4 条原则是什么、各自治什么。
- 为什么这种极简显式约束的 CLAUDE.md 有效。
1. Karpathy 指出的 3 类问题¶
仓库引用了 Karpathy 推文里的 3 段话,每一段对应 LLM 编码里一类具体的失败模式:
The models make wrong assumptions on your behalf and just run along with them without checking. They don’t manage their confusion, don’t seek clarifications, don’t surface inconsistencies, don’t present tradeoffs, don’t push back when they should.
模型替你做错误假设,不检查就继续往下跑。它们不管理自己的困惑、不寻求澄清、不暴露矛盾、不呈现权衡、在该反对的时候也不反对。
They really like to overcomplicate code and APIs, bloat abstractions, don’t clean up dead code… implement a bloated construction over 1000 lines when 100 would do.
它们特别喜欢把代码和 API 搞复杂、堆抽象、不清理死代码。100 行能写完的事非要堆成 1000 行。
They still sometimes change/remove comments and code they don’t sufficiently understand as side effects, even if orthogonal to the task.
它们偶尔仍然会作为副作用去改/删自己理解不够的注释和代码,哪怕跟当前任务正交。
3 段话指向同一个根本原因 —— LLM 不会管理自己的认知不确定性。它对自己「不知道什么」缺乏元认知,存在歧义、隐含假设、理解不到位时没有内置的「停下来」机制,默认行为是给一个合理回答然后往下跑。
这不是模型偷懒,是 RLHF 训练的副作用:「helpful」让模型学到「给出动作 > 提出问题」;「看起来周到」让模型学到「写完整 > 写最小」。两个加起来,就是 Karpathy 列举的所有行为 —— 替你假设、过度复杂、顺手改一切。
要纠正这件事,靠塞更多例子没用(例子越多越模仿”周到”),需要在 prompt 层加显式约束直接覆盖 RLHF 学到的默认。这就是为什么仓库选择把答案写成 CLAUDE.md。
2. 4 条原则的结构¶
仓库把它们并列成 4 条,但有 2+1+1 的层次:
| 层次 | 原则 | 治什么 |
|---|---|---|
| 范围约束(做什么) | Surgical Changes | 顺手改 / scope creep |
| 复杂度约束(怎么做) | Simplicity First | 过度抽象 / 过早优化 |
| 认知约束(开始前) | Think Before Coding | 假设漂移 / 不管理困惑 |
| 终止条件(怎么算完) | Goal-Driven Execution | 没有可验证完成信号 |
前 3 条规范 agent 写什么代码,第 4 条规范 agent 怎么知道写完了。
3. Think Before Coding¶
核心要求一句话:显式说出假设,不确定就停下来问。
具体落地:
- 多种解释存在时,列出来,不要默默挑一个。
- 存在更简单的方法时,说出来;该反对就反对。
- 哪里不清楚就停下来,指出不清楚的是什么,然后问。
仓库 EXAMPLES.md 给的例子是 “Make the search faster”。错的版本是 agent 默默选一种”变快”的解释(caching / async / partial render),写 200 行优化代码。对的版本是 agent 反问:「『更快』可能指 3 件不同的事 —— 响应时间、并发吞吐量、感知速度。你想优化哪个?」
副作用:agent 会反问得更多,包括一些本不需要问的小事。需要在 CLAUDE.md 末尾加一句 escape hatch:「对于显然的单行修改、明显的拼写错误,跳过本规则」。
4. Simplicity First¶
核心要求:用最少的代码解决问题。
具体落地:
- 不写任务以外的功能。
- 不为一次性代码做抽象。
- 不加没被要求的”灵活性 / 可配置性”。
- 不为不可能发生的场景做错误处理。
- 如果写了 200 行而本可以 50 行,重写。
仓库里写得很明确:「过度复杂」的例子并不是错 —— 它们都符合设计模式和最佳实践。问题是时机:在还不需要的时候引入复杂度。
EXAMPLES 给的例子是用户要 calculate_discount(amount, percent)。错的版本祭出策略模式 + 抽象基类 + 工厂方法,写 80 行。对的版本是 5 行纯函数:
def calculate_discount(amount: float, discount_percent: float) -> float:
return amount * (1 - discount_percent / 100)
这条对成熟项目的边际收益不大,因为大多数项目 CLAUDE.md 本来就反对过度抽象。更适合用作没有 CLAUDE.md 的新项目的起点。
5. Surgical Changes¶
核心要求:只改用户要求的,不改邻近的。
具体落地:
- 不要”改进”相邻的代码、注释或格式。
- 不要重构没坏的东西。
- 匹配现有风格,哪怕你更喜欢另一种。
- 如果发现无关的死代码,提出来,不要删除。
- 删除自己改动造成的孤立 import / 变量 / 函数。
- 不要删除原本就存在的死代码,除非被要求。
检测线:每一行修改都要能直接追溯到用户的请求。
EXAMPLES 给的例子是「修一下空 email 导致校验器崩溃的 bug」。错的版本顺手做了 5 件事:加强了 email 校验、加 username 长度校验、改注释、加 docstring、改变量名。对的版本只改了直接相关的 3 行。
这是 4 条里收益最快的一条。装上之后 PR diff 在第一周就会明显变薄 —— 没有 drive-by 改格式、加 type hint、改单双引号、加 docstring 这类东西。
6. Goal-Driven Execution¶
这是 4 条里唯一一条不约束怎么写代码,而约束怎么判定任务完成的。它对应 Karpathy 推文里另一句话:
LLMs are exceptionally good at looping until they meet specific goals… Don’t tell it what to do, give it success criteria and watch it go.
LLM 非常擅长循环到满足具体目标。不要告诉它做什么,给它成功标准,让它自己跑。
落地方式:把指令式动词翻译成可验证目标。
| 不要这样写 | 改成这样 |
|---|---|
| ”Add validation" | "Write tests for invalid inputs, then make them pass" |
| "Fix the bug" | "Write a test that reproduces it, then make it pass" |
| "Refactor X" | "Ensure tests pass before and after” |
多步任务给出每步配 verify 的 plan:
1. [Step] → verify: [check]
2. [Step] → verify: [check]
3. [Step] → verify: [check]
这个结构的作用:让 agent 在每一步都有可验证锚点,可以独立诊断、独立修正、不需要每两分钟回来问”对不对”。
在大任务上这条收益巨大;简单一次性任务收益微弱,因为简单任务没有循环空间。
7. 为什么 80 行能管这么多¶
回到开头那个问题:这种极简显式约束为什么有效?
约束颗粒度合适。4 条原则同时满足两个性质 —— sufficiently general(适用于所有 codebase / 所有语言)、concretely actionable(agent 看了知道怎么落地)。大部分项目的 CLAUDE.md 要么写得太具体(变成项目级规则,无法跨项目),要么写得太抽象(变成”努力写好代码”这种空话)。
元规则胜过 do/don’t checklist。这 4 条都是元规则 —— 教 agent 决策框架(“考虑时机 / 显式说假设 / 设可验证目标”),不是给穷举列表(“不要用全局变量 / 不要用 any / 不要 …”)。元规则更可泛化、不会过期、agent 在新情境下能自己推理。
对症的规则比规范的规则更短。这 4 条不是凭空列出的”最佳实践”,是直接对应 Karpathy 推文里指出的 4 类失败模式 —— 假设漂移、复杂度膨胀、scope creep、无可验证终止。规则跟症状一一对应,所以短、准、副作用小。
CLAUDE.md 形态本身的优势。CLAUDE.md 是每次会话都加载的行为基线,skill 是按需触发的流程方法论。Karpathy 这 4 条治的是”每次会话都会犯的毛病”,应该常驻,不应该埋在按需触发的 skill 里。
这也回答了一个常见的设计问题:什么放 CLAUDE.md、什么写成 skill?
| 适合放 CLAUDE.md | 适合写成 skill |
|---|---|
| 行为基线、决策框架 | 流程方法论(TDD / debug / PRD) |
| 跨任务的元规则 | 特定场景的工作流 |
| 几条短规则的集合 | 一组按顺序执行的步骤 |
| 静态的、不依赖任务 | 动态的、按需加载 |
Karpathy 的 4 条完全落在左列。
8. 安装方法¶
仓库给了三种方式。
A. 项目级 CLAUDE.md¶
新项目,直接 curl 到项目根:
curl -o CLAUDE.md \
https://raw.githubusercontent.com/forrestchang/andrej-karpathy-skills/main/CLAUDE.md
已有 CLAUDE.md,追加到末尾:
echo "" >> CLAUDE.md
curl https://raw.githubusercontent.com/forrestchang/andrej-karpathy-skills/main/CLAUDE.md \
>> CLAUDE.md
适合:单个项目快速试用、对项目 CLAUDE.md 有完全控制权时。文件只 80 行,可以读完后只挑想要的几条。
B. Claude Code Plugin(跨项目)¶
在 Claude Code 会话里先注册 marketplace,再装 plugin:
/plugin marketplace add forrestchang/andrej-karpathy-skills
/plugin install andrej-karpathy-skills@karpathy-skills
适合:多个项目都想用同一套行为基线、不想每个项目都 curl 一次。
更新:marketplace 升级时跑 /plugin update andrej-karpathy-skills。卸载:/plugin uninstall andrej-karpathy-skills@karpathy-skills。
C. Cursor Rule¶
仓库自带 .cursor/rules/karpathy-guidelines.mdc,打开仓库即生效。要在自己项目用,复制这个文件到 .cursor/rules/ 即可:
mkdir -p .cursor/rules
curl -o .cursor/rules/karpathy-guidelines.mdc \
https://raw.githubusercontent.com/forrestchang/andrej-karpathy-skills/main/.cursor/rules/karpathy-guidelines.mdc
详细配置参考仓库 CURSOR.md。
附:Skill 形态¶
仓库还有 skills/karpathy-guidelines/SKILL.md,内容跟 CLAUDE.md 一样,套了 skill 的 frontmatter。不推荐用这个形态 —— skill 是按需触发,但这套规则的设计意图是常驻;写成 skill 后只在用户主动调用 /karpathy-guidelines 时生效,等于削弱了它。
验证装上成功¶
下一次会话,给 agent 一个故意有歧义的任务,比如:
帮我加一下 export 功能
装上后,agent 应该反问:「『export』是想要哪种?API endpoint 返回数据、下载文件、还是后台任务发邮件?要导出哪些字段?」 —— 如果它直接开始写代码,说明这条规则没生效,需要检查 CLAUDE.md 或 plugin 是否加载。
跟项目已有规则冲突时¶
如果项目 CLAUDE.md 已有跟 Karpathy 4 条相关的指令,追加而不是替换。这 4 条规范的是行为基线,跟项目级关于命令、构建、风格、域知识的指令是正交的。
如果某条跟你的项目偏好冲突(比如你的项目要求 agent “自动加 type hint”,但 Surgical Changes 禁止),在 CLAUDE.md 里加一条 override 声明:「本项目对 Surgical Changes 的例外:自动加 type hint」。
9. 收益排序¶
装上后按”装上即感受到的收益”排序:
- Surgical Changes:收益最快。PR diff 第一周明显变干净。
- Goal-Driven Execution:在复杂任务上收益巨大。Agent 自己拆 plan、自己验证,需要回来检查的频率显著下降。
- Think Before Coding:双刃剑。少了因假设错误造成的返工,多了一些不必要的反问。需要 escape hatch。
- Simplicity First:对成熟项目收益有限。多数 CLAUDE.md 本来就反对过度抽象。
落到具体行动:
- 没有 CLAUDE.md 的新项目 → 直接
curl装上当起点。 - 已有 CLAUDE.md 但没明确写行为基线 → 追加这 4 条。
- 已有完整 CLAUDE.md 体系 → 不装,对比一下措辞,挑句子改进自己的版本。
文件就 80 行。直接读 仓库的 CLAUDE.md 和 EXAMPLES.md 比读这篇博客更快。