andrej-karpathy-skills 使用教程
本教程教你如何将 Andrej Karpathy 总结的 LLM 编码原则(先思考、求简洁、精准改、目标驱动)注入 Claude Code 或 Cursor,让 AI 助手写出更干净、更可控的代码。适合所有用 AI 写代码但常被“过度设计”“乱改代码”困扰的开发者。
1. 1. 它解决什么问题:AI 写代码的四大通病与 Karpathy 原则
好的,我们开始第一章。这一章是整个教程的起点,非常重要。在动手安装任何东西之前,我们得先搞清楚一个问题:我们为什么要这么做?或者说,我们正在试图解决什么烦恼?
如果你经常用 AI 帮你写代码,你可能会遇到一些让人哭笑不得的情况。明明只是让它修一个小 bug,结果它把你的整个函数都重写了,还引入了一堆你根本不需要的抽象类。或者,你让它加一个简单的功能,它却开始“自作聪明”,帮你“优化”了旁边一段完全正常的代码,结果导致别的地方出了问题。
别担心,你不是一个人。这其实是当前 AI 写代码时非常普遍的“通病”。Andrej Karpathy(前 Tesla AI 总监、OpenAI 创始成员)就曾一针见血地总结过这些问题。这一章,我们就来一起看看这些“通病”到底是什么,以及我们即将学习的“Karpathy 原则”是如何对症下药的。
我们遇到的四大“通病”
想象一下,你是一位项目经理,手下有一个能力很强但有点“莽撞”的新人程序员。他干活很快,但总是犯一些让你头疼的错误。AI 写代码时,就有点像这个新人。Karpathy 把这些错误归纳为四大类:
1. 不假思索,直接开干
这是最常见的问题。你给 AI 一个任务,比如“给这个用户列表加个搜索功能”。AI 不会停下来思考:“这个列表有多大?用户想搜什么字段?是前端过滤还是后端搜索?” 它会直接选择一个它“觉得”最可能的方案,然后埋头就写。
结果呢?它可能假设你的数据有 100 万条,于是写了一个复杂的后端搜索接口,还加了缓存。但实际上,你的列表只有几十条数据,一个简单的前端 filter() 方法就足够了。它没有告诉你它的假设,没有向你确认需求,也没有提出不同的方案让你选择。它只是“闷头干”,然后给你一个过度设计的方案。
2. 过度设计,追求“完美”
这个新人程序员特别喜欢“炫技”。你让他写一个简单的函数,比如把两个数字相加。他可能会给你写一个 Calculator 类,里面包含了加法、减法、乘法、除法,甚至还预留了一个“未来扩展”的接口。
你可能会好奇,为什么 AI 会这么做?因为它在训练数据里看到的大项目都是这么“优雅”和“可扩展”的。但它没意识到,对于你当前这个只有 10 行代码的小脚本来说,这种“优雅”就是累赘。它倾向于把代码搞复杂,增加不必要的抽象层,留下没用的“死代码”。就像 Karpathy 说的:“它们会用 1000 行代码实现一个臃肿的结构,而实际上 100 行就够了。”
3. 乱改代码,伤及无辜
这是最让人抓狂的一点。你让 AI 去修改 user.py 文件里的一个函数。它改完之后,你发现 order.py 文件里的一个注释被删掉了,或者 payment.py 里一个变量的命名风格被改了。
AI 在修改代码时,就像一个注意力不太集中的学生。它可能觉得旁边的注释“不够清晰”,顺手就帮你“优化”了;或者觉得某个变量名“不符合规范”,顺手就帮你改了。这些修改和你原本的任务毫无关系,是“附带损伤”。它改了自己不该碰的东西,导致你的代码库出现了一些莫名其妙的变化,增加了 review 的难度和引入 bug 的风险。
4. 目标模糊,做完拉倒
你给 AI 一个指令:“修复这个 bug。” AI 可能会尝试修改几行代码,然后告诉你“修好了”。但你怎么知道它真的修好了?它没有提供一个验证方法,比如一个能证明 bug 已修复的测试用例。
这就像你让一个厨师“做一道菜”,但没有告诉他“做成什么样算成功”。他可能做了一道味道奇怪的菜,然后告诉你“做好了”。你尝了一口,发现不对,让他重做。他可能又换了一种方式,还是不对。这个过程会反复很多次,因为你和 AI 之间没有对“成功”的定义达成共识。AI 缺乏一个明确的目标来驱动它,直到它真正完成任务。
解决方案:Karpathy 的四项原则
针对上面这四个问题,这个项目(也就是我们即将安装的规则)提出了四项非常清晰的原则。它们就像给那位“莽撞”的新人程序员制定的一套工作守则。
| 原则 (Principle) | 解决的通病 (Addresses) |
|---|---|
| 先思考再动手 (Think Before Coding) | 不假思索、隐藏假设、不提方案 |
| 简洁至上 (Simplicity First) | 过度设计、代码臃肿 |
| 精准修改 (Surgical Changes) | 乱改无关代码、附带损伤 |
| 目标驱动 (Goal-Driven Execution) | 目标模糊、无法验证 |
你看,每一项原则都精准地对应了我们上面提到的一个问题。
- 先思考再动手:这条原则要求 AI 在写代码前,必须先说出它的假设、它发现的歧义、以及它考虑过的不同方案。如果它不确定,它应该提问,而不是猜测。这能有效避免“闷头干”带来的错误方向。
- 简洁至上:这条原则要求 AI 只写解决问题所必需的代码。不要添加任何未经要求的功能、抽象或“灵活性”。如果 50 行能搞定,就不要写 200 行。这能遏制 AI 过度设计的冲动。
- 精准修改:这条原则要求 AI 只修改它被要求修改的部分。不要“顺手”优化旁边的代码、注释或格式。如果它发现了无关的“死代码”,可以提出来,但不要动手删除。这能保证你的代码库只发生预期的变化。
- 目标驱动:这条原则要求 AI 把“做什么”转化为“达成什么标准”。比如,不要说“修复 bug”,而是说“写一个能复现 bug 的测试,然后让这个测试通过”。这给了 AI 一个清晰的、可验证的目标,让它能自己循环直到成功。
一个关键洞察
Karpathy 还分享过一个非常有意思的观点,他说:“LLM 非常擅长在达成特定目标的过程中不断循环……不要告诉它该做什么,给它成功的标准,然后看着它自己完成。”
这句话点明了“目标驱动”原则的核心价值。AI 不擅长“理解模糊的意图”,但它极其擅长“完成明确的任务”。我们这套规则,本质上就是把我们模糊的意图,翻译成 AI 能理解和执行的、清晰的任务清单。
如何判断这套规则在起作用?
在后面的章节里,我们会一步步安装和使用这套规则。等你用上一段时间后,你可以留意一下这些迹象,它们能告诉你规则正在生效:
- 代码审查 (Code Review) 时的改动更少了:你只会看到你要求修改的部分,没有那些莫名其妙的“附带优化”。
- AI 第一次给出的代码就更简洁:它不再一上来就给你搞个复杂的架构,而是先给出最直接的实现。
- AI 在动手之前会先提问:它会说“我注意到这里有几种可能的实现方式,你想用哪一种?” 而不是直接选一个。
- 你收到的 Pull Request (PR) 干净、最小化:没有“路过式”的重构或“改进”,只包含解决特定问题所需的最小改动。
好了,现在你已经清楚了我们为什么要做这件事,以及我们要解决什么问题。从下一章开始,我们就正式进入安装环节,把这套“工作守则”交到你的 AI 助手手里。
2. 2. 安装:在 Claude Code 中一键安装插件(推荐)
好的,我们开始第二章。这一章会带你用最简单、最推荐的方式,把 Karpathy 的编码原则装进你的 Claude Code 里。整个过程就像在手机上装一个 App,几分钟就能搞定。
2. 安装:在 Claude Code 中一键安装插件(推荐)
在开始之前,我们先花一分钟理解一下,为什么我们要用“插件”这种方式,而不是直接把规则写进项目文件里。
你可能会好奇,直接把规则写进项目里不就行了吗?当然可以,我们下一章就会讲那种方法。但插件的方式有一个巨大的好处:它是一次安装,到处可用。想象一下,你手上有好几个项目,每个项目都有一套自己的规则。如果每个项目都要手动去配置一遍,那不仅麻烦,而且很容易忘记。插件就像你手机里的一个 App,安装一次,以后在任何项目里打开 Claude Code,它都会自动生效。这样,你的编码原则就能保持一致,不会因为换了一个项目就“打回原形”。
所以,这一章我们走的就是这条“一劳永逸”的路。
前置条件
在开始操作前,请确保你已经准备好了以下两样东西:
- 安装了 Claude Code:这是最基本的前提。如果你还没有安装,请先参考 Claude Code 的官方文档完成安装。
- 能在终端里运行 Claude Code 命令:你需要能打开一个终端(比如 macOS 的“终端”或 Windows 的“命令提示符”或“PowerShell”),并且输入
claude命令后能正常启动 Claude Code 的交互界面。
别担心,如果你现在还没打开终端,我们马上就会用到它。
第一步:添加插件市场
Claude Code 的插件并不是凭空出现的,它们都来自一个“插件市场”。我们需要先告诉 Claude Code,去哪里找到我们想要的插件。这个操作就像在手机的应用商店里,先添加一个“第三方应用商店”的源。
请打开你的终端,输入以下命令,然后按回车:
claude /plugin marketplace add forrestchang/andrej-karpathy-skills预期结果:你会看到 Claude Code 给出一个回应,类似“Plugin marketplace added successfully”或者“已成功添加插件市场”。这表示你已经成功添加了来源,现在可以搜索里面的插件了。
常见问题:
- 报错:
command not found: claude:这说明你的系统里没有安装 Claude Code,或者没有把它加到环境变量里。请先检查 Claude Code 是否安装成功。 - 报错:
Error: Plugin marketplace already exists:这没关系,说明你之前可能已经添加过这个市场了。可以忽略这个错误,直接进行下一步。
第二步:安装插件
市场添加成功后,我们就可以正式安装插件了。这个命令会从我们刚刚添加的市场里,下载并安装名为 karpathy-skills 的插件。
在同一个终端里,接着输入下面的命令:
claude /plugin install andrej-karpathy-skills@karpathy-skills预期结果:Claude Code 会开始下载并安装。安装完成后,你会看到一条成功消息,比如“Plugin 'karpathy-skills' installed successfully”或者“插件 'karpathy-skills' 安装成功”。
小提示:命令中的 andrej-karpathy-skills@karpathy-skills 可以这样理解:@ 符号前面是插件的“作者/仓库名”,后面是插件的“具体名称”。这样写是为了精确地找到并安装这个插件。
第三步:验证安装是否成功
安装完成之后,我们最好验证一下,确保它真的生效了。一个简单的方法就是,在 Claude Code 里问它一个关于编码原则的问题,看看它会不会按照 Karpathy 的原则来回答。
在终端里,输入 claude 启动 Claude Code 的交互界面。然后,你可以问它这样一个问题:
“请用 Karpathy 的编码原则,帮我检查一下这段代码有什么问题:
def add(a, b): return a + b”
预期结果:如果插件安装成功,Claude Code 的回答应该会体现出“先思考”、“求简洁”等原则。比如,它可能会先分析这段代码的用途,然后指出它已经足够简洁,不需要过度设计,或者询问你是否有更具体的需求。如果它只是简单地回答“这段代码没问题”,那可能插件没有生效,或者你需要重新检查一下安装步骤。
一个完整的例子
为了让你更直观地感受整个过程,我们把它串起来。假设你刚刚打开一个全新的终端,准备开始一个新项目。
- 你输入
claude,Claude Code 启动了。 - 你输入
/plugin marketplace add forrestchang/andrej-karpathy-skills,添加了市场。 - 你输入
/plugin install andrej-karpathy-skills@karpathy-skills,安装了插件。 - 你开始你的工作,比如让 Claude Code 帮你写一个函数。因为插件已经生效,它写出来的代码就会自动遵循“先思考”、“求简洁”这些原则,而不会自作主张地写出一大堆你用不到的复杂结构。
注意事项
- 插件是全局生效的:这意味着,一旦你安装了它,你在任何项目里使用 Claude Code,它都会遵循这套原则。如果你在某个项目里有自己特殊的规则,不用担心,我们会在第 9 章“自定义”里教你如何把它们合并起来。
- 如果安装后感觉没变化:有时候 Claude Code 可能需要重启才能完全加载新插件。你可以退出当前的 Claude Code 会话(输入
/exit),然后重新输入claude启动一次。 - 这是最推荐的方式:对于大多数用户来说,这是最省心、最不容易出错的方法。除非你有特殊原因(比如无法访问插件市场,或者想对规则进行深度定制),否则请优先选择这种方式。
好了,到这里,你已经成功地在 Claude Code 里安装好了 Karpathy 的编码原则插件。恭喜你!从此刻起,你的 AI 编程助手已经拥有了更“聪明”的编码思维。在下一章,我们会介绍另一种安装方式,让你了解如何把规则直接放进单个项目里。
3. 3. 安装:手动添加 CLAUDE.md 到你的项目
好的,我们开始第三章的内容。在上一章里,我们通过插件的方式,让 Claude Code 在所有项目里都能遵循 Karpathy 的编码原则。但如果你只想在某一个特定项目里应用这些原则,或者你希望把原则和项目自身的规则(比如“用 TypeScript 严格模式”、“测试覆盖率必须达到 80%”)放在一起管理,那么手动添加 CLAUDE.md 文件会是更灵活、更可控的方式。
这一章,我们就来学习如何手动把 Karpathy 的编码原则,注入到你项目的 CLAUDE.md 文件中。别担心,这个过程非常简单,你只需要执行一两条命令。
前置准备
在开始之前,请确保你已经:
- 有一个你想要应用这些原则的项目(可以是新项目,也可以是已有项目)。
- 你的电脑上已经安装了
curl命令。curl是一个用来从网络上下载文件的工具,几乎所有操作系统都自带它。如果你不确定,可以在终端里输入curl --version看看有没有返回版本信息。如果没有,请先搜索“如何安装 curl”来解决。
第一步:理解 CLAUDE.md 是什么
你可能会好奇,为什么是 CLAUDE.md 这个文件?简单来说,当你在项目根目录下创建这个文件时,Claude Code 就会自动读取它,并把它当作一份“项目说明书”或“行为守则”。Claude Code 会严格按照文件里的指示来工作。
你可以把它想象成你给一位新同事的“入职手册”。手册里写着:“在我们团队,我们写代码前要先想清楚,我们追求简洁,我们只改该改的地方。” 那么这位新同事(Claude Code)就会照着做。CLAUDE.md 就是这份手册。
第二步:为新项目创建 CLAUDE.md
如果你是从零开始的新项目,操作最简单。我们只需要把 Karpathy 原则的模板文件下载下来,放到你的项目根目录下。
打开你的终端,进入你的项目目录。比如你的项目叫 my-awesome-app,就执行:
cd my-awesome-app然后,执行下面这条命令:
curl -o CLAUDE.md https://raw.githubusercontent.com/forrestchang/andrej-karpathy-skills/main/CLAUDE.md我们来拆解一下这条命令做了什么:
curl:调用下载工具。-o CLAUDE.md:告诉curl,把下载的内容保存成一个名为CLAUDE.md的文件。- 后面那一长串 URL:就是存放 Karpathy 原则模板文件的网络地址。
预期结果:命令执行后,你的项目根目录下会多出一个 CLAUDE.md 文件。你可以用任何文本编辑器打开它,会看到里面包含了“Think Before Coding”、“Simplicity First”等四个原则的详细描述。恭喜你,你的新项目已经拥有了这些编码原则!
第三步:为已有项目添加 CLAUDE.md
如果你的项目里已经有一个 CLAUDE.md 文件了(比如你之前已经写过一些项目规则),那么我们不能直接覆盖它,而是要把 Karpathy 的原则追加到现有文件的末尾。
操作也很简单,执行下面这两条命令:
# 第一条命令:在文件末尾加一个空行,作为分隔
echo "" >> CLAUDE.md
# 第二条命令:下载原则内容,并追加到文件末尾
curl https://raw.githubusercontent.com/forrestchang/andrej-karpathy-skills/main/CLAUDE.md >> CLAUDE.md注意,第二条命令和刚才新项目的命令有一点不同:我们没有使用 -o 参数,而是用了 >> 符号。>> 的意思是“把输出内容追加到指定文件的末尾”,而不是覆盖它。
预期结果:打开你的 CLAUDE.md 文件,你会看到在原有内容的下方,新增了 Karpathy 的四个原则。你的项目规则和 Karpathy 原则现在“和平共处”在一个文件里了。
常见问题与排查
问题:执行命令后,
CLAUDE.md文件是空的,或者内容不完整。- 原因:最常见的原因是网络问题,导致下载中断。
- 解决:重新执行一次下载命令。如果反复失败,可以试试用浏览器直接打开那个 URL(
https://raw.githubusercontent.com/forrestchang/andrej-karpathy-skills/main/CLAUDE.md),看看能不能正常显示内容。如果能,把内容复制下来,手动粘贴到你的CLAUDE.md文件里。
问题:我执行了追加命令,但文件里出现了重复的内容。
- 原因:你之前可能已经执行过追加操作,或者文件里已经包含了这些原则。
- 解决:打开
CLAUDE.md文件,手动删除重复的部分,只保留一份即可。
一个小例子:把原则和项目规则结合起来
假设你的项目是一个 Python 的 Web 服务,你希望 Claude Code 在遵循 Karpathy 原则的同时,也遵守你项目的特定要求。那么你的 CLAUDE.md 文件最终看起来会像这样:
# 项目专属规则
- 使用 Python 3.11+
- 所有 API 端点必须使用 FastAPI 框架
- 数据库操作必须使用 SQLAlchemy 2.0 的异步方式
- 代码提交前必须通过 `pytest` 测试
## Karpathy 编码原则
### 1. Think Before Coding
**不要假设。不要隐藏困惑。把权衡点摆出来。**
LLM 常常默默地选择一个解释然后直接执行。这个原则强制进行显式推理:
- **明确陈述假设** —— 如果不确定,就问,不要猜
- **提出多种解释** —— 当存在歧义时,不要默默选择一种
- **在必要时提出异议** —— 如果存在更简单的方法,就说出来
- **感到困惑时停下来** —— 说出不清楚的地方,并请求澄清
...(其余原则以此类推)这样,Claude Code 在为你工作时,就会同时参考“项目专属规则”和“Karpathy 编码原则”,做到既遵守团队规范,又写出干净、可控的代码。
总结
手动添加 CLAUDE.md 是一个非常直接且强大的方法。它让你能够精确控制 Claude Code 在你项目中的行为,并且可以轻松地将通用编码原则与项目特定规则融合在一起。现在,你的项目已经装备上了 Karpathy 的四大原则,可以开始更高效、更可控的 AI 辅助编程之旅了。在下一章,我们会看看如何在另一个流行的编辑器——Cursor 中,也应用上同样的原则。
4. 4. 在 Cursor 中启用同样的编码原则
好的,我们开始第 4 章的内容。这一章会稍微有些不同,因为 Cursor 和 Claude Code 的工作方式不太一样。别担心,我们慢慢来,我会把每一步都讲清楚。
4. 在 Cursor 中启用同样的编码原则
你可能已经习惯了在 Claude Code 里用 /plugin 命令安装插件,觉得那很方便。但当你切换到 Cursor 时,可能会发现它没有同样的“插件市场”。那是不是意味着我们就没法在 Cursor 里用上 Karpathy 的编码原则了呢?当然不是。
这一章的目标,就是教会你如何把同样的四原则(先思考、求简洁、精准改、目标驱动)注入到 Cursor 的 AI 助手中。你可能会好奇为什么需要单独做这一步——因为 Cursor 和 Claude Code 读取项目规则的方式不同。Cursor 使用的是它自己的一套“项目规则”系统,我们需要把原则翻译成它能理解的语言。
前置条件
在开始之前,请确保你已经完成了以下步骤:
- 你的电脑上已经安装了 Cursor 编辑器。
- 你已经打开了你想应用这些原则的项目文件夹。
- 如果你还没有项目,可以先创建一个空文件夹,然后在 Cursor 中打开它。
第一步:理解 Cursor 的项目规则(.cursor/rules)
在 Claude Code 里,规则是写在项目根目录下的 CLAUDE.md 文件里的。而在 Cursor 里,规则是放在一个叫 .cursor/rules/ 的文件夹里。每个规则都是一个独立的 .mdc 文件。
这是什么、为什么需要?
你可以把 .cursor/rules/ 文件夹想象成一个“规则抽屉”,每个 .mdc 文件就是一张写满指令的卡片。当你向 Cursor 的 AI 提问时,它会自动查看这些卡片,并按照上面的指示来行动。如果不做这一步,Cursor 的 AI 就会使用它默认的行为,那它可能还是会犯那些我们之前讨论过的错误:过度设计、乱改代码等等。
怎么做? 我们先在项目的根目录下创建这个文件夹。
- 打开你的 Cursor 编辑器。
- 在左侧的文件浏览器中,右键点击你的项目根目录。
- 选择“新建文件夹”,并将其命名为
.cursor。注意,前面有一个点,这是一个隐藏文件夹。 - 接着,在
.cursor文件夹内,再新建一个文件夹,命名为rules。
现在,你的项目结构应该是这样的:
你的项目文件夹/
├── .cursor/
│ └── rules/
├── (你的其他文件)第二步:创建 Karpathy 原则的规则文件
现在,我们要在 rules 文件夹里创建一张“卡片”。这张卡片上写的就是 Karpathy 的四条原则。
这是什么、为什么需要?
这个 .mdc 文件就是 Cursor 能读懂的“CLAUDE.md”。它告诉 Cursor 的 AI:“嘿,当你帮我写代码的时候,请遵循这些规则。” 我们不需要从头开始写,项目已经为我们准备好了这个文件。
怎么做?
- 在你的浏览器中,打开这个链接:
https://raw.githubusercontent.com/forrestchang/andrej-karpathy-skills/main/.cursor/rules/karpathy-guidelines.mdc - 你会看到一些文本。全选(Ctrl+A 或 Cmd+A)并复制(Ctrl+C 或 Cmd+C)所有内容。
- 回到 Cursor,在
.cursor/rules/文件夹上右键,选择“新建文件”。 - 将文件命名为
karpathy-guidelines.mdc。注意,文件名可以自己取,但后缀必须是.mdc。 - 将你刚刚复制的内容粘贴(Ctrl+V 或 Cmd+V)到这个新文件中。
- 保存文件(Ctrl+S 或 Cmd+S)。
预期结果:
你现在在 .cursor/rules/ 文件夹下有了一个名为 karpathy-guidelines.mdc 的文件。它的内容看起来应该像是一份给 AI 的指令清单,包含了“Think Before Coding”、“Simplicity First”等章节。
第三步:验证规则是否生效
规则已经放好了,但我们怎么知道 Cursor 真的在读它呢?最好的办法就是测试一下。
怎么做?
- 在 Cursor 中,按下
Cmd+I(Mac) 或Ctrl+I(Windows/Linux) 打开 AI 对话框。 - 输入一个简单的问题,比如:“请列出这个项目的编码规则。”
- 观察 AI 的回答。
预期结果:
如果规则生效了,AI 应该会引用 karpathy-guidelines.mdc 文件中的内容,并告诉你它遵循“先思考”、“求简洁”等原则。它可能会说:“根据项目规则,我遵循以下原则:...” 如果它只是给出一个泛泛的回答,或者完全没提到这些原则,那说明规则可能没有正确加载。
常见问题与排查:
- AI 没有反应? 确保文件名后缀是
.mdc,而不是.md或.txt。Cursor 只识别.mdc文件作为规则。 - AI 说找不到规则? 检查一下
.cursor文件夹是否在项目的根目录下。如果你打开的是子文件夹,规则可能不会被读取。 - 我想确认一下? 你可以打开 Cursor 的设置(
Cmd+,或Ctrl+,),搜索“Rules”,看看有没有关于项目规则路径的选项。通常,只要文件位置正确,它就会自动生效。
第四步:将规则应用到其他项目(进阶)
如果你有多个项目,每个项目都手动创建一次 .cursor/rules/karpathy-guidelines.mdc 会有点麻烦。有没有更聪明的方法呢?
这是什么、为什么需要? 你可以创建一个“全局规则”,让 Cursor 在所有项目里都自动应用这些原则。这样你就不用每个项目都重复操作了。
怎么做?
- 在 Cursor 中,打开设置:点击左下角的齿轮图标,或者按下
Cmd+,(Mac) /Ctrl+,(Windows/Linux)。 - 在设置搜索框中,输入
Rules。 - 你会看到一个叫 “User Rules” 或 “全局规则” 的选项。这里可以写一些对所有项目都生效的指令。
- 将
karpathy-guidelines.mdc文件里的核心内容复制粘贴到这里。或者,更简单的方法是,写一行指令让它去读取项目内的规则文件。不过,最稳妥的方式还是直接粘贴核心原则。
预期结果: 现在,无论你打开哪个项目,Cursor 的 AI 都会默认遵循这些编码原则。你只需要设置这一次。
一个贴近真实场景的小例子
假设你正在用 Cursor 开发一个 Python 小工具,用来计算两个数的和。你写了一个函数,但觉得它有点乱,想让 AI 帮你“改进”一下。
没有规则时:
你可能会说:“帮我重构这个 add 函数。”
AI 可能会把它变成一个类,加上类型检查、异常处理、日志记录,甚至创建一个配置文件。代码从 3 行变成了 30 行,完全过度设计了。
有了规则后:
你同样说:“帮我重构这个 add 函数。”
AI 会先思考(Think Before Coding),它可能会问你:“这个函数目前只用于整数相加吗?需要处理浮点数或字符串吗?” 然后,它会遵循“求简洁”原则,可能只是把函数名改得更清晰,或者加一个简单的文档字符串。它不会添加任何你没有要求的功能。
你看,这就是规则的力量。 它让 AI 从一个“热情过度的实习生”变成了一个“经验丰富、懂得克制的工程师”。
现在,你已经成功地在 Cursor 中启用了 Karpathy 的编码原则。你可以像在 Claude Code 中一样,享受更干净、更可控的 AI 辅助编程体验了。下一章,我们将深入第一条原则,看看如何让 AI 真正做到“先思考再动手”。
5. 5. 实操原则一:让 AI 先思考再动手——Think Before Coding
好的,我们开始学习第五章。这一章要解决的是AI写代码时最常见、也最让人头疼的一个问题:它根本不问清楚就动手了。
你有没有遇到过这种情况?你让AI“给这个函数加个错误处理”,它二话不说,直接给你写了一大段try-catch,里面还自作主张地加了你根本没提过的日志记录和重试逻辑。等你一看,发现它对你代码的上下文理解完全是错的,改的东西跟你想要的南辕北辙。这就是典型的“先开枪,后瞄准”——AI在没搞明白你到底要什么、当前代码到底是什么状况之前,就闷头开干了。
“先思考再动手”(Think Before Coding)这个原则,就是专门来治这个毛病的。它的核心思想很简单:在AI动手写任何代码之前,必须先把它脑子里的想法、假设、疑问,全都说出来给你听。 就像一位经验丰富的程序员在改代码前,会先跟你确认:“我理解你的需求是X,我注意到这里有个潜在问题Y,我的方案是Z,你觉得对吗?” 而不是闷声不响地直接改。
这一章,我们就来亲手体验一下,如何让AI养成这个“先说出来,再动手”的好习惯。
前置准备
在开始之前,请确保你已经完成了前面章节的安装步骤。也就是说,你的项目里已经有了一个 CLAUDE.md 文件(或者你在Claude Code里安装了插件),并且这个文件里包含了我们之前讨论过的四条原则。如果你还没做,请先回到第2章或第3章,花两分钟把它搞定。别担心,这很快。
第一步:感受“不思考”的AI
为了让你更清楚地看到区别,我们先来模拟一下没有“先思考再动手”原则时,AI会怎么表现。
假设你有一个非常简单的Python函数,它从一个字典里读取用户信息:
# user_data.py
def get_user_info(user_id, database):
"""从数据库字典中获取用户信息"""
user = database.get(user_id)
return user现在,你向AI(比如Claude Code)提出一个请求:
“请给这个函数增加健壮性,防止它因为传入无效的user_id而崩溃。”
在没有原则约束的情况下,AI很可能会直接输出类似这样的代码:
def get_user_info(user_id, database):
"""从数据库字典中获取用户信息"""
if not isinstance(user_id, (int, str)):
raise TypeError("user_id must be an integer or string")
if not isinstance(database, dict):
raise TypeError("database must be a dictionary")
user = database.get(user_id)
if user is None:
return {"error": "User not found"}
return user看起来好像“更健壮”了,对吧?但它做了很多你没要求的事:
- 它假设了
user_id的类型必须是int或str。万一你的系统里user_id是UUID对象呢?它这个“健壮性”反而会引入一个bug。 - 它假设
database必须是字典。万一你将来想换成别的数据结构呢? - 它自作主张地返回了一个错误字典。这改变了函数的返回类型,可能会让调用这个函数的地方全部出错。
这就是“不思考”的后果:它选了一个它认为“最可能”的解释,然后直接执行了,完全没有跟你确认。
第二步:激活“先思考”原则
现在,我们让“先思考再动手”原则发挥作用。这个原则在 CLAUDE.md 里是这样描述的:
先思考再动手
- 明确陈述假设 — 如果不确定,要提问而不是猜测
- 呈现多种解读 — 当存在歧义时,不要默默地选择一种
- 在必要时提出异议 — 如果有更简单的方法,要说出来
- 遇到困惑时停下来 — 说出不清楚的地方,并请求澄清
这些规则就像给AI装了一个“刹车”。当它想直接写代码时,这些规则会强制它先停下来,把它的思考过程说出来。
现在,我们再次向AI提出同样的请求,但这次,因为 CLAUDE.md 里的规则在起作用,它的行为会完全不同。
你可能会看到类似这样的回复:
AI (Claude Code):
好的,在开始修改之前,我想先跟你确认一下我的理解,并分享一些想法。
1. 我的理解与假设:
- 你希望
get_user_info函数在遇到无效输入时不会直接抛出异常导致程序崩溃。- “无效的user_id”可能指:
user_id是None,或者user_id的类型不对(比如传了一个列表进来)。- “数据库字典”
database可能包含所有有效的用户ID。2. 我看到的潜在歧义:
- 如何处理无效的
user_id? 是返回None,返回一个特定的错误对象,还是抛出一个自定义异常?不同的处理方式会影响调用方的代码。- “健壮性”的范围是什么? 我们只处理
user_id无效的情况,还是也要处理database本身是None或空字典的情况?- 返回类型要改变吗? 目前函数返回的是用户信息字典或
None。如果增加错误处理,我们是否要保持返回类型一致?3. 我的建议: 最简单的方案是保持函数的核心逻辑不变,只增加对
user_id为None的检查,并返回None。这样改动最小,也最符合函数现有的设计(dict.get()在key不存在时返回None)。你觉得这个方向可以吗?或者你有更具体的想法?请告诉我你的偏好,我再开始写代码。
看到了吗?这才是“先思考再动手”。AI没有直接写代码,而是:
- 陈述了它的假设(“我假设‘无效’可能指……”)。
- 指出了歧义(“如何处理无效ID?有几种可能……”)。
- 提出了更简单的方案(“最简单的方案是……”)。
- 在困惑时停下来提问(“你觉得这个方向可以吗?”)。
现在,主动权回到了你手里。你可以根据它的分析,给出更精确的指令。比如你可以回复:“对,就按你的建议来,只处理 user_id 为 None 的情况,返回 None。其他情况不用管。” 这样,AI接下来的修改就会非常精准,绝不会乱改。
第三步:在你的工作流中实践
你可能会好奇,这个原则在实际的、更复杂的任务中怎么用?我们来看一个更贴近真实场景的例子。
假设你正在开发一个Web应用,有一个处理用户订单的函数。你希望AI帮你优化一下性能。
你的请求: “请优化 process_order 函数,让它更快。”
没有原则的AI:可能会直接重写整个函数,引入缓存、异步、甚至换一个数据库查询库,结果引入了一堆新bug和依赖。
有原则的AI:它会先停下来,像这样思考并提问:
AI (Claude Code):
在优化之前,我想先分析一下当前的瓶颈,并跟你确认优化目标。
1. 我的初步分析: 我注意到
process_order函数中,最耗时的部分可能是第15行的数据库查询get_user_address(),它在循环中被调用了多次。2. 我的假设:
- 我假设“更快”主要是指减少这个函数的总体执行时间。
- 我假设
get_user_address()的结果在同一个订单处理过程中是不变的。3. 我看到的潜在方案与权衡:
- 方案A(推荐): 将
get_user_address()移出循环,只查询一次。这是最小改动,风险最低,应该能解决大部分性能问题。- 方案B: 引入一个简单的内存缓存来存储用户地址。这会更复杂,但如果
get_user_address()本身就很慢,效果会更好。- 方案C: 将整个函数改为异步。这是最大的改动,会改变函数的调用方式,可能影响整个调用链,不推荐作为第一步。
4. 我的疑问:
- 你是否有性能测试或分析数据,能确认瓶颈确实在
get_user_address()上?- 你希望优化到什么程度?是“感觉上快一点”就行,还是有一个具体的性能指标(比如“从500ms降到100ms”)?
请告诉我你的想法,我们再决定具体怎么做。
这个回复是不是让你感觉舒服多了?AI不仅没有乱改,还帮你理清了思路,指出了最安全、最有效的路径。这就是“先思考再动手”的价值。
常见问题与提示
问:如果AI没有“先思考”就直接动手了怎么办?
- 答: 这说明
CLAUDE.md可能没有生效,或者你的请求太简单了,AI认为不需要思考。你可以直接打断它,说:“请先按照CLAUDE.md中的‘先思考再动手’原则,分析一下我的需求,再开始写代码。” 这相当于手动激活了它的“思考模式”。
- 答: 这说明
问:这个原则会不会让AI变得太啰嗦,每次都要问一堆问题?
- 答: 对于非常简单的任务(比如“把这个变量的名字从
a改成b”),AI通常不会触发这个原则,因为它没有歧义。这个原则主要在处理有模糊性或复杂性的任务时才会被激活。而且,随着你使用得多了,AI会学习你的偏好,提问会越来越精准。如果它问得太多,你也可以告诉它:“对于这类任务,以后不用问,直接按方案A做。”
- 答: 对于非常简单的任务(比如“把这个变量的名字从
一个实用技巧: 你可以在提出请求时,主动引导AI进行思考。比如,在请求的末尾加上一句:“在动手前,请先分析一下潜在的风险和更简单的方案。” 这会让合作更顺畅。
好了,现在你已经掌握了“先思考再动手”这个原则的精髓和用法。它就像给你的AI助手戴上了一副“思考眼镜”,让它不再是一个莽撞的执行者,而是一个能与你平等对话、共同决策的编程伙伴。下一章,我们将学习如何让AI拒绝“过度设计”,保持代码的简洁。
6. 6. 实操原则二:拒绝过度设计——Simplicity First
好的,我们开始学习第六章。这一章我们要解决一个非常常见但又让人头疼的问题:AI 写出来的代码,明明能跑,但总觉得“太复杂了”、“绕来绕去”、“加了很多我看不懂的东西”。这就是过度设计(Overengineering)的典型表现。Karpathy 的第二条原则“Simplicity First”(简洁优先),就是专门用来对抗这个问题的。学完这一章,你就能让 AI 助手写出更直接、更清爽、更容易理解的代码。
前置准备
在开始之前,请确保你已经完成了以下步骤之一:
- 如果你用的是 Claude Code,已经通过插件方式安装了本技能(参考第 2 章)。
- 如果你用的是 Cursor,已经按照第 4 章的说明,将规则文件添加到了你的项目中。
- 或者,你已经在项目根目录下创建了
CLAUDE.md文件,并包含了“Simplicity First”这条原则(参考第 3 章)。
简单来说,就是确保你的 AI 助手已经“认识”了这条规则。我们接下来要做的,就是理解它到底在说什么,以及如何让它真正生效。
第一步:理解“简洁优先”到底在要求什么
你可能会好奇,为什么需要专门强调“简洁”?难道 AI 不就应该写最少的代码吗?事实恰恰相反。AI 模型有一个很强的倾向:它喜欢“未雨绸缪”,喜欢“考虑周全”,结果就是写出一堆当前根本用不上的东西。
想象一下,你只是想让 AI 帮你写一个函数,用来计算两个数的和。一个“过度设计”的 AI 可能会这样做:
- 创建一个
Calculator类,因为“以后可能还需要其他运算”。 - 为这个类设计一个
Operation接口,因为“这样扩展性更好”。 - 添加一个
Logger来记录每次计算,因为“生产环境需要日志”。 - 处理各种你根本不会遇到的错误情况,比如“如果输入不是数字怎么办”。
你看,一个原本只需要一行的 return a + b,被硬生生地扩展成了几十行甚至上百行。这就是“过度设计”的典型例子。
“Simplicity First”原则就是用来制止这种行为的。它要求 AI 严格遵守以下几点:
- 不多做功能:只实现你明确要求的,不要猜测你“未来可能需要”的功能。
- 不多做抽象:如果一个函数或一段代码只在一个地方用到,就不要为了“复用”而把它抽象成一个类或一个模块。
- 不多做“灵活性”:不要为了“让用户能配置”而添加参数或选项,除非你明确要求了。
- 不多做错误处理:只处理那些确实可能发生的错误。不要为“世界末日”级别的场景编写防御代码。
- 能短则短:如果 200 行代码能压缩成 50 行,那就应该重写。
一个简单的判断标准:你可以问自己,或者让 AI 问自己:“一个经验丰富的工程师看到这段代码,会觉得它过于复杂了吗?” 如果答案是肯定的,那就需要简化。
第二步:在对话中激活“简洁优先”原则
仅仅把规则写在 CLAUDE.md 里还不够,你需要在和 AI 的对话中,有意识地激活它。最好的方式,就是在你的请求里,明确地加上“简洁”这个关键词。
不好的请求方式(容易引发过度设计):
“帮我写一个 Python 函数,用来从 CSV 文件里读取用户数据。”
这个请求太开放了。AI 会想:“用户数据?那可能有很多字段,我最好设计一个 User 类来封装。还要考虑文件不存在、格式错误、编码问题……最好再加个缓存机制,提高性能。” 结果可想而知。
好的请求方式(激活简洁优先):
“帮我写一个 Python 函数
load_users,它接收一个 CSV 文件路径作为参数,返回一个字典列表。请保持代码尽可能简洁,不要添加任何不必要的抽象或功能。”
看到了吗?通过加上“请保持代码尽可能简洁,不要添加任何不必要的抽象或功能”这句话,你就是在明确地告诉 AI:“收起你那些‘未雨绸缪’的想法,我只要最直接、最核心的功能。”
第三步:用具体例子来“调教”AI
有时候,光说“简洁”还不够,AI 可能还是不明白你的“简洁”标准是什么。这时候,最好的办法就是给它一个具体的例子。
假设你想让 AI 帮你写一个函数,用来检查一个字符串是否是有效的电子邮件地址。
你可能会这样问:
“写一个函数,验证电子邮件地址是否有效。”
AI 可能会给出一个非常“健壮”的版本,用上了正则表达式,甚至可能引入一个第三方库。但这可能不是你想要的。
更好的方式是,你提供一个“简洁”的模板:
“写一个函数
is_valid_email,验证电子邮件地址是否有效。请参考下面的简洁风格,不要过度设计:# 简洁风格的例子:检查字符串是否为空 def is_not_empty(s): return bool(s and s.strip())请用类似的风格来实现
is_valid_email。”
通过提供一个“简洁”的正面例子,你就在给 AI 设定一个具体的“锚点”。它会模仿你给出的例子,写出同样简洁的代码。
第四步:当 AI 给出复杂代码时,如何纠正
即使你提前打了“预防针”,AI 有时还是会“老毛病”发作,给出一个过度设计的方案。别担心,这很正常。这时候,你需要做的就是温和但坚定地纠正它。
假设 AI 给出了这样的代码:
class UserDataProcessor:
"""一个用于处理用户数据的类,未来可以扩展其他数据源。"""
def __init__(self, file_path: str, encoding: str = 'utf-8'):
self.file_path = file_path
self.encoding = encoding
self._data = None
def load_from_csv(self) -> list[dict]:
"""从 CSV 文件加载数据。"""
import csv
with open(self.file_path, 'r', encoding=self.encoding) as f:
reader = csv.DictReader(f)
self._data = list(reader)
return self._data
def get_record_count(self) -> int:
"""返回加载的记录数。"""
if self._data is None:
return 0
return len(self._data)你可以这样纠正它:
“谢谢你的代码。不过,我觉得这个实现有点过于复杂了。我们不需要一个类,也不需要
encoding参数和get_record_count方法。请把它重写成一个更简单的函数,就像这样:def load_users_from_csv(filepath: str) -> list[dict]: import csv with open(filepath, 'r') as f: return list(csv.DictReader(f))请按这个简洁的方向来修改。”
注意,你不是在批评 AI,而是在给它一个更明确的、更符合你需求的“简洁”方向。通过反复几次这样的互动,AI 会逐渐学会你的偏好。
一个完整的实战小例子
让我们把上面的步骤串起来,模拟一个完整的对话场景。
你的请求:
“我需要一个 Python 函数,它能接收一个包含数字的列表,并返回一个新的列表,其中只包含偶数。请保持代码简洁,不要使用类,不要添加任何不必要的功能。”
AI 的简洁回答(符合预期):
def get_even_numbers(numbers: list[int]) -> list[int]:
"""返回列表中所有的偶数。"""
return [num for num in numbers if num % 2 == 0]如果 AI 给出了复杂回答(不符合预期):
class NumberFilter:
"""一个数字过滤器,未来可以支持多种过滤条件。"""
def __init__(self, numbers: list[int]):
self.numbers = numbers
def filter_even(self) -> list[int]:
return [num for num in self.numbers if num % 2 == 0]
# 预留了未来可能添加的过滤方法
def filter_odd(self) -> list[int]:
return [num for num in self.numbers if num % 2 != 0]你的纠正:
“这个类有点多余了。我们只需要一个简单的函数,不需要为未来预留功能。请把它改成一个函数,就像我之前要求的那样。”
通过这样反复的练习,你会发现,AI 写出“简洁”代码的成功率会越来越高。记住,“Simplicity First”不仅仅是一条写在文件里的规则,更是一种你和 AI 之间需要不断磨合的沟通方式。 你越明确地表达你对“简洁”的期望,AI 就越能理解并满足你的要求。
7. 7. 实操原则三:只改该改的——Surgical Changes
好的,我们开始学习第七章。这一章我们要解决一个非常具体、也非常让人头疼的问题:AI 助手在帮你改代码的时候,总是“顺手”改了一些不该改的东西。
你可能遇到过这种情况:你只是想让 AI 帮忙修一个小 bug,结果它把整个函数的格式都“优化”了一遍,或者把旁边一个你精心写的注释给删掉了,甚至把另一个模块里完全不相干的变量名也给改了。这就像你请人来修水龙头,结果他把整个厨房的瓷砖都换了一遍,还顺手把你家的墙刷成了别的颜色。这就是我们常说的“过度修改”或“连带伤害”。
这一章的“外科手术式修改”(Surgical Changes)原则,就是为了解决这个问题。它的核心思想很简单:只动那些必须动的地方,不要碰任何无关的代码。 就像外科医生做手术一样,只切开需要操作的部位,绝不会因为顺手就把旁边的器官也切掉。
在学习本章之前,请确保你已经完成了前面章节的安装步骤,也就是你的项目中已经有了 CLAUDE.md 文件(或者你在 Claude Code 中安装了插件,在 Cursor 中配置了规则)。这样,我们接下来讲的所有原则,AI 助手才会真正去遵守。
好,我们开始。
第一步:理解“外科手术式修改”的核心原则
我们先来明确一下,这个原则到底要求 AI 做什么,不做什么。
AI 应该做的:
- 只修改你明确要求它修改的代码行。
- 如果它自己的修改导致某些代码变成“孤儿”(比如你删除了一个函数,导致某个 import 不再被使用),它应该清理掉这些由它自己造成的“垃圾”。
- 在修改时,尽量保持和周围代码一致的风格(缩进、命名方式等),即使它觉得自己的风格更好。
AI 不应该做的:
- “顺手”改进或重构它认为“不够好”的相邻代码。
- 修改或删除它不理解但看起来“没用”的注释。
- 改变代码的格式(比如把单引号改成双引号,或者重新排列 import 的顺序),除非你明确要求。
- 删除它发现的、但与你当前任务无关的“死代码”(dead code)。它应该做的是提出来,而不是直接删掉。
你可能会好奇,为什么 AI 会这么“多管闲事”?这是因为很多 AI 模型被训练成“尽力提供最好答案”的模式,它觉得“优化”代码是它的职责。但对我们开发者来说,这种“好心”往往办坏事,因为它引入了不可预测的变更,让代码审查(Code Review)变得非常困难,甚至可能引入新的 bug。
第二步:在 CLAUDE.md 中明确“外科手术式修改”规则
现在,我们要把这个原则写进 CLAUDE.md 文件里,让 AI 每次工作时都能读到它。
打开你项目根目录下的 CLAUDE.md 文件。如果你之前已经按照第二章或第三章的步骤安装了插件或添加了文件,那么里面应该已经有了一些内容。我们找到关于“Surgical Changes”的部分,或者直接添加一个新的章节。
你可以复制以下内容,粘贴到你的 CLAUDE.md 文件中。注意,这只是一个示例,你可以根据自己的项目进行调整。
## 外科手术式修改 (Surgical Changes)
**核心原则:只修改你被要求修改的代码。不要碰任何无关的东西。**
### 必须遵守的规则:
1. **精确修改**:只修改用户明确要求修改的代码行、函数或文件。不要“顺手”改进、重构或格式化相邻的代码。
2. **保留原样**:不要修改或删除你不完全理解的注释、代码或格式。即使你觉得它们“不够好”或“没用”,只要不是本次任务的目标,就保持原样。
3. **清理自己的“垃圾”**:如果你的修改导致某些代码不再被使用(例如,删除了一个函数,导致某个 import 语句变成未使用),你必须清理这些由你造成的“孤儿代码”。但是,**不要**清理项目中原本就存在的、与你本次修改无关的死代码。
4. **风格一致**:修改代码时,尽量匹配该文件现有的编码风格(缩进、命名约定等),即使你个人偏好不同的风格。
5. **报告,不要擅自行动**:如果你在修改过程中发现了与任务无关的死代码、潜在 bug 或可以改进的地方,**不要直接修改**。你应该在回答中向用户报告你的发现,并询问是否需要处理。
### 验证标准:
- 代码审查(diff)中,每一行被修改的代码都应该能直接追溯到用户的请求。
- 没有“顺便”的格式化、重命名或重构。预期结果:当你下次向 AI 助手提出修改请求时,它会读到这些规则,并严格按照“只改该改的”原则来执行。
第三步:用一个例子来感受变化
理论说完了,我们来看一个具体的例子。假设你有一个 Python 文件 calculator.py,内容如下:
import os
import math
# 这是一个计算器模块
def add(a, b):
"""返回两个数的和"""
result = a + b
return result
def multiply(a, b):
# 这个函数计算乘积
product = a * b
return product
def unused_function():
pass现在,你向 AI 助手提出请求:“请给 add 函数添加一个类型提示(type hint),让参数 a 和 b 都是 int 类型,返回值也是 int。”
如果没有“外科手术式修改”原则,AI 可能会这样做:
import math # 它可能会把 "import os" 删掉,因为它觉得没用
# 它可能会把这个注释改成更“标准”的 docstring
def add(a: int, b: int) -> int:
"""返回两个数的和。"""
result = a + b
return result
def multiply(a, b):
# 这个函数计算乘积
product = a * b
return product
# 它可能会把 unused_function 也删掉,并报告“我删除了一个未使用的函数”你看,它做了很多“额外”的事情:删除了 import os,修改了注释,甚至可能删除了 unused_function。这些都不是你要求的。
有了“外科手术式修改”原则,AI 应该只这样做:
import os
import math
# 这是一个计算器模块
def add(a: int, b: int) -> int:
"""返回两个数的和"""
result = a + b
return result
def multiply(a, b):
# 这个函数计算乘积
product = a * b
return product
def unused_function():
pass它只修改了 add 函数的定义那一行,添加了类型提示。其他所有代码,包括它可能觉得“没用”的 import os 和 unused_function,都保持原样。这才是我们想要的“精准手术”。
常见问题与排查
问题: 我已经把规则写进 CLAUDE.md 了,但 AI 好像还是改了一些无关的东西。
排查步骤:
- 检查文件是否被正确加载:在 Claude Code 中,你可以输入
/命令,看看有没有相关的插件或规则被激活。在 Cursor 中,可以检查.cursor/rules目录下的规则文件是否生效。 - 检查规则是否清晰:你的规则是否足够具体?比如,你只写了“不要改无关代码”,这可能不够。最好像我们上面那样,列出具体的“可以做什么”和“不可以做什么”。
- 检查你的请求是否模糊:有时候,AI 的“过度修改”源于你的请求不够精确。例如,你说“优化这个函数”,AI 可能会认为“优化”包括重构、加注释、改格式等。尽量使用更精确的动词,比如“添加类型提示”、“修复 bug”、“增加一个参数”。
- 在请求中再次强调:你可以在每次请求的最后,加上一句提醒,比如:“请严格遵守‘外科手术式修改’原则,只修改
add函数的签名。”
实用技巧
- 在代码审查中验证:这是检验原则是否生效的最好方法。每次 AI 提交修改后,你查看 diff(代码差异),如果发现任何与任务无关的变更,就说明原则没有被严格遵守。你可以把这次“误改”作为反面例子,反馈给 AI,或者更新你的
CLAUDE.md规则,让它更具体。 - 对于“孤儿代码”,要区分“我的”和“你的”:这个原则特别强调,AI 只清理它自己造成的“孤儿”。如果项目中本来就有一个未使用的变量,那不是它该管的。它应该做的是在回答里提一句:“我注意到
old_variable似乎没有被使用,需要我处理吗?” 把决定权交给你。
好了,这一章的内容就到这里。你现在应该理解了“外科手术式修改”原则的重要性,并且知道如何把它写进规则里,以及如何验证它是否生效。记住,一个好的 AI 编码助手,不是因为它能写多少代码,而是因为它能精确地只写你需要的代码。下一章,我们将学习最后一个原则:用测试驱动验证,确保 AI 的修改是正确且可验证的。
8. 8. 实操原则四:用测试驱动验证——Goal-Driven Execution
好的,我们开始学习第四章原则。这一章可能是整个教程里最让你感到“省心”的一个,因为它把主动权交还给了你,让AI自己验证自己的工作。
8. 实操原则四:用测试驱动验证——Goal-Driven Execution
你有没有过这样的经历:你让AI“修复一个bug”,它改了一堆代码,然后说“修好了”。你心里没底,只能自己手动测试一遍,结果发现bug还在,甚至引入了新问题。这就像你让一个朋友去帮你买“好吃的东西”,他买回来一包辣条,但你可能想要的是蛋糕。问题出在哪里?指令太模糊了。
“Goal-Driven Execution”原则就是为了解决这个问题。它的核心思想是:不要告诉AI“做什么”,而是告诉它“做到什么样子算成功”。 把模糊的任务,变成可验证的目标。这样,AI就能像一个有明确目标的机器人,自己反复尝试,直到达成目标为止,而你只需要在终点检查结果。
前置条件
在开始之前,请确保你的项目中已经成功应用了Karpathy原则(无论是通过插件还是CLAUDE.md)。我们会在本章的示例中,看到这个原则如何与其他原则协同工作。
第一步:理解“目标”与“任务”的区别
我们先来做一个简单的思想实验。假设你有一个函数,它应该计算两个数字的和,但里面有个bug,总是返回乘积。
旧的方式(模糊的任务):
“修复这个计算器函数里的bug。”
AI可能会猜测你的意图,然后改掉一些它认为“不对劲”的地方,甚至可能把整个函数重写一遍。你无法确定它是否真的修好了。
新的方式(清晰的目标):
“写一个测试,验证
add(2, 3)的结果是5,然后让这个测试通过。”
看到了吗?你不再描述“怎么做”(修复bug),而是定义了“成功的样子”(一个能通过的测试)。AI会先写一个会失败的测试(因为函数目前返回6),然后去修改函数代码,直到测试通过。这个过程是自动的、可验证的。
第二步:将日常任务转化为“目标-验证”循环
现在,我们来看看如何把常见的AI指令改写成这种形式。你可以把这个表格当作一个速查表:
| 模糊的任务 | 清晰的目标 |
|---|---|
| “给这个API加个输入验证。” | “写一个测试,当传入空字符串时,API返回400错误,然后让这个测试通过。” |
| “重构这个模块。” | “确保所有现有测试在重构前后都能通过。如果测试覆盖率不足,先为关键路径补充测试。” |
| “优化这个查询的性能。” | “写一个基准测试,证明优化后的查询比优化前快至少2倍,然后让这个基准测试通过。” |
| “修复这个登录bug。” | “写一个测试,用错误的密码登录时,应该返回‘认证失败’的错误信息,然后让这个测试通过。” |
关键点在于: 你的指令里必须包含一个可以自动检查的“验证条件”。测试是最理想的验证条件,但也可以是“检查日志输出”、“验证文件内容”或“确认某个API被调用了”。
第三步:在复杂任务中使用“分步计划”
对于多步骤的任务,我们可以更进一步。让AI在动手之前,先制定一个带有验证点的计划。这就像我们写代码之前先画流程图一样。
示例:为一个用户注册功能添加“邮箱验证”
你可以这样对AI说:
“请为我们的用户注册流程添加邮箱验证功能。请先制定一个分步计划,每一步都包含一个验证条件,然后开始执行。”
AI会生成类似这样的计划:
1. [步骤] 在用户模型中添加 `is_email_verified` 字段。
→ 验证: 运行数据库迁移,确认新字段已创建。
2. [步骤] 修改注册接口,在创建用户后发送一封包含验证链接的邮件。
→ 验证: 编写一个测试,调用注册接口后,检查是否调用了邮件发送服务。
3. [步骤] 创建验证邮箱的API端点 `/verify-email?token=...`。
→ 验证: 编写一个测试,用有效的token访问该端点,检查用户状态是否变为“已验证”。
4. [步骤] 处理无效或过期token的情况。
→ 验证: 编写一个测试,用无效token访问端点,检查是否返回错误信息。有了这个计划,AI的执行就会变得非常清晰。每完成一步,它都会停下来检查验证条件是否满足。如果某一步失败了,它不会盲目地继续,而是会尝试修复。这大大减少了“做到一半发现方向错了”的尴尬。
第四步:一个完整的实战演练
让我们把前面学到的原则串起来,看一个完整的例子。假设我们有一个简单的Python函数,它应该判断一个数字是否为质数,但实现有误。
你的指令(应用了Goal-Driven Execution):
“我们有一个
is_prime函数,它可能有问题。请遵循以下原则:
- 先思考(Think Before Coding):先解释一下你理解的质数定义,以及你打算如何测试。
- 目标驱动(Goal-Driven Execution):写一个测试,验证
is_prime(1)返回False,is_prime(2)返回True,is_prime(4)返回False,is_prime(17)返回True。然后,修改is_prime函数,直到所有这些测试都通过。- 简洁优先(Simplicity First):你的实现应该尽可能简单,不要引入不必要的优化或抽象。
- 精准修改(Surgical Changes):只修改
is_prime函数本身,不要改动任何其他代码或注释。”
AI可能的响应:
思考: 质数是大于1的自然数,且只能被1和自身整除。1不是质数。我将使用一个简单的循环从2到sqrt(n)来检查是否有因子。测试会覆盖边界情况(1, 2)和典型情况(合数4,质数17)。
执行:
- 编写测试(会失败):
# test_is_prime.py from your_module import is_prime def test_is_prime(): assert is_prime(1) == False assert is_prime(2) == True assert is_prime(4) == False assert is_prime(17) == True- 运行测试(预期:失败):
pytest test_is_prime.py会报错,因为当前的is_prime实现不正确。- 修复函数(简洁实现):
# your_module.py import math def is_prime(n): if n <= 1: return False for i in range(2, int(math.sqrt(n)) + 1): if n % i == 0: return False return True- 再次运行测试(预期:通过):
pytest test_is_prime.py应该全部通过。
你看,整个过程非常清晰、可控。AI没有自作主张地添加“缓存”或“并行计算”等不必要的功能(Simplicity First),也没有去修改你的测试框架配置(Surgical Changes)。它只是专注地完成了你设定的目标。
常见问题与排查
- 问题:AI没有写测试,而是直接修改了代码。
- 原因: 你的指令可能不够明确。AI有时会“偷懒”,选择它认为更直接的方式。
- 解决: 在指令中明确强调“先写一个会失败的测试,然后再修改代码”。你可以说:“请务必先写测试,不要跳过这一步。”
- 问题:AI写的测试太简单,没有覆盖所有情况。
- 原因: 你给出的“成功标准”不够具体。
- 解决: 提供更详细的测试用例。例如,不只是说“测试边界情况”,而是直接列出
n=0, n=1, n=2, n=3, n=一个大质数。
- 问题:AI在修复代码时,引入了新的bug。
- 原因: 这是“目标驱动”原则要解决的核心问题。如果测试写得足够好,新bug应该会被测试捕获。
- 解决: 检查你的测试是否全面。一个好的测试集是你的“安全网”。如果AI的修改导致其他测试失败,它应该能自己发现并修复。
实用技巧
- 从“小目标”开始: 对于大型任务,不要一次性给出一个巨大的目标。把它拆解成几个小的、可验证的子目标,让AI逐个击破。这就像玩一个复杂的游戏,先完成一个小任务,拿到奖励,再继续下一个。
- 善用“验证”这个词: 在你的指令中,多使用“验证”、“确认”、“检查”这类词。例如:“完成这一步后,请验证日志中是否输出了预期的信息。”
- 把“测试”作为默认要求: 养成习惯,在让AI做任何有风险的改动(修复bug、添加功能、重构)时,都要求它先写测试。这会让你的代码库越来越健壮。
当你开始熟练运用“Goal-Driven Execution”原则时,你会发现与AI协作的体验发生了质变。你不再是一个事无巨细的“监工”,而是一个设定目标的“产品经理”。AI则变成了一个能自我驱动、自我验证的“高级工程师”。这,才是我们使用AI辅助编程的真正魅力所在。
9. 9. 自定义:合并项目专属规则与调试技巧
好的,我们开始学习第九章。这一章非常重要,因为它教你如何让这套编码原则真正为你所用,而不是一个死板的模板。
第9章:自定义:合并项目专属规则与调试技巧
到目前为止,你已经成功地将 Karpathy 的四大编码原则(先思考、求简洁、精准改、目标驱动)注入到了你的 AI 助手中。这很棒,你的代码质量应该已经有了肉眼可见的提升。但是,你有没有想过一个问题:每个项目都有自己的“脾气秉性”。比如,你的项目可能强制使用 TypeScript 的严格模式,或者规定所有 API 端点都必须有测试,又或者你们团队有自己独特的错误处理方式。
如果 AI 助手不了解这些“项目专属规则”,它仍然可能写出风格不符、甚至违反团队规范的代码。这一章,我们就要来解决这个问题:如何把你项目的专属规则,和 Karpathy 的通用原则无缝地合并在一起,打造一个真正为你项目量身定制的 AI 编码助手。同时,我们也会学习一些调试技巧,当 AI 的行为不符合预期时,知道如何排查和修正。
前置条件
在开始之前,请确保你已经完成了以下步骤之一:
- 第2章:在 Claude Code 中成功安装了插件。
- 第3章:在你的项目根目录下成功创建或修改了
CLAUDE.md文件。 - 第4章:在 Cursor 中成功配置了规则文件。
简单来说,你的 AI 助手已经能遵循 Karpathy 的四大原则了。我们现在要做的,就是在此基础上“加料”。
第一步:理解“合并”的含义
你可能会好奇,为什么是“合并”,而不是“替换”?
想象一下,Karpathy 的原则就像是一套通用的“礼仪规范”,告诉 AI 在任何项目中都应该“先思考再动手”、“保持简洁”。而你的项目规则,则像是“家规”,比如“进门要换鞋”、“晚上10点后不能大声喧哗”。
AI 需要同时遵守“礼仪规范”和“家规”。所以,我们不能用“家规”覆盖掉“礼仪规范”,而是要把它们放在一起,让 AI 同时参考。
不做会怎样? 如果你只放了项目规则,AI 可能会忘记“先思考”和“求简洁”,重新变得鲁莽和过度设计。如果你只放了 Karpathy 的原则,AI 可能会写出符合原则但不符合你项目技术栈或团队习惯的代码。
第二步:在 Claude Code 中合并规则(如果你用的是插件)
如果你是通过第2章的插件方式安装的,操作非常简单。插件已经为你注入了 Karpathy 的原则,你只需要在项目的 CLAUDE.md 文件中添加你的专属规则即可。
打开或创建
CLAUDE.md:在你的项目根目录下,找到或创建一个名为CLAUDE.md的文件。添加项目专属规则:在文件的末尾,或者单独用一个章节,写下你的规则。格式可以很自由,用 Markdown 列表或段落写清楚就行。我们来看一个例子:
## Project-Specific Guidelines - **Language & Framework**: This is a Python 3.11 project using FastAPI. - **Type Hints**: All functions must have complete type hints. Use `from __future__ import annotations` at the top of every file. - **Testing**: Every new endpoint must have corresponding unit tests and integration tests in the `tests/` directory. Use `pytest` and `httpx` for async testing. - **Error Handling**: Use the custom `AppException` class defined in `app/exceptions.py`. Do not raise generic `Exception` or `HTTPException` directly. - **Database**: All database queries must use the repository pattern (see `app/repositories/`). Raw SQL is not allowed. - **Logging**: Use the project's structured logger (`from app.logging import logger`). Do not use `print()`.预期结果:现在,当你在这个项目目录下使用 Claude Code 时,AI 助手会同时读取插件注入的 Karpathy 原则和你刚刚写的项目规则。它会先思考(原则一),然后写出简洁(原则二)且符合你项目规范的代码。比如,它不会再问“要用什么测试框架?”,而是直接使用
pytest。
第三步:在 Cursor 中合并规则(如果你用的是 Cursor)
如果你用的是 Cursor,操作也类似,但文件位置和格式稍有不同。
找到规则文件:在项目根目录下,找到
.cursor/rules/文件夹。如果你按照第4章的指引操作,里面应该已经有了一个karpathy-guidelines.mdc文件。创建或修改项目规则文件:你可以选择两种方式:
- 方式A(推荐):创建一个新的
.mdc文件,比如project-rules.mdc,专门放你的项目规则。然后在karpathy-guidelines.mdc文件的globs字段中,确保它适用于你的项目(通常是*或你的主要代码目录)。Cursor 会自动合并同一个globs下的所有规则。 - 方式B:直接在你的
karpathy-guidelines.mdc文件末尾追加项目规则。
我们来看看方式A怎么做。创建一个新文件
.cursor/rules/project-rules.mdc,内容如下:--- description: Project-specific coding conventions for the MyApp project globs: src/**/*.ts, tests/**/*.ts --- # MyApp Project Rules - Use TypeScript in strict mode. Set `"strict": true` in `tsconfig.json`. - All API endpoints must be defined in `src/routes/` and use the `createRouter` helper. - Use the `zod` library for request validation. Define schemas in `src/schemas/`. - Follow the existing error handling pattern: throw `ApiError` from `src/utils/errors.ts`. - Component names must be in PascalCase. File names must be in kebab-case.- 方式A(推荐):创建一个新的
预期结果:现在,当你在 Cursor 中编辑
src/或tests/目录下的文件时,AI 助手会同时应用 Karpathy 原则和你的项目规则。它写出的 TypeScript 代码会是严格模式的,并且会使用zod进行验证,而不是自己发明一套。
第四步:调试技巧——当 AI 不听话时
即使你写好了规则,AI 有时也可能“犯糊涂”。别担心,这很正常。我们可以通过一些技巧来调试和修正。
常见问题1:AI 忽略了你的项目规则。
- 排查方法:检查你的规则是否足够清晰、具体。避免使用模糊的词语,比如“尽量”、“最好”。用“必须”、“禁止”、“使用 X 而不是 Y”这样的明确指令。
- 实用技巧:在对话中明确引用你的规则。比如,你可以说:“根据
CLAUDE.md中的项目规则,请使用pytest来编写这个测试。” 这能帮助 AI 定位到正确的上下文。 - 报错示例:AI 写了一个
print()语句。你可以回复:“项目规则要求使用结构化日志from app.logging import logger,请修改。”
常见问题2:AI 在“先思考”阶段提出了一个很好的计划,但执行时却跑偏了。
- 排查方法:这通常是因为“目标驱动”原则没有被严格执行。AI 可能只记住了“要做什么”,但忘记了“做到什么程度才算成功”。
- 实用技巧:在 AI 提出计划后,你可以追问:“好的,计划很清晰。那么对于第一步,我们如何验证它是否成功?请给出具体的验证标准。” 这能强制 AI 将计划与可验证的目标绑定。
- 报错示例:AI 说“第一步:添加用户输入验证”。你可以说:“请先写出验证成功的标准,比如‘当用户输入为空字符串时,函数应返回一个包含错误信息的 Result 对象’,然后再开始编码。”
常见问题3:AI 修改了你不希望它修改的代码(违反了“精准改”原则)。
- 排查方法:检查你的请求是否足够精确。如果你说“优化这个函数”,AI 可能会认为“优化”意味着可以重写整个模块。
- 实用技巧:使用更精确的指令。不要说“优化”,而是说“请只修改
calculateTotal函数内部的循环逻辑,将其改为列表推导式,不要改动函数签名、注释或其他任何代码。” - 报错示例:你让 AI 修复一个 bug,结果它把整个文件的格式都改了。你可以立即回滚,并重新下达指令:“请只修改第 15 行的条件判断,将
==改为is。不要改动任何其他代码,包括空格和注释。”
一个完整的例子:从头开始
让我们把这一切串起来,看一个贴近真实场景的例子。
场景:你有一个 Python 项目,使用 Flask 框架和 SQLAlchemy ORM。你希望 AI 助手帮你添加一个“创建用户”的 API 端点。
你的 CLAUDE.md(或 Cursor 规则文件)内容如下:
# Karpathy Guidelines (由插件或规则文件提供)
... (四大原则的完整内容) ...
## Project-Specific Guidelines
- **Framework**: Flask 2.3, SQLAlchemy 2.0
- **Code Style**: Use `black` formatter. All functions must have type hints.
- **Database**: Use SQLAlchemy's declarative base. All queries must go through the `db.session`.
- **API Design**: Use Flask blueprints. All endpoints must return JSON. Use `@blueprint.route()` decorator.
- **Error Handling**: Return a JSON response with `{"error": "message"}` and appropriate HTTP status code.
- **Testing**: Use `pytest` and the `app.test_client()` fixture.你的请求:“请为我的 Flask 应用添加一个 POST /api/users 端点,用于创建新用户。用户需要提供 username 和 email。”
AI 助手的理想行为(遵循了所有规则):
先思考:AI 会先列出计划。
“好的,我来规划一下。首先,我们需要在
users蓝图下添加一个新路由。接着,我会创建一个 Pydantic 模型来验证请求体。然后,编写 SQLAlchemy 代码将用户存入数据库。最后,我会建议编写一个测试来验证这个端点。您看这个计划可以吗?”求简洁:AI 不会创建一个复杂的“用户服务层”或“用户工厂”,而是直接在蓝图文件中添加必要的代码,保持最小改动。
精准改:AI 只会修改
routes/users.py文件(假设蓝图在那里),而不会去动models.py或config.py中不相关的部分。目标驱动:在写完代码后,AI 会说:“端点已添加。为了验证它是否工作,请运行
pytest tests/test_users.py -k test_create_user来执行我建议的测试用例。”
如果 AI 没有遵循规则,你的调试步骤:
- 如果 AI 用了
print()调试:回复:“请使用app.logger.info()而不是print(),这是项目规则。” - 如果 AI 直接返回了 HTML:回复:“项目规则要求所有端点返回 JSON,请修改
return语句。” - 如果 AI 试图修改
models.py中的表结构:回复:“请只修改routes/users.py文件。models.py中的 User 模型已经定义好了,不需要改动。”
通过这种方式,你就能将通用的编码原则和项目的具体需求完美结合,让 AI 助手成为一个真正懂你项目、遵守你团队规范的得力伙伴。
10. 10. 验证效果:如何判断原则正在生效
好的,我们开始学习最后一章。这一章非常重要,因为它关系到你之前付出的所有努力——如果你不知道如何判断原则是否生效,那你就无法确认自己是否真的在进步,也无法在团队中推广这套方法。
第10章:验证效果:如何判断原则正在生效
经过前面几章的学习和配置,你已经把“先思考、求简洁、精准改、目标驱动”这四条原则注入到了你的 AI 助手里。现在,你可能会好奇:我怎么知道它真的在起作用?有没有什么具体的迹象可以观察?如果效果不明显,又该如何调整?
别担心,这一章就是来帮你解决这个问题的。我们会一起学习如何“观察” AI 的行为变化,以及如何通过一些简单的测试来验证原则是否生效。这就像给 AI 做一次“体检”,确保它按照我们期望的方式工作。
前置条件
在开始验证之前,请确保你已经完成了以下步骤之一:
- 通过 Claude Code 插件安装(第2章),或
- 手动将
CLAUDE.md添加到项目根目录(第3章),或 - 在 Cursor 中配置了项目规则(第4章)。
简单来说,就是你的 AI 助手已经“读过”了那四条原则。
第一步:观察“思考”环节——它开始提问了吗?
这是最直观、也最容易观察到的变化。在没有原则指导时,AI 收到一个模糊的需求,往往会直接开始写代码,而且经常猜错你的意图。现在,它应该会先停下来,向你提问。
怎么做: 找一个你项目中稍微有点模糊的任务,比如“优化一下用户登录的逻辑”。然后,像往常一样把任务交给 AI。
预期结果: 你不再会立刻看到大段的代码生成。相反,AI 会先输出类似这样的内容:
“在开始之前,我想先确认一下我的理解:您说的‘优化’具体是指提升性能、增强安全性,还是改善用户体验?另外,当前的登录逻辑是否有已知的瓶颈或问题?如果存在多种可能的优化方向,我会先列出它们,并请您选择最优先的一项。”
这意味着什么: 这说明“Think Before Coding”(先思考再动手)原则正在生效。AI 没有盲目假设,而是主动澄清需求、暴露不确定性。如果你看到这样的提问,恭喜你,第一步已经成功了。
如果没看到怎么办:
- 检查你的
CLAUDE.md或 Cursor 规则文件是否真的被加载了。可以给 AI 一个简单的测试指令:“请复述一下你的核心编码原则。”如果它回答得出来,说明规则生效了;如果它说“我没有被设置任何原则”,那就需要重新检查安装步骤。 - 你的任务描述可能太具体了,以至于 AI 觉得没有提问的必要。可以尝试一个更开放、更模糊的任务来测试。
第二步:检查“简洁性”——代码是否变短了?
这是验证“Simplicity First”(简洁优先)原则是否生效的关键。我们来看看 AI 生成的代码是否还像以前那样“过度设计”。
怎么做: 找一个你以前让 AI 写过的小功能,比如“读取一个 CSV 文件并返回前 10 行数据”。现在,重新让 AI 实现这个功能。
预期结果:
你可能会看到类似这样的代码,而不是一个包含 DataProcessor 类、FileReader 接口和 ConfigurableParser 工厂模式的庞然大物。
import csv
def read_first_10_rows(filepath):
"""读取 CSV 文件的前 10 行数据。"""
with open(filepath, 'r', newline='') as file:
reader = csv.reader(file)
# 读取前 10 行
rows = []
for i, row in enumerate(reader):
if i >= 10:
break
rows.append(row)
return rows这意味着什么: 代码非常直接,没有多余的抽象,没有为“未来可能的需求”预留的扩展点。它只做了你要求它做的事。这就是“Simplicity First”的体现。如果 AI 给出的代码依然很复杂,你可以直接引用原则来纠正它:“请遵循简洁优先原则,移除所有不必要的抽象和灵活性。”
第三步:审查“改动范围”——它有没有乱改别的东西?
这是验证“Surgical Changes”(精准改动)原则最有效的方法。你需要对比 AI 修改前后的代码差异(diff)。
怎么做: 找一个你项目里已有的函数,让 AI 在里面添加一个简单的日志输出,比如“在函数开始时打印一条消息”。然后,仔细审查它生成的代码 diff。
预期结果: 你看到的 diff 应该非常干净,只包含你要求的那几行改动。例如:
def calculate_total(prices):
+ print("开始计算总价...")
total = sum(prices)
return total这意味着什么: AI 没有“顺手”帮你重命名变量、没有“好心”帮你重构旁边的代码、没有删除或修改你原有的注释。它只动了它该动的地方。如果你看到 diff 里出现了大量无关的格式化调整、变量重命名、或者删除了你认为有用的注释,那就说明“Surgical Changes”原则没有被很好地遵守。
如果没看到怎么办:
- 你可以直接提醒 AI:“请记住‘精准改动’原则,只修改与任务直接相关的代码,不要改动任何其他内容。”
- 检查你的任务描述是否足够精确。如果你说“优化这个函数”,AI 可能会认为“优化”意味着全面重构。尽量使用“添加”、“修改”、“删除”这类精确的动词。
第四步:验证“目标驱动”——它是否先写测试再写代码?
这是“Goal-Driven Execution”(目标驱动)原则的核心体现。我们来看看 AI 是否真的理解了“先定义成功标准,再动手实现”的理念。
怎么做: 给 AI 一个带有明确错误场景的任务,比如“修复一个在输入为空列表时会崩溃的函数”。不要告诉它如何修复,只描述症状。
预期结果: AI 可能会先写出一个测试用例来复现这个 bug,然后再去修复代码。例如:
“好的,我先写一个测试来复现这个 bug,确保我们理解了问题,然后修复它,最后让测试通过。”
接着,它会生成类似这样的测试和修复代码:
# 测试用例
def test_calculate_total_with_empty_list():
assert calculate_total([]) == 0 # 期望返回 0,而不是崩溃
# 修复后的函数
def calculate_total(prices):
if not prices:
return 0
total = sum(prices)
return total这意味着什么: AI 没有直接猜测修复方案,而是先定义了一个可验证的目标(测试通过),然后才动手。这大大降低了“修好一个 bug 又引入新 bug”的风险。如果你看到 AI 直接给出了修复代码而没有测试,你可以引导它:“请遵循目标驱动原则,先写一个能复现 bug 的测试,然后再修复。”
一个综合性的“体检”小例子
为了让你更直观地感受,我们用一个完整的例子来串起以上所有观察点。
任务: “帮我写一个函数,它能从一个文本文件中读取所有不重复的单词,并按字母顺序排序后返回。”
理想中的 AI 响应流程:
- 提问(先思考): “好的,在开始之前,我想确认一下:单词的定义是什么?是否只包含字母?标点符号需要处理吗?比如‘hello!’中的‘hello’应该算作‘hello’还是‘hello!’?另外,文件可能很大吗?我们需要考虑内存限制吗?”
- 给出计划(目标驱动): “我的计划是:1. 先写一个简单的测试,用一个小文件验证功能正确性。2. 实现函数。3. 运行测试确保通过。您看这个计划可以吗?”
- 生成简洁代码(简洁优先):
import re def get_sorted_unique_words(filepath): """从文件中读取不重复的单词,按字母排序后返回列表。""" with open(filepath, 'r') as file: text = file.read() # 使用正则表达式提取所有由字母组成的单词,并转为小写 words = re.findall(r'\b[a-zA-Z]+\b', text.lower()) # 去重并排序 unique_sorted_words = sorted(set(words)) return unique_sorted_words - 只改该改的(精准改动): 如果这是在一个已有项目里添加新文件,它不会去修改其他任何文件。
通过观察以上四个步骤,你就能清晰地判断出原则是否正在生效。记住,这不是一个“全有或全无”的事情。一开始,AI 可能只表现出部分原则,比如开始提问了,但代码依然有点复杂。这很正常,你可以通过持续地提醒和纠正,让它逐渐适应你的要求。
实用技巧: 你可以创建一个“验证清单”,每次完成一个任务后,对照这四点快速检查一下。久而久之,这就会变成你的本能反应。
常見問題
问题 1:安装时提示 /plugin marketplace add 命令找不到怎么办?
这个命令需要在 Claude Code 终端 中执行,而不是在你的系统终端(如 bash、zsh)中。请确保:
- 你已经安装了 Claude Code(通过
npm install -g @anthropic-ai/claude-code或类似方式)。 - 在终端输入
claude进入 Claude Code 交互环境。 - 在 Claude Code 的提示符下输入
/plugin marketplace add forrestchang/andrej-karpathy-skills。
如果仍然不行,可以直接使用 Option B 手动下载 CLAUDE.md 文件到项目根目录。
问题 2:安装后 Claude Code 的行为没有任何变化,怎么办?
最常见的原因是 CLAUDE.md 文件没有被正确加载。请检查:
- 文件必须命名为
CLAUDE.md(注意大小写),且位于项目根目录。 - 如果你使用的是 Option A 插件方式,确保插件已启用:在 Claude Code 中运行
/plugin list查看状态。 - 如果你使用的是 Option B,确保文件内容完整(约 200 行),没有因为
curl失败而截断。
验证方法:在 Claude Code 中问一个模糊的问题(如“帮我优化这个函数”),如果它开始反问“你的具体目标是什么?”,说明规则已生效。
问题 3:这些规则和 Claude Code 自带的系统提示冲突吗?
不冲突。CLAUDE.md 是 Claude Code 原生支持的项目级指令文件,它会附加到系统提示中,而不是覆盖。这些规则专门针对 Karpathy 提到的 LLM 编码陷阱(如过度复杂化、不检查假设),与 Claude Code 的基础能力互补。
如果你有自己的项目规则(如“使用 TypeScript strict mode”),可以合并到同一个 CLAUDE.md 中,规则会叠加生效。
问题 4:在 Cursor 中如何使用这套规则?
本项目已包含 Cursor 规则文件 .cursor/rules/karpathy-guidelines.mdc。在 Cursor 中打开项目时会自动生效。如果你想在其他 Cursor 项目中使用:
- 复制
.cursor/rules/karpathy-guidelines.mdc到目标项目的.cursor/rules/目录。 - 或者参考 CURSOR.md 中的详细说明。
注意:Cursor 和 Claude Code 的规则是独立的,需要分别配置。
问题 5:规则说“不要删除无关的死代码”,但我的修改产生了未使用的变量,该删吗?
删。规则明确区分了两类情况:
- 你的修改导致的孤儿代码(如你删除了某个函数调用,导致导入的变量不再使用)→ 必须清理。
- 项目中已有的死代码(与你本次修改无关)→ 不要删除,可以提一句但不要动手。
判断标准:每一行改动都应该能直接追溯到你的任务需求。
问题 6:这套规则和 GitHub Copilot / Cursor 的 Agent 模式比,有什么不同?
| 维度 | 本规则 (Karpathy Skills) | Copilot / Cursor Agent |
|---|---|---|
| 核心哲学 | 先思考、后编码、最小改动 | 快速生成、迭代修改 |
| 对模糊需求的处理 | 主动提问、列出多种解释 | 通常直接选一种实现 |
| 代码复杂度控制 | 强制简化,反对过度抽象 | 容易生成过度工程化的代码 |
| 适用场景 | 需要严谨、可维护的代码 | 快速原型、简单任务 |
简单说:这套规则更适合生产级代码和复杂重构,Copilot 更适合快速探索。两者可以互补使用。
问题 7:规则说“如果 200 行能写成 50 行,就重写”,但我的代码已经很简洁了,它还会乱改吗?
不会。规则的核心是“Simplicity First”(简洁优先),但前提是不改变原有功能。如果代码已经足够简洁,Claude Code 应该不会主动重写。如果它仍然过度修改,说明规则没有正确生效(见问题 2),或者你的任务描述不够明确。
你可以通过添加项目特定规则来进一步约束,例如:
## Project-Specific Guidelines
- 不要重构 `src/legacy/` 目录下的代码
- 保持现有注释风格不变问题 8:我用了这套规则后,Claude Code 变得太“啰嗦”了,总是问问题,怎么办?
这是设计如此——规则偏向“谨慎优先于速度”。对于简单任务(如修复拼写错误),你可以直接告诉它:
- “这是一个简单修复,不需要提问,直接改。”
- “不需要列出多种解释,按最常见的做法实现。”
规则本身也允许你覆盖:在任务描述中明确说“直接做,不要问”,Claude Code 会优先遵循你的指令。如果它仍然过度提问,说明规则中的“Think Before Coding”部分过于严格,你可以考虑在项目规则中弱化这一条。