编程 Andrej Karpathy 的 AI 编程「纪律准则」:一份 CLAUDE.md 如何修正 LLM 的四大编码顽疾——2026 年 AI 辅助开发完全指南

2026-06-26 14:47:01 +0800 CST views 5

Andrej Karpathy 的 AI 编程「纪律准则」:一份 CLAUDE.md 如何修正 LLM 的四大编码顽疾——2026 年 AI 辅助开发完全指南

前 Tesla AI 总监、OpenAI 创始成员 Andrej Karpathy 在社交媒体上尖锐指出了 LLM 编码的三大陷阱。开发者 Forrest Chang 将这番观察提炼成一份仅 70 行的 CLAUDE.md 文件,却在 GitHub 上狂揽 182K+ Stars。本文深度解析这份「AI 编程纪律准则」的四大原则、实现原理、集成方案,以及如何在生产环境中让 AI 编程助手从「会写代码」进阶到「会做工程」。

目录

  1. 引言:AI 编程助手的「纪律危机」
  2. Karpathy 观察到的三大 LLM 编码陷阱
  3. 四大原则详解:从理论到实践
  4. CLAUDE.md 实现原理深度解析
  5. 代码实战:Before & After 对比
  6. 集成方案:Claude Code、Cursor、Codex 全覆盖
  7. 生产环境最佳实践
  8. 与其他 AI 编程方法论的对比
  9. 性能影响与度量指标
  10. 常见误区与注意事项
  11. 未来展望:AI 编程纪律的演进方向
  12. 总结

1. 引言:AI 编程助手的「纪律危机」

2026 年,AI 编程工具已经从「代码补全」进化到「自主 Agent」,能够处理复杂的多步骤任务。但与此同时,开发者们发现了一个尴尬的事实:

AI 写的代码越多,技术债务积累得越快。

1.1 现象:速度背后的隐患

Claude Code、Cursor、GitHub Copilot 等工具可以在几秒钟内生成上百行代码。这种速度让开发者兴奋,但也带来了新问题:

  • 不当假设:AI 不理解业务上下文,经常基于错误假设生成代码
  • 过度复杂:简单的需求被实现成复杂的抽象层
  • 副作用修改:改一个 Bug,不小心引入了三个新 Bug
  • 缺乏验证:代码「看起来对」,但缺乏可验证的成功标准

1.2 为什么需要「纪律准则」?

人类程序员有自己的编码规范(如 Google Style Guide、Airbnb JavaScript Style Guide),但 AI 编程助手没有。它们学习自海量代码库,却无法理解「工程判断力」。

Andrej Karpathy 的洞察在于:LLM 不是能力不足,而是缺乏行为约束。通过一份精心设计的 CLAUDE.md 文件,我们可以把资深工程师的「工程直觉」注入到 AI 的工作流中。

1.3 项目背景

仓库multica-ai/andrej-karpathy-skills
作者:Forrest Chang(Jiayuan Zhang)
Stars:182K+(截至 2026 年 6 月)
核心文件:单个 CLAUDE.md(约 70 行)
许可证:MIT

这个项目不是框架,不是工具,而是一份行为准则——它告诉 AI:「你应该如何思考、如何编码、如何与人协作」。


2. Karpathy 观察到的三大 LLM 编码陷阱

Andrej Karpathy 在 X(Twitter)上发表了一篇长推文(链接),尖锐指出了 LLM 编码的三大顽疾。这些观察成为了 andrej-karpathy-skills 项目的理论基础。

2.1 陷阱一:错误假设与隐藏困惑

原话

"The models make wrong assumptions on your behalf and just run along with them without checking. They don't manage their confusion, don't seek clarifications, don't surface inconsistencies, don't present tradeoffs, don't push back when they should."

中文翻译

模型会替你做错误假设,然后一错到底。它们不管理自己的困惑,不寻求澄清,不提出不一致之处,不展示权衡,在该推反的时候不推反。

实战场景

用户需求:「帮我实现一个用户登录功能」

AI 的典型反应(错误):

# AI 假设:你需要 JWT + Redis + 微服务架构
# AI 没有问:你的用户规模?单体还是分布式?需要单点登录吗?

import jwt
import redis
from fastapi import FastAPI, Depends
from fastapi.security import HTTPBearer
# ... 100+ 行代码,引入了 5 个不需要的依赖

AI 的理想反应(遵循原则一):

我注意到你需要用户登录功能。在开始之前,我需要确认几个关键点:

1. 用户规模:< 1000 还是 > 10万?
2. 部署方式:单体应用还是微服务?
3. 会话管理:Session Cookie 还是 JWT?
4. 密码存储:bcrypt 还是 Argon2?

根据你的回答,我会选择最简单的实现方案。

2.2 陷阱二:过度复杂化与抽象膨胀

原话

"They really like to overcomplicate code and APIs, bloat abstractions, don't clean up dead code... implement a bloated construction over 1000 lines when 100 would do."

中文翻译

它们真的喜欢把代码和 API 过度复杂化,膨胀抽象层,不清理死代码……用 1000 行实现一个臃肿的构造,而 100 行就够。

实战场景

用户需求:「写一个函数,把 CSV 转换成 JSON」

AI 的典型反应(错误):

# AI 的过度工程化实现
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Protocol, Generic, TypeVar
import csv
import json
from pathlib import Path
from functools import wraps

T = TypeVar('T')

class DataTransformer(Protocol, Generic[T]):
    """数据转换器协议"""
    def transform(self, data: T) -> T: ...

@dataclass
class TransformationConfig:
    """转换配置"""
    delimiter: str = ','
    quotechar: str = '"'
    encoding: str = 'utf-8'

class CSVToJSONStrategy(ABC):
    """CSV 到 JSON 转换策略"""
    @abstractmethod
    def execute(self, filepath: Path, config: TransformationConfig) -> dict:
        pass

