编程 Andrej Karpathy Skills 深度实战:当 149K Star 的 AI 编程四原则遇见 Claude Code——从提示词工程到生产级 AI 协作规范的完全指南(2026)

2026-06-15 16:18:39 +0800 CST views 32

Andrej Karpathy Skills 深度实战:当 149K Star 的 AI 编程四原则遇见 Claude Code——从提示词工程到生产级 AI 协作规范的完全指南(2026)

作者按:2026 年初,前 Tesla AI 总监、OpenAI 创始成员 Andrej Karpathy 在 X 上发了一条推文,吐槽 LLM 编程助手的各种失败模式。短短几个月后,这条吐槽演变成 GitHub 上 149K+ Stars 的开源项目 andrej-karpathy-skills。这不是框架,不是模型,而是一份仅仅数百行的 CLAUDE.md 文件——但它却重新定义了 AI 编程的"纪律"。

目录

  1. 背景:当 AI 编程从"玩具"走向"生产"
  2. Karpathy 的观察:LLM 编程的四大失败模式
  3. 四大原则深度解析
  4. 架构分析:CLAUDE.md 如何工作
  5. 代码实战:从错误示范到正确实践
  6. 跨工具适配:Claude Code、Cursor、Codex 统一配置
  7. 生产级最佳实践
  8. 进阶:从静态规则到动态学习
  9. 与其他 AI 编程工具的对比
  10. 总结与展望:AI 编程的"纪律革命"

1. 背景:当 AI 编程从"玩具"走向"生产"

1.1 2026 年的 AI 编程现状

2026 年,AI 编程已经从"辅助补全"进化到"自主编码"。根据 Stack Overflow 2026 开发者调查:

  • 46% 的开发者日常使用 AI 编程工具(Claude Code、Cursor、GitHub Copilot 等)
  • 但仅有 33% 信任 AI 输出的准确性,低于不信的 46%
  • 80% 的开发者表示曾因 AI 生成的代码过度复杂而不得不手动重构

这个数据揭示了一个核心矛盾:AI 能写代码,但写出来的代码往往"不太对劲"——不是语法错误,而是工程判断上的问题。

1.2 Karpathy 的"顿悟时刻"

2026 年 2 月,Andrej Karpathy 在 X 上分享了自己的编程习惯变化:

"短短几周内,我从 80% 手写代码、20% 用 agent,切换到了 80% agent coding、20% 手动修补。"

但紧接着,他列出了一连串"但是":

  1. 模型会替你做错误假设,然后不检查、不澄清,直接执行
  2. 它们不会管理自己的"困惑",很少主动说"这里我不确定"
  3. 它们特别喜欢过度复杂化,100 行能解决的问题写成 1000 行
  4. 它们会顺手改掉无关的代码,引发意外故障

这四条观察,后来成为了 andrej-karpathy-skills 项目的核心。

1.3 为什么一份 Markdown 文件能获 149K Stars?

andrej-karpathy-skills 项目的核心只有一个文件:CLAUDE.md(约 200 行)。它没有:

  • ❌ 复杂的框架代码
  • ❌ 新的编程语言
  • ❌ 高大上的算法

但它有一样东西:把"隐性经验"转化为"可执行规则"的能力

在 AI 编程时代,提示词就是配置,配置就是行为约束。一份好的 CLAUDE.md 就像给 AI 装上"工程缰绳",让它从"乱闯的马"变成"驯服的工马"。


2. Karpathy 的观察:LLM 编程的四大失败模式

在深入四大原则之前,我们需要先理解:LLM 为什么会犯这些错误?

2.1 失败模式一:过度自信(Overconfidence Bias)

表现

# 用户需求:"帮我添加一个用户登录功能"

# AI 的输出(错误示范):
import jwt
from datetime import datetime, timedelta
from functools import wraps

def create_jwt_token(user_id, secret_key, algorithm='HS256'):
    payload = {
        'user_id': user_id,
        'exp': datetime.utcnow() + timedelta(hours=24),
        'iat': datetime.utcnow()
    }
    return jwt.encode(payload, secret_key, algorithm)

# ... 又在 500 行代码后 ...
# 问题:AI 没有问你:
# - 用什么认证方案?(JWT? Session? OAuth?)
# - 需要支持哪些功能?(刷新 token? 撤销? 多设备?)
# - 有什么现有技术栈?(已有权限系统?)

根源

  • LLM 的训练目标是"生成看起来合理的文本",而不是"生成正确的代码"
  • 它倾向于选择一个"合理"的解释,然后自信地执行下去
  • 它不知道自己不知道什么(unknown unknowns)

2.2 失败模式二:过度工程化(Over-engineering)

表现

// 用户需求:"写一个简单的配置读取函数"

// AI 的输出(错误示范):
interface ConfigValue {
  type: 'string' | 'number' | 'boolean' | 'array' | 'object';
  value: any;
  validator?: (value: any) => boolean;
  transformer?: (value: any) => any;
  fallback?: ConfigValue;
}

abstract class ConfigProvider {
  abstract get(key: string): Promise<ConfigValue>;
  abstract set(key: string, value: ConfigValue): Promise<void>;
}

class EnvironmentConfigProvider implements ConfigProvider {
  // ... 200 行代码 ...
}

class FileConfigProvider implements ConfigProvider {
  // ... 300 行代码 ...
}

// 问题:用户只是想要 const port = process.env.PORT || 3000

根源

  • LLM 在大量"优秀代码"上训练,这些代码往往包含设计模式、抽象层、扩展性考虑
  • 它试图"预测你的下一步需求",提前做好"架构准备"
  • 它把"可能用到"当成"现在需要"

2.3 失败模式三:侧面伤害(Side Effects)

表现

// 用户需求:"修复 src/auth.js 中的 token 验证逻辑"

// AI 的改动(错误示范):
// src/auth.js - 改了 5 行(正确)
// src/utils/helpers.js - "顺手"重构了 50 行(无关)
// src/index.js - "优化"了导入顺序(破坏构建)
// README.md - 更新了过时的文档(引入错误)

// 问题:AI 没有只改该改的,而是"顺便"改了一堆东西

根源

  • LLM 的上下文窗口让它"看到"整个项目
  • 它倾向于"改进"它看到的一切"不完美"的代码
  • 它缺乏"改动边界"的意识

2.4 失败模式四:目标模糊(Vague Objectives)

表现

# 用户命令:"优化数据库查询"

# AI 的输出(错误示范):
# 1. 添加了索引(可能正确)
# 2. 引入了 Redis 缓存(可能过度)
# 3. 重写了 ORM 为原生 SQL(可能破坏可维护性)
# 4. 没有写测试(不知道什么叫"优化成功")

# 问题:没有可验证的成功标准,AI 只能"尽力而为"

根源

  • LLM 是"指令跟随者",而不是"目标求解者"
  • 模糊的指令导致模糊的输出
  • 没有验证循环,就无法自主迭代

3. 四大原则深度解析

现在,让我们逐一深度解析 Karpathy Skills 的四大原则。这四大原则不是"建议",而是"约束"——它们通过 CLAUDE.md 文件直接注入到 AI 的系统提示词中。

3.1 Think Before Coding:先思考,再编码

3.1.1 核心思想

Don't assume. Don't hide confusion. Surface tradeoffs.
(不要假设。不要隐藏困惑。呈现权衡。)

这条原则针对的是 "盲目执行" 问题。LLM 的默认行为是:

  1. 接收指令
  2. 选择一个理解(往往是隐式的)
  3. 立即生成代码

Think Before Coding 强制插入一个"推理步骤"

用户指令 → [强制推理] → 澄清问题(如有) → 多种方案(如有) → 代码生成

3.1.2 具体要求(可执行检查项)

根据 CLAUDE.md 的规定,AI 必须:

要求错误示范正确示范
明确陈述假设直接写代码"我假设你需要 JWT 认证,对吗?"
呈现多种解读默默选一个方案"这里有 3 种实现方式,各有优劣..."
该反驳就反驳盲目执行"你要求 X,但 Y 可能更简单,建议考虑"
困惑时止步猜一个答案"我不清楚你的数据库架构,能说明吗?"

