引言
"LLMs excel at looping until they meet specific goals --- so provide success criteria rather than imperative instructions."
这是"一天一个开源项目"系列的第108篇文章。今天带你了解的项目是 andrej-karpathy-skills。
这个项目非常特别:它的核心不是一个工具、框架或库------就是一个 CLAUDE.md 文件。
故事起点是 Andrej Karpathy 在大量使用 Claude Code 之后发的一个 X 帖子,记录了他发现 LLM 在编码任务中反复出现的失效模式:不问清楚就动手、把简单问题工程化成复杂方案、顺手改了不该改的代码......
multica-ai 团队把这些观察提炼成了四条可操作的行为准则,打包进一个 CLAUDE.md 文件------你把它放进项目,Claude Code 就会改变行为方式。同时提供 Claude Code 插件和 Cursor 规则两种格式,覆盖主流 AI 编码工具。
这个项目很好地回答了一个常被忽视的问题:与其教 LLM 具体做什么,不如告诉它怎么思考。
你将学到什么
- Karpathy 观察到的 LLM 编码四大失效模式是什么
- 四条行为准则的具体内容与实际案例
- 三种安装方式:独立 CLAUDE.md / Claude Code 插件 / Cursor 规则
- 为什么"给出成功标准"比"给出操作步骤"更有效
- 如何验证这套准则是否真的在起作用
前置知识
- 使用过 Claude Code 或 Cursor 等 AI 编码工具
- 有一定的日常开发经验,能感受到 LLM 编码的痛点
项目背景
项目简介
andrej-karpathy-skills 的核心是一份行为配置文件。它的设计哲学来自一个关键洞察:
LLM 编码的问题,往往不是能力不够,而是行为没有约束。
模型有能力写简单的代码,但没人告诉它"不要写复杂的"。模型有能力先问清楚需求,但没有压力让它问。模型知道不该动无关的代码,但"顺便改一下"的习惯很难克制。
这份 CLAUDE.md 文件把这些约束显式化,让每次对话都带着这些行为准则进入上下文。
项目同时提供了三种分发格式,适配不同的使用场景和工具链。
作者/团队介绍
- 维护方 :multica-ai(Multica AI 团队)
- 灵感来源:Andrej Karpathy 在 X 上分享的 LLM 编码使用笔记
- 原始作者 :该 CLAUDE.md 内容最初由 forrestchang 整理,multica-ai 将其扩展为插件生态
关于 Andrej Karpathy:OpenAI 联合创始人之一,前特斯拉 AI 负责人,现独立研究者,以 nanoGPT、Neural Networks: Zero to Hero 等教学项目在 AI 社区广为人知。他对 AI 工具的实际使用反馈,在业内有很强的参考价值。
项目数据
- 📄 核心文件:
CLAUDE.md(行为准则) - 🔌 Claude Code 插件 + Cursor 规则
- 📖 附带:
EXAMPLES.md(四原则的对比示例) - 📄 License: MIT
- 🌐 仓库: multica-ai/andrej-karpathy-skills
主要功能
核心作用
这份 CLAUDE.md 直接对抗 LLM 编码中最常见的四个失效模式:
markdown
LLM 编码常见失效
├── 静默假设(不问清楚直接动手)
├── 过度工程化(把简单问题变复杂)
├── 扩大改动范围(顺手改了不相关代码)
└── 模糊执行(缺乏可验证的完成标准)
↓ CLAUDE.md 注入四条行为准则
行为改变
├── 编码前先思考(Think Before Coding)
├── 简单优先(Simplicity First)
├── 外科手术式修改(Surgical Changes)
└── 目标驱动执行(Goal-Driven Execution)
快速开始
方式一:Claude Code 插件(推荐,全局生效)
bash
/plugin marketplace add forrestchang/andrej-karpathy-skills
/plugin install andrej-karpathy-skills@karpathy-skills
安装后对所有项目生效,无需在每个项目中单独配置。
方式二:项目级 CLAUDE.md(只对当前项目生效)
bash
cd your-project
curl -o CLAUDE.md https://raw.githubusercontent.com/forrestchang/andrej-karpathy-skills/main/CLAUDE.md
如果项目中已有 CLAUDE.md,可手动将内容合并进去。
方式三:Cursor 规则
仓库中已包含 .cursor/rules/karpathy-guidelines.mdc,设置了 alwaysApply: true。将该文件复制到你的项目中即可:
bash
mkdir -p .cursor/rules
cp path/to/karpathy-guidelines.mdc .cursor/rules/
验证是否生效:打开 Cursor → Settings → Rules,查看规则是否出现在列表中。
验证准则是否在起作用的信号:
- 实现前 Claude 会主动提问而不是直接开始写
- PR diff 里的改动更干净,只涉及被请求的部分
- 不再出现"顺便优化了一下"的代码变动
四条准则详解
准则一:编码前先思考(Think Before Coding)
针对的问题:LLM 在遇到模糊需求时倾向于做出隐性假设并直接执行,而不是把不确定性暴露出来。
错误行为示例:
makefile
用户: 给我导出用户数据的功能
LLM: [直接开始写代码]
→ 假设导出 CSV,假设所有字段,假设同步下载
→ 但用户实际需要的是后台任务 + 特定字段 + JSON 格式
正确行为(准则要求先把不确定性表面化):
markdown
用户: 给我导出用户数据的功能
LLM: 在开始之前,有几个问题需要确认:
1. 范围:导出所有用户还是按条件过滤?
2. 格式:CSV / JSON / Excel?
3. 交付方式:浏览器直接下载、后台任务发邮件,还是 API 接口?
4. 字段:需要哪些字段?是否包含敏感数据?
另一个典型案例------"让搜索更快"有三种完全不同的含义:
| 解释 | 实际需求 | 解决方案 |
|---|---|---|
| 响应时间 | API 返回慢 | 加索引、缓存、优化查询 |
| 吞吐量 | 并发量高 | 水平扩展、队列 |
| 体感速度 | 用户觉得慢 | 预加载、骨架屏、即时反馈 |
三种解释需要完全不同的方案,任何一个都不能"默认"。
准则要求:当存在多种合理解释时,呈现所有解释让用户选择,而不是悄悄选一个。在真正困惑时停下来说"我不确定这里应该如何处理",而不是硬撑下去。
准则二:简单优先(Simplicity First)
针对的问题:LLM 有强烈的过度工程化倾向,在复杂性真正需要之前就引入抽象、框架和"灵活性"。
错误行为示例------折扣计算:
python
# 用户要求:实现一个简单的折扣计算
# ❌ LLM 给出的"方案"(10 倍代码量):
class DiscountStrategy(ABC):
@abstractmethod
def calculate(self, price: float) -> float: ...
class PercentageDiscount(DiscountStrategy):
def __init__(self, config: DiscountConfig): ...
def calculate(self, price: float) -> float: ...
class DiscountCalculator:
def __init__(self, strategy: DiscountStrategy): ...
def apply(self, cart: Cart) -> float: ...
# 工厂类、配置类、注册器......
# ✅ 实际需要的(1 个函数):
def apply_discount(price: float, discount_pct: float) -> float:
return price * (1 - discount_pct / 100)
另一个示例------"保存用户偏好设置":
markdown
❌ LLM 实现了:
- 带失效时间的缓存层
- 输入验证(用户没要求)
- 冲突合并逻辑(用户没遇到这个问题)
- 变更通知系统(用户没提到)
✅ 实际需要的:
- 把偏好写入数据库的一个函数
准则给出的判断标准:
"一个 senior 工程师看到这段代码,会说它过于复杂吗?"
如果 200 行代码可以写成 50 行,就重写成 50 行。
核心格言:
"Good code is code that solves today's problem simply, not tomorrow's problem prematurely."
过早引入的复杂性不只是浪费,还会让代码更难理解、引入更多 bug,哪怕它遵循了正确的设计模式。
准则三:外科手术式修改(Surgical Changes)
针对的问题:LLM 做"顺路重构"------修复一个 bug 时,顺便改了引号风格、加了类型注释、重命名了变量、整理了导入顺序。
这个行为看起来是好意,但实际上有两个严重问题:
- 让 diff 变得难以审查:reviewer 无法区分哪些改动是 bug 修复、哪些是"顺便"
- 引入意外 regression:每一行未经要求的改动都是潜在的风险点
正确的做法:
python
# 原始代码(有 bug,同时有一些"不完美"之处)
def calculate_total(items):
total = 0
for item in items:
total += item['price'] # 单引号
return total # 缺少类型注释
# ❌ LLM 的"全面改善":
def calculate_total(items: list[dict]) -> float: # 加了类型注释
"""Calculate total price of items.""" # 加了文档字符串
total: float = 0.0 # 改了变量类型
for item in items:
total += item["price"] # 改成双引号("风格统一")
return total
# ✅ 只修复 bug(假设 bug 是 items 为空时的问题):
def calculate_total(items):
if not items: # 只加了这一行
return 0
total = 0
for item in items:
total += item['price'] # 保持原有风格不变
return total
准则的具体要求:
- 每一行改动都要能追溯到用户的请求
- 匹配现有代码风格,即使你更喜欢另一种
- 不要改进"路过"的代码,除非被明确要求
- 只清理你的改动产生的无用导入/变量,不要动原有的
准则四:目标驱动执行(Goal-Driven Execution)
针对的问题:LLM 在接到模糊任务时,会给出看起来很全面但缺乏可验证性的计划。
模糊计划的示例:
markdown
任务: "重构 auth 模块"
❌ 模糊计划:
1. 审查现有代码
2. 识别问题
3. 改进结构
4. 运行测试
→ 没有任何一步有明确的完成标准
准则要求把任务转化为可验证的目标:
yaml
任务: "修复登录 bug"
✅ 目标驱动计划:
步骤 1: 写一个复现 bug 的失败测试
验证点: 测试确实在当前代码上失败
步骤 2: 实现修复
验证点: 刚才写的测试现在通过
步骤 3: 运行完整测试套件
验证点: 没有新的回归
→ 每步都有明确的"完成"定义
另一个示例:
markdown
任务: "重构 auth 模块"
✅ 具体化后:
1. 所有现有测试通过(记录基线)
2. 抽取 TokenService(验证:独立单元测试通过)
3. 重构 AuthController 使用 TokenService(验证:集成测试通过)
4. 所有原有测试仍然通过(无回归)
Karpathy 的核心洞察:
LLM 最擅长的事是"循环直到满足特定目标"------因此,提供成功标准比提供操作步骤更有效。
命令式指令("先做 A,然后做 B,然后做 C")在出错时会让 LLM 不知道该怎么处理。声明式目标("这个测试要通过"、"这个接口要可调用")让 LLM 可以自主决定路径,同时有清晰的完成标准。
为什么是一个文件,而不是一个工具?
这个项目的设计选择本身就值得深思。面对 LLM 编码的行为问题,可以有很多种解决方案:
- 构建一个代理框架来约束行为
- 开发后处理工具来检测和修正
- 训练一个更好的模型
andrej-karpathy-skills 选择的是最简单的那个:一个文本文件,放进项目里,让 LLM 自己读自己执行。
这个选择本身就是对"简单优先"原则的最好示范------用最少的机制,解决今天的问题。而且,文本文件有一个工具无法比拟的优势:可以随时阅读、理解和修改,没有任何黑盒。
项目地址与资源
官方资源
- 🌟 GitHub : github.com/multica-ai/...
- 📄 原始 CLAUDE.md : 直接
curl下载即可使用 - 📖 示例文档 :
EXAMPLES.md(四原则的对比示例,推荐阅读)
适用人群
- Claude Code / Cursor 日常用户:希望减少 LLM 的过度工程化和不必要的代码改动
- 团队工程效能负责人:在团队 CLAUDE.md 中集成这套行为规范,统一 AI 辅助编码的行为基准
- 追求代码可审查性的开发者:厌倦了 LLM 生成的"超级 diff",想要干净的、只包含请求变更的 PR
总结与展望
核心要点回顾
- 来源:直接提炼自 Karpathy 对 LLM 编码失效模式的一手观察,有真实使用基础
- 四条准则 :
- 编码前先思考:把隐性假设变成显性问题,而不是悄悄选一个
- 简单优先:写解决今天问题的最少代码,不预建"灵活性"
- 外科手术式修改:每行改动都能追溯到请求,不做顺路重构
- 目标驱动执行:给成功标准,不给操作步骤
- 三种安装格式:CLAUDE.md(项目级)/ Claude Code 插件(全局)/ Cursor 规则
- 核心哲学:LLM 最擅长循环直到达成目标------给目标,不给步骤
- 自我示范:用最简单的方式(一个文件)解决问题,自身就是"简单优先"原则的体现
一句话评价
andrej-karpathy-skills 做了一件看似微小但影响深远的事:把"怎么用好 LLM 写代码"的工程智慧,压缩进一个任何人都能读懂、放进任何项目的文本文件------而这个文件本身,就是它所倡导的简单哲学的最好证明。
欢迎来我的个人主页找到更多有用的知识和有趣的产品