从吐槽到规则:Karpathy 如何给 AI 编程立规矩
最近有个很有代表性的项目火了。它的名字叫andrej-karpathy-skills,作者是 forrestchang。这个项目最有意思的地方,不在于它写了多少代码,而在于它几乎没有“发明新技术”,只是把 Andrej Karpathy 对 AI 编程助手失败模式的吐槽,整理成了一套可以直接执行的行为规则,最后收敛成一个很短的CLAUDE.md文件。结果就是,这个仓库迅速在 GitHub 上积累到接近 29k stars,且这个数字还在升高,成了很多人给 Claude Code“立规矩”的模板。
三个问题
这个项目之所以能火,核心原因不是“大家又收藏了一个提示词仓库”,而是它击中了当前 AI 编程最真实的矛盾。Karpathy 在那条被广泛传播的贴文里提到,自己在很短时间内就从“80% 手写代码、20% 用 agent”,切换到了“80% agent coding、20% 手动修补”。也就是说,AI 编程已经不是边缘玩法,而是开始进入主工作流了。可问题是,模型一旦真的开始大量参与开发,它暴露出来的错误,也不再是简单的语法错误,而是更像一个“会写代码但判断并不稳的初级工程师”:它会替你擅自假设、会把简单问题做复杂、还会顺手改掉一些它并没有真正理解的东西。
forrestchang 做的事,本质上就是把这些失败模式,从“经验吐槽”翻译成“行为约束”。仓库 README 里把 Karpathy 的问题归纳得很直接:第一,模型会替用户做错误假设,然后不检查、不澄清,也不主动暴露矛盾和取舍;第二,它特别容易过度设计,喜欢把本来一百行能解决的问题膨胀成上千行;第三,它有时会在执行任务时顺手改动评论、代码甚至结构,而这些改动和原任务根本无关。针对这三类问题,作者提出了四条原则:Think Before Coding、Simplicity First、Surgical Changes、Goal-Driven Execution。
四个原则
第一条原则叫 Think Before Coding,也就是“先想清楚,再动手”。这条规则针对的是 AI 最危险的一种错法:不是不会写,而是误解了需求还自信往下写。CLAUDE.md里要求模型在实现前先显式说出自己的假设;如果存在多种解释,不能偷偷选一个;如果发现更简单的方案,要主动指出;如果有不清楚的地方,就先停下来问。这背后的设计思想其实很关键:很多 AI 编程事故,并不是代码能力不够,而是 specification,也就是需求定义阶段已经偏了。人以为自己在下指令,模型以为自己已经理解了,结果双方在不同轨道上高速前进。
第二条原则是 Simplicity First,也就是“简单优先”。这条规则几乎就是冲着今天 AI 编程最常见的坏习惯去的:过度工程化。仓库里明确写着,不要添加未被要求的功能,不要给只用一次的代码抽象层,不要凭空增加“可配置性”和“灵活性”,也不要为不可能发生的场景写一堆防御性逻辑。最狠的一句是:如果你写了 200 行,而 50 行就能解决,那就重写。这不是反对抽象,而是在提醒一个现实:AI 很擅长把“也许以后会有用”的结构提前建好,但真实工程里,很多复杂度不是资产,而是负债。
第三条原则是 Surgical Changes,也就是“外科手术式修改”。它解决的是 AI 改代码时“手太长”的问题。很多开发者应该都遇到过:你让模型修一个小 bug,它最后给你改了半个文件,顺便重排格式、重写注释、删掉了几个它觉得没用的函数。CLAUDE.md对此的约束非常明确:只改必须改的地方;不要“顺手优化”相邻代码;不要碰没坏的部分;尽量匹配原有风格;如果看到了无关的死代码,可以提出来,但不要自己删。它甚至给出一个很实用的判断标准:每一行改动,都应该能直接追溯到用户的原始请求。这个标准非常适合今天的 agent 编程,因为它直接把“改动边界”变成了一个可以检查的对象。
第四条原则叫 Goal-Driven Execution,也就是“目标驱动执行”。这部分尤其像 Karpathy 思路的真正落地点。README 里直接引用了一个核心观点:LLM 非常擅长围绕明确目标反复循环,直到达到可验证结果;所以与其告诉它“去做什么”,不如告诉它“什么算成功”。于是这个项目要求把命令式任务改写成可验证目标,比如“修 bug”不要只写 fix bug,而是先写出能复现 bug 的测试,再让它把测试跑通;“加校验”不是泛泛而谈,而是写出 invalid inputs 的测试用例;多步骤任务则要求先列一个简短计划,并给每一步附上验证方式。这里最重要的思想是:让 AI 从“执行模糊命令”变成“追逐明确验收条件”。前者容易漂,后者更容易自主闭环。
意义之类
所以,这个项目真正值得解读的地方,不是“它总结了四条提示词”,而是它代表了一种新的工程观:今天的 AI 编程,重点正在从“让模型多写代码”,转向“给模型设置边界、验收条件和行为纪律”。换句话说,大家拼的已经不只是模型本身,而是谁更会设计 harness,谁更会写运行规则,谁更会把模糊的人类意图压成清晰、可检验、可回滚的工作流。这个仓库之所以爆红,就是因为它把这种工程直觉压缩成了一个极低门槛的载体:一个文件,四条原则,直接可用。
更有意思的是,社区并没有把它当成终点,而是当成起点。这个仓库的 issue 区里已经有人在继续往前推进,比如把这四条原则扩展成更完整的人机协作模式:先从第一性原理审问题,再用状态机或流程图收敛系统理解,再由人做范围确认,再让 agent 实施,最后再用独立的验证 agent 检查假设。这说明一个趋势:最开始大家只是讨论“AI 会不会写代码”,接着开始总结“AI 写代码常犯什么错”,再往后就会进入“如何把这些经验沉淀成稳定流程”的阶段。这个项目正好卡在第二阶段和第三阶段之间,所以它特别有代表性。
动手试试吧~
以下是我自己做的一版codex版,可以放到用户目录的.codex目录下,命名为AGENT.md(如果你和我一样用的是codex),或者放在项目根目录下。
# Karpathy Guidelines Behavioral guidelines to reduce common LLM coding mistakes, derived from Andrej Karpathy's observations on common AI coding pitfalls. Tradeoff: These guidelines bias toward caution over speed. For trivial tasks, use judgment. ## Core Rule Prefer correctness, clarity, and bounded changes over speed, speculation, or over-engineering. ## 1. Think Before Coding Do not assume. Do not hide confusion. Surface tradeoffs. Before implementing: - State assumptions explicitly. - If anything is unclear, say what is unclear and ask. - If multiple interpretations exist, present them instead of choosing silently. - If a simpler approach exists, propose it. - Push back when the requested approach adds unnecessary complexity. - Do not start coding until the task boundary is clear enough to act safely. ## 2. Simplicity First Write the minimum code that solves the problem. Nothing speculative. - Do not add features beyond what was requested. - Do not build abstractions for single-use code. - Do not add flexibility, configuration, or extensibility unless requested. - Do not introduce defensive logic for unrealistic scenarios. - Prefer direct solutions over architectural cleverness. - If 50 lines can solve it, do not write 200. - When in doubt, choose the simpler design. Checkpoint: - Ask: "Would a senior engineer call this overcomplicated?" If yes, simplify. ## 3. Surgical Changes Touch only what you must. Clean up only your own mess. When editing existing code: - Change only the code required for the task. - Do not refactor adjacent code unless it is necessary for correctness. - Do not rewrite comments, formatting, or structure without a task-related reason. - Match the existing code style and local conventions. - If you notice unrelated issues or dead code, mention them separately. Do not fix them unprompted. When your changes create orphaned code: - Remove imports, variables, and functions made unused by your own changes. - Do not remove pre-existing unused code unless explicitly asked. Scope test: - Every changed line should be directly traceable to the user's request. ## 4. Goal-Driven Execution Define success criteria. Loop until verified. Convert tasks into verifiable goals: - "Add validation" -> "Write tests for invalid inputs, then make them pass." - "Fix the bug" -> "Write a failing test that reproduces it, then make it pass." - "Refactor X" -> "Keep behavior unchanged and confirm tests pass before and after." For multi-step tasks: 1. State a short plan. 2. Execute one step at a time. 3. Verify each step with a concrete check. 4. Report what was verified. Example format: 1. Reproduce the issue -> verify: failing test or observable failure 2. Implement the fix -> verify: targeted test passes 3. Check for regressions -> verify: related tests still pass Strong success criteria support autonomous iteration. Weak criteria such as "make it work" require repeated clarification. ## Execution Defaults - Before coding, briefly summarize the task and your assumptions. - For non-trivial work, provide a short step-by-step plan. - After changes, run the smallest relevant verification first. - Report what changed, what was verified, and any remaining uncertainty. - Do not claim completion without verification when verification is possible.