ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Anthropic SKILL机制深度解析:渐进式披露与工程化实践指南

Anthropic SKILL机制深度解析:渐进式披露与工程化实践指南

1. 从一次踩坑说起:为什么我们需要认真聊聊SKILL

去年年底我接手了一个内部知识库项目,团队想把散落在各个文档里的操作流程、代码规范、排查手册统一收拢,让AI助手能直接调用。一开始我的思路很朴素——把所有内容塞进一个巨大的提示词里,按章节分好,让模型自己去检索。结果第一次测试就翻车了:上下文窗口被撑爆,模型开始胡言乱语,明明写在第三段的规范,回答时却引用成了第七段的内容。更离谱的是,同一个问题问两遍,答案能差出十万八千里。

后来我花了两周时间研究Anthropic官方放出的SKILL机制,才意识到自己犯了一个根本性错误:我把SKILL当成了“更长的提示词”,而它本质上是一套按需加载、渐进披露的能力封装体系。这个认知转变直接决定了你写出来的SKILL是能用还是不能用。

这篇文章就是把我这段时间踩过的坑、试过的方案、以及最终跑通的实践整理出来。不管你是刚接触SKILL这个概念,还是已经写过几个但总觉得效果不稳定,下面这些内容应该都能帮你少走弯路。我会从SKILL到底是什么讲起,拆解它的核心机制,然后手把手带你写一个真正优秀的SKILL,最后把常见问题和排查技巧一次性说清楚。

提示:本文讨论的SKILL特指Anthropic在Claude生态中定义的技能封装机制,不涉及其他平台的类似概念。如果你用的是其他AI助手的技能系统,底层逻辑相通,但具体文件格式和加载方式需要对照对应平台的文档。

2. SKILL到底是什么:别被名字骗了

2.1 一句话说清楚SKILL的本质

SKILL不是提示词模板,不是知识库文件,也不是简单的函数封装。用一句话概括:SKILL是一份写给AI看的“操作说明书”,它告诉模型在什么场景下、按照什么步骤、调用哪些资源来完成一件具体的事。

这个定义里有三个关键词需要拆开理解。“什么场景下”指的是触发条件,模型需要知道什么时候该用这个SKILL。“按照什么步骤”指的是执行流程,这是SKILL的核心内容。“调用哪些资源”指的是SKILL可以引用外部文件、脚本、模板等辅助材料,而不是把所有东西都塞进一个文件里。

我见过太多人把SKILL写成了“百科全书”——恨不得把某个领域的所有知识都塞进去。结果就是模型加载时消耗大量token,真正执行时反而抓不住重点。优秀的SKILL应该像一份精炼的SOP,只写这个任务需要知道的东西,其他内容通过引用外部文件的方式按需加载。

2.2 SKILL和普通提示词的本质区别

很多人第一次接触SKILL时会问:这不就是写个提示词吗?有什么区别?我一开始也这么想,直到实际用起来才发现差异巨大。

普通提示词是“一次性”的。你写一段话,模型读完执行,结束。下次换个任务,你得重新写一段。SKILL是“可复用”的。你写好一个SKILL文件,放在指定目录,模型在需要的时候自动加载,执行完这个任务后,这个SKILL的上下文可以被释放,不会持续占用窗口。

更关键的区别在于渐进式披露机制。普通提示词是你写多少模型读多少,SKILL是分层的——第一层只有元数据(名称和描述),模型根据描述判断是否需要加载;第二层是SKILL.md的主体内容,包含核心步骤;第三层是引用的外部文件,只有在执行到特定步骤时才读取。这种分层设计让SKILL可以在不撑爆上下文的前提下,承载远超普通提示词的信息量。

我做过一个对比测试:同样一个“代码审查”任务,用普通提示词写,大概能塞进去800字左右就开始出现注意力涣散;用SKILL结构写,主文件控制在500字以内,引用三个外部文件分别存放检查清单、常见反模式、修复示例,总信息量超过3000字,模型执行准确率反而更高。

2.3 SKILL的目录结构长什么样

一个标准的SKILL在文件系统里是这样的:

