← 返回文档索引

name: karpathy-coding-discipline description: Karpathy 式编程纪律——四条铁律 + 完整代码案例注入(源自 multica-ai/andrej-karpathy-skills 全量吸收)。涉及 coding 时 100% 严格执行。 version: 2.0.0


Karpathy 编程纪律(全量注入版)

来源: Andrej Karpathy 对 LLM 编程 Agent 常见陷阱的观察,经 multica-ai/andrej-karpathy-skills(14.3k ⭐)提炼为 CLAUDE.md + Cursor 规则 + Claude Code 插件 + 完整代码案例集,再全量转换为 Hermes SKILL 内部格式。

仓库目录(本地镜像:~/andrej-karpathy-skills/):

├── .claude-plugin/          # Claude Code 插件打包
│   ├── plugin.json          # 插件声明(指向 skills/karpathy-guidelines)
│   └── marketplace.json     # 插件市场元数据(/plugin install 用)
├── .cursor/rules/
│   └── karpathy-guidelines.mdc  # Cursor 规则(alwaysApply: true)
├── skills/karpathy-guidelines/
│   └── SKILL.md             # 他们自己的 Hermes 风格 skill 格式
├── CLAUDE.md                # 核心行为准则(70行)
├── CURSOR.md                # Cursor vs Claude Code 平台引导
├── EXAMPLES.md              # 14.8KB —— 8 个真实代码反例,最值钱的部分
├── README.md
└── README.zh.md

⚠️ 研究外部仓库的标准流程(本仓库研究的教训): 1. 不要只看 README/主页 — 完整 clone 或下载全量目录 2. 检查所有文件,包括隐藏目录(.claude-plugin/.cursor/skills/ 等) 3. 特别关注 examples/use-cases 文件(往往最有价值,如 EXAMPLES.md 14.8KB 的 diff 对比) 4. 研究插件/平台适配层的结构(了解它是如何在多种工具之间复用的) 5. 再提炼核心价值注入到 Hermes 体系

适用范围: 所有涉及代码编写、修改、审查的任务(forge / chief / tester / aide / default 均适用)

强制等级: ⚠️ 涉及 coding 时 100% 强制执行,不得跳过。 这不是可选的风格建议。

引用材料路径(全量注入): ~/server-config/skills/references/karpathy-original-repo/(已 git commit 推至 CNB sieta/server-config commit 58ff5eb)。包含完整 EXAMPLES.md(14.8KB 8 个反例)、.claude-plugin/ 插件定义、.cursor/rules/ Cursor 规则、skills/karpathy-guidelines/ 原始 SKILL.md。


Karpathy 的三个核心诊断

仓库源起的三个观察是理解全部原则的基础:

1. "模型会代你做错误假设,不假思索就执行。它们不管理困惑、不寻求澄清、不暴露矛盾、不展示权衡、不反驳。" 2. "它们真的很喜欢把代码和 API 搞复杂……明明 100 行能搞定的事,非要 1000 行。" 3. "它们仍然会改动或删除自己没充分理解的代码和注释——即使与任务无关。"

这三句话分别对应了原则一/三/二/四


原则一:Think Before Coding(先思考再动手)

「不要假设。不要隐藏困惑。暴露权衡。」

在开始实现之前:

  1. 显式声明你的假设 — 不确定的输入/接口/边界情况,问,不擅自猜
  2. 有歧义时列出多种解释 — 不要沉默地选一个走下去
  3. 有更简单方案就说出来 — 该 push back 的时候要说,别闷头写复杂的
  4. 困惑时停下来 — 说出哪部分不清楚,请求澄清,不要假装理解

自检: 实现前是否清楚所有接口的输入输出?不确定的地方确认过了吗?

典型案例(EXAMPLES.md)

场景:用户说"加个导出功能"

❌ LLM 的错误做法:

def export_users(format='json'):
    users = User.query.all()  # 假设导出全部用户(没问范围/隐私)
    if format == 'json':
        with open('users.json', 'w') as f:  # 假设存本地文件(没问方式)
            json.dump(...)
    elif format == 'csv':
        # 假设字段名(没问数据结构)

✅ 正确的做法——先列清模糊点:

在实现之前我需要确认:
1. 全部用户还是子集?(隐私影响)
2. "导出"是指浏览器下载、后台发邮件还是 API 端点?
3. 哪些字段?(有些可能敏感)
4. 数据量多大?(影响实现方式)

原则二:Simplicity First(极简优先)

「最少代码解决问题。绝不写投机性代码。」

自检: 自问"一个 senior engineer 看了会觉得过度复杂吗?"如果会,简化。

典型案例(EXAMPLES.md)

场景:用户说"加个折扣计算函数"

❌ LLM 的错误做法(过度抽象):

# 策略模式 + 抽象基类 + 配置类 + 30行 setup
class DiscountStrategy(ABC):
    @abstractmethod
    def calculate(self, amount: float) -> float: pass
class PercentageDiscount(DiscountStrategy): ...
class FixedDiscount(DiscountStrategy): ...
class DiscountCalculator: ...
# → 30+行 setup 才能算个折扣

✅ 正确做法:

def calculate_discount(amount: float, percent: float) -> float:
    return amount * (percent / 100)

原则:当复杂性被需要时才加,而不是提前预判。

