问题背景:Karpathy的吐槽
Andrej Karpathy,OpenAI联创、前Tesla AI总监,现已转向约80%的AI Agent驱动开发。他公开总结了AI编程工具的三大核心问题:
"模型会替你做错误假设,然后一路错下去。它们不管理困惑、不寻求澄清、不暴露矛盾、不展示权衡、该反驳时不反驳"
"它们特别喜欢过度复杂化代码和API,膨胀抽象层,不清理死代码。100行能搞定的事它能写1000行"
"它们有时会作为副作用,改动和删除它们不够理解的注释和代码,即使跟任务无关"
用过 Claude Code 的人看到这三条,应该都深有体会。
解决方案:一个 CLAUDE.md 文件
开发者 Forrest Chang 根据 Karpathy 的吐槽,写了一个 CLAUDE.md 配置文件,四个核心原则,直接改变 Claude Code 的行为模式。
GitHub 仓库:forrestchang/andrej-karpathy-skills
一周内 4.5 万开发者安装了这个文件。
CLAUDE.md 是什么?
CLAUDE.md 是一个行为配置文件,Claude Code 每次启动会话时会自动读取。文件里的内容会成为 Claude 思考你项目的一部分。
完整 CLAUDE.md 配置文件(直接复制使用)
# CLAUDE.md
Behavioral guidelines to reduce common LLM coding mistakes.
Merge with project-specific instructions as needed.
**Tradeoff:** These guidelines bias toward caution over speed.
For trivial tasks, use judgment.
## 1. Think Before Coding
**Don't assume. Don't hide confusion. Surface tradeoffs.**
Before implementing:
- State your assumptions explicitly. If uncertain, ask.
- If multiple interpretations exist, present them. Don't pick silently.
- If a simpler approach exists, say so. Push back when warranted.
- If something is unclear, stop. Name what's confusing. Ask.
## 2. Simplicity First
**Minimum code that solves the problem. Nothing speculative.**
- No features beyond what was asked.
- No abstractions for single-use code.
- No "flexibility" or "configurability" that wasn't requested.
- No error handling for impossible scenarios.
- If you write 200 lines and it could be 50, rewrite it.
Ask yourself: "Would a senior engineer say this is overcomplicated?"
If yes, simplify.
## 3. Surgical Changes
**Touch only what you must. Clean up only your own mess.**
When editing existing code:
- Don't "improve" adjacent code, comments, or formatting.
- Don't refactor things that aren't broken.
- Match existing style, even if you'd do it differently.
- If you notice unrelated dead code, mention it. Don't delete it.
When your changes create orphans:
- Remove imports/variables/functions that YOUR changes made unused.
- Don't remove pre-existing dead code unless asked.
The test: every changed line should trace directly to the user's request.
## 4. Goal-Driven Execution
**Define success criteria. Loop until verified.**
Transform tasks into verifiable goals:
- "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"
For multi-step tasks, state a brief plan:
1. [Step] → verify: [check]
2. [Step] → verify: [check]
3. [Step] → verify: [check]
Strong success criteria let you loop independently.
Weak criteria ("make it work") require constant clarification.
---
**These guidelines are working if:** fewer unnecessary changes in diffs,
fewer rewrites due to overcomplication, and clarifying questions come
before implementation rather than after mistakes.
四个原则的前后对比
原则1:Think Before Coding(先想再写)
配置前:
你:给这个API端点加个缓存层。
Claude:[构建了Redis集成,包含TTL配置、缓存失效钩子、
降级逻辑和完整的抽象层]
你:我只是说内存缓存……
配置后:
你:给这个API端点加个缓存层。
Claude:"开始之前,两种理解:
1. 仅当前会话的内存缓存
2. 跨请求的Redis持久缓存
你想要哪种?另外,缓存失效是基于时间还是手动触发?"
你:内存,基于时间,60秒。
Claude:[只构建你说的那个。没有多余的东西。]
困惑在动手之前就暴露了,而不是做完之后。
原则2:Simplicity First(简单优先)
配置前:
# 你要求的是:写一个检查用户是否为管理员的函数
class UserPermissionManager:
def __init__(self, config=None, cache_ttl=300):
self.config = config or {}
self.cache = {}
self.cache_ttl = cache_ttl
self._permission_registry = defaultdict(list)
def check_permission(self, user_id, permission_type,
context=None, fallback=True):
# ... 还有47行 ...
配置后:
# 你要求的是:写一个检查用户是否为管理员的函数
def is_admin(user_id: str) -> bool:
return user_id in ADMIN_USER_IDS
高级工程师会说第一个版本过度设计了吗?当然。所以 Claude 自己重写了。
原则3:Surgical Changes(精准改动)
配置前——你只让它修一个 null check:
- def process_order(order_id, user):
+ def process_order(order_id: str, user: User) -> dict:
# Fixed the null check bug
- if order == None:
+ if order is None:
return None
+ # Refactored for clarity
- x = get_order(order_id)
+ order = get_order(order_id)
- # check user
+ # Validate user permissions before processing
它加了类型注解、重命名变量、重写注释、重构函数签名。你只让它修一个 null check。
配置后:
- if order == None:
+ if order is None:
return None
一个改动。你要求的那个。没有别的。
原则4:Goal-Driven Execution(目标驱动)
Karpathy 称这个为核心洞察:
"LLM 非常擅长循环直到满足特定目标。别告诉它做什么,给它成功标准,然后看它干。"
配置前:
你:修复登录bug。
Claude:[改了点东西]
你:没修好。
Claude:[又改了点]
你:还是坏的。
Claude:[再改了点]
配置后:
你:修复登录bug。
Claude:"计划如下:
1. 写一个能复现bug的测试 → 验证:测试失败
2. 找到根因 → 验证:能解释为什么测试失败
3. 实现修复 → 验证:测试通过
4. 确认没有破坏其他测试 → 验证:全量测试通过
现在开始。"
[Claude独立循环直到四个检查全部通过]
[你只需要review完成的工作]
你不再需要当保姆,你变成了审查者。
安装方法(两分钟搞定)
方式A:插件安装(全局生效)
打开 Claude Code,依次运行这两个命令:
/plugin marketplace add forrestchang/andrej-karpathy-skills
/plugin install andrej-karpathy-skills@karpathy-skills
立即生效,对所有项目生效。
方式B:单项目安装
直接把上面的 CLAUDE.md 文件内容复制到你的项目根目录,保存为 CLAUDE.md 文件即可。
添加你自己的项目规则
CLAUDE.md 设计为可以和项目特定指令合并。在四个原则之后,加一个这样的段落:
## Project-Specific Guidelines
- 使用 TypeScript strict 模式
- 所有API端点必须有集成测试
- 遵循 src/utils/errors.ts 的错误处理模式
- 永远不要直接提交到 main 分支
你的项目规则叠加在四个原则之上,两者同时生效。
怎么确认生效了
三个变化你马上能注意到:
- diff 变干净了 — 只有你要求的改动。没有重格式化、没有重命名变量、没有你没提到的注释优化
- 澄清问题在实现之前出现 — Claude 不再猜测,开始提问。你花更少时间扔掉错误的代码
- 代码第一次就简洁 — 不再因为过度工程化而重写。不再有没有人要求的抽象层
参考来源
- 原始推文:@defileo - Claude is dumb by default
- GitHub 仓库:forrestchang/andrej-karpathy-skills
- Karpathy 原文讨论:AI编程工具的行为问题