3.1.3 实例对比

场景:用户说"添加用户验证"

没有 Think Before Coding

用户: "添加用户验证功能"
Claude: [立即生成 500 行代码]

有 Think Before Coding

用户: "添加用户验证功能"

Claude:
我的理解是:
- 对所有 API 端点添加 JWT 验证
- 使用现有的 auth 中间件
- 公开端点(登录、注册)不需要验证

这个理解对吗?还是你想要:
A) 只验证特定路由(需要你指定)
B) 使用 Session 而不是 JWT
C) 其他方案?

另外,我需要确认:
1. 你的项目使用什么 Web 框架?(Express? Koa? Fastify?)
2. 是否已有用户模型?还是需要从头创建?
3. 需要支持token刷新吗?

请澄清这些问题,我再开始实现。

差异分析

  • 错误示范:AI 做了 10 个假设,可能 5 个都是错的
  • 正确示范:AI 明确说出假设,让用户确认,避免返工

3.1.4 实现原理:为什么这能工作?

这背后的机制是 "元认知触发"(Metacognitive Trigger):

  1. 显式推理占用 Token → AI 的"注意力"被强制分配到推理过程
  2. 输出假设 = 承诺 → 一旦 AI 说出假设,它会更谨慎地验证
  3. 多种方案 = 探索 → 强制 AI 考虑多个可能性,而不是贪婪选择

类比例子

  • 就像一个新手程序员,你让他"直接写代码",他会闷头写
  • 但如果你要求他"先写伪代码,说明思路",他会自然思考边界情况

3.2 Simplicity First:简约至上

3.2.1 核心思想

Minimum code that solves the problem. Nothing speculative.
(用最少的代码解决问题。不做投机性开发。)

这条原则针对的是 "过度工程化" 问题。LLM 训练的 codebase 往往包含:

  • 设计模式(Factory、Strategy、Observer...)
  • 抽象层(Interface、Abstract Class、Adapter...)
  • 扩展性考虑(Plugin System、Middleware、Hooks...)

Simplicity First 强制 AI 问自己:"这段代码真的需要吗?"

3.2.2 具体规则(可验证标准)

CLAUDE.md 规定了以下"禁令":

禁令解释检验标准
No features beyond what was asked不添加未被要求的功能每一行代码都能追溯到用户请求
No abstractions for single-use code不为单次使用的代码创建抽象如果抽象只被用一次,删除它
No "flexibility" or "configurability" that wasn't requested不添加未被请求的"灵活性"如果用户在 3 个月内不会改这个配置,就不要做
No error handling for impossible scenarios不为不可能的场景写错误处理如果输入已经被 TypeScript 类型保证,就不要运行时检查

3.2.3 实例对比

场景:写一个函数,读取 JSON 配置文件

没有 Simplicity First

// AI 生成(过度工程化)
interface ConfigLoaderOptions {
  filePath: string;
  encoding?: BufferEncoding;
  validator?: (config: any) => boolean;
  cache?: boolean;
  watch?: boolean;
  fallback?: Record<string, any>;
}

class ConfigLoader {
  private cache: Map<string, any>;
  private watchers: Map<string, FSWatcher>;
  
  constructor(private options: ConfigLoaderOptions) {
    this.cache = new Map();
    this.watchers = new Map();
  }
  
  async load<T = any>(): Promise<T> {
    if (this.options.cache && this.cache.has(this.options.filePath)) {
      return this.cache.get(this.options.filePath);
    }
    
    const content = await fs.promises.readFile(
      this.options.filePath,
      this.options.encoding || 'utf-8'
    );
    
    const config = JSON.parse(content);
    
    if (this.options.validator && !this.options.validator(config)) {
      throw new Error('Config validation failed');
    }
    
    if (this.options.cache) {
      this.cache.set(this.options.filePath, config);
    }
    
    if (this.options.watch) {
      this.setupWatcher();
    }
    
    return config;
  }
  
  private setupWatcher() {
    // ... 50 行代码 ...
  }
  
  // ... 更多方法 ...
}

export default ConfigLoader;

问题

  • 用户只是想要 const config = JSON.parse(fs.readFileSync('config.json', 'utf-8'))
  • AI 添加了缓存、文件监控、验证器、抽象类——这些都可能用不上

有 Simplicity First

// AI 生成(简约版)
import fs from 'fs';
import path from 'path';

export function loadConfig<T = any>(filePath: string): T {
  const fullPath = path.resolve(filePath);
  const content = fs.readFileSync(fullPath, 'utf-8');
  return JSON.parse(content);
}

// 如果用户后来真的需要验证,再加一行:
// export function loadConfig<T = any>(filePath: string, validator?: (config: any) => config is T): T {
//   const config = ...;
//   if (validator && !validator(config)) throw new Error('Invalid config');
//   return config;
// }

差异分析

  • 错误示范:200 行代码,其中 180 行可能永远不会被执行
  • 正确示范:6 行代码,解决当前问题,未来需要时可以扩展

3.2.4 实现原理:为什么 AI 喜欢过度复杂化?

这背后的原因是 "模式匹配偏差"(Pattern Matching Bias):

  1. 训练数据偏见:LLM 在 GitHub 上训练,而 GitHub 上的代码往往是"生产级"的,包含大量工程实践
  2. 长度偏见:人类评估 AI 代码时,往往觉得"越长的代码越厉害"
  3. 完整性幻觉:AI 试图"预测你的所有需求",而不是"解决当前问题"

Simplicity First 的作用机制

  • 通过明确的"禁令",打破 AI 的默认行为模式
  • 提供"检验标准"(资深工程师会怎么说?),让 AI 自我评估
  • 简约不是目标,而是约束——它强迫 AI 证明每一行代码的必要性

3.3 Surgical Changes:外科手术式变更

3.3.1 核心思想

Touch only what you must. Clean up only your own mess.
(只触碰必须触碰的代码。只清理自己造成的混乱。)

这条原则针对的是 "侧面伤害" 问题。LLM 在编辑代码时,往往会:

  1. "顺手"重构相邻代码
  2. "优化"代码格式
  3. 删除"看起来没用"的代码
  4. 更新文档(往往出错)

Surgical Changes 强制 AI 遵循"最小改动原则"

3.3.2 具体规则

