编程 60行CLAUDE.md,25K Stars:Karpathy揭示的LLM编程四大致命陷阱与工程解法

2026-04-19 23:44:59 +0800 CST views 10

60行CLAUDE.md,25K Stars:Karpathy揭示的LLM编程四大致命陷阱与工程解法

引言:一个令人不安的真相

2025年底,AI大牛Andrej Karpathy在X上发了几条观察,直指当前大语言模型编程工具的共性缺陷。他写道:

"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."

"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."

这些话说出了无数程序员心里想说却没敢说出口的感受——LLM编程工具确实很强大,但它们有一个根深蒂固的毛病:沉默地犯错,暗地里加戏,热情地重构不该动的代码

更让人意外的是,这个问题的解法出奇地简单:一份60行的CLAUDE.md文件

2026年1月底,GitHub用户forrestchang把Karpathy的这些观察整理成了一套编码指南,做成了一个Claude Code插件和CLAUDE.md模板。项目上线两个多月,收获了超过25,000颗Stars,成为GitHub Trending历史上增长最快的AI编程辅助项目之一。截至2026年4月,Stars数持续攀升,热度不减。

今天我们就来深度解剖这个项目,看看Karpathy到底发现了什么,60行文件里藏着的工程哲学是什么,以及这套方法论对每一个AI编程实践者的深层启示。


一、问题诊断:LLM编程工具的四大系统性缺陷

在讨论解法之前,必须先把问题看清楚。Karpathy的观察之所以引发广泛共鸣,是因为他指出的不是偶发的bug,而是系统性的设计缺陷——这些缺陷在几乎所有主流LLM编程工具中都存在,具有高度的一致性。

1.1 沉默的假设:错误的前提被悄悄执行

当用户给LLM一个模糊的需求时,它不会停下来问"你确定是这个意思吗?"而是直接选一个最可能的解释,然后闷头干到底

举个例子:用户说"给这个API加个缓存"。LLM可能会默认选Redis,但你实际想用的是内存缓存。等它写完了200行代码,你才发现架构选型不对。此时改还是不改?两难。

这背后是一个信息不对称问题:LLM不知道用户脑子里装的是什么,它宁可"做点什么"也不愿"什么都不做"。沉默假设让错误在代码里生了根,等到发现时已经扎得很深。

1.2 过度的工程化:100行能搞定,非要写1000行

Karpathy第二个观察切中要害:LLM有严重的过度工程化倾向。具体表现为:

  • 为"将来可能用到"的功能预留抽象层
  • 创建大量"灵活配置"的中间层,实际上永远不会被配置
  • 写错误处理逻辑来处理"不可能发生"的场景
  • 用设计模式装饰最简单的CRUD操作

为什么?一种解释是训练数据中的代码充满了过度工程化,LLM从中学到的"好代码"模板本身就包含了这些元素。另一种解释是,模糊指令给了LLM巨大的自由度,它选择用"更多代码"来表达"更多价值"

1.3 边界意识薄弱:动了他不该动的代码

当你让LLM"修复这个bug"时,它有时候会顺手"优化"旁边毫不相关的代码。改完之后,bug可能修了,但引入了一堆新问题,因为你原本不需要那些改动。

这不是恶意破坏,而是**"有用"的冲动驱动**:LLM看到了"可以改进"的地方,就去改了。这种行为模式在代码库越大、越复杂的环境中,破坏力越强。

1.4 目标模糊:不知道"做完"是什么样子

"帮我优化一下这个模块的性能"——这句话对LLM来说太模糊了。它不知道优化到什么程度算"够好",不知道应该优先优化哪个指标(延迟?吞吐量?内存?),不知道优化后应该通过什么测试验证。

结果是:LLM做了一堆努力,但你不知道这算不算"完成",两个人在互相猜测。


二、四大原则:一份文件解决系统性缺陷

forrestchang/andrej-karpathy-skills 项目的核心,就是把Karpathy的观察提炼成四大编码原则,每条原则对应一类问题:

原则解决的问题
Think Before Coding沉默假设、隐藏的不确定性
Simplicity First过度工程化、臃肿抽象
Surgical Changes边界意识薄弱、动了不该动的代码
Goal-Driven Execution目标模糊、无法判断"完成"

