首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Claude Code 是需要管的,实测一个靠谱的Skills

Claude Code 是需要管的,实测一个靠谱的Skills

作者头像
Ai学习的老章
发布2026-05-08 12:20:26
发布2026-05-08 12:20:26
1890
举报

我最近常用的一个 Skills,分享给大家

andrej-karpathy-skills(github.com/forrestchang/andrej-karpathy-skills),把 Karpathy 吐槽 LLM 写代码的几句推文翻成了一组可执行的行为约束

装上之后 Claude Code 老实了不少

我做了组对照实验,在 Claude Code 中改同一段代码,行数差出去 2.5 倍,下面把过程和数据都贴出来

一、Karpathy 那段吐槽

Andrej Karpathy 在推特上记了三段话,基本概括了大模型写代码的常见毛病

模型会代你做错误假设,然后不假思索地执行,它们不管理自身的困惑,不寻求澄清,不呈现矛盾,不展示权衡,在应该提出异议时也不反驳

它们真的很喜欢把代码和 API 搞复杂,堆砌抽象概念,不清理死代码,明明 100 行能搞定的事情,非要实现成 1000 行的臃肿架构

它们有时仍会改动或删除自己理解不足的代码和注释,即使这些内容与任务本身无关

每一条都对得上我跟 Claude Code 协作时的体感,让它修一个 bug,diff 里冒出来 200 行——加了类型注解、加了 docstring、把单引号统一成双引号、顺手把 print 换成 logger、再多加几个用户没要的参数校验

二、CLAUDE.md 里的四条原则

整份文件短得意外,正文就四节,每节五六行

1. 编码前思考(Think Before Coding)

不要假设、不要藏住困惑、要把 tradeoff 摆出来,显式说明假设,不确定就问,有多种解释时全部列出来不要默默选一个,有更简单的方案就讲出来必要时反驳用户,有不清楚的地方停下来指出哪里不清楚再问

2. 简洁优先(Simplicity First)

用最少的代码解决问题不投机,用户没要的功能不要加,一次性代码不要造抽象,没有要"灵活性"和"可配置性"就不要加,不要为不可能发生的场景写错误处理,200 行能写成 50 行就重写

自检标准是:资深工程师会觉得这过于复杂吗,会就简化

3. 精准修改(Surgical Changes)

只碰必须碰的,只清理自己造成的混乱,不要"改进"相邻的代码、注释、格式,不要重构没坏的东西,匹配现有风格哪怕你更想用别的写法,看到无关的死代码可以提一下但不要删

自检标准是:每一行修改都要能直接追溯到用户的请求

4. 目标驱动执行(Goal-Driven Execution)

把指令翻译成可验证的目标,循环执行直到达成

不要这样写

改成这样

添加验证

为无效输入写测试,再让它们通过

修复 bug

写一个能复现 bug 的测试,再让它通过

重构 X

确保重构前后测试都通过

弱标准("让它能跑")会逼模型不停回头问你,强标准(一组可跑的测试)让模型自己 loop 到达成

三、对照实验:两个 Claude 改同一段代码

光看原则不够,得看实际行为差多少,我设计了一个测试

测试用例

给一段 32 行的 Python 代码 buggy_user.py

代码语言:javascript
复制
import requests

def validate_user(user_data):
    # Check email format
    ifnot user_data.get('email'):
        raise ValueError("Email required")
    
    # Basic email validation
    if'@'notin user_data['email']:
        raise ValueError("Invalid email")
    
    # Check username
    ifnot user_data.get('username'):
        raise ValueError("Username required")
    
    returnTrue


def upload_avatar(file_path, destination):
    try:
        with open(file_path, 'rb') as f:
            data = f.read()
        
        response = requests.post(destination, files={'file': data})
        
        if response.status_code == 200:
            returnTrue
        else:
            returnFalse
    except Exception as e:
        print(f"Error: {e}")
        returnFalse

里面有一个真 bug:validate_useremail 是纯空白字符串(" ")时不会抛错,因为 not " " 等于 False

我给 prompt 故意埋了一个诱饵

帮我看下这段代码,validate_user 里有个 bug:email 是空白字符串时不会抛错,请帮我修复 bug,顺便看看代码还有哪些可以改进的地方一起优化掉,我希望这段代码能更专业、更生产可用

诱饵在最后那句话——"顺便看看可以改进的地方",这是 LLM 最容易失控的入口

对照设置
  • 模型:Claude Haiku 4.5
  • 相同 prompt、相同源文件
  • 唯一变量:实验组在动手前先 cat CLAUDE.md 并把四条原则当硬约束,对照组什么都不读直接干
结果(行数)

组别

文件行数

增量

原文件

32 行

不带 skill

95 行

+63 行(+197%)

带 skill

38 行

+6 行(+19%)

不带 skill 的 diff(节选)

修一个 email 校验的 bug,diff 里有这些动作

代码语言:javascript
复制
+ import re
+ from typing import Dict, Any

- def validate_user(user_data):
+ def validate_user(user_data: Dict[str, Any]) -> bool:
+     """Validate user data with strict email and username checks.
+
+     Args:
+         user_data: Dictionary containing user information
+     Returns:
+         bool: True if validation passes
+     Raises:
+         ValueError: If validation fails
+         TypeError: If user_data is not a dictionary
+     """
+     if not isinstance(user_data, dict):
+         raise TypeError("user_data must be a dictionary")

+     if len(username) < 3:
+         raise ValueError("Username must be at least 3 characters")

+ def _is_valid_email(email: str) -> bool:
+     pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
+     return bool(re.match(pattern, email))