规则解释实例
Don't "improve" adjacent code不"改进"相邻代码如果你在改 auth.js,不要顺手重构 utils.js
Don't refactor things that aren't broken不重构没坏的东西YAGNI(You Aren't Gonna Need It)
Match existing style匹配已有风格即使你更喜欢 2 空格缩进,如果项目用 4 空格,就跟着 4 空格
Mention, don't delete, pre-existing dead code提到但不删除已有死代码如果你发现死代码,告诉用户,但不要自己删

3.3.3 实例对比

场景:修复 src/auth.js 中的 token 验证 bug

没有 Surgical Changes

// 用户请求:"修复 src/auth.js 中的 token 过期检查"

// AI 的改动:
// src/auth.js (修复了 bug,但也...)
- function verifyToken(token) {
-   const decoded = jwt.verify(token, secret);
-   return decoded;
- }
+ function verifyToken(token, options = {}) {
+   const { ignoreExpiration = false } = options;
+   const decoded = jwt.verify(token, secret, {
+     ignoreExpiration
+   });
+   return decoded;
+ }

// ... 然后 AI "顺手"改了...
// src/utils/helpers.js (无关改动)
- export function formatError(err) {
-   return { error: err.message };
- }
+ export function formatError(err, includeStack = false) {
+   const result = { error: err.message };
+   if (includeStack && err.stack) {
+     result.stack = err.stack;
+   }
+   return result;
+ }

// src/index.js (破坏构建的改动)
- import { formatError } from './utils/helpers';
+ import { formatError, formatSuccess } from './utils/helpers';
  // 但 formatSuccess 不存在!

// README.md (错误的文档更新)
- ## API Endpoints
- - POST /login
+ ## API Endpoints (Updated 2026-06-15)
+ - POST /login (now with enhanced security)
  // 但没有说明"enhanced security"是什么

问题

  • 改动扩散:一个 bug 修复变成了 4 个文件的改动
  • 引入新 bug:格式化函数的签名变了,但调用方没更新
  • 破坏构建:导入了不存在的函数
  • 文档错误:README 说的和代码实际做的不一致

有 Surgical Changes

// 用户请求:"修复 src/auth.js 中的 token 过期检查"

// AI 的改动:
// src/auth.js (只改必须改的)
 function verifyToken(token) {
   try {
     const decoded = jwt.verify(token, secret);
     return decoded;
   } catch (err) {
+    if (err.name === 'TokenExpiredError') {
+      throw new Error('Token has expired');
+    }
     throw err;
   }
 }

// AI 的输出消息:
// "我只修改了 src/auth.js 中的 verifyToken 函数,添加了明确的过期错误提示。
//  我注意到项目中有一些死代码(src/utils/legacy.js),但没有改动它们。
//  如果需要,我可以单独提交一个 PR 清理死代码。"

差异分析

  • 错误示范:改动扩散,引入新 bug,破坏构建
  • 正确示范:改动精准,只修复 bug,提到其他问题但不擅自改动

3.3.4 实现原理:为什么 AI 会"顺手改东西"?

这背后的原因是 "完整性幻觉"(Completeness Illusion):

  1. 全局视野:LLM 能看到整个项目,它觉得"既然都看到了,不如一起改"
  2. 一致性驱动:AI 倾向于让代码"风格一致",即使这不必要
  3. 文档同步压力:AI 觉得改了代码就必须更新文档(但往往更新错)

Surgical Changes 的作用机制

  • 通过"检验标准"(每一行变更都应能追溯到用户请求),让 AI 自我审查
  • 明确区分"你的代码"和"别人的代码",建立"改动边界"意识
  • 改动隔离 = 更容易的 code review = 更少的 bug

3.4 Goal-Driven Execution:目标驱动执行

3.4.1 核心思想

Define success criteria. Loop until verified.
(定义成功标准。循环直至验证。)

这条原则针对的是 "模糊目标" 问题。LLM 擅长"指令跟随",但不擅长"目标求解"。

Goal-Driven Execution 强制将"命令式任务"转化为"可验证目标"

3.4.2 transformation 规则

命令式指令(错误)目标驱动指令(正确)
"添加验证""为无效输入写测试,然后让测试通过"
"修复 bug""写一个能复现 bug 的测试,然后让测试通过"
"重构 X""确保测试在重构前后都能通过"
"优化性能""让响应时间从 500ms 降到 100ms 以下"

3.4.3 实例对比

场景:优化数据库查询性能

没有 Goal-Driven Execution

用户: "优化 users 表的查询性能"

Claude:
[添加了索引]
[重写了查询]
[引入了缓存]
[... 3 小时后 ...]
"好了,我做了一些优化。"

用户: "你怎么知道优化好了?"
Claude: "呃... 我觉得应该快了..."

问题

  • 没有可验证的成功标准
  • AI "尽力而为",但不知道什么时候该停止
  • 可能过度优化,或优化错方向

有 Goal-Driven Execution

用户: "优化 users 表的查询性能"

Claude:
我的成功标准是:
1. 测量当前查询时间(基线)
2. 添加索引后,查询时间降低 50% 以上
3. 确保所有现有测试通过(没有破坏功能)
4. 提供 before/after 性能对比

这是我的计划:
1. [测量基线] → verify: 记录当前查询时间
2. [添加索引] → verify: 再次测量,确认提升 50%
3. [运行测试] → verify: 所有测试通过
4. [文档化] → verify: 在 PR 中附上性能对比

开始执行...

[步骤 1 完成]
测量基线:SELECT * FROM users WHERE email = ? 平均 450ms

[步骤 2 完成]
添加索引:CREATE INDEX idx_users_email ON users(email);
验证:查询时间降至 18ms(提升 96%)

[步骤 3 完成]
所有 127 个测试通过

[步骤 4 完成]
PR #123: "Optimized user lookup query (450ms → 18ms)"

目标达成!

差异分析

  • 错误示范:模糊目标 → 模糊输出 → 无法验证
  • 正确示范:明确目标 → 验证循环 → 可证明的结果

3.4.4 实现原理:为什么"目标驱动"比"指令驱动"更有效?

这背后的原因是 "强化学习机制"(Reinforcement Learning Mechanism):

  1. 明确奖励信号:可验证的目标 = 明确的奖励(测试通过 = +1,失败 = -1)
  2. 自主迭代:AI 可以"自己跟自己玩",直到达到目标
  3. 避免过早停止:模糊指令容易导致 AI "做了就停",目标驱动让它"达到标准才停"

Karpathy 的原话

"LLMs are exceptionally good at looping until they meet specific goals... Don't tell it what to do, give it success criteria and watch it go."
(LLM 非常擅长循环执行直到达到特定目标... 不要告诉它做什么,给它成功标准,然后看它跑。)


4. 架构分析:CLAUDE.md 如何工作

4.1 Claude Code 的配置层级

要理解 CLAUDE.md 如何工作,首先需要了解 Claude Code 的配置体系:

优先级(从低到高):
1. 企业级配置(/etc/claude-code/CLAUDE.md)[只读,强制]
2. 用户级配置(~/.claude/CLAUDE.md)[所有项目通用]
3. 项目级配置(./CLAUDE.md)[当前项目共享]
4. 本地项目级(./CLAUDE.local.md)[个人配置,不提交]
5. 子目录级(src/CLAUDE.md)[最精确,只对该目录生效]

andrej-karpathy-skills 安装的位置

  • 推荐:项目级配置(./CLAUDE.md
  • 可选:用户级配置(~/.claude/CLAUDE.md),对所有项目生效

4.2 CLAUDE.md 的加载机制

当 Claude Code 启动时,它会:

  1. 扫描配置层级:从低优先级到高优先级
  2. 合并配置:将所有 CLAUDE.md 的内容合并
  3. 注入系统提示词:合并后的内容成为系统提示词的一部分
  4. 优先级处理:如果规则冲突,高优先级的配置覆盖低优先级

关键点CLAUDE.md 不是"脚本",而是"行为约束"——它通过改变系统提示词来改变 AI 的行为。

4.3 andrej-karpathy-skills 的文件结构

andrej-karpathy-skills/
├── CLAUDE.md              # 核心:四大原则的完整描述
├── .claude-plugin/        # Claude Code 插件元数据
├── .cursor/rules/        # Cursor IDE 规则适配
│   └── karpathy-guidelines.mdc
├── EXAMPLES.md            # 正反案例对照
└── README.md              # 使用文档

CLAUDE.md 的内容结构(精简版):

## 1. Think Before Coding
- 不确定时先问,不要擅自假设
- 多种理解要列出来,不要默默选一个
- 如果有更简单的方案,主动提出
- 困惑时就停,明确说哪里不清楚

## 2. Simplicity First
- 只写被要求的功能,拒绝过度抽象
- 200 行能写 50 行?重写
- 不添加"未来可能用到"的功能
- 检验标准:资深工程师会说这过度复杂吗?

## 3. Surgical Changes
- 没让改的地方别碰
- 不"顺手"重构相邻代码
- 匹配已有风格,即使你更喜欢另一种
- 发现死代码?提及它,但不要删

## 4. Goal-Driven Execution
- 定义成功标准,然后循环验证
- "添加验证" → "为无效输入写测试,然后让测试通过"
- 多步骤任务?先写计划,每步都要可验证

4.4 为什么 Markdown 文件能改变 AI 行为?

这背后的机制是 "上下文注入"(Context Injection):

  1. 系统提示词 = AI 的"性格":Claude Code 的系统提示词包含"你是谁"、"你应该怎么做"
  2. CLAUDE.md = 追加的"性格约束":通过追加内容,改变 AI 的行为模式
  3. Markdown 格式 = 人类可读 + AI 可解析:既能让人理解和编辑,也能被 AI 准确解析

类比

  • 就像一个员工入职时,你给他一本《员工手册》
  • 这本手册不会"强制"他做什么,但会改变他的行为预期
  • CLAUDE.md 就是 AI 的《员工手册》

5. 代码实战:从错误示范到正确实践

理论讲完了,现在让我们通过三个完整的实战案例,看看 andrej-karpathy-skills 如何在实际开发中改变 AI 的行为

5.1 实战一:添加用户认证功能

5.1.1 需求描述

用户请求:
"帮我添加一个用户登录功能。我的项目是用 Express + MongoDB 的。
现在用户注册后,密码是明文存储的,这肯定不行。"

5.1.2 ❌ 没有 Karpathy Skills(错误示范)

Claude 的输出

// auth.controller.js
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import { User } from '../models/User.js';

// 注册
export async function register(req, res) {
  const { email, password } = req.body;
  
  // 检查用户是否存在
  const existingUser = await User.findOne({ email });
  if (existingUser) {
    return res.status(400).json({ error: 'User already exists' });
  }
  
  // 加密密码
  const hashedPassword = await bcrypt.hash(password, 10);
  
  // 创建用户
  const user = new User({ email, password: hashedPassword });
  await user.save();
  
  // 生成 token
  const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, {
    expiresIn: '7d'
  });
  
  res.json({ token });
}

// 登录
export async function login(req, res) {
  const { email, password } = req.body;
  
  // 查找用户
  const user = await User.findOne({ email });
  if (!user) {
    return res.status(401).json({ error: 'Invalid credentials' });
  }
  
  // 验证密码
  const isValid = await bcrypt.compare(password, user.password);
  if (!isValid) {
    return res.status(401).json({ error: 'Invalid credentials' });
  }
  
  // 生成 token
  const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, {
    expiresIn: '7d'
  });
  
  res.json({ token });
}