my-skill/ ├── SKILL.md # 主文件,必须存在 ├── references/ # 参考文档目录,可选 │ ├── checklist.md │ └── examples.md ├── scripts/ # 可执行脚本目录,可选 │ └── validate.py └── assets/ # 静态资源目录,可选 └── template.json

SKILL.md是入口文件,必须存在。它的开头有一段YAML格式的元数据,包含name和description两个字段。这两个字段决定了模型是否会在正确的时机加载这个SKILL。很多人写SKILL时把大量精力花在主体内容上,却忽略了元数据的打磨,结果就是SKILL写得再好,模型该用的时候想不起来用。

references目录存放参考文档,比如检查清单、示例集合、背景说明等。这些文件不会在SKILL加载时全部读入,而是当SKILL.md中明确指示“读取references/checklist.md”时才会被加载。scripts目录存放可执行脚本,模型可以调用这些脚本来完成确定性计算或外部操作。assets目录存放模板、配置等静态资源。

注意:不同平台对SKILL目录结构的支持程度不同。有些平台只支持SKILL.md单文件,有些平台支持完整的目录结构。写之前先确认你的运行环境支持哪些能力,避免写了引用却加载不了。

3. 渐进式披露:SKILL最核心的设计哲学

3.1 为什么不能把所有东西写在一个文件里

上下文窗口是有限资源。即使现在很多模型支持超长上下文,但“能塞进去”和“能有效利用”是两回事。我做过一个实验:把一份两万字的操作手册直接塞进提示词,然后问模型手册里第三部分第七条的细节。模型确实能回答,但响应速度明显变慢,而且当问题涉及跨章节关联时,准确率大幅下降。

渐进式披露解决的就是这个问题。它的核心思想是:只在需要的时候加载需要的内容。SKILL.md只写“做什么”和“怎么做”的骨架,具体细节放在外部文件里,等执行到那一步再读取。这样模型在大部分时间里只需要处理几百字的上下文,注意力高度集中,执行准确率自然就上去了。

我自己的经验是,一个设计良好的SKILL,SKILL.md主体控制在300到800字之间最合适。太短了说不清楚,太长了模型注意力分散。超过800字的内容,就应该考虑拆到references目录里。

3.2 三层加载机制的实际运作方式

第一层是元数据加载。当模型启动时,它会扫描所有可用SKILL的元数据,把name和description读进来。这一层的信息量极小,通常每个SKILL只有几十个字。模型根据当前任务和这些描述做匹配,决定是否加载某个SKILL。

第二层是主体加载。当模型判断需要某个SKILL时,它会把SKILL.md的完整内容读入上下文。这一层包含了执行这个任务的核心步骤、注意事项、以及对外部文件的引用指令。

第三层是按需加载。当执行到某一步,SKILL.md中写着“读取references/checklist.md并逐项检查”时,模型才会去读取那个文件。读完执行完,这个文件的内容就可以从上下文中释放,为后续步骤腾出空间。

这个机制的美妙之处在于,你可以把一个复杂任务的完整知识体系拆成十几个文件,但模型在执行时永远只加载当前需要的那一两个。我试过把一个包含二十多个检查项的质量审查SKILL拆成主文件加五个参考文件,总信息量超过一万字,但模型在整个执行过程中上下文峰值只有两千字左右,执行效果比之前塞在一个文件里好得多。

3.3 渐进式披露的常见误用

最常见的误用是把所有内容都放在SKILL.md里,然后安慰自己“反正模型上下文够大”。这种做法在简单任务上可能看不出问题,一旦任务复杂起来,模型就会开始丢三落四。

另一个极端是过度拆分。我见过有人把一个简单的“生成周报”SKILL拆成主文件加七个参考文件,每个文件只有一两句话。结果模型在执行时频繁跳转读取,反而增加了出错概率。拆分的粒度应该以“一个完整的逻辑单元”为标准,比如“检查清单”是一个单元,“示例集合”是一个单元,不要把一句话也单独拆出去。

还有一个隐蔽的坑是引用路径写错。SKILL.md里写“读取references/checklist.md”,但实际文件放在references/checklists/checklist.md,模型找不到文件就会跳过这一步,而且很多时候不会报错,只是默默忽略。这种问题在测试时如果不仔细看执行日志,很难发现。

4. 动手写一个优秀的SKILL:从零到跑通

