Karpathy 准则定制化实践:从通用规则到项目级行为约束
Andrej Karpathy 提出的 4 条 CLAUDE.md 编码准则,在 GitHub 上已经获得了超过 12 万星标。这四条原则精准地击中了 LLM 编程助手的四个慢性失败模式。但问题在于:通用规则缺乏项目上下文,在复杂项目中约束力不足。
本文记录了将这四条通用原则落地到一个真实项目(mini-agent —— 一个 24/7 运行的 Python 异步守护进程)的过程,并总结出一套可复制的定制化方法。
Karpathy 的四条原则(原始版本)
Karpathy 观察 LLM 在编码时有四种典型的失败模式:
- 默认假设 —— 不确认就选一种理解开干
- 过度设计 —— 50 行能解决的问题写 200 行
- 范围蔓延 —— “顺手”重构旁边的代码,改没坏的东西
- 目标模糊 —— 没定义什么叫”完成”就开始编码
他将这些反模式编码为四条行为原则:
1. Think Before Coding
不要假设,不要隐藏困惑,主动呈现权衡。
- 不确定时先问,而不是猜
- 有歧义时给出所有合理的解读
- 发现更简单的方案要主动提
- 困惑时停下来,说清楚哪里不懂
2. Simplicity First
用最少的代码解决问题,不为假想的需求编码。
- 不加没要求的功能
- 一次性代码不搞 class / ABC
- 不加没人要求的”灵活性”或”可配置性”
- 不处理不可能发生的错误场景
- 如果 200 行可以写成 50 行,就重写
- 检验标准:高级工程师会说这是过度设计吗?
3. Surgical Changes
只动必须动的代码,只清理自己造成的混乱。
- 不要”改进”相邻的代码、注释或格式
- 不要重构没坏的东西
- 匹配已有风格,即使你不认同
- 发现不相关的死代码提一句,不要删
- 删除你自己的改动造成的无用 import / 变量 / 函数
- 不要删除早已存在的死代码
- 检验标准:每一行改动都应该能追溯到用户的请求
4. Goal-Driven Execution
定义成功标准,循环验证直到通过。
- 把祈使句任务转化为可验证的目标
- “加校验” → “为无效输入写测试,然后让测试通过”
- “修 bug” → “写一个能复现的测试,然后让测试通过”
- “重构 X” → “确保重构前后测试都通过”
- 多步骤任务要列计划:1. [步骤] → 验证: [检查方式]
- 明确的成功标准让 LLM 可以独立循环
痛点:通用规则在真实项目中不够用
在 mini-agent 项目中,我们原先已经有四条行为规则:
- Before coding, reason through the approach. If ambiguous, ask instead of guessing.- Make minimal, surgical changes. Do not refactor or modify unrelated code.- After making changes, run uv run pytest. Fix failures before reporting done.- Prefer the simplest solution. No over-engineering, no speculative abstractions.这四条分别对应了 Karpathy 的四个原则,但问题很明显:太简短,缺乏项目特定约束。
对于一个 24/7 运行的异步守护进程,有 EventBus 事件总线、Telegram Bot、SQLite 数据库、APScheduler 定时任务,通用规则完全覆盖不了这些组件之间的耦合风险。比如:
- 改了一个 EventBus handler,会不会影响订阅同一事件的其他 handler?
- 改了 Telegram 相关代码,消息分片(4096 字符限制)还好使吗?polling watchdog 还正常吗?
- 加了 async 代码,有没有未 await 的协程?有没有竞态条件?
这些是通用规则回答不了的。
定制化实践:从通用到项目级
第一步:为每个原则添加项目上下文
针对 mini-agent 的架构特点,将四条原则分别扩展:
### 1. Think Before Coding- 需求不明确时先问,不要默默选一种理解就开干- 改动涉及 EventBus 事件流时,先说清楚影响范围再动手- 如果有更简单的方案,主动提出来
### 2. Simplicity First- 这是个人 agent,不是框架。不要加抽象层、插件系统、"灵活性"- 只有一处调用的代码不搞 class/ABC- 没人要求的错误处理不要加(尤其是不可能发生的场景)- 不要为未来的需求预先设计
### 3. Surgical Changes- 只改和任务直接相关的代码,不要"顺手"重构旁边的代码- 改 EventBus handler 时,确保不影响订阅同一事件的其他 handler- 匹配已有代码风格,即使你不认同- 发现不相关的死代码提一句就好,不要删
### 4. Goal-Driven Execution- 改完后必须跑 uv run pytest,测试通过才算完成- 涉及 Telegram 的改动,验证消息分片(4096 字符限制)和 polling watchdog 不受影响- 涉及 async 改动时,确认没有引入未 await 的协程或竞态条件- 多步骤任务要说明每步的验证方式关键变化:每条原则都不再是抽象的忠告,而是绑定了具体的技术约束和验证方法。
第二步:分层架构 —— 用户级 vs 项目级
更进一步,我们采用了两层分离的策略:
用户级 ~/.claude/CLAUDE.md —— 适用于所有项目的通用基线:
# Karpathy Principles (all projects)
### 1. Think Before Coding- Ask when uncertain, don't guess- Present all reasonable interpretations when ambiguous- Speak up when a simpler approach exists
### 2. Simplicity First- Minimum code that solves the problem- No unprompted abstractions, configuration, or error handling- Don't design for future requirements
### 3. Surgical Changes- Only touch code directly related to the task- No drive-by refactoring, reformatting, or comment additions- Mention dead code, don't delete it
### 4. Goal-Driven Execution- Tests must pass before marking done- State verification method for each step in multi-step tasks项目级 CLAUDE.md —— 只包含项目特有的扩展,不重复通用规则:
## Behavior Rules(项目特有扩展)
- 改动涉及 EventBus 事件流时,先说清影响范围- 这是个人 agent 不是框架,不要加抽象层/插件系统- 改 EventBus handler 时确保不影响同事件的其他 handler- 涉及 Telegram 改动要验证 4096 分片和 polling watchdog- async 改动要确认没有未 await 的协程或竞态条件这样的好处:
- 通用原则只需维护一份,修改时所有项目同步生效
- 项目级规则不重复,只补充差异化的约束
- 新增项目时,通用原则自动生效,只需补充项目特有的 5-6 条规则
可复制的定制化模板
总结为五个维度,任何新项目只需填写这张表:
| 维度 | 要问的问题 | mini-agent 示例 |
|---|---|---|
| 架构约束 | 哪些组件变更会级联影响? | EventBus 事件流、handler 间耦合 |
| 项目身份 | 框架 / 库 / 应用 / 脚本? | 个人 agent,不是框架 |
| 运行环境 | 24/7 守护进程?CLI?Serverless? | 守护进程,必须能干净重启 |
| 技术栈陷阱 | 什么容易踩坑? | async 竞态、Telegram 限制、SQLite 并发 |
| 验证手段 | 怎么确认改对了? | pytest、systemctl restart、手动 Telegram 测试 |
填写完这张表后,将每个维度的答案转化为具体的行为约束条款,追加到项目级 CLAUDE.md 即可。
小结
Karpathy 的四条原则是好的起点,但通用规则的最大问题是缺乏项目上下文。通过两层分离(用户级通用 + 项目级扩展),以及结构化的五维度模板,可以在保持简洁的同时让规则真正有约束力。
核心思路只有一句话:让每条规则都能回答”在这个项目里,具体怎么做”。