1. SKILL到底是什么:先把这个概念从"高级Prompt模板"里摘出来
聊到Anthropic的Agent Skills(官方文档里统称SKILL),第一次接触的人十有八九会把它当成"高级一点的Prompt模板"。我第一次看到这个概念的时候也是这么想的——直到真的在Claude Code里把一个SKILL文件夹丢给模型去跑,让它自己决定什么时候加载、怎么用,我才意识到这完全不是一个东西。
SKILL的官方定义很简洁:一组打包好的指令和相关资源,让Claude在需要时自动调用,从而获得某一项专业能力。它可以是分析财报的技能、生成SVG图标的技能、填写PDF表格的技能,也可以是复制某个品牌设计风格的技能。关键在于"按需加载"这四个字——它不是每轮对话都塞进上下文的固定指令,而是一个放在旁边、等任务匹配时才被读取的"专业手册"。
在SKILL出现之前,想让Claude稳定输出某种特定格式或者具备某种专业行为,通常只有两条路:要么把几千行的领域规则硬塞进System Prompt,结果上下文被占满,普通对话的质量肉眼可见地下降;要么专门写一个MCP服务器,用代码把工具和数据接进来,成本高、维护也重。SKILL正好补上了中间地带:它不需要长驻上下文,也不需要写代码,只需要一份高质量的Markdown指令文件,外加可选的脚本和静态资源。
对我来说,理解SKILL最好的切入点,是把Claude想象成一个新入职的顾问。System Prompt是这个人的性格底色和工作原则,MCP是他能调用的数据库和外部系统,而SKILL则是他办公桌上那一摞"遇到XX任务时先翻这一本"的操作手册。手册平时不摊开,等真接到对应任务,他才会翻开按照流程执行。理解了这层关系,后面很多写作规范就顺理成章了。
另外一个容易忽略的点是SKILL的适用范围。它并不只是Claude Code的专属功能,API、Claude桌面端和网页版都支持。在API里通过skills参数传入,在Claude Code里放进skill目录,在Claude应用中通过设置上传。同一个SKILL文件夹,换不同入口都能被识别,这也是它适合团队成员之间共享复用的原因。
2. 拆开一个标准的SKILL目录:每个文件都是干什么的
一个SKILL本质上就是一个目录,目录里最重要的文件叫SKILL.md。官方推荐的目录结构大概是这样的:
my-skill/ ├── SKILL.md ├── SKILL.py ├── assets/ │ ├── report-template.xlsx │ └── brand-colors.md └── requirements.txt2.1 SKILL.md的三层结构
SKILL.md是整个技能的"主控制器"。它由三部分组成:开头的YAML frontmatter(元信息区)、正文指令区,以及可选的示例区。
--- name: meeting-notes description: When to use this skill to extract meeting minutes and action items from a transcript. --- # Meeting Notes Skill ## Instructions Extract the following from the transcript: - Key decisions - Action items, each with owner and deadline ...frontmatter里有两个必填字段:name和description。name要求小写字母、数字和连字符的组合,最好控制在40个字符以内,这个值会作为技能的唯一标识。description则直接决定Claude会不会在合适的时机调用这个技能——它需要清晰地说明"什么场景下使用这个技能"以及"这个技能能做什么",一般1到2句话就够了。
正文部分才是技能的真正内容。官方推荐的做法是,SKILL.md整体控制在500行以内,极限不要超过2000行。如果超过,多半是你把太多细节塞进了主文件,而不是通过渐进式披露(progressive disclosure)把深度知识放到被引用的附属文件里。
2.2 附属资源文件:SKILL.py、assets和依赖清单
SKILL.py是一个可选文件。当你希望技能具备计算或自动化能力时,可以在这里放Python代码。Claude会在需要时调用它并读取执行结果。相比在指令里让模型"手算"或用bash跑一堆命令,把逻辑放进Python脚本显然更可靠、更可复现。
assets目录用来存放模板、参考文档、图片等静态资源。比如做一个Excel报表生成的SKILL,就可以把带格式的模板文件放在assets里,指令里用相对路径引用它。requirements.txt则声明技能依赖的Python包,Claude环境会自动处理安装。
2.3 技能应该放在哪里
在Claude Code里,技能可以放在用户级目录~/.claude/skills/,也可以放在项目级目录.claude/skills/下。放用户级意味着所有项目都能用,放项目级则只对当前项目生效。Claude app则是在设置-技能里上传或添加。有一点要注意:技能目录名需要和SKILL.md里的name保持一致,否则识别会出现问题。
我自己习惯把所有技能用git管理。每个技能一个仓库目录,改动有记录,团队里其他人直接clone过来就能用。这比反复复制粘贴文件靠谱得多。
3. 官方最佳实践拆解:怎么写出一份真正好用的SKILL.md
Anthropic官方文档里有一些非常具体的写作建议,我把它们翻译、消化之后,结合自己的实测经验整理成下面这几条。每一条都会配上"错误示范"和"正确做法"的对比,方便对照。
3.1 description是唯一的入口闸门,值得单独打磨
Claude不会提前读你的SKILL.md正文,它只会在每轮对话开始前快速扫描各个技能的描述。所以description写得好不好,直接决定它会不会在正确的时机打开这个技能。
错误示范是宽泛、模糊的描述,比如"A skill for data analysis"。这种描述会让Claude拿不准什么时候该用,结果就是该触发时不触发,或者不该触发时频繁触发。正确做法是把触发条件写完全:
description: When the user asks to analyze sales data from CRM exports, use this skill to build a monthly summary report with YoY comparison and anomaly flags.这个描述同时包含了触发场景(CRM导出、销售数据)和产出形态(月度摘要、同比对比、异常标记)。Claude只需要扫一眼就能做判断。
3.2 指令要写"怎么做",而不是只写"做什么"
这是官方明确强调的一条:好的SKILL不是描述结果,而是解释过程。直接写"Resolve the user's issue"的问题是,模型的自由度太高,输出风格和结构都不可控。
正确的方式是给出步骤化指令。比如做一个日志排查技能,不要只写"Analyze the logs and identify the error",而要拆解成:
1. Read the log file and extract the first 20 lines of context around each ERROR entry. 2. Classify each error into: authentication, rate limiting, infrastructure, or application logic. 3. For each class, list the top 3 most likely causes based on the surrounding log lines. 4. Propose a fix, ordered by implementation effort.每一步都是可验证的动作,输出才有稳定的结构。这背后其实是一种思维:你把"分析日志"这件事从一个模糊目标,拆成了模型可以逐步执行的子任务。
3.3 渐进式披露:用500行原则保持上下文干净
渐进式披露是SKILL设计里最核心的思想。它的意思是:SKILL.md里只放高信号、高频使用的核心指令,把低频但重要的细节放在附属文件里,等模型真正需要时再去读取。
我见过不少失败的SKILL,都是把整个领域的知识百科全塞进一个文件,结果上下文被大量低概率信息占据,模型反而抓不住重点。官方推荐的"500行以内"像一个强制约束,逼着你做取舍。那放不下的细节怎么办?放在references.md或者assets目录里,然后在正文中用一句话引用:"If you need the detailed data dictionary, read assets/data-dictionary.md first."
这和我日常写代码的习惯很像:主函数保持短小,复杂的实现抽到工具类里,按需import。SKILL.md就是主函数,附属文件就是工具类。
3.4 示例的价值超乎想象,尤其是"坏输入"示例
光说"要做什么"还不够,模型需要看到"做出来的东西长什么样"。官方最佳实践里有一条:用示例展示期望的输出格式,效果远好于大段文字说明。
更进阶的用法是给"边界示例"。比如日期解析技能,示例里不只是常规的"2025-01-15",还要有"last Friday、Q3、FY26"这类模糊表达怎么处理。把容易出错的输入类型写进示例,等于给模型打了一针预防疫苗,实测下来能显著减少边界情况的翻车。
3.5 重要规则要放在显眼位置,固定措辞直接引用
如果某项规则特别关键,比如"所有的金额都必须四舍五入到两位小数""所有报告必须包含免责声明",不要把它淹没在长段落中间,而是要单独成节,放在Instructions的顶部或者专门的"Critical Rules"部分。模型对上下文头尾的注意力天然高于中间部分,重要规则放在头部比放在尾部稳定得多。
另外有一种特殊场景——品牌合规或内容安全。当技能需要强制输出某些固定句子时,不要把意思转述给模型,直接把原文放进代码块里引用,并要求逐字复制。这样比"换种说法也可以"要稳得多。
3.6 时间感知的写法:用相对时间而不是硬编码日期
技能会在任意时间点被调用,如果指令里写死"2025年第一季度"。这个技能半年后就过时了。官方建议使用相对时间表达,比如"use the current date and refer to 'today'、'this quarter'"——让模型基于系统时间现场推算。
我曾经写过一个做季度汇报的技能,就因为没有强调"以系统当前时间为准",导致模型在4月份生成报告时仍然引用上一个季度的数据口径。后来在指令里加了一句:"All date references must be based on the current system date, never assume a fixed date."这个问题再没出现过。
3.7 反面清单:什么样的SKILL一定会翻车
官方文档里也列举了一些反面案例,我照着踩过坑之后深有体会:
| 问题 | 具体表现 | 我的建议 |
|---|---|---|
| 追求大而全 | 一个技能想覆盖所有场景 | 拆成多个单一职责的小技能 |
| 用形容词描述风格 | "make it beautiful/polished" | 给出具体标准(色值、字号、结构) |
| 塞入大量通用知识 | 把百科内容复制进技能 | 只保留流程性、步骤性知识 |
| 引用外部登录资源 | 指令里让模型去读需要鉴权的链接 | 把内容直接放进assets里 |
| 盲目堆砌长指令 | 2000行以上还想让模型全记住 | 坚持渐进式披露 |
4. SKILL、MCP、System Prompt、插件:四者的边界与选型
很多人混淆SKILL和MCP,这不能怪大家,因为两者确实都是在"扩展Claude能力"这个目标下工作。但它们解决的问题完全不同,选错方案的代价也不小。
MCP(Model Context Protocol)的本质是给模型提供工具和数据访问能力。它让Claude可以查询数据库、调用REST API、操作外部系统,而且通常需要你维护一个服务端。SKILL的本质是给模型提供专业指令和领域知识,它不需要任何服务端,纯粹是一份"怎么做这件事"的说明书。
打个比方:MCP是给顾问接通了公司内部的ERP系统,他可以直接查数据;SKILL是给他一本《如何做月度经营分析》的方法论文档,让他知道查哪些数据、怎么算、怎么呈现。一个解决"能不能访问",一个解决"会不会做"。
System Prompt则是另一回事。它每轮对话都全程加载,适合放全局性的行为规则、身份设定和价值观约束。而SKILL是条件加载的,适合放局部的专业任务指令。如果某个规则必须任何时候都生效,比如"永远用简体中文回复",那它属于System Prompt;如果只是在做数据分析时才需要遵守的规则,则更适合做成SKILL。
插件(Plugin)在Claude Code生态里是更上层的概念,它可以把SKILL、MCP服务器、命令、子代理打包在一起分发。你可以把插件理解成一个"全家桶安装包",而SKILL是其中一个独立的模块。
选型时我的判断依据很简单:
- 需要连接外部系统、读写数据 → MCP
- 需要专业技能、领域流程、格式模板 → SKILL
- 全局必守的规则 → System Prompt
- 你要打包发给团队协作、组合多能力 → 插件
还有一个常见误区:有人想用SKILL来做"通用知识问答增强",把一堆百科条目放进技能里。这是对SKILL的误解。技能不是知识库,它是"如何执行任务"的程序化说明。通用知识应该靠模型自身能力或RAG方案解决,塞进SKILL只会造成上下文浪费和触发不确定性。
5. 实战:从零写一个"会议纪要与行动项抽取"SKILL
理论说再多,不如实际走一遍。我以最近常用的一个技能为例,把从需求定义到测试迭代的完整过程记录下来。
5.1 第一步:界定输入输出
做任何技能前先回答三个问题:输入是什么?输出是什么?什么场景触发?我当时的答案:
- 输入:一段会议录音转文字文本,可能夹杂无关闲聊
- 输出:结构化会议纪要,包含会议主题、关键决策、行动项(每个行动项含负责人和截止日期)
- 触发场景:用户提供会议transcript并要求整理
这三个问题不搞清楚,后面怎么写都不对。很多人写SKILL翻车,第一步就栽在连自己的技能边界都没想明白。
5.2 第二步:编写SKILL.md
--- name: meeting-minutes description: When the user provides a meeting transcript (or asks to summarize meeting notes), use this skill to produce structured minutes with key decisions and action items. Output as Markdown. --- # Meeting Minutes Skill ## Instructions Follow these steps when processing a meeting transcript: 1. Read the full transcript first. Do not skip sections. 2. Extract and state the meeting topic in one sentence, based on the dominant agenda. 3. Identify the participants, only if explicitly named. 4. Summarize key decisions as bullet points. Each decision must have a "Decision:" prefix. 5. Extract action items, one per bullet, using this format: - Owner: [person or "unassigned"] - Task: [specific deliverable] - Due: [date if mentioned, otherwise "no deadline"] 6. Ignore small talk, repeated points, and unrelated tangents. 7. If the transcript is ambiguous, note it in an "Open Questions" section instead of guessing. ## Example Output # Meeting Summary **Topic:** Q3 OKR planning **Participants:** Alice, Bob, Carol **Key Decisions:** - Decision: Focus on retention metrics over acquisition this quarter. - Decision: Launch the mobile beta by the end of Q3. **Action Items:** - Owner: Alice | Task: Write the retention dashboard spec | Due: 2025-06-20 - Owner: Bob | Task: Draft beta launch checklist | Due: no deadline **Open Questions:** - Who owns the migration plan for legacy users?这个SKILL.md不到50行,大部分是步骤和示例。注意第5步给出的行动项格式,它直接告诉模型"列出字段值",而不是一句抽象的"提取行动项"。示例区的作用是让模型有一个可以复制的输出骨架,实际测试中模型几乎不会偏离这个格式。
5.3 第三步:测试与迭代
写好之后我把一份真实的工作会议纪要(约3000字)作为测试输入跑了一遍。第一版的问题很明显:行动项的责任人被识别错了一次,因为原文里有个人名因为被前面大量"Alice说"干扰,模型把"the PM team"识别成了Alice。这说明第5步的Owner解析规则不够明确。
我的修正是在步骤5里加了一句:Owner必须是在原文中被明确指派任务的人或团队,如果只是参与讨论但未被指派,不要列为Owner。再次测试,识别准确率明显提升。反复跑5到10组不同风格的输入(有的啰嗦、有的跳跃、有的中英混杂),直到输出稳定,这个技能才算能用。
5.4 第四步:通过调试命令验证
在Claude Code里,可以用/skills命令查看当前项目可用的技能列表并手动激活某个技能,方便单独测试。也可以启动一个带技能但不会真正执行的dry-run模式做快速回归。我会把测试用的transcript样本存成一个固定的测试文件,每次改完技能先跑一遍dry-run,再跑一次真实对话,保证改动没有破坏既有能力。
5.5 注意别踩的坑
这个技能从初期版本到稳定,我踩过几个值得说说的坑:
一是description写得太泛。最初我写的是"Use this skill to summarize meetings",结果Claude在用户只是闲聊两句会议话题时也去加载技能,白白浪费上下文。改成"when the user provides a meeting transcript"之后,触发准确率高了很多。
二是指令里有歧义词。我最初写的是"summarize the decisions",模型有时候输出"Alice decided to"这种过程性描述,而不是决策本身。后来要求每个决策都用"Decision:"前缀,强制格式统一,彻底解决了歧义。
三是没有处理"信息不足"的情况。真实纪要里经常有人名缺失、日期缺失,以前模型会自己编一个。加上第7步的"Open Questions"机制后,它学会了诚实标注未知项,这份能力远比编造正确答案重要。
6. 实用技巧与维护心得:让技能长期稳定地工作
技能写出来只是开始,维护才是大头。以下几条是我在实际使用中总结出来的经验,不一定都在官方文档里,但非常实用。
6.1 坚持单一职责
一个技能只做一件事,做到极致。我早期写过一个"综合助手"技能,既管翻译又管排版还管数据提取,结果每次调用上下文里都充斥着大量无关指令,模型经常在翻译任务里突然开始排表格。拆成三个独立技能之后,每个都更短更精准,触发也更稳定。官方说的"more skills is not always better",前提是每个技能都足够聚焦。
6.2 用git管理技能,并维护版本记录
技能是会演化的。我通常在description里不带版本号(避免干扰触发),但在SKILL.md首段保留一行变更记录。例如:
## Changelog - 2025-06-01: Strict owner detection rules. - 2025-05-20: Initial version.这样既不影响模型判断,又方便人类追踪。
6.3 别在技能里放敏感信息
这个坑比较隐蔽。技能文件因为是共享的,经常会被同步到团队的公共仓库或者发给外部协作者。如果你的技能里包含了内部系统的绝对路径、数据库表名、API密钥,一旦分发出去就是安全事故。我的原则是:技能里只放方法和模板,凡是涉及内部信息的都改用占位符,真正的内容通过环境变量或配置文件在运行时注入。
6.4 定期用真实数据回归
技能不是写一次就一劳永逸。模型升级、办公流程调整、输入数据格式变化,都可能让一个原本正常的技能逐渐失效。我给自己定了一个习惯:每两周用固定的测试样本集把核心技能跑一遍,发现漂移就微调指令。这有点像给代码库做回归测试,工作很机械,但能避免"突然某天技能就不好使了"的尴尬。
6.5 与其他技能共用规则时,优先抽取公共模块
如果你的多个技能都涉及"输出内容必须严格按Markdown格式""货币数值保留两位小数"这类共性规则,不要在每个SKILL.md里复制一遍。复制会导致改一处忘一处,最后几个技能行为不一致。更合理的做法是,把公共规则写进System Prompt,技能里只保留自己特有的部分。如果非要放在技能层,也做成一个公共技能并在其他技能开头引用它。
回到最初的问题:什么是SKILL?我的理解是,它把"教Claude做专业事"这件事工程化了,让它从文本框里的固定话术变成可管理、可共享、可迭代的代码资产。怎么写一个优秀的SKILL?遵守官方那条最核心的建议就够了——为模型而写,不要为给人看而写;指令要像给同事的交接文档那样清晰,示例要像测试用例那样覆盖边界,结构要像好代码那样简单到不需要注释。按照这个标准写出来的技能,即使过半年回头看,你依然能一眼看懂它当时的设计意图,而Claude也依然能稳定地交出符合预期的结果。