4.1 先想清楚三件事再动笔

写SKILL之前,先回答三个问题。第一个问题:这个SKILL解决什么具体问题?不要写“帮助处理文档”这种模糊描述,要写“把Markdown格式的会议记录转换成包含行动项、决策记录、待跟进问题的结构化摘要”。越具体越好。

第二个问题:模型在执行这个任务时,最容易在哪一步出错?这个问题的答案决定了你需要在SKILL里重点强调什么。比如代码审查SKILL,模型最容易漏掉的是边界条件检查,那你就要在SKILL里明确写“必须检查空值、越界、并发冲突三类边界情况”。

第三个问题:哪些内容是每次执行都必须知道的,哪些是偶尔才需要的?必须知道的放SKILL.md主体,偶尔需要的放references目录。这个判断直接决定了你的SKILL结构是否合理。

我自己的习惯是先拿一张纸,把整个任务的执行流程画出来,然后在每个步骤旁边标注“这一步需要什么信息”。画完之后,信息需求最密集的步骤就是SKILL.md要重点写的,信息需求独立且量大的就拆到外部文件。

4.2 元数据怎么写才能让模型正确触发

元数据里的name和description是模型决定是否加载这个SKILL的唯一依据。很多人在这里写得太随意,导致SKILL明明存在却从来不被触发。

name要简洁明确,用英文小写加连字符,比如code-review、meeting-summary、>name: code-review description: 对代码变更进行系统性审查,检查逻辑错误、边界条件、安全漏洞和性能问题。当用户提交代码片段或请求审查PR时使用。输出包含问题列表、严重程度评级和修复建议。

这段描述里,“对代码变更进行系统性审查”说明了做什么,“当用户提交代码片段或请求审查PR时使用”说明了什么时候用,“输出包含问题列表、严重程度评级和修复建议”说明了结果形式。模型读到这样的描述,就能准确判断当前任务是否匹配。

提示:description的长度控制在100到200字之间比较合适。太短了信息不足,太长了模型处理时也会稀释注意力。如果你发现description写不下,说明这个SKILL可能承担了太多职责,考虑拆成两个。

4.3 SKILL.md主体的黄金结构

主体内容我推荐用“目标-步骤-注意事项-输出格式”四段式结构。这个结构经过多次迭代验证,在大多数任务类型上都能取得不错的效果。

目标部分用一两句话重申这个SKILL要完成什么。虽然元数据里已经写了,但主体里再写一遍有助于模型在加载后快速进入状态。步骤部分是核心,按执行顺序列出每一步做什么。每一步的粒度要适中,太粗了模型不知道怎么执行,太细了又显得啰嗦。我的经验是,一个步骤对应一个明确的动作,比如“读取输入文件”、“提取关键信息”、“按照模板生成输出”。

注意事项部分写那些容易出错的地方。比如“如果输入文件为空,直接返回错误提示,不要尝试生成内容”、“日期格式统一使用YYYY-MM-DD,不要使用其他格式”。这些注意事项往往是从实际踩坑中总结出来的,是SKILL价值的重要体现。

输出格式部分明确告诉模型最终输出应该长什么样。可以给一个模板,也可以给一个示例。有明确格式要求的任务,这一步不能省。我试过不写输出格式,结果模型每次生成的格式都不一样,后续处理非常麻烦。

4.4 一个完整SKILL示例:会议记录结构化

下面这个SKILL是我在实际项目中反复打磨过的,用来把自由格式的会议记录转换成结构化摘要。你可以直接拿去用,也可以根据自己的需求调整。