这四条原则不是高高在上的哲学宣言,而是可以直接写进CLAUDE.md的行为指令。接下来逐一深入解析。

2.1 Think Before Coding:强制显式推理

传统的LLM编程流程是:接收指令 → 开始写代码。而Think Before Coding在中间插入了一个强制节点:推理 → 显式表达 → 验证 → 写代码

具体操作是:

# Think Before Coding 核心指令

- State assumptions explicitly — If uncertain, ask rather than guess
- Present multiple interpretations — Don't pick silently when ambiguity exists
- Push back when warranted — If a simpler approach exists, say so
- Stop when confused — Name what's unclear and ask for clarification

这个原则解决的核心矛盾是:LLM倾向于"做得快"而不是"做得对"。强制显式假设表达,使得错误假设在执行前就被暴露。实际效果是:

❌ 之前:用户说"加缓存",LLM直接引入Redis,半小时后用户发现架构不对
✅ 现在:用户说"加缓存",LLM先问"你想用内存缓存还是分布式缓存?"

这里有一个重要的工程认识:提问不是低效,提问是避免更大的浪费。在LLM编程场景中,一次澄清问题可能节省30分钟的返工。

在Claude Code中激活此原则,只需在项目CLAUDE.md中加入:

## Think Before Coding

在开始任何非平凡任务之前:
1. 显式陈述你对需求的理解和你打算使用的技术方案
2. 如果存在多种可行方案,列出各方案的权衡
3. 如果遇到不确定的地方,先停下来问清楚再动手

2.2 Simplicity First:对抗过度工程化的工程学武器

Simplicity First是四条原则中最"反直觉"的一条,因为大多数技术文档在教我们"如何写更复杂的代码",而这条原则在教我们**"如何克制住写复杂代码的冲动"**。

# Simplicity First 核心指令

- No features beyond what was asked
- No abstractions for single-use code
- No "flexibility" or "configurability" that wasn't requested
- No error handling for impossible scenarios
- If 200 lines could be 50, rewrite it

# 判断标准
Would a senior engineer say this is overcomplicated? If yes, simplify.