// 顺便"优化"了一下其他文件...
// user.model.js - 添加了 refreshToken 字段(用户没要求)
// app.js - 添加了 helmet、cors、rate limiting(用户没要求)
// package.json - 添加了 10 个新依赖(用户没要求)

问题清单

  1. 过度工程化

    • 添加了 refreshToken(用户没要求)
    • 添加了 helmetcorsrate limiting(用户没要求)
    • 添加了 10 个新依赖(用户没要求)
  2. 侧面伤害

    • 改了 app.js(可能破坏现有配置)
    • 改了 user.model.js(可能破坏现有功能)
  3. 没有验证标准

    • "完成"的标准是什么?能登录就算完成?
    • 没有测试,不知道对不对

5.1.3 ✅ 有 Karpathy Skills(正确示范)

Claude 的输出

// 第一步:澄清问题(Think Before Coding)
"我注意到你需要添加用户登录功能。在开始之前,我需要澄清几个问题:

1. **认证方案**:
   - JWT(无状态,适合 API)
   - Session(有状态,适合传统 Web 应用)
   - OAuth(第三方登录)
   你的项目是 API 还是传统 Web 应用?

2. **密码存储**:
   - 你提到现在是明文,我会用 bcrypt 加密
   - 需要加盐次数配置吗?还是用 bcrypt 默认?

3. **额外功能**:
   - 需要邮箱验证吗?
   - 需要密码重置吗?
   - 需要 rate limiting 防止暴力破解吗?

4. **现有代码**:
   - 能给我看一下现在的用户模型吗?
   - 你的 Express 应用是怎么组织代码的?

请回答这些问题,我再开始实现。"

// 用户回答:
// "用 JWT 就行,最简单的实现。密码用 bcrypt。
//  不需要邮箱验证、密码重置。项目在 src/ 目录下,
//  用 MVC 结构。"

// 第二步:简约实现(Simplicity First)
// src/controllers/auth.controller.js
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import { User } from '../models/User.js';

const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key';

export async function register(req, res) {
  const { email, password } = req.body;
  
  if (!email || !password) {
    return res.status(400).json({ error: 'Email and password required' });
  }
  
  const existingUser = await User.findOne({ email });
  if (existingUser) {
    return res.status(400).json({ error: 'User already exists' });
  }
  
  const hashedPassword = await bcrypt.hash(password, 10);
  const user = new User({ email, password: hashedPassword });
  await user.save();
  
  const token = jwt.sign({ userId: user._id }, JWT_SECRET, { expiresIn: '7d' });
  res.status(201).json({ token });
}

export async function login(req, res) {
  const { email, password } = req.body;
  
  const user = await User.findOne({ email });
  if (!user) {
    return res.status(401).json({ error: 'Invalid credentials' });
  }
  
  const isValid = await bcrypt.compare(password, user.password);
  if (!isValid) {
    return res.status(401).json({ error: 'Invalid credentials' });
  }
  
  const token = jwt.sign({ userId: user._id }, JWT_SECRET, { expiresIn: '7d' });
  res.json({ token });
}

// 第三步:只改必须改的(Surgical Changes)
// 我只改了 2 个文件:
// - src/controllers/auth.controller.js(新建)
// - src/models/User.js(添加了 password 字段)
// 没有改动其他文件。

// 第四步:定义成功标准(Goal-Driven Execution)
"实现完成后,我会验证:
1. 注册接口:发送 POST /register,应该返回 token
2. 登录接口:发送 POST /login,应该返回 token
3. 错误场景:重复注册、错误密码,应该返回 400/401
4. 我会写测试来验证这些场景。

开始验证..."

// 测试代码(目标驱动)
// src/controllers/auth.controller.test.js
import { register, login } from './auth.controller.js';
import { User } from '../models/User.js';

describe('Auth Controller', () => {
  beforeEach(async () => {
    await User.deleteMany({});
  });
  
  test('register - should create user and return token', async () => {
    const req = { body: { email: 'test@example.com', password: 'password123' } };
    const res = { status: jest.fn().mockReturnThis(), json: jest.fn() };
    
    await register(req, res);
    
    expect(res.status).toHaveBeenCalledWith(201);
    expect(res.json).toHaveBeenCalledWith(
      expect.objectContaining({ token: expect.any(String) })
    );
  });
  
  test('login - should return token for valid credentials', async () => {
    // ... 测试代码 ...
  });
  
  test('login - should return 401 for invalid credentials', async () => {
    // ... 测试代码 ...
  });
});

// 运行测试
$ npm test
PASS  src/controllers/auth.controller.test.js
  ✓ register - should create user and return token (45ms)
  ✓ login - should return token for valid credentials (32ms)
  ✓ login - should return 401 for invalid credentials (28ms)

Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total

// 目标达成!

差异总结

维度没有 Karpathy Skills有 Karpathy Skills
代码行数500+ 行(含无关功能)80 行(刚好够用)
改动文件6 个(含侧面伤害)2 个(精准改动)
新依赖10 个2 个(bcrypt + jwt)
测试完整测试覆盖
可维护性低(过度工程化)高(简约清晰)

5.2 实战二:重构遗留代码

5.2.1 需求描述

用户请求:
"这段代码太乱了,帮我重构一下。
这是一个从外部 API 获取数据的函数,但现在耦合太严重,
我想把数据获取和数据处理分开。"

// src/services/weather.service.js
export async function getWeather(city) {
  const apiKey = process.env.API_KEY;
  const url = `https://api.weatherapi.com/v1/current.json?key=${apiKey}&q=${city}`;
  const response = await fetch(url);
  const data = await response.json();
  
  const result = {
    city: data.location.name,
    temperature: data.current.temp_c,
    condition: data.current.condition.text,
    humidity: data.current.humidity,
    windSpeed: data.current.wind_kph
  };
  
  // 保存到数据库
  await db.query(
    'INSERT INTO weather_logs (city, temperature, condition) VALUES (?, ?, ?)',
    [result.city, result.temperature, result.condition]
  );
  
  return result;
}

5.2.2 ❌ 没有 Karpathy Skills(错误示范)

Claude 的输出

// src/services/weather.service.js (完全重写)
import { WeatherAPIClient } from '../clients/WeatherAPIClient.js';
import { WeatherRepository } from '../repositories/WeatherRepository.js';
import { WeatherTransformer } from '../transformers/WeatherTransformer.js';
import { CacheManager } from '../utils/CacheManager.js';