其他的过度复杂反例(来自 EXAMPLES.md): - ❌ PreferenceManager 类带了 cache/validation/notification/merge 四个没人要的功能 - ✅ 一个 UPDATE SQL 就搞定


原则三:Surgical Changes(外科手术式修改)

「只动必须改的东西。只清理自己造成的混乱。」

编辑已有代码时: - 不要"顺手改进"相邻代码、注释或格式 - 不要重构没有坏的东西 - 匹配现有风格,即使你个人更喜欢另一种写法 - 发现无关的死代码 → 提一句,但不删(除非用户明确让删)

自己改动造成孤儿代码时: - 只清理你的修改导致的未使用 import/变量/函数 - 不要删已有的死代码,除非用户要求

自检: 每一行修改是否能直接追踪到用户的需求? 问自己:这一行改变是修 bug 的必要步骤,还是我的"锦上添花"?

典型案例(EXAMPLES.md)

场景:用户说"修 bug:空邮箱会让验证器崩溃"

❌ LLM 的错误做法——顺手把半个文件改了一遍:

- # Check email format
- if not user_data.get('email'):
+ """Validate user data."""
+ # 改了注释
+ # 改了 email 校验逻辑(加了 @ 和 . 的完整校验)
+ # 加了 username 校验(三行没人要的校验)
+ # 加了 docstring

✅ 正确做法——只改引起 bug 的那两行:

- if not user_data.get('email'):
+ email = user_data.get('email', '')
+ if not email or not email.strip():
      raise ValueError("Email required")
- if '@' not in user_data['email']:
+ if '@' not in email:
      raise ValueError("Invalid email")
# username 部分:不动

风格漂移(更常见)

场景:用户说"在上传函数里加日志"

❌ LLM 改了单引号为双引号 + 加了类型注解 + 加了 docstring + 改了 return 逻辑:

- def upload_file(file_path, destination):
+ def upload_file(file_path: str, destination: str) -> bool:
+     """Upload file..."""
+     logger.info(f"Uploading {file_path} to {destination}")
-         with open(file_path, 'rb') as f:
-         with open(file_path, "rb") as f:  # ' → "
-         if response.status_code == 200:
-             return True
-         else:
-             return False
+         success = response.status_code == 200  # 改了 return 逻辑

✅ 正确做法——匹配现有风格,只加那几行 logger:

+ import logging
+ logger = logging.getLogger(__name__)

  def upload_file(file_path, destination):
+     logger.info(f'Starting upload: {file_path}')
      try:
          with open(file_path, 'rb') as f:
              data = f.read()
          response = requests.post(destination, files={'file': data})
          if response.status_code == 200:
+             logger.info(f'Upload successful: {file_path}')
              return True
          else:
+             logger.error(f'Upload failed: {file_path}, status={response.status_code}')
              return False
      except Exception as e:
-         print(f"Error: {e}")
+         logger.exception(f'Upload error: {file_path}')
          return False

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

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

把命令式任务转换成可验证的目标:

不要说... 改成...
"加验证" "写测试让无效输入失败,然后让它们通过"
"修这个 bug" "写一个能复现 bug 的测试,然后让它通过"
"重构 X" "确保测试在重构前后都通过"

多步骤任务的结构化计划格式(必须用):

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

自检: 验收标准是否明确、可验证?能明确判断"做完了"吗?

典型案例(EXAMPLES.md)

场景:用户说"修复排序在有重复分数时出问题"

❌ LLM 的错误做法——直接改 sort 逻辑,不先复现 bug:

def sort_scores(scores):
    return sorted(scores, key=lambda x: (-x['score'], x['name']))

✅ 正确做法——先写复现测试,再修:

# 1. 先写测试复现 bug
def test_sort_with_duplicate_scores():
    scores = [
        {'name': 'Alice', 'score': 100},
        {'name': 'Bob', 'score': 100},
        {'name': 'Charlie', 'score': 90},
    ]
    result = sort_scores(scores)
    # 跑 10 次 → 顺序不稳定 → 测试失败 ✓ 确认 bug

# 2. 再修
def sort_scores(scores):
    return sorted(scores, key=lambda x: (-x['score'], x['name']))
# 测试现在稳定通过 ✓

反模式总表(EXAMPLES.md 核心总结)

原则 反模式 正确做法
Think Before Coding 默认假设文件格式/范围/字段 列出假设,逐个问清楚
Simplicity First 折扣计算用例策略模式 一个函数解决问题,复杂度等到真需要再加
Surgical Changes 修 bug 时顺手改引号/类型注解/return 逻辑 只改修复 bug 的必要行
Goal-Driven "我来审查改进代码" "先写复现 bug 的测试 → 让它通过 → 验证无回归"

核心洞察

那些"过度复杂"的例子并不是明显错误的——它们遵循了设计模式和最佳实践。问题出在时机:它们在需要之前就加了复杂度。

好的代码是用简单方式解决今天的问题,而不是过早预测明天的问题。


📋 Coding 执行检查清单(强制)

每次 coding 任务完成后,过一遍这个清单:

如果以上任何一项回答"不确定"或"可能超标",stop and clarify。

⚠️ 特别警告:Surgical Changes(原则三)是 Karpathy 认为 LLM 最容易犯、也最让人沮丧的错。修 Bug 时每次 check 一下 diff 里有没有不属于任务的行——任何与用户需求无关的改动都是问题**。


相关参考