Skill 进阶:bundle 附件、控制触发、保持 SKILL.md 精简
- 理解 SKILL.md 臃肿为什么反而坑,能说清楚两个具体的副作用
- 掌握 bundle 附件结构:把脚本和长参考放进 Skill 文件夹,SKILL.md 按需引用
- 写出让触发时机可控的 description,知道过宽和过窄各有什么问题
- 能组织多个 Skill 不乱,会识别并修复"SKILL.md 塞太多 / 附件没被引用"两类高频坑
第一个 Skill 能跑了,就觉得找到门道了——好,那就继续塞。把团队规范塞进去,把参考命令塞进去,把几段解释说明也塞进去。SKILL.md 越写越长,心里越踏实。
然后有一天你发现:这个 Skill 触发越来越慢,有时候还会在不该出现的场景里冒头,改了一处描述整个文件又难读了。
这不是 Skills 机制的问题。是用错了方向——Skill 进阶靠的是会做减法,不是会堆内容。
臃肿的 SKILL.md 为什么反而坑
Skills 入门那篇解释过渐进式披露的原理:Skill 闲置时只加载 description 那一行元数据,触发后才把 SKILL.md 全文塞进上下文。这个机制给了你"装 100+ 个 Skill 不撑爆上下文"的自由,但随之而来有一个隐含的代价:一旦触发,正文全进来。
如果你的 SKILL.md 写了 800 字,触发时就是 800 token 的上下文占用,加上你塞进去的脚本、规范细则、背景解释,很快就能搞出 2000+ token 的巨无霸。代价有两层:
第一层:精度下降。 长文件里,模型要从一大堆内容里提炼出"这次应该做什么"。关键指令淹没在解释说明里,执行时容易对焦偏。这不是模型笨,是信噪比问题——写得越多,重要的反而越不突出。
第二层:维护变难。 你在第三段改了一行脚本,顺手要检查第一段的引用有没有过时,第五段的说明要不要同步更新——文件越长,改动一处要检查的地方越多。Skill 本来是为了减少重复劳动的,结果变成一个需要专门维护的文档。
解法不是把 Skill 写短就了事,而是分层:SKILL.md 只放核心指令,细节放进附件,主文件按需引用。
bundle 附加文件:把细节放进文件夹
写你的第一个 Skill 里介绍的是最小结构:一个文件夹 + 一个 SKILL.md。进阶做法是在这个文件夹里放更多文件,SKILL.md 通过路径引用它们。
这就是 bundle——把属于同一个 Skill 的资产打包在一起,而不是全部塞进主文件。
典型的 bundle 结构
.claude/skills/
└── commit/
├── SKILL.md ← 主文件,只放核心指令和引用
├── commit-types.md ← 参考资料:提交类型说明表
└── check.sh ← 脚本:提交前 lint 检查
SKILL.md 里的内容大概是这样:
---
name: commit
description: 需要提交代码时,帮用户写规范的 git commit 信息并执行
---
## 执行步骤
1. 运行 `./check.sh` 检查 lint(如果项目有 eslint 配置)。
2. `git diff --staged` 读取暂存区变更。
3. 按 `commit-types.md` 里的类型规范,生成 `type(scope): subject` 格式的信息。
4. 展示给用户确认,确认后执行 `git commit -m "..."`.
## 注意
- subject 不超过 72 字符
- 不用被动语态,用祈使句(add / fix / update,不是 added / fixed)
- 如果改动涉及多个模块,拆成多条 commit 而不是一条塞满
核心指令清晰、可读。commit-types.md 里可以写一个完整的类型说明表,几十行都没关系,因为它只有被 SKILL.md 显式引用时才会加载——或者更准确地说,模型会根据 SKILL.md 的指令决定是否读取这个文件。你可以在正文里写"参考 commit-types.md 里的类型定义",模型执行时会去读那个文件,而不是在 Skill 触发时就把它全部吞进上下文。
什么东西适合放进附件
- 参考表格:类型说明、代码风格规范、命名约定——这类内容很长,但每次执行不一定全用上
- 脚本文件:
.sh、.py、.js——可执行的辅助脚本,SKILL.md 只管"在什么时候、用什么参数调用它" - 模板文件:PR 描述模板、changelog 格式模板——主文件引用路径,执行时填充
什么东西留在 SKILL.md
- 触发判断逻辑:让 description 和核心指令精简、突出
- 执行流程骨架:步骤编号、分支判断——告诉模型"先做什么再做什么"
- 附件引用:
参考 xxx.md或运行 xxx.sh——告诉模型去哪里找细节
经验规律:SKILL.md 超过 400 字就该考虑拆文件了。不是硬规定,是个提醒自己的信号。
控制触发:description 写准,渐进式披露的精髓
Skills 的触发由 description 字段决定——模型在每次对话开始时扫描所有 Skill 的 description,判断当前任务是否匹配。description 写得好,触发时机精准;写得不好,有两种常见的失控:
触发太宽:description 写的是"帮助用户处理代码相关任务"。结果几乎任何场景都能匹配,Skill 频繁出现在不该出现的地方,干扰正常对话。
触发太窄:description 写的是"当用户输入 /commit 时执行提交"。结果用户说"帮我提一个 commit"完全不触发,还要手动召唤。
好的 description 应该回答一个问题:用户在什么场景、说了什么关键词或者意图时,这个 Skill 应该介入?
对比三个版本:
| 版本 | description | 问题 |
|---|---|---|
| 差 | "处理代码任务" | 太宽,几乎总触发 |
| 差 | "用户输入 /commit 时" | 太窄,自然语言触发不了 |
| 好 | "用户要提交代码、写 commit 信息或问 commit 规范时" | 意图明确,场景范围合理 |
几个写 description 的实用原则:
用用户的语言描述意图,不是描述 Skill 的功能。"用户要提交代码"比"执行 git commit 流程"更容易被模型匹配到真实对话。
列举触发场景的变体。"提交 / 写 commit / commit 规范 / 代码记录"——用户说法不同,但意图一样,都应该触发。
说清楚不应该触发的边界(可选)。如果你有一个写 PR 的 Skill 和一个写 commit 的 Skill,后者的 description 可以加一句"注意:仅限提交阶段,PR 描述由单独的 pr-review Skill 处理",帮模型区分两者。
保持 SKILL.md 精简:为什么减法比加法难
把 SKILL.md 控制在精简状态,比刚开始写的时候更难。因为随着你用它的场景越来越多,"顺手加一段"的冲动会一直有:加一条边界情况的处理、加一段背景解释、加一个备注。每次加的理由都成立,结果就是文件越来越膨胀。
一个有用的思维定势:每次往 SKILL.md 加内容,先问"这是执行指令还是参考资料"。
执行指令:告诉模型"在什么情况下做什么",必须留在 SKILL.md,因为模型需要在触发时立刻理解。
参考资料:告诉模型"某个细节是什么",可以移到附件,SKILL.md 只留一个引用。
背景解释:给人看的、解释为什么这样设计的说明——可以删掉或者移到附件,模型不需要读懂你的设计理由才能执行。
另一个信号:如果 SKILL.md 里有多个独立的流程,通常说明你在一个文件里塞了不止一个 Skill。拆成两个文件,各自 description 清晰,比合并在一起更好维护,触发也更精准。
组织多个 Skill
当你积累了几个 Skill,目录结构该怎么管?
项目级 Skill 放在项目目录的 .claude/skills/ 下,只有这个项目生效。全局 Skill 放在 ~/.claude/skills/ 下,所有项目都能用。判断标准很简单:这个 Skill 是针对这个项目的流程,还是我走哪都要用的习惯?
~/.claude/skills/
├── commit/ ← 全局:提交规范,所有项目通用
│ ├── SKILL.md
│ └── commit-types.md
└── daily-standup/ ← 全局:每日站会记录格式
my-project/.claude/skills/
├── deploy/ ← 项目级:这个项目特有的部署流程
│ ├── SKILL.md
│ └── deploy-check.sh
└── api-review/ ← 项目级:这个项目的 API 评审清单
├── SKILL.md
└── api-checklist.md
全局 Skill 相当于"我的工作方式",项目 Skill 相当于"这个项目的规矩"。两层不冲突,但如果你有一个全局 commit Skill 和一个项目级 commit Skill,注意 description 要能区分,或者直接让项目级覆盖全局级。
命名也值得统一:文件夹名用动词或意图短语(commit、pr-review、changelog),看目录结构就知道这个 Skill 管什么。不要用 skill-1、my-skill-v2 这类名字,维护两个月后你自己也不记得是干嘛的。
跨工具复用 Skill 的标准化做法,可以参考 AgentSkills 规范——如果你在多个 AI 工具(不只是 Claude Code)之间共用一套 Skill,统一结构非常重要。
带 bundle 的 Skill 完整目录示例
下面是一个实际可用的 changelog Skill,包含主文件和两个附件:
.claude/skills/
└── changelog/
├── SKILL.md
├── changelog-format.md
└── categorize.py
SKILL.md(精简版,~200 字):
---
name: changelog
description: 用户要更新 CHANGELOG、生成发版记录或整理本次发布的变更时
---
## 步骤
1. 运行 `git log --oneline [上一个 tag]..HEAD` 获取提交列表。
2. 用 `categorize.py` 对提交分类(Breaking / Feature / Fix / Chore)。
3. 按 `changelog-format.md` 里的模板格式,生成这次发版的 changelog 段落。
4. 输出到 CHANGELOG.md 对应版本号下方,保留已有历史记录不动。
## 注意
- 版本号格式遵循 semver(x.y.z)
- Breaking changes 单独放在最前,加粗标出
changelog-format.md(可以写 100 行的格式说明,SKILL.md 不受影响)
categorize.py(分类逻辑脚本,SKILL.md 只管调用它)
这就是 bundle 的完整形态:主文件一眼看完,附件各司其职,换任何一个附件都不影响主文件的可读性。
故障排查表
| 症状 | 原因 | 解法 |
|---|---|---|
| Skill 经常在不相关的对话里触发 | description 写得太宽泛,意图范围过大 | 缩小 description 的场景范围,加具体触发关键词 |
| 明明在说相关任务,Skill 却没触发 | description 用的是功能描述而不是用户意图描述 | 改成"用户想做 X 时"的表达方式,并列举常见说法变体 |
| 附件放进去了但模型没用到 | SKILL.md 里没有引用附件路径,模型不知道去哪找 | 在 SKILL.md 的步骤里加明确引用,如"参考 xxx.md"或"运行 xxx.sh" |
| SKILL.md 改了一处,执行结果变了很多 | 文件太长,各部分之间存在隐性耦合 | 把无关内容拆到附件,保持主文件的每一段只管一件事 |
| 多个 Skill 同时触发,行为混乱 | 两个 Skill 的 description 覆盖范围重叠 | 检查 description 是否有场景交叉,明确各自的边界或合并为一个 Skill |
常见问题
Q:附件里的脚本 Claude Code 能直接运行吗?
能。你在 SKILL.md 里写"运行 ./deploy-check.sh",Claude Code 会在 Skill 执行时调用它(需要你确认权限)。脚本路径相对于 Skill 文件夹,所以 ./check.sh 指的就是同级目录里的 check.sh。
Q:bundle 里能放多少个附件?没有限制吗?
技术上没有数量限制,但经验上超过 4-5 个附件就要思考一下这个 Skill 是不是在管太多事情了。附件多通常是 Skill 边界模糊的信号,考虑拆分。
Q:全局 Skill 和项目 Skill 同名会怎样?
一般情况下项目级优先,具体行为以工具版本为准。更稳妥的做法是避免同名,或者在项目 Skill 的 description 里明确"仅限本项目的 X 流程",跟全局版本区分开。
Q:SKILL.md 能写多短?有没有最低要求?
没有最低字数要求。你可以只写一句话的指令,只要 description 和正文合在一起能让模型理解"触发条件"和"执行步骤"就够了。能短则短——渐进式披露的精髓就是"不用时尽量少占空间"。
Q:附件用中文写还是英文写?
随你的习惯。SKILL.md 和附件的语言不需要统一,模型能理解混排。如果团队共用,建议保持一致,方便其他人维护。关于团队共享 Skill 的规范,参考 Skills 跨工具共享。
继续往下走
这三节(3.5-3.7)把 Skills 从"能跑"到"好用"的路走了一遍:入门原理 → 写第一个 → bundle 进阶。
下一步是让 Skill 跨工具、跨团队复用——标准化结构是关键,在 AgentSkills 跨工具复用规范 里展开。
回 AI 编程教程大全 看完整的 L3 路线。
👉 看看我们的 AI 编程实战体系课,或逛 AI 编程教程大全 把基本功打扎实。