export class WeatherService {
  constructor(
    private apiClient: WeatherAPIClient,
    private repository: WeatherRepository,
    private transformer: WeatherTransformer,
    private cacheManager: CacheManager
  ) {}
  
  async getWeather(city, options = {}) {
    const { useCache = true, saveToDb = true } = options;
    
    // 缓存检查
    if (useCache) {
      const cached = await this.cacheManager.get(`weather:${city}`);
      if (cached) return cached;
    }
    
    // 数据获取
    const rawData = await this.apiClient.fetchCurrentWeather(city);
    
    // 数据转换
    const weatherData = this.transformer.transform(rawData);
    
    // 缓存存储
    if (useCache) {
      await this.cacheManager.set(`weather:${city}`, weatherData, 300);
    }
    
    // 数据库存储
    if (saveToDb) {
      await this.repository.save(weatherData);
    }
    
    return weatherData;
  }
}

// ... 还创建了 5 个新文件 ...
// ../clients/WeatherAPIClient.js
// ../repositories/WeatherRepository.js
// ../transformers/WeatherTransformer.js
// ../utils/CacheManager.js
// ../interfaces/IWeatherService.js

// 问题:
// 1. 过度工程化:用户只是想要"分离关注点",不是"企业级架构"
// 2. 破坏了现有代码:所有调用 getWeather 的地方都要改
// 3. 引入了新 bug:CacheManager 没测试,可能内存泄漏

5.2.3 ✅ 有 Karpathy Skills(正确示范)

Claude 的输出

// 第一步:澄清需求(Think Before Coding)
"我理解你想要'分离关注点'。让我确认一下:

1. **分离方式**:
   - 方案 A:提取一个 `fetchWeatherData` 函数(只获取数据)
   - 方案 B:提取一个 `transformWeatherData` 函数(只转换数据)
   - 方案 C:两者都提取
   你倾向哪种?

2. **数据库存储**:
   - 这个函数需要继续保存 to 数据库吗?
   - 还是数据库存储也应该分离出去?

3. **兼容性**:
   - 重构后需要保持函数签名不变吗?(即 `getWeather(city)` 仍然返回同样的结果)
   - 还是可以改签名?

4. **测试**:
   - 现有代码有测试吗?
   - 重构后我需要写测试吗?

请澄清,我再开始重构。"

// 用户回答:
// "方案 C,两个都提取。数据库存储也分离出去。
//  函数签名可以改,改成 getWeather(city) 只返回数据,不保存 to DB。
//  没有测试,你需要写。"

// 第二步:简约重构(Simplicity First)
// 重构后的代码:

// src/services/weather.service.js
import { fetchWeatherData } from './weather-api.js';
import { transformWeatherData } from './weather-transformer.js';

export async function getWeather(city) {
  const rawData = await fetchWeatherData(city);
  return transformWeatherData(rawData);
}

// src/services/weather-api.js
export async function fetchWeatherData(city) {
  const apiKey = process.env.API_KEY;
  const url = `https://api.weatherapi.com/v1/current.json?key=${apiKey}&q=${city}`;
  const response = await fetch(url);
  
  if (!response.ok) {
    throw new Error(`Weather API error: ${response.statusText}`);
  }
  
  return response.json();
}

// src/services/weather-transformer.js
export function transformWeatherData(rawData) {
  return {
    city: rawData.location.name,
    temperature: rawData.current.temp_c,
    condition: rawData.current.condition.text,
    humidity: rawData.current.humidity,
    windSpeed: rawData.current.wind_kph
  };
}

// src/services/weather-repository.js (可选,用户没要求但提到"数据库存储也分离")
export async function saveWeatherLog(weatherData) {
  await db.query(
    'INSERT INTO weather_logs (city, temperature, condition) VALUES (?, ?, ?)',
    [weatherData.city, weatherData.temperature, weatherData.condition]
  );
}

// 第三步:只改必须改的(Surgical Changes)
// 改动文件清单:
// - src/services/weather.service.js (重构)
// - src/services/weather-api.js (新建)
// - src/services/weather-transformer.js (新建)
// - src/services/weather-repository.js (新建,但没改动原调用方)
// - 调用方代码(如果有的话)需要更新,但我会先问你

"我重构完成了。现在 `getWeather(city)` 只返回数据,不保存 to DB。
如果你需要保存,可以手动调用 `saveWeatherLog()`。

另外,我注意到现有代码可能有调用 `getWeather()` 的地方,
这些地方现在需要改成:
```javascript
const weather = await getWeather(city);
await saveWeatherLog(weather);

需要先改调用方吗?还是我可以先不改,保持向后兼容?"

// 第四步:写测试(Goal-Driven Execution)
// src/services/weather.service.test.js
import { getWeather } from './weather.service.js';
import { fetchWeatherData } from './weather-api.js';
import { transformWeatherData } from './weather-transformer.js';

jest.mock('./weather-api.js');
jest.mock('./weather-transformer.js');

describe('getWeather', () => {
test('should return transformed weather data', async () => {
const mockRawData = { /* ... */ };
const mockTransformedData = { city: 'London', temperature: 20 };

fetchWeatherData.mockResolvedValue(mockRawData);
transformWeatherData.mockReturnValue(mockTransformedData);

const result = await getWeather('London');

expect(fetchWeatherData).toHaveBeenCalledWith('London');
expect(transformWeatherData).toHaveBeenCalledWith(mockRawData);
expect(result).toEqual(mockTransformedData);

});
});

// 运行测试
$ npm test
PASS src/services/weather.service.test.js
PASS src/services/weather-api.test.js
PASS src/services/weather-transformer.test.js

Test Suites: 3 passed, 3 total
Tests: 8 passed, 8 total

// 目标达成!


**差异总结**:

| 维度 | 没有 Karpathy Skills | 有 Karpathy Skills |
|------|---------------------|-------------------|
| **新增文件** | 6 个(含不必要抽象) | 3 个(刚好够用) |
| **代码复杂度** | 高(依赖注入、接口、缓存) | 低(简单函数分离) |
| **向后兼容** | 破坏(所有调用方都要改) | 可配置(询问用户) |
| **测试** | 无 | 完整测试覆盖 |
| **可理解性** | 低(需要理解 5 个新类) | 高(简单函数调用) |

---

### 5.3 实战三:调试复杂 Bug

#### 5.3.1 需求描述

用户请求:
"我的 Node.js 应用偶尔会崩溃,错误信息是:
'Error: Cannot read property "userId" of undefined'
但只在生产环境出现,本地复现不了。
帮我排查一下。"

// 错误堆栈
Error: Cannot read property 'userId' of undefined
at middleware/auth.js:45:23
at Layer.handle [as handle_request] (/node_modules/express/lib/layer.js:95:5)
at next (/node_modules/express/lib/router/route.js:144:13)


#### 5.3.2 ❌ 没有 Karpathy Skills(错误示范)

**Claude 的输出**:

```javascript
// 看了错误堆栈后...
// Claude "猜测"问题出在哪里,然后直接改代码

// middleware/auth.js
export function authMiddleware(req, res, next) {
  const token = req.headers.authorization?.split(' ')[1];
  
  if (!token) {
    return res.status(401).json({ error: 'No token' });
  }
  
  try {
    const decoded = jwt.verify(token, JWT_SECRET);
    req.user = decoded;
    next();
  } catch (err) {
    return res.status(401).json({ error: 'Invalid token' });
  }
}

// ... Claude "顺手"改了其他东西 ...
// app.js - 添加了 try-catch(可能掩盖问题)
// user.model.js - "优化"了查询(无关)
// package.json - 升级了 5 个依赖(可能引入新 bug)

// 问题:
// 1. 没有定位根本原因,只是"猜测"并加了一堆防御性代码
// 2. 没有复现 bug,不知道改没改对
// 3. 侧面伤害严重

5.3.3 ✅ 有 Karpathy Skills(正确示范)

Claude 的输出

// 第一步:澄清问题 + 提出假设(Think Before Coding)
"我看到了错误堆栈。这个错误说明 `req.user` 是 `undefined`,
然后在某个地方试图访问 `req.user.userId`。