这里的核心思想可以用一句程序员老话概括:YAGNI(You Aren't Gonna Need It)。不是"将来可能需要"就现在加,而是"现在确实需要"才加。

在实际工程中,这一条原则的执行经常遇到挑战。LLM会倾向于写这样的代码:

// ❌ LLM的典型过度工程化输出
class CacheManager<T> {
  private storage: Map<string, T>;
  private ttlConfig: Map<string, number>;
  private evictionPolicy: 'lru' | 'lfu' | 'fifo';
  private maxSize: number;
  private stats: CacheStats;
  
  async set(key: string, value: T, ttl?: number, options?: CacheOptions): Promise<void> {
    // 150 lines of "flexible" cache implementation
  }
}

// ✅ Simplicity First版本
const cache = new Map<string, { value: unknown; expires: number }>();

第二条可能只有20行,但完全解决了当下的问题。第一条有150行,用了泛型、策略模式、统计收集,但你真的需要这些吗?

在CLAUDE.md中激活Simplicity First

## Simplicity First

- 每次写完代码后自问:"这段代码是否比必要的复杂度更高?"
- 不要为"将来可能需要"的功能预留抽象
- 不要写针对"不可能发生"场景的错误处理
- 代码行数是衡量复杂度的反向指标(越少越好)

2.3 Surgical Changes:精准手术刀原则

Surgical Changes(外科手术式改动)是四条原则中工程意义最深远的一条。它解决的核心问题是:LLM在修改代码时缺乏边界意识

# Surgical Changes 核心指令

- Don't "improve" adjacent code, comments, or formatting
- Don't refactor things that aren't broken
- Match existing style, even if you'd do it differently
- If you notice unrelated dead code, mention it — don't delete it

# 你的改动产生的孤儿代码,清理
- Remove imports/variables/functions that YOUR changes made unused
- Don't remove pre-existing dead code unless asked

# 判断标准
Every changed line should trace directly to the user's request.

这个原则用一个极简的判断标准:每一行改动都应该能追溯到用户的原始请求。如果一行代码的改动理由是"看起来不好看"或者"我顺便优化了一下",那这行就不应该动。

这和我们平时做代码review的标准高度一致——好的改动是有边界的。一个PR里既有bugfix又有风格改动又有架构重构,看起来很"丰富",实际上是三类不同的改动混在一起,应该拆分成三个独立的PR。

在Claude Code中激活Surgical Changes

## Surgical Changes

当你修改现有代码时:
1. 改动范围严格限定在用户请求的问题上
2. 不修改与你任务无关的代码(风格、格式、注释)
3. 如果你发现了其他问题,用评论/建议的方式提及,而不是直接改
4. 改动完成后,清理你自己引入的未使用导入/变量
5. 不要删除已有的"死代码",除非用户明确要求

2.4 Goal-Driven Execution:从"做任务"到"达目标"

Goal-Driven Execution是四条原则中最具方法论深度的一条。它解决的是**"不知道什么算做完"**这个根本性问题。

# Goal-Driven Execution 核心指令

Instead of...            Transform to...
"Add validation"    →    "Write tests for invalid inputs, then make them pass"
"Fix the bug"       →    "Write a test that reproduces it, then make it pass"
"Refactor X"        →    "Ensure tests pass before and after"

# 多步骤任务的格式
1. [Step] → verify: [check]
2. [Step] → verify: [check]
3. [Step] → verify: [check]

这个原则背后的洞察是:LLM在"达到特定目标"上比"执行模糊指令"上表现好得多。给定一个可验证的目标,LLM可以自主循环迭代直到达成;给定一个模糊指令,LLM会一直做下去直到你喊停。

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."

Goal-Driven Execution的工程价值在于它把AI编程从"人盯着AI干活"变成了**"人定义目标,AI自主完成"**。这对效率的提升是指数级的——你可以同时开启多个带明确目标的任务,AI各自独立完成,而不是一个任务占满整个会话。

在Claude Code中激活Goal-Driven Execution

## Goal-Driven Execution

- 将所有任务转化为可验证的目标
- 优先写测试,用测试定义"完成"的标准
- 每个步骤完成后,明确验证结果再进入下一步
- 多步骤任务用"[步骤] → verify: [验证方式]"的格式规划

三、CLAUDE.md:超越配置的工程契约

forrestchang/andrej-karpathy-skills项目之所以能火爆,另一个重要原因是它重新定义了CLAUDE.md的本质

3.1 CLAUDE.md不是配置,是工程契约

很多人把CLAUDE.md理解为"给AI看的配置文件",就像.eslintrctsconfig.json一样。这是对CLAUDE.md的极大低估。

CLAUDE.md实际上是一份工程契约(Engineering Contract):它定义了项目与AI编程工具之间的权责边界,阐明了"这里什么重要"、"这里什么不能做"、"这里怎么做是正确的"。

# 一个典型的工程契约CLAUDE.md结构

## 项目背景
(本项目的技术栈、业务场景、核心约束)

## 技术规范
(强制要求:语言版本、框架约束、代码规范)

## 四大原则(从这里引入Karpathy框架)
(将Think Before Coding等四条原则适配到本项目上下文)

## 项目特定规则
(具体的业务逻辑约束、API规范、测试要求)

## 禁止事项
(明确列出:本项目不使用XXX,不用YYY,不用ZZZ)

3.2 CLAUDE.md的加载机制

Claude Code在每次会话启动时,会自动加载项目根目录下的CLAUDE.md作为系统级上下文。这意味着:

每次启动新会话,CLAUDE.md里的规则自动生效,无需重复输入。Claude Code会自动将CLAUDE.md内容注入上下文窗口,作为系统级约束。

这就是CLAUDE.md相比传统提示词工程的核心优势:不需要每次都粘贴一遍指令,它是持久化的、一次配置永久生效的

3.3 插件模式的工程价值

forrestchang/andrej-karpathy-skills除了提供CLAUDE.md,还提供了Claude Code插件模式

# 安装步骤
/plugin marketplace add forrestchang/andrej-karpathy-skills
/plugin install andrej-karpathy-skills@karpathy-skills

插件模式的意义在于:这份指南可以在所有项目间共享,不需要每个项目都复制一遍CLAUDE.md。安装插件后,Karpathy的四大原则在全局生效,项目特定的CLAUDE.md在此基础上叠加定制。

这种"全局基础层 + 项目定制层"的架构,和我们平时设计软件的"基础设施 + 业务逻辑"分层完全一致。


四、实践指南:如何将这套方法论落地

知道了四大原则是什么,接下来最关键的问题是:如何在日常工作中真正用起来

4.1 个人开发者的最小起步方案

对于个人开发者,建议按以下顺序逐步引入:

第一步:在所有新项目初始化CLAUDE.md

# 一行命令拉取Karpathy的CLAUDE.md模板
curl -o CLAUDE.md https://raw.githubusercontent.com/forrestchang/andrej-karpathy-skills/main/CLAUDE.md

然后在模板基础上添加你的项目特定信息(技术栈、编码规范等)。

第二步:在新会话开始时显式声明目标

不要上来就说"帮我写个功能",而是说:

帮我实现一个用户认证模块,具体要求:
1. 使用JWT,包含过期时间
2. 错误处理:token无效/过期/缺失分别返回什么
3. 验证:先写测试,确保覆盖上述三种情况
4. 完成后运行现有测试套件确认无回归

这实际上是在用Goal-Driven Execution原则指导你的指令。

第三步:review时重点关注改动范围

当你看到Claude Code的改动diff时,问自己两个问题:

  1. 每一行改动是否都能追溯到我的原始请求?
  2. 是否有"顺便优化"但与我的需求无关的改动?

有,则指出,让AI回退这些改动。

4.2 团队协作场景的CLAUDE.md工程化

在团队中使用CLAUDE.md需要注意几个额外的工程化考量:

(1)CLAUDE.md的版本控制

CLAUDE.md应该和其他代码文件一样,通过Git管理。在PR review中,CLAUDE.md的改动应该被单独review,因为它定义了整个项目的AI编程行为边界。

(2)团队共识的四大原则定制

每个团队对"简单"的理解不同。"外科手术式改动"的范围也不同。建议团队在引入Karpathy框架时,先做一次内部讨论,明确以下问题:

  • 什么算"过度工程化"?我们的阈值在哪里?
  • 什么改动需要被显式禁止(如"不要使用jQuery")?
  • 多步骤任务的规划格式团队是否都认同?

(3)CLAUDE.md与现有规范的协同

如果项目已有.editorconfigeslintprettier等规范,CLAUDE.md应该与它们形成互补关系:

  • 机器可执行规范(eslint、prettier):自动检查,无需人工review
  • CLAUDE.md:处理机器无法检查的行为决策(架构选择、抽象层级、边界意识)

两者各司其职,不是重复建设。

4.3 判断"有效"的标准

forrestchang/andrej-karpathy-skills项目本身给出了一套验证标准

These guidelines are working if you see:

✅ Fewer unnecessary changes in diffs — Only requested changes appear
✅ Fewer rewrites due to overcomplication — Code is simple the first time
✅ Clarifying questions come before implementation — Not after mistakes
✅ Clean, minimal PRs — No drive-by refactoring or "improvements"

这四条标准实际上是一个AI编程质量评估框架,可以用来持续衡量你的AI编程工作流是否在改善。如果发现这四条都没有改善,说明CLAUDE.md没有被正确执行,需要回顾是哪条原则被违反了。


五、深度反思:这60行文件背后的工程哲学

5.1 从"AI取代程序员"到"AI放大程序员"

forrestchang/andrej-karpathy-skills项目最深刻的意义,不是它解决了某个具体的技术问题,而是它揭示了一个重要的范式转变:AI编程工具的价值不在于替代程序员,而在于放大程序员的判断力

四大原则本质上都是人类工程判断力的延伸

  • Think Before Coding:延伸了"先理解再动手"的工程常识
  • Simplicity First:延伸了"最小化系统复杂度"的架构原则
  • Surgical Changes:延伸了"改动要有边界"的代码所有权意识
  • Goal-Driven Execution:延伸了"可测量才可管理"的目标管理思维

LLM不缺少写代码的能力,它缺少的是工程判断力。CLAUDE.md的本质,是把人类的工程判断力注入AI的行为中。

5.2 为什么是60行,而不是600行?

一个值得深思的细节:这个项目最初只有60行CLAUDE.md,却能解决那么多问题。为什么?

答案在于约束的杠杆效应。越简洁的约束,覆盖面越广;越具体的约束,执行成本越高。60行足够表达核心原则,让LLM有足够的推理空间,同时不会因为规则太多而让LLM陷入"处处受限制"的困境。

这和我们设计API的原则一样:好的接口是简洁的、有表达力的、让人能猜到用法的。CLAUDE.md作为人机接口,也遵循同样的设计哲学。

5.3 AI编程的下一个阶段

forrestchang/andrej-karpathy-skills的25K Stars背后,是整个行业对AI编程工具使用方式的集体反思。

过去一年,行业经历了三个阶段的认知升级:

  1. "AI能写代码"(2023-2024):Copilot、Claude Code横空出世,震惊程序员
  2. "AI写的代码需要人review"(2024-2025):AI代码质量不稳定,需要人工把控
  3. "AI的行为需要被引导"(2025-至今):CLAUDE.md代表的新范式——不是review AI的输出,而是引导AI的行为方式

第三阶段的核心转变是:从"输出质量控制"到"行为模式塑造"。CLAUDE.md不是在AI写完后检查,而是从源头塑造AI的编码行为。


六、总结:一条值得践行的工程原则

forrestchang/andrej-karpathy-skills给我们的最深刻启示,不是Karpathy说了什么、60行文件里写了什么,而是这个项目本身验证了一个工程真理:

最好的工程工具,往往是最简洁的。

60行CLAUDE.md能解决的问题,比很多大型AI编程框架都多。原因在于它触及了问题的本质:LLM编程工具的问题,不是技术能力不足,而是行为模式需要引导

四大原则——Think Before Coding、Simplicity First、Surgical Changes、Goal-Driven Execution——不是什么高深的新发明,而是把几十年软件工程积累的常识,用LLM能理解的方式重新表达了出来。

所以,这篇文章的最终结论是:

与其不断训练更强大的模型,不如教会AI更好地执行最简单的工程原则。

这不仅仅是AI编程的方法论,更是整个软件工程界的智慧:大道至简,行稳致远。


参考资源:

  • 项目地址:https://github.com/forrestchang/andrej-karpathy-skills
  • Andrej Karpathy原帖:https://x.com/karpathy/status/2015883857489522876
  • Claude Code官方文档
  • 四大原则原文(GitHub项目README)

本文首发于程序员茄子(chenxutan.com),如需转载,请保留原文链接。

复制全文 生成海报 Claude Code LLM AI编程 Karpathy 工程实践

推荐文章

前端如何一次性渲染十万条数据?
2024-11-19 05:08:27 +0800 CST
Vue3中的v-slot指令有什么改变?
2024-11-18 07:32:50 +0800 CST
MySQL 1364 错误解决办法
2024-11-19 05:07:59 +0800 CST
php curl并发代码
2024-11-18 01:45:03 +0800 CST
Vue3中的组件通信方式有哪些?
2024-11-17 04:17:57 +0800 CST
Vue 3 是如何实现更好的性能的?
2024-11-19 09:06:25 +0800 CST
Golang 中你应该知道的 noCopy 策略
2024-11-19 05:40:53 +0800 CST
PHP来做一个短网址(短链接)服务
2024-11-17 22:18:37 +0800 CST
乐观锁和悲观锁,如何区分?
2024-11-19 09:36:53 +0800 CST
在 Rust 生产项目中存储数据
2024-11-19 02:35:11 +0800 CST
利用Python构建语音助手
2024-11-19 04:24:50 +0800 CST
php 连接mssql数据库
2024-11-17 05:01:41 +0800 CST
内网穿透技术详解与工具对比
2025-04-01 22:12:02 +0800 CST
Golang 中应该知道的 defer 知识
2024-11-18 13:18:56 +0800 CST
程序员茄子在线接单