别让 AI 替你写代码,然后你给它擦屁股

Andrej Karpathy 在 Twitter 上吐槽过不少 LLM 的编码毛病:

  • 喜欢写 // TODO: implement later 然后溜掉
  • 随手丢出一堆重复代码,美其名“可读性”
  • 对于边界条件视而不见,只处理 happy path
  • 动不动就说“在我的设置下能运行”,然后让你自己去调试

这些不是 bug,是 LLM 的默认行为。好消息是——如果你用 Claude Code,可以通过一个配置文件一次性纠正大部分问题。

claude_code_configuration

这份 CLAUDE.md 到底做了什么

multica-ai/andrej-karpathy-skills 本质上就是一个套了 Karpathy 经验的 CLAUDE.md 文件。你把它扔到项目根目录,Claude Code 在每次生成代码前都会读取这些规则。

关键条目(我过滤掉鸡汤,只留硬货):

1. 禁止空承诺

markdown
1
- Never say "I will implement this later" or "this can be done in a future update". If the code is not complete, don't pretend it is.

这是最有效的一条。Claude Code 原本喜欢在函数里写 # TODO 然后告诉你“我完成了”。禁止它撒谎,要么写完整,要么明确标记不完整。

2. 优先添加测试,而不是增加注释

markdown
1 2
- When adding new functionality, write the tests first (or at least at the same time).
- Comments are for explaining *why*, not *what*. The code should be self-documenting.

这一条对 Python 和 JavaScript 开发者尤其有用。实测发现,加了这条后 Claude Code 生成的测试覆盖率从 20% 左右提升到 45%(我自己用同一需求测试三次取平均)。

3. 显式处理错误和边界

markdown
1 2
- Always check for None/null, empty inputs, and edge cases before processing.
- Never silently swallow exceptions.

默认的 Claude Code 经常产出只考虑最常见路径的代码。这条规则让它学会先想“如果输入是空的/文件不存在/网络超时”怎么办。

4. 不要生成“样板嵌套”

markdown
1 2
- Prefer early returns over nested if-else.
- Keep functions under 20 lines.

这条见仁见智。20 行限制对某些场景(比如复杂的数据校验)会逼出反模式——把本来一个函数拆成五个微函数,反而更难读。我的建议:按项目现有风格调整行数上限。

真实配置步骤(含踩坑)

  1. 把仓库里的 CLAUDE.md 下载到项目根目录
  2. 必须修改:把 language 替换成你项目的实际语言,否则 Claude Code 会忽略特定语言的规则
  3. 踩坑:如果你同时有 .claude 目录下的自定义指令,优先级冲突会导致 CLAUDE.md 失效。官方文档说两个都会读,但我测试发现 .claude 里的指令会覆盖 CLAUDE.md 里的同名规则。建议统一到一个位置。
  4. 启动 Claude Code,输入 claude,然后随便提一个代码需求,看看输出是否遵守了新规则。

实测:前后对比

测试任务:实现一个 read_csv 函数,从文件路径加载 CSV 并返回列表。

未配置 CLAUDE.md 的典型输出

python
1 2 3 4 5
def read_csv(path):
    import csv
    with open(path, 'r') as f:
        reader = csv.DictReader(f)
        return list(reader)

没有异常处理,没有检查文件是否存在。

配置后的输出

python
1 2 3 4 5 6 7 8 9 10 11 12 13 14
def read_csv(path: str) -> list[dict]:
    import csv
    import os
    if not os.path.exists(path):
        raise FileNotFoundError(f"CSV file not found: {path}")
    if os.path.getsize(path) == 0:
        return []
    with open(path, 'r') as f:
        try:
            reader = csv.DictReader(f)
            rows = list(reader)
        except csv.Error as e:
            raise ValueError(f"Invalid CSV format: {e}")
    return rows

同时自动生成了一个测试文件(按第二条规则)。

适用场景与局限

适用

  • 长期维护的项目,需要保持代码一致性
  • 团队使用 Claude Code 辅助开发,减少 Review 成本
  • Python/JavaScript/Go 等主流语言(规则模板已覆盖)

局限

  • 只对 Claude Code 生效,对 Copilot、Cursor 等无效
  • 过度约束可能让 AI 变得保守,写出的代码僵化(例如强制 20 行限制)
  • 这份配置偏向 Karpathy 的个人风格(Python + 学术界习惯),偏重数据处理的团队可能需要砍掉一半规则

和同类工具对比

类似的概念在 Cursor 里通过 .cursorrules 实现,在 Copilot 里通过 GitHub 的 Repository Rules 实现。但 CLAUDE.md 的优势是文件级别生效,且 Claude Code 原生支持,无需额外插件。

缺点是可组合性差——你没办法在不同子目录用不同规则。如果项目有前端和后端两个部分,需要手动拆成两个配置,或者用条件判断(官方尚未支持)。

我的看法:直接抄,但别全抄

这份 CLAUDE.md 的核心价值不是里面的每一条规则,而是把 Karpathy 的问题感知变成了一个可复用的脚本。开发者可以借此理解“提示工程不是写一段花哨的话,而是建立约束”。

我建议你用如下方式使用:

  1. 把这个文件作为起点
  2. 跑一个礼拜,收集 Claude Code 继续犯的错
  3. 针对性地增删规则,形成你自己的版本

别让 AI 替你思考——但你可以替 AI 设定边界。