用AI编程工具最让我头疼的,不是它写不出代码,而是它写太多。 上周让Claude Code给一个内部工具加个导出CSV的功能。需求很简单:把查询结果导出,表头用英文字段名,文件编码UTF-8 with BOM(Excel能识别中文)。结果它给我整了一套抽象工厂模式------ExportStrategy接口、CsvExportStrategy实现类、ExportContext上下文、一个工厂方法、外加一个配置类。420行代码。我要的是一个60行的函数。 这种"过度设计"我以前忍了。毕竟改改也花不了多少时间。但当你一天要做十几次这样的修改,心态就变了------你不是在review代码,你是在做减脂手术,一刀一刀切掉AI觉得"可能需要"但实际永远不会用到的东西。 然后我看到了Karpathy的一条推文。
老头说得对
Andrej Karpathy,前Tesla AI总监、OpenAI联创,最近在X上发了一长串关于LLM编程行为的观察。原话比较长,但核心就三句:
"模型会替你做出错误的假设,然后一条道走到黑。它们不管自己的困惑,不去澄清,不暴露矛盾,不呈现权衡,该推回的时候不推回。"
"它们真的很喜欢过度复杂化代码和API,膨胀抽象层,不清理死代码......用1000行实现一个100行就能搞定的东西。"
"它们有时候会修改/删除它们并不充分理解的注释和代码,作为副作用------即使跟任务完全无关。"
这三条读完,我第一反应是:这不就是我每天在干的事情吗。 第二反应是:有人把这做成规则了? 还真有。GitHub上有个仓库叫 andrej-karpathy-skills,star数现在20万出头。它做了一件事:把Karpathy的观察提炼成一个65行的 CLAUDE.md 文件,塞进项目根目录,让Claude Code每次启动都先读一遍。 说白了,就是给AI立规矩。
这四条规矩,专治各种手痒
我把CLAUDE.md的完整内容贴一下,总共就65行。重点看第2条和第3条,那两条治的是最痛的病:
vbnet
# CLAUDE.md
Behavioral guidelines to reduce common LLM coding mistakes.
Merge with project-specific instructions as needed.
**Tradeoff:** These guidelines bias toward caution over speed.
For trivial tasks, use judgment.
## 1. Think Before Coding
**Don't assume. Don't hide confusion. Surface tradeoffs.**
Before implementing:
- State your assumptions explicitly. If uncertain, ask.
- If multiple interpretations exist, present them.
- If a simpler approach exists, say so. Push back when warranted.
- If something is unclear, stop. Name what's confusing. Ask.
## 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.
- No error handling for impossible scenarios.
- If you write 200 lines and it could be 50, rewrite it.
## 3. Surgical Changes
**Touch only what you must. Clean up only your own mess.**
When editing existing code:
- 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.
When your changes create orphans:
- Remove imports/variables/functions that YOUR changes made unused.
- Don't remove pre-existing dead code unless asked.
## 4. Goal-Driven Execution
**Define success criteria. Loop until verified.**
Transform tasks into verifiable goals:
- "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"
看完你可能会觉得这不就是常识嘛。对,就是常识。但问题是AI没有常识------你不告诉它"别加没被要求的功能",它真的会觉得帮你搞一套抽象工厂是贴心的表现。 拿第三条"Surgical Changes"来说吧。以前让AI修一个bug,它修完之后经常"顺手"把周围的代码格式化了、注释改了、变量名"优化"了。review的时候根本分不清哪些改动是修bug必须的,哪些是它"看不过去"改的。有一次我花20分钟review一个3行的bugfix,因为AI额外改了14行"看起来无关但也许有深意"的代码。那一刻我是真想把键盘扔了。
实际效果怎么样
说个真实数据。 我在一个中等规模的TypeScript项目里试用了这套规则。项目大概3万行代码,前后端都有。
装CLAUDE.md之前 : 让AI实现一个带分页的列表查询接口。它给了我一堆东西:PaginationParams泛型接口、PaginatedResult<T>返回类型、一个BaseRepository抽象类、加上业务代码。总共380行。实际需要的:一个带skip/take参数的函数加一个返回对象,70行。 改动涉及12个文件,其中8个文件改的是"基础设施"代码------它觉得我需要一套通用的分页框架。我不需要。我只有一个列表。
装CLAUDE.md之后: 同样的需求,它先问了一句:"分页参数是走query string还是body?有没有已有的分页组件可以复用?" 我回答走query string,项目里已有一个类似的接口可以参考。 然后它给了75行代码,改了2个文件(controller和service),完全匹配现有代码风格。没有抽象类,没有泛型,没有"通用分页框架"。 我愣了几秒。这跟我之前用的不是一个AI? 当然不是。AI还是那个AI。区别在于它每次启动前都会读一遍CLAUDE.md,知道"不要加没被要求的功能"、"不要给单次使用的代码搞抽象"。
不是万能的,有几处我加了补充
用了一周之后,规矩确实好使了。但慢慢地我又发现了新的问题------CLAUDE.md没覆盖到的场景。不是规则不好,是真实项目里的坑比70行文件能想到的多。 最明显的是依赖安装。CLAUDE.md的"Simplicity First"让它倾向于写最小代码,但有时候"最小代码"的代价是引入一个新依赖。比如我需要解析一个冷门格式的配置文件,它宁可想自己写parser(200行),也不愿意用现成的库。你说用npm装一个吧,它倒是照做了,但选了一个周下载量不到100的包------我差点没被气笑。 我在CLAUDE.md后面追加了一条:
markdown
## 5. Dependencies
Before writing a parser/converter/formatter from scratch:
- Check if a well-maintained npm package exists (< 50KB,
weekly downloads > 10K)
- If yes, use it. Don't reinvent.
- If no, then write minimal implementation.
另一个问题是测试。 "Goal-Driven Execution"要求"先写测试再写代码"。思路没问题,但在实际项目里,有些东西写测试成本极高(比如涉及外部API调用的集成逻辑)。我加了一条:
markdown
## 6. Testing Pragmatism
Not everything needs a unit test. Write tests for:
- Business logic with clear input/output
- Edge cases you've been bitten by before
- Anything that would be expensive to debug in production
Skip tests for:
- Simple data mapping/transformation
- Third-party library wrappers (mock the boundary instead)
- UI layout/positioning (visual regression tools are better)
这两条是我根据自己的项目加的。CLAUDE.md的README也说了,鼓励merge项目特定的规则。
还有个ponytail,理念差不多但套路不同
这个仓库火了之后,GitHub上冒出来一个类似的项目叫 ponytail(★111K),口号挺逗的------"让AI agent像房间里最懒的资深工程师一样思考"。 核心思路都是YAGNI(You Aren't Gonna Need It),但走的路子不一样。Karpathy的CLAUDE.md像一份行为准则,从AI常犯的错误出发,逐条告诉它"你不该干什么"。ponytail则更像一个决策漏斗------先问"这件事到底需不需要存在",再看"代码库里有没有现成的",再看"标准库能不能搞定"......一层一层往下滤,最后才写最小实现。它的阶梯是这样的:
- Does this need to be built at all? (YAGNI)
- Does it already exist in this codebase? Reuse it.
- Does the standard library already do this?
- Does a native platform capability do this?
- Does an installed dependency do this?
- Can this be done in one line?
- Write the minimum working implementation.
我两个都试了。体感区别是:CLAUDE.md让代码质量更高------diff明显干净了,不会动不动"顺手优化"一堆。ponytail让代码量更少------能省则省,恨不得一个函数搞定所有事。 工具兼容性方面,如果你主力是Claude Code,CLAUDE.md的适配最好(毕竟就是为它设计的)。如果你Cursor、Codex、Copilot CLI混着用,ponytail的覆盖面更广。 当然也不冲突。我有个同事把两个都装上了,跑了一周说"效果确实叠加了,就是AI有时候过于谨慎,改个typo都要先确认三遍"。 这个吐槽很真实。CLAUDE.md自己也说了:These guidelines bias toward caution over speed. For trivial tasks, use judgment. 问题在于AI的"judgment"不太靠谱。它分不清什么是trivial task。
一些实操建议
如果你打算试,几个建议: 安装方式 :最简单的方式是直接在项目根目录创建 CLAUDE.md,把规则贴进去。如果你用Claude Code的plugin系统,可以全局安装:
bash
# Claude Code plugin方式
/plugin marketplace add forrestchang/andrej-karpathy-skills
/plugin install andrej-karpathy-skills@karpathy-skills
如果你用Cursor,项目里也有对应的 .cursor/rules/ 配置。
不要直接照搬 :每个项目情况不同。CLAUDE.md是给通用场景写的,你需要根据自己的技术栈和项目规范做调整。比如前端项目可以加一条"不要给CSS-in-JS和Tailwind之间做选型决策,项目用Tailwind就用Tailwind"。另外提醒一下:CLAUDE.md只对Claude Code有完整约束力,对Cursor等工具需要通过.cursor/rules/目录配置类似的规则文件,直接放CLAUDE.md效果有限。
观察diff变化:装了一周之后,对比一下前后PR的diff大小和"无关改动"的比例。如果diff明显变干净了,说明规则在起作用。如果没什么变化,可能是规则太多AI选择性忽略了------试试精简到2-3条最痛的。
别指望一劳永逸:这些规则本质上是prompt engineering,模型会更新,你的项目会演进,规则也要跟着变。隔两周回来看看diff质量,如果又开始膨胀了,说明该调规则了。
就写到这吧。反正我现在的项目里CLAUDE.md已经成标配了,新建仓库第一件事就是把它copy过去。你们可以试试看,不好使来打我。