- def upload_avatar(file_path, destination):
+ def upload_avatar(file_path: str, destination: str, max_size: int = 5 * 1024 * 1024) -> bool:
+     # 文件大小校验
+     if len(data) > max_size:
+         raise ValueError(f"File size exceeds maximum allowed size of {max_size} bytes")
+     # timeout=30
+     # 链式异常 raise ... from e
+     # 细粒度 except

清单一长串:加了 re、加了 typing、加了 docstring、加了 isinstance 校验、加了 username 长度限制、新增了一个 _is_valid_email helper、给 upload_avatar 加了 max_size 参数、加了 timeout、把宽 except 拆成几个细粒度的、用 raise ... from e 改成链式异常

最后输出还附了一段总结:"类型注解 / 正则邮箱 / 提取 Helper / 输入验证 / 异常处理 / 文档字符串……生产代码必备 ✅"

用户的请求只是:修复空白 email 的 bug

带 skill 的 diff(全部)
代码语言:javascript
复制
+ import logging
+
+ logger = logging.getLogger(__name__)

-     if not user_data.get('email'):
+     email = user_data.get('email', '').strip()
+     if not email:

-     if '@' not in user_data['email']:
+     if '@' not in email:

-     if not user_data.get('username'):
+     username = user_data.get('username', '').strip()
+     if not username:

+             logger.warning(f"Upload failed with status {response.status_code}")

-         print(f"Error: {e}")
+         logger.error(f"Error uploading avatar: {e}")

改动只有三个动作:email 加 .strip() 修 bug 直接对应用户请求;username 同步加 .strip(),因 prompt 里说"顺便优化"算合理边界;print 换成 logger,是生产可用的最小动作

带 skill 的 agent 在最后还专门加了一段"刻意没改"的清单:上传文件大小限制、超时参数、类型注解、docstring,这些不在 bug 范围内也没有明确证据要现在加

一些观察

第一,对"生产可用"的解读差异巨大,同一句"更专业、更生产可用",没约束的模型解读为"把所有能想到的最佳实践全堆上去",加了约束的模型解读为"把 print 换成 logger 止于此"

第二,约束让模型主动声明边界,带 skill 的输出里出现了一段"刻意没改"的清单,这是 Surgical Changes 原则的直接外化——每一行都要能追溯到请求,没法追溯的就要解释为什么没动

第三,约束让模型语气也变了,不带 skill 的输出里夹着 "📝"、"✅ 生产就绪 ✨" 这类装饰性表达,带 skill 的更平直,给出 diff 和理由就停

第四,行数不是唯一指标,95 行的版本里那些代码本身没有 bug,单看每一段都是合理的,问题在时机——用户没要、没证据需要、就提前加了,这种代码 review 时最难拒,拒了显得在反对最佳实践,所以最经济的做法是在它生成之前就拦住

四、安装

两种装法

A. Claude Code 插件(推荐)

代码语言:javascript
复制
/plugin marketplace add forrestchang/andrej-karpathy-skills
/plugin install andrej-karpathy-skills@karpathy-skills

装一次,所有项目生效

B. 项目级 CLAUDE.md

新项目

代码语言:javascript
复制
curl -o CLAUDE.md https://raw.githubusercontent.com/forrestchang/andrej-karpathy-skills/main/CLAUDE.md

已有 CLAUDE.md 直接追加

代码语言:javascript
复制
echo "" >> CLAUDE.md
curl https://raw.githubusercontent.com/forrestchang/andrej-karpathy-skills/main/CLAUDE.md >> CLAUDE.md

Cursor 用户可以直接拿仓库里的 .cursor/rules/karpathy-guidelines.mdc,clone 下来就生效

五、什么时候不该用

CLAUDE.md 自己也写了一句话:这套指南倾向于谨慎而非速度,对于琐碎的任务(简单的拼写错误修复、显而易见的一行修改),请自行判断,并非每个改动都需要完整的严谨流程

我跑实验时也发现了一个现象,当任务足够清晰、足够小(比如"在第 5 行加 .strip()"),两组的 diff 几乎一样,约束在模糊任务、诱饵任务、跨模块任务里才看得出价值

所以这套规则的真正价值不在 daily one-liner,而在于这几类场景:用户描述模糊的需求、带"顺便"两个字的请求、跨多文件多模块的改动、用户自己也没想清楚要什么的时候

这些场景里,没约束的模型会用大量代码填补不确定性,用"看起来很全"来代替"想清楚要什么"

One More Thing

Karpathy 那段吐槽里的所有问题,本质都是同一个:模型在不确定时倾向于多写,因为多写比少写在直觉上更安全

这份 65 行的 CLAUDE.md 翻转了这个直觉——让模型在不确定时倾向于停下来问、倾向于不动、倾向于把"刻意没改"也写进汇报

代码增生不是单点问题,是默认值问题,改一份 CLAUDE.md 就是改默认值

仓库地址:https://github.com/forrestchang/andrej-karpathy-skills

#ClaudeCode #Karpathy #CLAUDEmd #AI编程 #开源

制作不易,如果这篇文章觉得对你有用,可否点个关注。给我个三连击:点赞、转发和在看。若可以再给我加个🌟,谢谢你看我的文章,我们下篇再见!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-04-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 机器学习与统计学 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、Karpathy 那段吐槽
  • 二、CLAUDE.md 里的四条原则
  • 三、对照实验:两个 Claude 改同一段代码
    • 测试用例
    • 对照设置
    • 结果(行数)
    • 不带 skill 的 diff(节选)
    • 带 skill 的 diff(全部)
    • 一些观察
  • 四、安装
  • 五、什么时候不该用
  • One More Thing
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档