class DefaultCSVToJSONStrategy(CSVToJSONStrategy):
    """默认实现"""
    def execute(self, filepath: Path, config: TransformationConfig) -> dict:
        # 实际的 5 行代码藏在 100+ 行抽象后面
        pass

# 使用装饰器添加日志、重试、缓存...
def with_logging(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

# ... 又写了 50 行

AI 的理想反应(遵循原则二):

import csv
import json

def csv_to_json(filepath: str) -> list[dict]:
    """将 CSV 文件转换为 JSON 格式"""
    with open(filepath, 'r', encoding='utf-8') as f:
        reader = csv.DictReader(f)
        return list(reader)

# 就这 6 行,完事。需要更多功能?用了再说。

2.3 陷阱三:副作用修改与代码破坏

原话

"They still sometimes change/remove comments and code they don't sufficiently understand as side effects, even if orthogonal to the task."

中文翻译

它们有时仍会作为副作用修改/删除它们不充分理解的注释和代码,即使与任务正交。

实战场景

用户需求:「修复 calculate_total() 函数中的 off-by-one 错误」

AI 的典型反应(错误):

# 原代码
def calculate_total(items):
    # 计算所有物品的总价
    total = 0
    for item in items:
        total += item.price * item.quantity
    return total

def format_currency(amount):
    # 格式化货币显示
    return f"${amount:.2f}"

# AI 的修改(不止修复了 bug,还「改进」了其他东西)
def calculate_total(items):
    # 重构:使用列表推导式(其实没必要)
    # 添加:支持折扣逻辑(用户没要求)
    # 修改:变量名从 item 改成 cart_item(不影响功能但增加了 diff)
    return sum([
        item.price * item.quantity * (1 - item.discount)
        for item in items
    ])

def format_currency(amount):
    # AI 顺便「改进」了这个函数的格式(增加了不必要的改动)
    return "{:.2f}".format(amount)  # 改变了实现方式

AI 的理想反应(遵循原则三):

# 只修改 bug,其他一律不动
def calculate_total(items):
    # 计算所有物品的总价
    total = 0
    for item in items:
        total += item.price * item.quantity
    return total  # 修复:原本是 return total - 1(off-by-one 错误)

3. 四大原则详解:从理论到实践

andrej-karpathy-skills 将 Karpathy 的观察提炼成四大可执行原则,直接写入 CLAUDE.md 文件。

3.1 原则一:Think Before Coding(先思考再编码)

3.1.1 核心思想

不要假设。不要隐藏困惑。展示权衡。

LLM 倾向于默默选择一个解释然后执行。这个原则强制显式推理

3.1.2 具体规则

  1. 显式陈述假设 —— 如果不确定,问而不是直接猜
  2. 呈现多种解释 —— 当存在歧义时,不要默默选择一个
  3. 在适当时推反 —— 如果有更简单的方案,说出来
  4. 困惑时停止 —— 说出不清楚的地方,并要求澄清

3.1.3 代码示例:需求澄清

用户需求(模糊):「帮我优化数据库查询」

❌ 不遵循原则一

-- AI 直接重写了多少索引,修改了表结构
CREATE INDEX idx_optimized ON users (email, created_at);
ALTER TABLE users ADD COLUMN search_vector TSVECTOR;
-- ... 完全没有问:你的查询是什么样的?数据量多大?瓶颈在哪?

✅ 遵循原则一

在优化之前,我需要了解:

1. 当前查询:你能分享慢查询的 SQL 吗?
2. 数据规模:users 表有多少行?
3. 瓶颈表现:是延迟高(ms 级)还是吞吐量低(QPS 不够)?
4. 业务场景:这个查询是事务内还是分析型?

根据这些信息,我会选择最合适的优化策略(索引、分区、缓存或重写查询)。

3.1.4 底层原理:为什么「先思考」有效?

LLM 的生成过程是自回归的:每个 token 基于前面的 token 预测。如果一开始就有错误假设,后面的代码会沿着错误方向加速。

强制显式推理可以:

  • 让错误假设在早期暴露
  • 让人类有机会纠正方向
  • 让 AI 「停下来思考」,而不是「盲目生成」

3.1.5 实践技巧

CLAUDE.md 中添加项目特定的澄清清单:

## Project-Specific Clarification Checklist

Before implementing any feature:
- [ ] 数据规模:< 1K / 1K-100K / 100K+
- [ ] 并发需求:单机 / 集群
- [ ] 一致性要求:强一致性 / 最终一致性
- [ ] 性能 SLA:延迟 < X ms / 吞吐量 > Y QPS

3.2 原则二:Simplicity First(简洁优先)

3.2.1 核心思想

解决问题的最小代码量。没有推测性的功能。

对抗过度工程的倾向:

3.2.2 具体规则

  1. 不添加未要求的功能
  2. 不为单次使用的代码创建抽象
  3. 不添加未要求的「灵活性」或「可配置性」
  4. 不为不可能的场景添加错误处理
  5. 如果 200 行可以简化成 50 行,就重写

测试标准:一位资深工程师会说这过度复杂了吗?如果是,简化它。

3.2.3 代码示例:避免过早抽象

用户需求:「写一个函数,发送 HTTP 请求并解析 JSON」

❌ 不遵循原则二

from abc import ABC, abstractmethod
from typing import Generic, TypeVar, Callable
from dataclasses import dataclass
import requests
from requests.auth import AuthBase
from functools import wraps

T = TypeVar('T')
R = TypeVar('R')

@dataclass
class RequestConfig:
    """请求配置"""
    timeout: int = 30
    retries: int = 3
    backoff_factor: float = 0.3

class HttpClientStrategy(ABC, Generic[T]):
    """HTTP 客户端策略"""
    @abstractmethod
    def execute(self, url: str, method: str, **kwargs) -> T:
        pass

class RequestsStrategy(HttpClientStrategy[dict]):
    """基于 requests 的实现"""
    def __init__(self, config: RequestConfig):
        self.config = config
        self.session = requests.Session()
    
    def execute(self, url: str, method: str, **kwargs) -> dict:
        response = self.session.request(
            method=method,
            url=url,
            timeout=self.config.timeout,
            **kwargs
        )
        response.raise_for_status()
        return response.json()

# 使用装饰器添加重试、日志、指标...
def with_retry(max_retries: int = 3):
    def decorator(func: Callable) -> Callable:
        @wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(max_retries):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    if attempt == max_retries - 1:
                        raise
            return None
        return wrapper
    return decorator

class HttpClient(Generic[T]):
    """HTTP 客户端门面"""
    def __init__(self, strategy: HttpClientStrategy[T]):
        self._strategy = strategy
    
    def request(self, url: str, method: str = 'GET', **kwargs) -> T:
        return self._strategy.execute(url, method, **kwargs)

# 使用
config = RequestConfig(timeout=30, retries=3)
strategy = RequestsStrategy(config)
client = HttpClient(strategy)
result = client.request('https://api.example.com/data')

✅ 遵循原则二

import requests

def fetch_json(url: str, timeout: int = 30) -> dict:
    """发送 GET 请求并返回 JSON"""
    response = requests.get(url, timeout=timeout)
    response.raise_for_status()
    return response.json()

# 4 行代码,完事。需要重试?遇到网络错误再说。

3.2.4 什么时候可以添加抽象?

规则:当你有至少三个具体用例时,才考虑抽象。

反模式(过早抽象):

# 用例 1:发送邮件
# 就开始写 EmailSender 抽象类、SMTP 实现、SendGrid 实现...

正模式(延迟抽象)**:

# 用例 1:发送邮件 → 写一个简单的函数
def send_email(to: str, subject: str, body: str):
    ...

# 用例 2:发送邮件(不同提供商)→ 复制函数,改实现
def send_email_smtp(to: str, subject: str, body: str):
    ...

def send_email_sendgrid(to: str, subject: str, body: str):
    ...

# 用例 3:需要统一的接口 → 现在可以考虑抽象
from abc import ABC, abstractmethod

class EmailSender(ABC):
    @abstractmethod
    def send(self, to: str, subject: str, body: str):
        pass

3.3 原则三:Surgical Changes(精准修改)

3.3.1 核心思想

只碰你必须碰的。只清理你自己的烂摊子。

编辑现有代码时:

3.3.2 具体规则

  1. 不「改进」相邻代码、注释或格式
  2. 不重构没坏的东西
  3. 匹配现有风格,即使你会用不同的方式
  4. 如果注意到不相关的死代码,提及它 —— 不要删除它

当你的修改创建了孤儿时:

  1. 删除你的修改导致未使用的导入/变量/函数
  2. 不删除预先存在的死代码,除非被要求

测试标准:每一行修改的代码都应该直接追溯到用户的请求。

3.3.3 代码示例:精准修复 Bug

用户需求:「修复 User.validate() 中的邮箱验证正则」

原代码

# auth/user.py
import re
from datetime import datetime

class User:
    def __init__(self, email: str, password: str):
        self.email = email
        self.password = password
        self.created_at = datetime.now()
    
    def validate(self):
        # TODO: 修复邮箱验证
        if not re.match(r'email', self.email):  # Bug: 错误的正则
            raise ValueError("Invalid email")
        return True
    
    def to_dict(self):
        # 序列化用户对象
        return {
            'email': self.email,
            'created_at': self.created_at.isoformat()
        }

# auth/session.py
def create_session(user: User):
    # 创建用户会话
    return {'user_id': user.email, 'token': '...'}

❌ 不遵循原则三(过度修改):

# auth/user.py
import re
from datetime import datetime
from typing import Dict, Any  # 新增导入(不需要)

class User:
    def __init__(self, email: str, password: str):
        self.email = email
        self.password = password
        self.created_at = datetime.now()
    
    def validate(self):
        # 修复:使用正确的正则
        if not re.match(r'^[\w\.-]+@[\w\.-]+\.\w+$', self.email):
            raise ValueError("Invalid email")
    
    def to_dict(self) -> Dict[str, Any]:  # 「改进」了类型注解
        """序列化用户对象"""  # 「改进」了注释格式
        return {
            'email': self.email,
            'created_at': self.created_at.isoformat()
        }

# auth/session.py
from auth.jwt_helper import generate_token  # 新增导入(不需要)

def create_session(user: User):
    # 重构:使用 JWT(用户没要求)
    return {'user_id': user.email, 'token': generate_token(user)}

✅ 遵循原则三(精准修改):

# auth/user.py
import re
from datetime import datetime

class User:
    def __init__(self, email: str, password: str):
        self.email = email
        self.password = password
        self.created_at = datetime.now()
    
    def validate(self):
        # 修复:使用正确的正则
        if not re.match(r'^[\w\.-]+@[\w\.-]+\.\w+$', self.email):
            raise ValueError("Invalid email")
        return True
    
    def to_dict(self):
        # 序列化用户对象
        return {
            'email': self.email,
            'created_at': self.created_at.isoformat()
        }

# auth/session.py(完全没碰)
def create_session(user: User):
    # 创建用户会话
    return {'user_id': user.email, 'token': '...'}

Diff 对比

❌ 不遵循原则三: 修改了 3 个文件,20+ 行改动
✅ 遵循原则三: 修改了 1 个文件,3 行改动(只修复正则)

3.4 原则四:Goal-Driven Execution(目标驱动执行)

3.4.1 核心思想

定义成功标准。循环直到验证通过。

将命令式任务转换为可验证的目标:

3.4.2 具体规则

不要说...转换为...
"添加验证""为无效输入编写测试,然后让测试通过"
"修复 bug""编写复现 bug 的测试,然后让测试通过"
"重构 X""确保测试在重构前后都通过"

对于多步骤任务,陈述简要计划:

1. [步骤] → 验证:[检查]
2. [步骤] → 验证:[检查]
3. [步骤] → 验证:[检查]

强成功标准让 LLM 能够独立循环。弱标准(「让它工作」)需要不断澄清。

3.4.3 代码示例:测试驱动修复

用户需求:「修复 divide() 函数在除零时的崩溃」

❌ 不遵循原则四(没有明确成功标准):

# AI 直接修改代码
def divide(a: float, b: float) -> float:
    if b == 0:
        return 0  # 随意的处理方式
    return a / b

# 问题:「修复」后,行为正确吗?覆盖所有边界情况了吗?

✅ 遵循原则四(目标驱动 + 测试先行):

# 步骤 1: 编写复现 bug 的测试
import pytest

def test_divide_by_zero():
    """除零应该抛出 ValueError"""
    with pytest.raises(ValueError, match="Cannot divide by zero"):
        divide(10, 0)

def test_divide_normal():
    """正常除法应该返回正确结果"""
    assert divide(10, 2) == 5.0

def test_divide_negative():
    """负数除法"""
    assert divide(-10, 2) == -5.0

# 步骤 2: 运行测试,确认失败(红)
# pytest test_math.py::test_divide_by_zero -- 失败(ZeroDivisionError)

# 步骤 3: 修改代码让测试通过(绿)
def divide(a: float, b: float) -> float:
    """执行除法,除零时抛出 ValueError"""
    if b == 0:
        raise ValueError("Cannot divide by zero")
    return a / b

# 步骤 4: 运行测试,确认通过(绿)
# pytest test_math.py -- 全部通过

# 成功标准:所有测试通过 + 代码覆盖率 100%

3.4.4 底层原理:为什么「目标驱动」有效?

Andrej 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 的优势

  • 擅长循环:给定明确目标,可以不断尝试直到满足
  • 不擅长开放性任务:「让它工作」太模糊,AI 不知道何时停止

强制可验证目标可以:

  • 让 AI 自主迭代,减少人工干预
  • 提供明确的「完成信号」,避免无限循环
  • 让代码质量可度量(测试通过 = 完成)

3.4.5 实践技巧

CLAUDE.md 中添加项目特定的成功标准模板:

## Success Criteria Templates

### For Bug Fixes
1. Write a test that reproduces the bug
2. Run test → should fail
3. Fix the code
4. Run test → should pass
5. Run entire test suite → no regressions

### For New Features
1. Write acceptance criteria as tests
2. Implement minimal code to pass tests
3. Refactor only after tests pass
4. Add edge case tests
5. Documentation update

### For Refactoring
1. Ensure test coverage > 80% before start
2. Run all tests → record baseline
3. Refactor
4. Run all tests → same pass rate
5. No new linting warnings

4. CLAUDE.md 实现原理深度解析

4.1 CLAUDE.md 是什么?

CLAUDE.md 是一个特殊的 Markdown 文件,Claude Code 会在每次对话开始时自动读取它(如果存在于项目根目录)。

工作原理

  1. 用户启动 Claude Code
  2. Claude Code 检查当前目录是否有 CLAUDE.md
  3. 如果有,将其内容注入到 system prompt
  4. 后续所有对话都受这个文件约束

4.2 为什么单个文件就能改变 AI 行为?

LLM 的行为受 prompt 强烈影响。通过 CLAUDE.md,我们可以:

  • 设置角色:「你是一个谨慎的资深工程师」
  • 定义规则:「先思考,后编码」
  • 提供上下文:「本项目使用 TypeScript + FastAPI」

类比CLAUDE.md 就像是给 AI 的 README —— 但它不是给人看的,而是给 AI 看的。

4.3 andrej-karpathy-skills 的 CLAUDE.md 结构

# Karpathy-Inspired Claude Code Guidelines

## The Problems
[Karpathy 观察到的三大问题]

## The Solution
[四大原则概览表格]

## The Four Principles in Detail
### 1. Think Before Coding
[具体规则 + 示例]

### 2. Simplicity First
[具体规则 + 示例]

### 3. Surgical Changes
[具体规则 + 示例]

### 4. Goal-Driven Execution
[具体规则 + 示例]

## Install
[安装方法]

## How to Know It's Working
[效果检验清单]

设计亮点

  • 问题 → 解决方案结构:先说明「为什么」,再讲「怎么做」
  • 具体规则:不是抽象原则,而是可执行的指令
  • 示例驱动:每个原则都配有 Before/After 代码对比

4.4 与其他 .md 文件的对比

文件作用对象用途
README.md人类开发者项目介绍、安装、使用说明
CONTRIBUTING.md人类开发者贡献指南、代码规范
CLAUDE.mdAI 编程助手AI 行为准则、编码规范
.cursorrulesCursorAI 行为准则(Cursor 专用)
AGENTS.md多种 AI 工具AI Agent 规范(通用)

关键差异CLAUDE.md给 AI 读的,所以要用 AI 能理解的方式写(结构化、明确、无歧义)。


5. 代码实战:Before & After 对比

5.1 案例一:重构过度抽象的代码

场景:代码库中有一段「设计模式狂热」写的代码,需要简化。

原代码(过度工程化):

from abc import ABC, abstractmethod
from typing import List, Protocol, Generic, TypeVar
from dataclasses import dataclass
from enum import Enum

T = TypeVar('T')

class Shape(Protocol):
    """形状协议"""
    def area(self) -> float:
        ...

class ShapeType(Enum):
    """形状类型枚举"""
    CIRCLE = "circle"
    RECTANGLE = "rectangle"
    TRIANGLE = "triangle"

@dataclass
class ShapeConfig:
    """形状配置"""
    color: str = "black"
    filled: bool = False

class ShapeFactory(ABC):
    """形状工厂抽象类"""
    @abstractmethod
    def create(self, config: ShapeConfig) -> Shape:
        pass

class CircleFactory(ShapeFactory):
    """圆形工厂"""
    def create(self, config: ShapeConfig) -> Shape:
        return Circle(config=config)

class RectangleFactory(ShapeFactory):
    """矩形工厂"""
    def create(self, config: ShapeConfig) -> Shape:
        return Rectangle(config=config)

class Circle(Shape):
    """圆形"""
    def __init__(self, config: ShapeConfig, radius: float = 1.0):
        self.config = config
        self.radius = radius
    
    def area(self) -> float:
        import math
        return math.pi * self.radius ** 2

class Rectangle(Shape):
    """矩形"""
    def __init__(self, config: ShapeConfig, width: float = 1.0, height: float = 1.0):
        self.config = config
        self.width = width
        self.height = height
    
    def area(self) -> float:
        return self.width * self.height

# 使用
factory = CircleFactory()
config = ShapeConfig(color="red", filled=True)
circle = factory.create(config)
print(f"Area: {circle.area()}")

问题

  • 为了创建两个形状,引入了 5 个类 + 1 个协议 + 1 个枚举 + 1 个配置类
  • 实际项目可能只用得到 CircleRectangle,根本不需要工厂模式

✅ 遵循原则二(简洁优先)后的重构

import math
from dataclasses import dataclass

@dataclass
class Circle:
    radius: float
    
    def area(self) -> float:
        return math.pi * self.radius ** 2

@dataclass
class Rectangle:
    width: float
    height: float
    
    def area(self) -> float:
        return self.width * self.height

# 使用
circle = Circle(radius=5.0)
print(f"Area: {circle.area()}")

对比

  • 原代码:150+ 行,5 个类,1 个抽象层
  • 重构后:20 行,2 个类,0 个抽象层
  • 功能完全相同,可读性大幅提升

5.2 案例二:修复 Bug 的正确姿势

场景:用户报告 process_data() 函数在处理空列表时崩溃。

原代码

def process_data(items: list[dict]) -> dict:
    """处理数据列表,返回汇总信息"""
    total = 0
    for item in items:
        total += item['value']
    
    average = total / len(items)
    
    return {
        'total': total,
        'average': average,
        'count': len(items)
    }

Bug:当 items 为空列表时,total / len(items) 会触发 ZeroDivisionError

❌ 不遵循原则四(没有测试驱动)

# AI 直接「修复」
def process_data(items: list[dict]) -> dict:
    """处理数据列表,返回汇总信息"""
    if not items:
        return {'total': 0, 'average': 0, 'count': 0}
    
    total = 0
    for item in items:
        total += item['value']
    
    average = total / len(items)
    
    return {
        'total': total,
        'average': average,
        'count': len(items)
    }

# 问题:AI 选的默认值(0)合适吗?空列表是否应该返回 None?是否应该抛异常?

✅ 遵循原则四(目标驱动 + 测试先行)

# 步骤 1: 编写测试,定义成功标准
import pytest

def test_process_data_empty_list():
    """空列表应该返回零值汇总"""
    result = process_data([])
    assert result == {'total': 0, 'average': 0, 'count': 0}

def test_process_data_normal():
    """正常数据处理"""
    items = [{'value': 10}, {'value': 20}, {'value': 30}]
    result = process_data(items)
    assert result['total'] == 60
    assert result['average'] == 20
    assert result['count'] == 3

# 步骤 2: 运行测试 → 失败(ZeroDivisionError)

# 步骤 3: 修复代码
def process_data(items: list[dict]) -> dict:
    """处理数据列表,返回汇总信息"""
    if not items:
        return {'total': 0, 'average': 0, 'count': 0}
    
    total = sum(item['value'] for item in items)
    average = total / len(items)
    
    return {
        'total': total,
        'average': average,
        'count': len(items)
    }

# 步骤 4: 运行测试 → 通过

# 步骤 5: 边界情况测试
def test_process_data_single_item():
    """单个元素"""
    items = [{'value': 42}]
    result = process_data(items)
    assert result['average'] == 42

def test_process_data_zero_value():
    """包含零值"""
    items = [{'value': 0}, {'value': 10}]
    result = process_data(items)
    assert result['total'] == 10
    assert result['average'] == 5

5.3 案例三:添加新功能的最小化实现

场景:需要添加「导出 CSV」功能。

用户需求:「添加 CSV 导出功能」

❌ 不遵循原则二(过度复杂)

# AI 的实现(过度工程化)
from abc import ABC, abstractmethod
from typing import Protocol, Iterator
from dataclasses import dataclass
import csv
from pathlib import Path
from enum import Enum

class ExportFormat(Enum):
    """导出格式"""
    CSV = "csv"
    JSON = "json"
    XLSX = "xlsx"

@dataclass
class ExportConfig:
    """导出配置"""
    delimiter: str = ','
    quotechar: str = '"'
    encoding: str = 'utf-8'
    include_header: bool = True

class Exporter(Protocol):
    """导出器协议"""
    def export(self, data: list[dict], filepath: str) -> None:
        ...

class CSVExporter:
    """CSV 导出器"""
    def __init__(self, config: ExportConfig):
        self.config = config
    
    def export(self, data: list[dict], filepath: str) -> None:
        with open(filepath, 'w', encoding=self.config.encoding) as f:
            if not data:
                return
            writer = csv.DictWriter(
                f,
                fieldnames=data[0].keys(),
                delimiter=self.config.delimiter,
                quotechar=self.config.quotechar
            )
            if self.config.include_header:
                writer.writeheader()
            writer.writerows(data)

class ExportManager:
    """导出管理器"""
    def __init__(self):
        self._exporters = {
            ExportFormat.CSV: CSVExporter(ExportConfig())
        }
    
    def register_exporter(self, format: ExportFormat, exporter: Exporter):
        self._exporters[format] = exporter
    
    def export(self, data: list[dict], filepath: str, format: ExportFormat = ExportFormat.CSV):
        exporter = self._exporters.get(format)
        if not exporter:
            raise ValueError(f"Unsupported format: {format}")
        exporter.export(data, filepath)

# 使用
manager = ExportManager()
manager.export(data, 'output.csv', ExportFormat.CSV)

问题

  • 用户只要求 CSV 导出,AI 却设计了可扩展的「导出框架」
  • 引入了抽象层、配置类、管理器类 —— 都是推测性的(用户可能永远不需要 JSON/XLSX 导出)

✅ 遵循原则二(简洁优先)

import csv
from pathlib import Path

def export_to_csv(data: list[dict], filepath: str) -> None:
    """将数据集导出为 CSV 文件"""
    if not data:
        return
    
    with open(filepath, 'w', encoding='utf-8', newline='') as f:
        writer = csv.DictWriter(f, fieldnames=data[0].keys())
        writer.writeheader()
        writer.writerows(data)

# 使用
export_to_csv(data, 'output.csv')

如果需要更多格式(未来):

# 等到真的需要 JSON 导出时,再添加
def export_to_json(data: list[dict], filepath: str) -> None:
    """将数据集导出为 JSON 文件"""
    import json
    with open(filepath, 'w', encoding='utf-8') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

# 等到真的需要多种格式时,再考虑抽象
def export_data(data: list[dict], filepath: str, format: str = 'csv') -> None:
    """导出数据(支持多种格式)"""
    exporters = {
        'csv': export_to_csv,
        'json': export_to_json
    }
    exporter = exporters.get(format)
    if not exporter:
        raise ValueError(f"Unsupported format: {format}")
    exporter(data, filepath)

关键差异

  • AI 的倾向:提前设计「完美」的抽象,应对未来所有可能
  • 资深工程师的做法:只实现当前需要的,等到真的需要扩展时再重构

6. 集成方案:Claude Code、Cursor、Codex 全覆盖

andrej-karpathy-skills 不仅支持 Claude Code,还可以通过不同方式集成到多种 AI 编程工具。

6.1 Claude Code 集成

方式一:插件安装(推荐)

# 在 Claude Code 中执行
/plugin marketplace add forrestchang/andrej-karpathy-skills
/plugin install andrej-karpathy-skills@karpathy-skills

优点

  • 全局安装,所有项目生效
  • 自动更新

方式二:项目级 CLAUDE.md

# 新项目
curl -o CLAUDE.md https://raw.githubusercontent.com/forrestchang/andrej-karpathy-skills/main/CLAUDE.md

# 现有项目(追加)
echo "" >> CLAUDE.md
curl https://raw.githubusercontent.com/forrestchang/andrej-karpathy-skills/main/CLAUDE.md >> CLAUDE.md

优点

  • 版本控制友好(可以提交到 Git)
  • 项目特定定制

6.2 Cursor 集成

项目包含 .cursor/rules/karpathy-guidelines.mdc 文件,Cursor 会自动读取。

手动集成到其他项目

  1. 复制 .cursor/rules/karpathy-guidelines.mdc 到你的项目
  2. 或者创建 .cursorrules 文件,内容来自 CURSOR.md

.cursor/rules/karpathy-guidelines.mdc 内容示例

# Karpathy Guidelines for Cursor

You are an AI programming assistant in Cursor.

## Core Principles

1. Think Before Coding
   - State assumptions explicitly
   - Ask before guessing
   - Present tradeoffs

2. Simplicity First
   - Minimum viable code
   - No speculative features
   - If 200 lines can be 50, rewrite

3. Surgical Changes
   - Touch only what's necessary
   - Don't "improve" adjacent code
   - Match existing style

4. Goal-Driven Execution
   - Define success criteria
   - Write tests first
   - Loop until verified

6.3 GitHub Copilot Chat 集成

Copilot Chat 不支持 CLAUDE.md,但可以通过工作区提示词实现类似效果。

方式:在项目根目录创建 .github/copilot-instructions.md

# Copilot Instructions

When generating code, follow these principles:

1. **Think Before Coding**: Ask clarifying questions if the requirement is ambiguous
2. **Simplicity First**: Generate the simplest code that meets the requirement
3. **Surgical Changes**: Only modify code directly related to the task
4. **Goal-Driven**: Write tests that define success criteria

Refer to https://github.com/multica-ai/andrej-karpathy-skills for details.

6.4 其他 AI 编程工具的集成

工具集成方式支持文件
Claude Code插件 / CLAUDE.mdCLAUDE.md
Cursor项目规则.cursor/rules/*.mdc / .cursorrules
GitHub Copilot工作区提示词.github/copilot-instructions.md
CodexSystem prompt手动粘贴到 prompt
WindsurfCODEIUM.mdCODEIUM.md(推测)
Aider.aiderules.aiderules

通用策略:无论使用什么工具,核心思想都是:

  1. 找到工具的「系统提示词注入点」(如 CLAUDE.md.cursorrules
  2. 把四大原则写入该文件
  3. 在项目根目录版本控制该文件

7. 生产环境最佳实践

7.1 渐进式采用策略

不要一次性在所有项目上应用。建议路径:

  1. 新项目:直接从第一天使用 CLAUDE.md
  2. 小型现有项目:评估收益 > 成本后采用
  3. 大型遗留项目:在新建文件/模块中试用,逐步推广

7.2 定制化:项目特定规则

andrej-karpathy-skillsCLAUDE.md 是通用原则。在生产环境中,应该叠加项目特定规则

# CLAUDE.md(项目特定版本)

## Karpathy Guidelines
[从上游拉取的标准四大原则]

## Project-Specific Guidelines

### Tech Stack
- Language: Python 3.11+
- Framework: FastAPI
- Database: PostgreSQL + Redis
- Testing: pytest + pytest-cov

### Coding Standards
- Type hints required for all public functions
- All API endpoints must have integration tests
- Use `async/await` for I/O operations
- Follow PEP 8 (line length = 100)

###禁止事项
- No `print()` for logging → use `logging` module
- No hardcoded secrets → use environment variables
- No `except Exception:` → catch specific exceptions

### Database Guidelines
- All migrations must be reversible
- Use `SQLAlchemy` ORM, not raw SQL (except for performance)
- Index foreign keys by default

### Success Criteria Template
For any new API endpoint:
1. Write OpenAPI spec first
2. Write integration test (happy path + error cases)
3. Implement minimal code to pass tests
4. Add request/response validation with Pydantic
5. Document in `API.md`

7.3 团队协作:如何推广?

挑战:团队成员可能不习惯 AI 生成代码的审查方式。

解决方案

  1. 代码评审清单:在 CODE_REVIEW.md 中添加 AI 代码专项检查项

    • AI 生成的代码是否遵循了 CLAUDE.md 原则?
    • 是否有不必要的复杂度?
    • 是否有未问清楚的假设?
    • 测试是否充分?
  2. 定期回顾:每月回顾 AI 生成代码的质量,调整 CLAUDE.md

  3. 培训:让团队理解四大原则背后的「为什么」

7.4 监控与度量

如何知道 CLAUDE.md 在起作用?

度量指标:

指标工具目标
PR 平均 diff 行数GitHub API下降(更精准的修改)
代码复杂度(Cyclomatic Complexity)radon / pylint下降
测试覆盖率pytest-cov上升
Bug 回归率issue tracker下降
AI 代码被人工大改的比例代码评审记录下降

示例:采集脚本

# metrics.py
import subprocess
import json

def get_avg_pr_diff(repo_path: str) -> float:
    """获取过去 30 天 PR 的平均 diff 行数"""
    result = subprocess.run(
        ['gh', 'pr', 'list', '--limit', '30', '--json', 'additions,deletions'],
        capture_output=True,
        text=True,
        cwd=repo_path
    )
    prs = json.loads(result.stdout)
    total_lines = sum(pr['additions'] + pr['deletions'] for pr in prs)
    return total_lines / len(prs) if prs else 0

# 使用前(没有 CLAUDE.md):avg_diff = 250 行
# 使用后(有 CLAUDE.md):avg_diff = 120 行(精准修改原则生效)

8. 与其他 AI 编程方法论的对比

8.1 vs. Superpowers

Superpowers(204K Stars)是另一套 AI 编程方法论,强调「可组合技能系统」。

维度andrej-karpathy-skillsSuperpowers
核心理念纪律约束(不要做什么)能力扩展(可以做什么)
文件大小70 行数千行(多个技能文件)
学习曲线低(读一遍就懂)高(需要理解技能系统)
适用场景修正 AI 的坏习惯扩展 AI 的能力边界
可组合性低(单一文件)高(技能可组合)

最佳实践两者结合使用——

  • andrej-karpathy-skills 约束 AI 的行为底线
  • Superpowers 扩展 AI 的能力上限

8.2 vs. ECC (Everything Claude Code)

ECC(20K Stars)是一套「AI 编程操作系统」,包含 181 个 Skills、47 个 Agents。

维度andrej-karpathy-skillsECC
定位行为准则工程化平台
复杂度简单(单个文件)复杂(多 Agent 系统)
适用阶段项目全生命周期中大型项目
学习成本5 分钟数小时

关系:ECC 包含了类似「先思考后编码」的原则,但封装在复杂的系统中。andrej-karpathy-skills 更适合作为「入门第一步」。

8.3 vs. 纯提示词工程

纯提示词工程:在每次对话中手动输入指令,如「请先思考再编码」。

维度andrej-karpathy-skills纯提示词
一致性高(自动注入)低(每次都要说)
可版本控制是(CLAUDE.md 提交到 Git)否(散落在聊天记录中)
团队统一容易(共享同一份 CLAUDE.md困难(每个人提示词不同)

结论CLAUDE.md 是「提示词工程」的持久化、标准化、团队化方案。


9. 性能影响与度量指标

9.1 定量研究:CLAUDE.md 的效果

虽然还没有大规模的学术研究,但社区反馈和作者观察显示:

指标使用前使用后变化
AI 代码的首次通过率~60%~85%+25%
PR 平均 diff 行数250120-52%
测试覆盖率40%75%+35%
「过度工程化」投诉显著下降

注意:这些数据来自社区反馈,非严格对照实验。

9.2 定性观察:开发者体验改善

** before(没有 CLAUDE.md)**:

开发者:帮我实现一个缓存装饰器
AI:好的!我给你写了一个支持 Redis、Memcached、内存缓存的通用装饰器,
    带有 TTL、LRU、线程安全、分布式锁...(500 行代码)
开发者:呃,我只需要简单的内存缓存...

After(有 CLAUDE.md)

开发者:帮我实现一个缓存装饰器
AI:在写代码之前,我需要确认几点:
    1. 缓存后端:内存 / Redis / 其他?
    2. 过期策略:TTL / LRU / 手动失效?
    3. 并发场景:单线程 / 多线程?
开发者:内存缓存,TTL 1 小时,单线程
AI:(生成 30 行代码)

9.3 Token 成本影响

疑问CLAUDE.md 会增加每次对话的 token 消耗吗?

答案:会,但影响很小。

  • andrej-karpathy-skillsCLAUDE.md:约 2000 tokens
  • Claude 3.5 的上下文窗口:200K tokens
  • 占比:1%

结论:成本可以忽略,收益显著。


10. 常见误区与注意事项

10.1 误区一:「有了 CLAUDE.md,AI 就不会犯错」

真相CLAUDE.md行为指南,不是银弹。AI 仍可能:

  • 忽略原则(特别是复杂任务中)
  • 误解原则的适用范围
  • 遇到训练数据中的「坏习惯」时复发

解决方案:人工代码评审仍不可少。CLAUDE.md 是辅助,不是替代。

10.2 误区二:「四大原则适用于所有场景」

真相:原则是为了减少代价高的错误,不是拖慢简单任务。

Tradeoff 说明(来自项目 README):

These guidelines bias toward caution over speed. For trivial tasks (simple typo fixes, obvious one-liners), use judgment — not every change needs the full rigor.

示例

任务是否需要严格遵循四大原则?
修复 typos不需要(简单改动)
添加新 API 端点需要(影响面广)
重构核心算法需要(风险高)
更新文档不需要(低风险)

10.3 误区三:「CLAUDE.md 是给 AI 看的,人类不需要懂」

真相:团队成员需要理解原则背后的逻辑,才能在代码评审中识别 AI 的偏离行为。

建议

  • 团队内部培训:讲解四大原则
  • 代码评审清单:检查 AI 代码是否符合原则
  • 定期回顾:根据实际案例调整 CLAUDE.md

10.4 注意事项:版本管理

问题CLAUDE.md 应该提交到 Git 吗?

答案应该。好处:

  • 版本控制:追踪原则的演化
  • 团队统一:所有人用同一份规则
  • 新人入职:自动获得项目 AI 编程规范

建议的 Git 工作流

# 1. 在主分支维护标准 CLAUDE.md
main/
  ├── CLAUDE.md          # 标准原则
  ├── .cursor/
  │   └── rules/
  │       └── karpathy-guidelines.mdc
  └── ...

# 2. 团队成员fork后,Claude Code 自动读取
# 3. 如果需要项目特定规则,追加到 CLAUDE.md(标注项目特定部分)

11. 未来展望:AI 编程纪律的演进方向

11.1 从「静态文件」到「动态学习」

当前 CLAUDE.md静态文件。未来可能演进为:

  • 自适应原则:根据项目类型自动调整规则权重
  • 反馈循环:从代码评审中学习效果(类似 RLHF)
  • 团队知识图谱:将项目特定经验结构化

11.2 标准化:AI 编程规范的「PEP 8」

Python 有 PEP 8,Go 有 gofmt。AI 编程也需要行业标准

预测

  • andrej-karpathy-skills 可能成为事实标准(就像 Linux 的编码风格)
  • 主流 IDE 可能内置类似功能(「AI Coding Standards」选项)

11.3 多工具互联互通

当前不同 AI 工具使用不同格式(CLAUDE.md.cursorrules.aiderules)。

未来:可能出现通用格式(类似 LSP 之于编辑器),让同一份规则在所有工具中生效。

社区努力

  • Multica(作者 Forrest Chang 的新项目):运行和管理编码 Agent 的开源平台,支持可复用技能
  • OpenClaw:跨 AI 工具的技能系统

12. 总结

12.1 核心要点回顾

  1. 问题:AI 编程助手有三大顽疾 —— 错误假设、过度复杂、副作用修改
  2. 解决方案andrej-karpathy-skills —— 一份 70 行的 CLAUDE.md,四大原则
  3. 四大原则
    • Think Before Coding:先思考,后编码
    • Simplicity First:简洁优先,反对过度工程
    • Surgical Changes:精准修改,只碰该碰的
    • Goal-Driven Execution:目标驱动,测试先行
  4. 效果:更少的 bug、更简洁的代码、更清晰的 diff、更高的测试覆盖率
  5. 适用性:所有使用 AI 编程助手的个人和团队

12.2 行动清单

今天就可以开始

本周可以完成

  • 根据项目特点定制 CLAUDE.md(添加项目特定规则)
  • 在代码评审中检查 AI 代码是否符合四大原则
  • 度量和记录效果(PR diff 行数、测试覆盖率等)

长期实践

  • 定期回顾和优化 CLAUDE.md
  • 在团队内建立「AI 代码质量」文化
  • 关注项目更新(作者可能在 PR #164 中添加新原则)

12.3 结语

Andrej Karpathy 的洞察和 Forrest Chang 的实现,揭示了一个简单却深刻的道理:

AI 不需要更「聪明」,而是需要更「自律」。

andrej-karpathy-skills 不是魔法,而是一套工程纪律 —— 它把资深工程师的「直觉」变成了 AI 可以执行的「规则」。

在 AI 编程工具越来越强大的 2026 年,纪律将是区分「AI 写代码」和「AI 做工程」的关键。

让 AI 成为你的助手,而不是技术债的制造机。


参考资源

  1. 项目仓库multica-ai/andrej-karpathy-skills
  2. Karpathy 原推文Twitter/X 链接
  3. 作者 X 账号@jiayuan_jy
  4. 相关项目
  5. 中文资料

文章元数据

  • 字数:约 9,500 字
  • 阅读时间:约 30 分钟
  • 适用读者:使用 AI 编程工具的开发者、技术负责人、AI 工程化研究者
  • 更新日期:2026 年 6 月 26 日
  • 许可:本文基于 MIT License 共享(与原始项目一致)

如果你觉得这篇文章有价值,欢迎分享给更多开发者。让我们一起让 AI 编程更自律、更工程化。

推荐文章

Python实现Zip文件的暴力破解
2024-11-19 03:48:35 +0800 CST
任务管理工具的HTML
2025-01-20 22:36:11 +0800 CST
html折叠登陆表单
2024-11-18 19:51:14 +0800 CST
npm速度过慢的解决办法
2024-11-19 10:10:39 +0800 CST
一个收银台的HTML
2025-01-17 16:15:32 +0800 CST
为什么要放弃UUID作为MySQL主键?
2024-11-18 23:33:07 +0800 CST
程序员茄子在线接单