让我先提出几种可能的根本原因:

**假设 1:authMiddleware 没有正确设置 req.user**
- 可能 token 验证失败,但没有调用 next(error)
- 可能 jwt.verify 抛出异常,但没有被 catch

**假设 2:某些路由没有使用 authMiddleware**
- 可能某个路由忘记加 `app.use(authMiddleware)`
- 导致 `req.user` 为 `undefined`

**假设 3:异步问题**
- 可能 authMiddleware 是异步的,但没等它完成就执行了后续代码

**假设 4:生产环境特定问题**
- 可能生产环境的 token 格式与本地不同
- 可能生产环境的 JWT_SECRET 配置错误

为了排查,我需要:
1. 看完整的 `middleware/auth.js` 代码
2. 看路由配置,确认所有需要认证的路由都用了 authMiddleware
3. 在生产环境添加详细日志,复现 bug

我可以先提方案吗?还是需要我先看代码?"

// 用户:"先看代码,然后给我一个排查计划"

// 第二步:简约调试(Simplicity First)
// Claude 看了代码后...

"我找到问题了!在 `middleware/auth.js` 第 45 行:

```javascript
// 错误的代码
export function authMiddleware(req, res, next) {
  const token = req.headers.authorization?.split(' ')[1];
  
  if (!token) {
    return res.status(401).json({ error: 'No token' });
  }
  
  jwt.verify(token, JWT_SECRET, (err, decoded) => {
    if (err) {
      return res.status(401).json({ error: 'Invalid token' });
    }
    req.user = decoded;
    // 问题:这里没有调用 next()!
    // 导致后续中间件拿不到 req.user
  });
}

根本原因jwt.verify 的回调函数中忘记调用 next()
导致请求挂起,后续中间件访问 req.user 时为 undefined

修复方案(最简单版本):

export function authMiddleware(req, res, next) {
  const token = req.headers.authorization?.split(' ')[1];
  
  if (!token) {
    return res.status(401).json({ error: 'No token' });
  }
  
  jwt.verify(token, JWT_SECRET, (err, decoded) => {
    if (err) {
      return res.status(401).json({ error: 'Invalid token' });
    }
    req.user = decoded;
    next(); // 添加这行
  });
}

但我需要先验证这个修复是否正确。我的成功标准是:

  1. 复现 bug:写一个测试,模拟 authMiddleware 忘记调用 next() 的场景
  2. 修复验证:确保添加 next() 后,后续中间件能正确访问 req.user
  3. 回归测试:确保现有功能没有被破坏

开始写测试..."

// 第三步:精准修复(Surgical Changes)
// 只改了 1 个文件,1 行代码

// middleware/auth.js
export function authMiddleware(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];

if (!token) {
return res.status(401).json({ error: 'No token' });
}

jwt.verify(token, JWT_SECRET, (err, decoded) => {
if (err) {
return res.status(401).json({ error: 'Invalid token' });
}
req.user = decoded;
next(); // 这是唯一的改动
});
}

// 第四步:验证修复(Goal-Driven Execution)
// test/auth.middleware.test.js
import { authMiddleware } from '../middleware/auth.js';
import jwt from 'jsonwebtoken';

describe('authMiddleware', () => {
test('should call next() after setting req.user', (done) => {
const req = {
headers: {
authorization: 'Bearer valid-token'
}
};
const res = {};

jwt.verify = jest.fn((token, secret, callback) => {
  callback(null, { userId: 123 });
});

const next = jest.fn();

authMiddleware(req, res, next);

setTimeout(() => {
  expect(req.user).toEqual({ userId: 123 });
  expect(next).toHaveBeenCalled(); // 验证 next() 被调用
  done();
}, 10);

});

test('should return 401 if no token provided', () => {
const req = { headers: {} };
const res = { status: jest.fn().mockReturnThis(), json: jest.fn() };
const next = jest.fn();

authMiddleware(req, res, next);

expect(res.status).toHaveBeenCalledWith(401);
expect(next).not.toHaveBeenCalled();

});
});

// 运行测试
$ npm test
PASS test/auth.middleware.test.js
✓ should call next() after setting req.user (15ms)
✓ should return 401 if no token provided (5ms)

// 目标达成!


**差异总结**:

| 维度 | 没有 Karpathy Skills | 有 Karpathy Skills |
|------|---------------------|-------------------|
| **调试方法** | 猜测 + 乱改 | 假设 + 验证 |
| **改动范围** | 5 个文件(侧面伤害) | 1 个文件,1 行代码 |
| **根本问题解决** | 否(加防御性代码) | 是(找到并修复根本原因) |
| **验证** | 无(不知道改没改对) | 完整测试覆盖 |
| **文档** | 无 | 在 PR 中详细说明根本原因 |

---

## 6. 跨工具适配:Claude Code、Cursor、Codex 统一配置

### 6.1 为什么需要跨工具适配?

2026 年,开发者往往同时使用多个 AI 编程工具:

- **Claude Code**:用于复杂重构、架构设计
- **Cursor**:用于日常编码、代码补全
- **GitHub Copilot**:用于快速原型
- **Codex CLI**:用于 OpenAI 生态

**问题**:每个工具有自己的配置文件格式!

| 工具 | 配置文件 | 格式 |
|------|---------|------|
| Claude Code | `CLAUDE.md` | Markdown |
| Cursor | `.cursor/rules/*.mdc` | 类 Markdown + YAML front matter |
| Codex CLI | `codex.md` | Markdown |
| GitHub Copilot | `.github/copilot-instructions.md` | Markdown |

### 6.2 andrej-karpathy-skills 的跨工具支持

`andrej-karpathy-skills` 项目提供了**多工具适配**:

andrej-karpathy-skills/
├── CLAUDE.md # Claude Code
├── .cursor/
│ └── rules/
│ └── karpathy-guidelines.mdc # Cursor
├── codex.md # Codex CLI(如果有)
└── .github/
└── copilot-instructions.md # GitHub Copilot(如果有)


#### 6.2.1 Cursor 适配:`.cursor/rules/karpathy-guidelines.mdc`

```yaml
---
description: Andrej Karpathy's AI coding guidelines
glob: "**/*"
---

# Karpathy Guidelines for Cursor

## 1. Think Before Coding
- 不确定时先问,不要擅自假设
- 多种理解要列出来,不要默默选一个

## 2. Simplicity First
- 只写被要求的功能,拒绝过度抽象
- 200 行能写 50 行?重写

## 3. Surgical Changes
- 没让改的地方别碰
- 不"顺手"重构相邻代码

## 4. Goal-Driven Execution
- 定义成功标准,然后循环验证
- "添加验证" → "为无效输入写测试,然后让测试通过"

关键点

  • Cursor 使用 .mdc 格式(Markdown + YAML front matter)
  • glob: "**/*" 表示对所有文件生效
  • 内容与 CLAUDE.md 保持一致

6.2.2 Codex CLI 适配:codex.md

# Karpathy Guidelines for Codex

(内容与 CLAUDE.md 相同)

关键点

  • Codex CLI 使用 codex.md(与 CLAUDE.md 格式相同)
  • 可以通过软链接共享同一份文件

6.2.3 统一配置策略

为了在多个工具间共享同一份配置,可以使用软链接

# 假设你在项目根目录有 CLAUDE.md

# 为 Cursor 创建软链接
ln -s ../CLAUDE.md .cursor/rules/karpathy-guidelines.mdc

# 为 Codex 创建软链接
ln -s CLAUDE.md codex.md

# 为 GitHub Copilot 创建软链接
ln -s ../CLAUDE.md .github/copilot-instructions.md

好处

  • 单一真相源(Single Source of Truth)
  • 修改一处,所有工具同步更新
  • 避免配置漂移(Configuration Drift)

7. 生产级最佳实践

7.1 如何将 Karpathy Skills 集成到现有项目

7.1.1 新项目:从零开始

# 方法一:直接下载 CLAUDE.md
curl -o CLAUDE.md https://raw.githubusercontent.com/forrestchang/andrej-karpathy-skills/main/CLAUDE.md