--- name: meeting-summary description: 将自由格式的会议记录转换为结构化摘要,提取行动项、决策记录和待跟进问题。当用户提供会议记录文本并请求整理时使用。输出为Markdown格式的结构化文档。 ---
# 会议记录结构化 ## 目标 将非结构化的会议记录转换为包含行动项、决策记录、待跟进问题的标准格式摘要。 ## 执行步骤 1. 读取用户提供的会议记录全文。如果内容为空或明显不是会议记录,返回提示信息并终止。 2. 识别会议基本信息:日期、参会人员、会议主题。如果某项信息缺失,标注为“未提及”。 3. 提取行动项。行动项的判断标准:包含明确的动作动词(如“完成”、“提交”、“确认”),且有明确的负责人或截止时间。每条行动项记录为:负责人 | 动作 | 截止时间 | 备注。 4. 提取决策记录。决策的判断标准:包含“决定”、“确定”、“通过”等表示结论的词汇。每条决策记录为:决策内容 | 决策依据 | 影响范围。 5. 提取待跟进问题。判断标准:讨论中没有得出结论、需要后续确认、或明确标记为“待定”的事项。每条记录为:问题描述 | 当前状态 | 建议下一步。 6. 按照输出格式生成最终文档。 ## 注意事项 - 行动项的负责人如果原文没有明确,标注为“待分配”,不要自行推断。 - 决策记录只记录已经明确结论的事项,讨论过程中的观点不作为决策。 - 如果会议记录中同一事项在不同位置重复出现,合并为一条,取最完整的描述。 - 日期格式统一为YYYY-MM-DD。如果原文只有“下周三”这类相对时间,保留原文并标注“需确认具体日期”。 ## 输出格式 ```markdown # 会议摘要:[会议主题] **日期**:[日期] **参会人员**:[人员列表] ## 行动项 | 负责人 | 动作 | 截止时间 | 备注 | |--------|------|----------|------| | ... | ... | ... | ... | ## 决策记录 | 决策内容 | 决策依据 | 影响范围 | |----------|----------|----------| | ... | ... | ... | ## 待跟进问题 | 问题描述 | 当前状态 | 建议下一步 | |----------|----------|------------| | ... | ... | ... |
这个SKILL的SKILL.md主体大约600字,结构清晰,每一步都有明确的判断标准。实际测试中,模型执行这个SKILL的准确率比我之前写的“把所有要求混在一起”的版本高出很多。 ### 4.5 外部文件怎么组织才合理 当SKILL.md主体超过800字,或者某些内容只在特定条件下才需要时,就应该拆到外部文件。我常用的拆分策略是:检查清单放一个文件,示例集合放一个文件,背景知识放一个文件。 检查清单文件适合存放那些“逐项核对”的内容。比如代码审查SKILL里,可以把所有检查项列成一个清单文件,SKILL.md里写“读取references/checklist.md,逐项检查并记录结果”。这样模型在执行时会先读清单,然后一项一项过,不容易遗漏。 示例文件适合存放“输入输出对照”的内容。比如格式转换SKILL,可以把几个典型的输入输出示例放在一个文件里,SKILL.md里写“参考references/examples.md中的示例格式”。模型看到具体示例后,生成的结果会更符合预期。 背景知识文件适合存放那些“解释为什么”的内容。比如某个业务规则SKILL,可以把规则背后的业务逻辑放在一个文件里,SKILL.md里写“如果遇到规则冲突,读取references/background.md了解优先级判断依据”。这样模型在遇到边界情况时,有据可依。 > 注意:外部文件的引用路径要写相对路径,从SKILL根目录开始。不要写绝对路径,不要写“../”这种跳出SKILL目录的路径。不同平台对路径的处理方式可能不同,相对路径是最稳妥的选择。 ## 5. 常见问题与排查技巧实录 ### 5.1 SKILL不被触发怎么办 这是最常见的问题。你写了一个SKILL,测试时模型却完全不用它。排查思路按以下顺序进行。 先检查元数据。description是否准确描述了使用场景?我见过有人写“处理数据”,结果模型遇到数据相关任务时根本想不起来用这个SKILL。改成“当用户提供CSV文件并请求清洗和格式转换时使用”,触发率立刻上去了。 再检查文件位置。SKILL是否放在了平台指定的目录下?不同平台的目录约定不同,有的放在项目根目录的`.skills/`下,有的放在用户主目录的`~/.claude/skills/`下。放错位置模型扫描不到,自然不会触发。 然后检查文件命名。SKILL.md必须大写,不能写成skill.md或Skill.md。有些平台对文件名大小写敏感,写错了就加载不了。 最后检查是否有冲突。如果你有多个SKILL的description描述的场景有重叠,模型可能会犹豫不决。这时候需要把description写得更精确,明确区分各自的适用场景。 ### 5.2 SKILL执行到一半中断或跳过步骤 这种情况通常是外部文件引用出了问题。模型读到“读取references/checklist.md”时,如果文件不存在或路径不对,它可能会跳过这一步继续执行,也可能直接中断。排查方法是先确认文件确实存在,然后确认路径拼写完全一致。 另一个可能的原因是步骤描述不够明确。比如写“检查代码质量”,模型不知道具体检查什么,可能就随便看看跳过了。改成“逐行检查代码,确认每个函数都有错误处理、每个循环都有边界检查、每个外部调用都有超时设置”,模型就知道具体要做什么了。 还有一种情况是步骤太多导致模型“疲劳”。我试过一个SKILL有十五个步骤,执行到第十步左右模型就开始敷衍。后来拆成两个SKILL,每个七八步,执行质量明显提升。一个SKILL的步骤数控制在十步以内比较稳妥。 ### 5.3 输出格式不稳定怎么调 输出格式不稳定的根本原因通常是格式要求不够具体。只写“输出Markdown格式”是不够的,模型对Markdown的理解可能和你不一致。要给出具体的模板或示例。 我习惯在SKILL.md里直接嵌入一个输出模板,用代码块包起来。模型看到具体模板后,生成的结果会高度一致。如果模板比较复杂,可以放在references目录里,SKILL.md里写“严格按照references/output-template.md的格式生成输出”。 还有一个技巧是在注意事项里加一条“输出中不要添加模板之外的任何额外内容”。有时候模型会自作主张加一些“总结”、“备注”之类的东西,明确禁止后就能避免。 ### 5.4 常见问题速查表 | 问题现象 | 可能原因 | 排查方法 | 解决措施 | |----------|----------|----------|----------| | SKILL不被触发 | 元数据描述不准确 | 检查description是否包含场景关键词 | 重写description,明确使用场景 | | SKILL不被触发 | 文件位置错误 | 确认SKILL目录是否在平台指定路径下 | 移动到正确目录 | | 执行中断 | 外部文件引用路径错误 | 检查SKILL.md中的引用路径 | 修正为正确的相对路径 | | 执行中断 | 外部文件不存在 | 确认references目录下文件是否存在 | 创建缺失的文件 | | 跳过步骤 | 步骤描述过于模糊 | 检查步骤是否有明确的动作和判断标准 | 细化步骤描述,增加判断条件 | | 输出格式不稳定 | 格式要求不具体 | 检查是否提供了模板或示例 | 在SKILL.md中嵌入输出模板 | | 输出内容冗余 | 缺少禁止性约束 | 检查注意事项是否明确禁止额外内容 | 增加“不要添加模板之外内容”的约束 | | 执行质量下降 | 步骤过多导致注意力分散 | 统计SKILL.md中的步骤数量 | 拆分为多个SKILL,每个不超过十步 | ### 5.5 几个我踩过的坑 第一个坑是过度依赖模型的理解能力。我一开始写SKILL时喜欢用“合理处理”、“适当调整”这类模糊表述,觉得模型应该能理解。实际测试发现,模型对“合理”的理解和我的预期经常不一致。后来我把所有模糊表述都改成了具体判断标准,执行准确率大幅提升。 第二个坑是忽略了负面约束。我只写了“要做什么”,没写“不要做什么”。结果模型在执行时经常添加一些我没要求的内容,比如自动生成总结、自动补充示例。后来在注意事项里加了“不要生成模板之外的任何内容”、“不要自行推断缺失信息”,输出就干净多了。 第三个坑是测试用例太少。我写完一个SKILL后只测了两三个用例就上线了,结果遇到边界情况时各种出问题。后来我养成了习惯,每个SKILL至少准备十个测试用例,包括正常情况、边界情况、异常输入。测试用例多了,问题暴露得就充分。 第四个坑是版本管理混乱。我改SKILL时经常直接覆盖原文件,改坏了想回退都回不去。后来用Git管理SKILL目录,每次修改都提交,出问题随时回退。这个习惯强烈推荐。 ## 6. 让SKILL真正好用的几个进阶思路 ### 6.1 用脚本处理确定性计算 SKILL里有些步骤是确定性的,比如日期格式转换、数据校验、文件解析。这些步骤如果让模型来做,不仅慢,还可能出错。更好的做法是写一个脚本放在scripts目录里,SKILL.md里写“运行scripts/validate.py进行数据校验,根据返回结果决定下一步”。 脚本的好处是结果确定、速度快、不消耗模型注意力。我有个数据处理SKILL,原本让模型逐行检查数据格式,一千行数据要跑好几分钟,还经常漏检。后来写了个Python脚本做格式校验,模型只需要读取脚本输出的错误列表,处理时间降到几秒钟,准确率也上去了。 脚本的编写要注意几点:输入输出格式要明确,错误处理要完善,不要依赖外部环境。脚本最好用标准库,避免依赖第三方包,因为不同运行环境的包安装情况可能不同。 ### 6.2 用示例锚定输出风格 模型生成内容时,风格往往不稳定。有时候很简洁,有时候很啰嗦。解决方法是给示例。在SKILL.md或references里放几个输入输出对照的示例,模型会模仿示例的风格。 示例的选择有讲究。不要只给一个示例,至少给三个,覆盖不同的输入情况。示例要典型,不要选太特殊的案例。示例的输出要精心打磨,因为模型会把它当作标准来模仿。 我有个文档摘要SKILL,之前生成的摘要长度忽长忽短。后来在references里放了三个示例,分别对应短文档、中等文档、长文档的摘要风格,输出长度就稳定多了。 ### 6.3 用条件分支处理复杂场景 有些任务在不同情况下需要走不同的流程。比如代码审查SKILL,审查新功能和审查bug修复的关注点不同。这时候可以在SKILL.md里写条件分支:“如果变更类型是新功能,重点检查接口设计和测试覆盖;如果变更类型是bug修复,重点检查根因分析和回归测试”。 条件分支不要写得太复杂,两三层就够了。分支太多模型容易迷路。如果分支逻辑很复杂,考虑拆成多个SKILL,让模型根据场景选择加载哪个。 ### 6.4 持续迭代:从能用 to 好用 SKILL不是写完就完了。实际使用中会发现各种问题,需要持续迭代。我的习惯是每次使用SKILL后,记录三个东西:哪里执行得好、哪里执行得不好、下次怎么改进。积累几次之后,针对性地修改SKILL.md。 迭代时要注意版本管理。每次修改前先提交当前版本,修改后对比测试结果。不要一次性改太多地方,否则出了问题不知道是哪个改动导致的。小步快跑,每次改一两个点,验证有效后再继续。 还有一个技巧是收集“失败案例”。每次SKILL执行出问题时,把输入和输出保存下来,作为后续测试的用例。这些失败案例是最宝贵的改进依据,比凭空想测试用例有效得多。 ## 7. 关于SKILL工程化的一点个人体会 写了这么多SKILL之后,我最大的体会是:**SKILL的质量不取决于你写了多少,而取决于你删了多少。** 我早期写的SKILL动辄两三千字,恨不得把所有知道的东西都塞进去。后来发现,真正好用的SKILL往往很精炼,SKILL.md主体控制在五百字左右,只写最核心的步骤和最容易出错的注意事项,其他内容全部拆到外部文件按需加载。 另一个体会是,SKILL的调试成本比写代码高。代码出错了有报错信息,SKILL出错了往往只是“结果不太对”,需要仔细对比输入输出才能定位问题。所以测试用例要准备充分,执行日志要仔细看。我现在的习惯是每个SKILL至少跑二十个测试用例,覆盖各种边界情况,确认稳定后才正式使用。 最后一个体会是关于“去AI味”的。很多人写SKILL时喜欢用很正式、很书面化的语言,觉得这样显得专业。但实际上,模型对自然语言的指令理解得更好。用“检查一下有没有空值”比用“执行空值校验操作”效果更好。写SKILL时想象你在跟一个聪明但不太了解你业务的同事交代任务,用最直接、最具体的语言,效果往往最好。 如果你刚开始写SKILL,建议从最简单的任务入手,比如“把一段文字翻译成英文并保持格式”。写完之后反复测试,观察模型在哪里出错,然后针对性地修改。写三五个简单SKILL之后,你对SKILL的运作机制就会有直观感受,再写复杂SKILL就顺手多了。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进