# 方法二:使用 Claude Code 插件系统
# 在 Claude Code 中执行:
/plugin marketplace add forrestchang/andrej-karpathy-skills
/plugin install andrej-karpathy-skills@karpathy-skills

7.1.2 现有项目:合并配置

如果你已经有 CLAUDE.md,不要直接覆盖,而是合并

# 步骤 1:下载 Karpathy Skills 到临时文件
curl -o CLAUDE.karpathy.md https://raw.githubusercontent.com/forrestchang/andrej-karpathy-skills/main/CLAUDE.md

# 步骤 2:手动合并(推荐)
# 打开 CLAUDE.md,在末尾添加:
echo "" >> CLAUDE.md
echo "# Andrej Karpathy Skills" >> CLAUDE.md
cat CLAUDE.karpathy.md >> CLAUDE.md

# 步骤 3:清理重复内容
# 如果 Karpathy Skills 与你的现有规则冲突,
# 手动调整优先级(后面的规则覆盖前面的)

7.1.3 团队项目:版本管理

CLAUDE.md 应该被提交到版本控制系统:

# 提交到 Git
git add CLAUDE.md
git commit -m "Add Andrej Karpathy Skills for AI-assisted coding"
git push origin main

团队协注意项

  1. 代码审查 CLAUDE.md 的改动

    • 就像审查代码一样,审查 CLAUDE.md 的改动
    • 确保新规则不会与项目风格冲突
  2. 在 PR 模板中添加检查项

    ## PR Checklist
    - [ ] 代码符合项目风格
    - [ ] 测试通过
    - [ ] `CLAUDE.md` 规则未被违反
    - [ ] 如果 AI 辅助编码,附上会话记录
    
  3. 定期审查 AI 生成的代码

    • 每周抽 1-2 个 AI 生成的 PR,检查是否符合 CLAUDE.md 规则
    • 如果频繁违反某条规则,考虑调整规则或加强 AI 提示词

7.2 团队协作:CLAUDE.md 的版本管理

7.2.1 问题:不同开发者有不同的 AI 偏好

场景

  • 开发者 A 喜欢详细的注释
  • 开发者 B 喜欢简约的代码
  • 开发者 C 喜欢函数式编程
  • 开发者 D 喜欢面向对象

如果 CLAUDE.md 包含所有人的偏好,会变得矛盾

7.2.2 解决方案:分层配置

项目配置(提交到 Git):
CLAUDE.md
  - 四大原则(Karpathy Skills)
  - 项目特定规则(编码规范、框架约定等)

个人配置(不提交到 Git):
CLAUDE.local.md
  - 个人偏好(注释风格、代码格式等)
  - 实验性规则(还没达成共识的)

加载顺序

  1. Claude Code 先加载 CLAUDE.md(项目级)
  2. 然后加载 CLAUDE.local.md(本地个人配置)
  3. 个人配置可以覆盖项目配置

示例

// CLAUDE.md(项目级)
## Code Style
- 使用 2 空格缩进
- 使用单引号
- 末尾加逗号(trailing comma)

## Framework
- 使用 Express.js
- 使用 Mongoose for MongoDB

// CLAUDE.local.md(个人配置,不提交)
## Personal Preferences (Overrides Project Rules)
- 我喜欢更详细的注释,请在复杂逻辑处添加注释
- 我偏好函数式编程,如果适合的话可以用 Ramda
- 我正在尝试 "goal-driven" 开发,请先写测试再实现

7.2.3 配置冲突处理

如果项目配置与个人配置冲突,个人配置优先(更具体)。

但为了团队协作,建议:

  1. 在项目级配置中只放"共识"(所有人都同意的规则)
  2. 在个人配置中放"偏好"(个人习惯,不影响他人)
  3. 定期同步:如果个人配置中的某条规则被团队认可,合并到项目配置

7.3 性能优化:Token 消耗与控制

7.3.1 问题:CLAUDE.md 太长会消耗大量 Token

CLAUDE.md 的内容会被注入到每一次对话的系统提示词中。

计算

  • 假设 CLAUDE.md 有 2000 个 token
  • 每次对话平均 20 轮
  • 每轮对话都需要加载 CLAUDE.md
  • 总消耗:2000 × 20 = 40000 token(只算输入)

如果 CLAUDE.md 太长,会:

  1. 增加成本(按 token 计费)
  2. 降低性能(更长的上下文 = 更慢的推理)
  3. 挤占上下文窗口(留给代码的 token 变少)

7.3.2 解决方案:分层 + 按需加载

方案 A:精简 CLAUDE.md

只保留最核心的规则

# CLAUDE.md(精简版,约 500 token)

## Core Principles
1. Think before coding - ask if unsure
2. Simplicity first - no over-engineering
3. Surgical changes - touch only what's needed
4. Goal-driven - define success criteria first

## Project Rules
- Use TypeScript strict mode
- All API endpoints must have tests
- Follow existing code style

(详细的示例和解释放到 EXAMPLES.md,不加载到系统提示词)

方案 B:使用"引用"而不是"内联"

# CLAUDE.md

## Core Principles
See EXAMPLES.md for detailed examples of:
- Think Before Coding: https://github.com/your-repo/EXAMPLES.md#think-before-coding
- Simplicity First: https://github.com/your-repo/EXAMPLES.md#simplicity-first
- ...

(AI 在需要时自己去找示例,而不是每次都加载)

方案 C:使用 Claude Code 的 --context 参数

# 只在需要时加载完整配置
claude --context CLAUDE.full.md  # 完整配置(复杂任务)
claude --context CLAUDE.lite.md  # 精简配置(简单任务)

7.3.3 Token 优化实战

优化前

# CLAUDE.md(优化前,约 3000 token)
## Think Before Coding
(详细解释 + 5 个示例 = 800 token)

## Simplicity First
(详细解释 + 5 个示例 = 800 token)

## Surgical Changes
(详细解释 + 5 个示例 = 800 token)

## Goal-Driven Execution
(详细解释 + 5 个示例 = 800 token)

优化后

# CLAUDE.md(优化后,约 800 token)
## Core Principles (Brief)
1. Think before coding: Ask if unsure, present tradeoffs
2. Simplicity first: Minimum code, no speculation
3. Surgical changes: Touch only what's needed
4. Goal-driven: Define success criteria, loop until verified

→ Details & examples: EXAMPLES.md

## Project Rules (Concise)
- TypeScript strict mode
- Tests required for API endpoints
- Match existing style

Token 节省:3000 → 800(节省 73%)


8. 进阶:从静态规则到动态学习

8.1 问题:静态规则无法覆盖所有场景

CLAUDE.md静态规则,但每个项目有自己的隐性知识

  • 项目的架构决策
  • 常见的坑
  • 团队的习惯

示例

# 静态规则无法捕获的隐性知识

## 项目特定规则(只能靠经验积累)
- 不要直接用 `User.findById()`,用 `UserRepository.findById()`
  (因为后者有缓存 + 权限检查)

- API 路由必须返回标准格式 `{ success: boolean, data: any, error?: string }`
  (前端依赖这个格式)

- 数据库查询必须用 `select` 指定字段,不要 `SELECT *`
  (性能要求)

8.2 解决方案:动态学习 + 自动更新 CLAUDE.md

8.2.1 工作流:从错误中学习

# 场景:AI 犯了错误,用户纠正它

用户: "不要用 `User.findById()`,用 `UserRepository.findById()`"
Claude: "好的,我记住了。我要把这个规则更新到 CLAUDE.md 吗?"
用户: "是的"

# Claude 自动更新 CLAUDE.md
# 在 "Project-Specific Guidelines" 部分添加:
## Project-Specific Guidelines
- Use `UserRepository.findById()` instead of `User.findById()`
  (Reason: caching + permission checks)

8.2.2 工具推荐:ECC(Everything Claude Code)

ECC 是一个"AI 编程助手的操作系统",它提供了:

  1. 自动从会话中提取模式

    • 分析你的对话记录
    • 提取常见的错误模式
    • 自动生成 CLAUDE.md 规则
  2. 记忆持久化

    • 跨会话保存上下文
    • 自动加载相关记忆
  3. 持续学习

    • 从每次纠正中学习
    • 定期建议更新 CLAUDE.md

安装 ECC

# 方法一:使用 npm(推荐)
npm install -g ecc-universal

# 方法二:使用 Homebrew(macOS)
brew install affaan-m/ecc/ecc

# 初始化
ecc init

ECC 的工作流

# 1. 在编码会话结束后,ECC 自动分析
ecc analyze-session

# 输出:
"我发现你在 3 个会话中都纠正了 AI 的同样错误:
- 错误:直接使用 Mongoose 模型
- 正确:使用 Repository 模式

建议添加到 CLAUDE.md:
'Always use Repository pattern for database access'

应用建议? [Y/n]"

9. 与其他 AI 编程工具的对比

9.1 andrej-karpathy-skills vs. 其他提示词工程方法

方法核心思想优点缺点
Karpathy Skills行为约束(不要做什么)精准、可验证、防止错误需要手动维护
Few-shot Prompting示例驱动(这样做)直观、易理解占用大量 token
Chain-of-Thought推理链(一步步想)提高复杂任务准确率增加延迟和成本
ReAct推理 + 行动交替适合多步骤任务需要工具调用支持
AutoGPT/CrewAI自主 Agent全自动化不可控、成本高

9.2 andrej-karpathy-skills 的独特价值

  1. 专注于"不要做什么"而不是"要做什么"

    • 传统提示词:"写简洁的代码"
    • Karpathy Skills:"不要过度工程化,如果 200 行能写 50 行,重写"
  2. 可验证性

    • 每条原则都有"检验标准"
    • AI 可以自我评估是否遵守了规则
  3. 跨工具通用

    • 不依赖特定 AI 模型
    • 不依赖特定编程工具
    • 纯文本 Markdown,任何 AI 都能理解

10. 总结与展望:AI 编程的"纪律革命"

10.1 核心收获

通过本文的深度解析,我们应该认识到:

  1. AI 编程的最大问题不是"能力",而是"判断"

    • LLM 能写代码,但不知道什么时候该停
    • 它需要"纪律约束",就像人类程序员需要代码审查
  2. CLAUDE.md 不是"提示词",而是"行为准则"

    • 它通过改变系统提示词来改变 AI 的行为模式
    • 它是 AI 的《员工手册》
  3. 四大原则的本质是"元认知"

    • Think Before Coding = 迫使 AI "想一想"
    • Simplicity First = 迫使 AI "证明必要性"
    • Surgical Changes = 迫使 AI "考虑侧面伤害"
    • Goal-Driven Execution = 迫使 AI "定义成功"

10.2 实践建议

如果你想在项目中应用 Andrej Karpathy Skills,建议:

  1. 从四大原则开始

    • 不要一开始就写 100 条规则
    • 先把四大原则用起来,观察效果
  2. 迭代优化

    • 每次 AI 犯错误,就更新 CLAUDE.md
    • 逐渐建立项目的"隐性知识库"
  3. 团队培训

    • 教会团队成员如何写清晰的指令
    • 目标驱动 > 命令驱动
  4. 定期审查

    • 每周看一次 AI 生成的代码
    • 如果频繁违反某条规则,考虑调整

10.3 未来展望

2026 年下半年,我们可能会看到:

  1. 动态 CLAUDE.md

    • 根据上下文自动调整规则
    • 例如:简单任务用宽松规则,复杂任务用严格规则
  2. 多 Agent 协作

    • 一个 Agent 写代码,另一个 Agent 审查(根据 CLAUDE.md
    • 类似"两人结队编程"
  3. IDE 深度集成

    • Cursor、Claude Code 等工具原生支持 CLAUDE.md
    • 实时提示:"这段代码违反了 Simplicity First 原则"
  4. 社区规则库

    • 不同语言、框架的 CLAUDE.md 模板
    • 例如:CLAUDE.react.mdCLAUDE.django.md

10.4 最后的思考

Andrej Karpathy Skills 的爆火,揭示了一个深层趋势:

AI 编程正在从"能力竞赛"转向"纪律建设"

2023-2024 年,大家比的是"谁的模型更聪明";
2025-2026 年,大家比的是"谁的 AI 更守规矩"。

这不是退步,而是进步。当一个技术从"玩具"走向"生产",纪律比能力更重要

就像建筑业:

  • 古代:比的是"谁能盖更高的塔"
  • 现代:比的是"谁能盖更安全、更合规的楼"

AI 编程也一样。andrej-karpathy-skills 就是 AI 编程的"建筑规范"。


附录

A. 完整 CLAUDE.md 示例

# CLAUDE.md - Andrej Karpathy Skills

## Core Principles

### 1. Think Before Coding
Don't assume. Don't hide confusion. Surface tradeoffs.

- State assumptions explicitly
- Present multiple interpretations if ambiguous
- Push back when a simpler approach exists
- Stop when confused, ask for clarification

### 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
- If 200 lines could be 50, rewrite it

Test: Would a senior engineer say this is overcomplicated?

### 3. Surgical Changes
Touch only what you must. Clean up only your own mess.

- Don't "improve" adjacent code
- Don't refactor things that aren't broken
- Match existing style
- Mention, don't delete, pre-existing dead code

Test: Every changed line should trace to the user's request.

### 4. Goal-Driven Execution
Define success criteria. Loop until verified.

Transform:
- "Add validation" → "Write tests for invalid inputs, then make them pass"
- "Fix the bug" → "Write a test that reproduces it, then make it pass"

## Project-Specific Guidelines

- Use TypeScript strict mode
- All API endpoints must have tests
- Follow existing error handling patterns in `src/utils/errors.ts`

## Notes

- These guidelines bias toward caution over speed
- For trivial tasks (typo fixes, obvious one-liners), use judgment
- The goal is reducing costly mistakes on non-trivial work

B. 推荐阅读

  1. Andrej Karpathy 的原贴:https://x.com/karpathy/status/2015883857489522876
  2. andrej-karpathy-skills 项目:https://github.com/multica-ai/andrej-karpathy-skills
  3. ECC (Everything Claude Code):https://github.com/affaan-m/ECC
  4. Anthropic 的 Claude Code 文档:https://docs.anthropic.com/claude-code

C. 社区讨论

  • Hacker News 讨论:https://news.ycombinator.com/item?id=XYZ
  • Reddit r/programming:https://reddit.com/r/programming/XYZ
  • Twitter #KarpathySkills:https://twitter.com/search?q=%23KarpathySkills

文章字数统计:约 18,500 字

代码示例数量:15+ 个完整可运行示例

覆盖的主题

  • ✅ 四大原则的深度解析
  • ✅ 架构分析与实现原理
  • ✅ 三个完整的代码实战(添加认证、重构遗留代码、调试复杂 Bug)
  • ✅ 跨工具适配(Claude Code、Cursor、Codex)
  • ✅ 生产级最佳实践(团队协作、版本管理、性能优化)
  • ✅ 进阶话题(动态学习、ECC 工具)
  • ✅ 与其他方法的对比
  • ✅ 未来展望

适合读者

  • 正在使用 AI 编程工具的开发者
  • 希望提高 AI 代码质量的团队负责人
  • 对提示词工程感兴趣的研究者

行动建议

  1. 立即在你的项目中添加 CLAUDE.md
  2. 从四大原则开始,观察 AI 行为变化
  3. 加入社区,分享你的实践经验

如果你觉得这篇文章对你有帮助,欢迎在 GitHub 上给 andrej-karpathy-skills 一个 Star ⭐️

也欢迎关注我的 X @jiayuan_jy,分享更多 AI 编程的实践经验。

推荐文章

PostgreSQL日常运维命令总结分享
2024-11-18 06:58:22 +0800 CST
利用图片实现网站的加载速度
2024-11-18 12:29:31 +0800 CST
php客服服务管理系统
2024-11-19 06:48:35 +0800 CST
一个简单的html卡片元素代码
2024-11-18 18:14:27 +0800 CST
Claude:审美炸裂的网页生成工具
2024-11-19 09:38:41 +0800 CST
程序员茄子在线接单