今年做 AI Agent 相关项目,绕不开一件事:让模型在特定场景下稳定地“会干活”。提示词写了一堆,模型表现还是忽上忽下;微调成本太高、周期太长;好不容易把某个业务流程跑通了,换个项目又得从零开始。我自己的实践结论是,与其在提示词里堆砌规则,不如把能力封装成模块——而目前最值得参考的封装标准,就是 Anthropic 官方提出的 Skill 规范。
Skill 这个概念,简单说就是把“模型该怎么做某类任务”的指令、依赖的脚本、参考材料,按照统一结构打包成一个目录。模型在执行任务时,如果判断当前场景与某个 Skill 匹配,就会自动加载这份“说明书”,按里面的步骤和规则干活。这样做的最大好处是能力可复用、行为可预期、维护成本低。这篇文章我想从结构设计的角度,把符合 Anthropic 官方规范的主流 Skills 结构方案完整拆一遍,包括目录怎么搭、SKILL.md 怎么写、脚本怎么接、坑在哪里。不论你就是想让项目里的模型更听话,还是想把已有能力沉淀成可复用的资产,这篇文章都值得看完。
1. 结构设计前必须想清楚的几个核心问题
1.1 Skill 到底解决的是哪一类问题
先说一个我反复遇到的场景。给模型一个任务,比如“从 PDF 里抽取合同关键字段”。第一版提示词写了五百字,效果还行,但是换个 PDF 版式就崩;第二轮加上各种边界条件,提示词膨胀到两千字,模型开始“选择性失忆”,该提取的字段漏掉,不该出现的“脑补”倒是很积极。后来我把这个任务封装成 Skill,才发现根本问题在于就是:模型不是在“执行任务”,而是在“理解一段越来越复杂的文字”。提示词越长,注意力越容易被稀释,行为越不稳定。
Skill 的解决思路是反过来的。它不要求模型在上下文中一次性记住所有规则,而是把规则写进 SKILL.md,模型需要时再去读取。这样做的好处非常明显:
- 上下文窗口被省下来,模型专心处理真实业务数据;
- 不同任务的指令彼此隔离,互不干扰;
- 能力可以跨项目复用,改逻辑只改一个文件。
一句话总结:Skill 把“提示词工程”升级成了“能力工程”。这不只是写法变了,是整个开发范式的转变。
1.2 为什么一定要贴合官方规范
市面上关于 Agent 能力的封装方式并不少,有些团队自己约定了一套 JSON 配置,有些项目干脆就把工具函数当成“技能”。这些方案都能跑,但会有三个隐患:不通用、不标准、不可传承。新同事接手看不懂,换个框架全得重写,官方出工具链也接不上。
Anthropic 官方规范的含金量就在于“最小约定”:目录怎么组织、元信息放哪里、正文怎么写,都有明确要求。遵守这套规范,你写出来的 Skill 可以直接被任意兼容 Claude 模型能力的 Agent 框架加载。更关键的是,官方生态里的工具链(比如工程助手、SDK、MCP 工具)都对这个格式做了原生支持,你设计的结构越贴近规范,未来能享受的生态红利就越大。
我在实际项目里的体会是,规范的核心其实就一句话:SKILL.md 是一个带 YAML 前置信息的 Markdown 文件,技能目录下可以附带脚本和资源。这一条记住,剩下的都是细节。
1.3 如何划定 Skill 的粒度
结构设计的第一个真正决策点,是“一个 Skill 应该装多大能力”。拆太细了,技能目录爆炸,模型光是判断用哪个就消耗大量时间;拆太粗了,里面塞了一堆互不相干的操作,模型读起来费劲,执行起来更容易出错。
我常用的判断标准有三个:
- 场景一致性:Skill 服务的任务是同一类场景,而不是多个无关场景的“杂货铺”。
- 流程完整性:Skill 内部应该描述一条完整的处理链路,而不是单个零散操作。
- 复用独立性:Skill 的封装单位,应当是你会反复用到的那一层能力。
用这三个标准去卡,基本就不会出大问题。比如“文档转换”是一个合理粒度,但“把 PDF 第一页转成图片再识别文字再翻译成英文”这种多跳流程,拆成三个 Skill 更合适,中间任何一步都能单独复用于其他任务。
2. 符合官方规范的标准目录结构解析
2.1 目录骨架:一个 Skill 就是一个文件夹
官方规范描述得非常直白:一个 Skill 就是一个文件夹,文件夹里必须有 SKILL.md,其他所有文件都围绕这个主文件服务。标准骨架如下:
my-skill/ ├── SKILL.md ├── scripts/ │ ├── run.py │ └── requirements.txt ├── assets/ │ ├── template.xlsx │ └── reference/ │ ├── spec.pdf │ └── examples.md几个关键的约定需要说清楚:
- SKILL.md 是入口文件,文件名必须完全一致,大小写也不能错。
- scripts/ 目录放可执行脚本,脚本应能独立完成某个子任务,而不是依赖模型在对话里逐步操作。
- assets/ 目录放参考材料,比如模板文件、静态资源、领域资料。
- reference/ 如果材料很多,可以放在 assets 下的子目录里单独管理,方便模型按需深度读取。
这个结构与传统的项目工程化思路完全一致:主文档负责“说明”,脚本负责“执行”,材料负责“补给”。各司其职,模型加载起来路径清晰。
2.2 命名规范:目录名就是模型认知的第一印象
目录名看起来是小问题,实际影响很大。Anthropic 官方对目录名有明确约定:使用小写字母、数字和连字符(-),不能用空格和下划线。比如pdf-field-extractor是合法的,PDF_Field_Extractor就不符合约定。
为什么这么严格?因为目录名会被拼进文件路径,而文件路径是模型读取时的重要线索。路径越干净,模型越不容易产生误判。更重要的是,目录名还会被用作 Skill 的唯一标识符,在日志、跟踪、权限控制里都会出现。命名规范是结构设计的第一道门,别在这里省事。
2.3 版本管理与演进:结构也会“长毛”
目录结构不是一次性定死的,随着需求迭代,Skill 内部文件会越来越多。这里我给一个非常重要的建议:在 SKILL.md 的 YAML 前置信息里加上 version 字段,每一次结构性调整都更新版本号。别小看这一步,出问题回退时,你能精确知道自己改了什么。
另外,scripts 目录下的脚本一旦稳定,就尽量不要频繁改接口参数。我踩过两次坑,改脚本时顺手改了参数名,忘了同步更新 SKILL.md 里的调用说明,模型按旧文档调用,结果脚本直接报错。后来我给自己定了个规矩:只要动了 scripts 下的任何文件,必须同步跑一遍完整的端到端验证,避免文档与实现脱节。
3. SKILL.md 的设计要点与写作技法
3.1 YAML 前置信息:让模型在几毫秒内知道“该不该用”
SKILL.md 的开头是 YAML 格式的前置信息,官方规定必须包含 name 和 description 两个字段。这俩字段直接决定了模型能不能在合适的时机选中这个 Skill,所以我单独拿出来细讲。
name 字段要简短、精确,能概括这个技能的核心身份。description 字段则是一段“给模型看的话”,它决定了模型在什么情况下会激活这个技能。官方文档给过一个重要建议:description 应尽量精确描述触发场景,而不是泛泛地介绍能力。举个反例:
name: pdf_tool description: 处理 PDF 文件这是绝对的差设计。“处理 PDF 文件”太宽泛,模型可能在任何提到 PDF 的对话里都尝试激活它,激活了又发现当下的任务根本用不上,白白浪费一次调度。好的写法是给足触发条件、输入类型、输出内容:
name: pdf_field_extractor description: | 从合同类 PDF 文件中提取关键字段(合同编号、签约方、金额、日期等)。 当用户提供 PDF 文件并希望提取结构化字段时使用。输入为 PDF 文件路径, 输出为 JSON 结构。本技能不适用于扫描件 OCR 场景。这样写的妙处在于,模型能根据“提供 PDF + 提取字段”这两个信号精准触发,同时“不适用于扫描件 OCR”这个负向描述又帮模型排除了日光下的错误匹配。
3.2 正文结构:渐进式披露是核心心法
SKILL.md 的正文部分,官方建议全部使用 Markdown 编写,内容上要遵循“渐进式披露”(Progressive Disclosure)原则。这个概念听上去抽象,理解起来其实就一句话:正文先给出最精简、最关键的步骤,再逐步展开细节,不要让模型一口气读五千字才动手。
推荐的正文结构排序如下:
- 简短说明:这个 Skill 做什么,用一句话交代。
- 使用时机:什么情况下调用,什么情况下明确不用。
- 执行步骤:按顺序编号,每步讲清楚输入、操作、产出。
- 关键参数:如果要调用脚本,把参数列表和含义列全。
- 输出规范:数据以什么格式返回,字段名、类型、边界值都要说清楚。
- 注意事项:模型容易踩的坑、容易产生的幻觉、需要人工复核的地方。
这个顺序背后有一个心理模型:模型读取文档是从前往后线性进行的,它越早看到的指令权重越高。因此“先做什么、后做什么”绝对不能放在文档后段。我曾见过一个写法把执行步骤放在最后,模型每次读文档读到一半就开干,步骤全乱,后来调整顺序后效果立刻改善。
3.3 描述写作的“上下文预算”问题
写 SKILL.md 时,始终要提醒自己:模型每次读它都是要花上下文的。文档写得太啰嗦,模型处理主任务的余量就被压缩了。我的经验是,SKILL.md 正文一般控制在 300 到 800 行以内是一个合理范围,但这不是定死的。如果技能本身需要处理非常多领域约束,可以拆一个 reference 文件把详细规则放进去,SKILL.md 正文只写“何时需要读取 reference 以及读取哪一部分”。这就是渐进式披露的实战用法。
另外还有一个很实用的技巧:在文末放一个“快速参考”小节,用表格列出常见操作和对应命令。模型在需要的时候可以直接定位表格,不需要重新回读全文,这对执行效率和上下文占用都有好处。
4. 实战:搭建一个自己的 Skill 结构
4.1 一个可落地的脚手架示例
理论讲再多,不如动手搭一个。我以“合同关键信息抽取”为例,一步步演示符合官方规范的结构设计过程。
先建目录:
mkdir contract-extractor cd contract-extractor mkdir -p scripts assets/reference创建 SKILL.md,内容如下:
--- name: contract_extractor description: | 从合同类 PDF 中提取结构化关键字段,包括合同编号、签约方、 合同金额、签署日期与有效期。用户提供 PDF 路径并要求提取 合同时使用;不适用于图像型 PDF 或扫描件。 version: 1.2.0 --- # 合同关键信息抽取 ## 何时使用 仅在用户明确要求从合同 PDF 中提取字段时调用。若文件为扫描件, 应先引导用户使用 OCR 流程,回到本技能。 ## 执行步骤 1. 确认输入 PDF 路径存在且可读。 2. 调用 `scripts/extract.py`,传入 PDF 路径参数。 3. 读取输出 JSON,按字段校验规则检查。 4. 将结构化结果呈现给用户;若字段缺失,标注 `null` 并说明原因。 ## 脚本参数 | 参数 | 类型 | 必需 | 说明 | |------|------|------|------| | --pdf | string | 是 | PDF 文件绝对路径 | | --output | string | 否 | 输出 JSON 文件路径,默认 stdout | ## 输出规范 输出 JSON 包含:contract_no, party_a, party_b, amount, sign_date, expiry_date。 金额以元为单位;日期格式统一为 YYYY-MM-DD。创建脚本scripts/extract.py:
import json import argparse import sys from pathlib import Path def extract_fields(pdf_path: str) -> dict: # 实际项目里这里对接现有解析引擎 # 我这里只做演示,假设固定返回一个结构 return { "contract_no": "CT-2025-001", "party_a": "甲方示例公司", "party_b": "乙方示例公司", "amount": 100000.00, "sign_date": "2025-01-01", "expiry_date": "2026-01-01", } def main(): parser = argparse.ArgumentParser() parser.add_argument("--pdf", required=True) parser.add_argument("--output", default=None) args = parser.parse_args() if not Path(args.pdf).exists(): print(json.dumps({"error": f"file not found: {args.pdf}"})) sys.exit(1) result = extract_fields(args.pdf) if args.output: Path(args.output).write_text(json.dumps(result, ensure_ascii=False, indent=2)) else: print(json.dumps(result, ensure_ascii=False)) if __name__ == "__main__": main()这就完成了一个最小可用、完全符合官方格式要求的 Skill。实际落地时,extract_fields函数里换成你们项目自己的解析逻辑即可,其他结构不用动。
4.2 脚本接入的三个设计原则
scripts 里的脚本是整个 Skill 的“手”。模型通过文档理解任务,但最终还要靠脚本落地执行。围绕脚本设计,我有几条反复验证过的经验:
第一,脚本必须是确定性的。同一个输入,永远给出同一个输出。不要在脚本里引入随机性,不要依赖外部服务的不稳定状态,否则模型的自我纠错能力会被浪费在处理变动上。
第二,脚本返回结果要结构化。能输出 JSON 就不要输出纯文本,能输出有 schema 的 JSON 就不要输出飞象版。模型对结构化数据的解析能力远超纯文本,这能大幅降低后续处理环节的出错率。
第三,脚本要有清晰的退出码和错误信息。模型在执行脚本时如果拿不到明确反馈,它就会“猜测”哪里出了问题,一猜就离跑偏不远了。我通常让脚本在出错时输出 JSON 格式错误信息,并设置非零退出码,这样 Skill 内部就能根据退出码决定是否重试、是否回退。
4.3 上下文与资源管理策略
assets 里放什么、放多少,也会直接影响模型的行为质量。我的建议是严格控制资源体积:单个资源文件尽量压缩到几百 KB 以内,如果是超长参考文档,建议拆成多个按主题划分的文件,并在 SKILL.md 里说明“什么情况读哪个文件”。
还有一个常被忽略的细节:脚本本身的帮助信息也要写全。模型如果真的调用脚本出错,它会尝试自己加--help看帮助文本。因此脚本 argparse 里的 help 描述必须够清楚,这相当于是给模型准备的“二次说明书”。我在每一个生产级脚本里都会认真写 help 字段,这个习惯救过很多次场。
4.4 多文件结构的权限设计
如果你的 Skill 需要读取文件、写文件、调外部服务,建议在 SKILL.md 里先说明所需权限,并在assets/reference 里附一份权限申请模板。官方规范里虽然没有强制要求这一点,但工程化落地时必不可少。团队多人协作场景下,权限模型一旦在技能层缺失,就会出现“本地能跑、线上报错”的经典尴尬局面。结构设计时就把权限边界写清楚,后面省非常多事。
5. 常见问题与排查技巧实录
5.1 描述写得太泛导致技能“乱入”
最典型的表现是:模型在完全不相干的任务里激活了某个 Skill。排查思路非常简单,先看 description 里有没有出现“一刀切”的宽泛词,比如“处理文档”“分析数据”。然后就是负向描述有没有写清“不适用场景”。这两个点只要补上,乱入概率大幅下降。
5.2 SKILL.md 格式没问题但模型就是不读取
这种情况我遇到至少三次,最后定位的根因基本都在目录权限或文件编码上。官方要求 SKILL.md 使用 UTF-8 编码,如果你的文件是 UTF-8 with BOM,某些加载器会解析出错。另外确认目录层级是否放到了 Agent 的 skills 搜索路径下。命令行工具一般会把~/.claude/skills或项目内.claude/skills作为默认路径,路径不对,格式再标准也没用。
5.3 脚本报错但模型不会自救
模型调用脚本时,最忌惮的是脚本抛出的异常信息不够“结构化”。如果脚本崩溃输出一大段 Python traceback,模型要么看不懂,要么误以为是自己调用方式错了,反复尝试错误路径。我给脚本定的硬指标:任何异常情况都必须输出一条人能看出来龙去脉的 JSON 错误,并且把最可能的原因写进去。
瞎一段处理逻辑:
# 错误处理示例 err_context = { "error": "pdf_file_not_found", "hint": "check the --pdf parameter path", "exit_code": 1, } print(json.dumps(err_context)) sys.exit(err_code)像这样,模型拿到错误后就知道是路径出了问题,下一步它要么向用户要正确路径,要么检查自己拼接参数时是否出错。所有的排查链条就清晰了。
5.4 问题排除速查表
| 现象 | 可能原因 | 处理思路 |
|---|---|---|
| 技能在无关场景被调用 | description 宽度超范围 | 压缩触发场景,补充负向约束 |
| 技能该调用时未调用 | 描述里缺少触发关键词 | 模拟模型视角,检查触发链路 |
| SKILL.md 读了但执行混乱 | 正文步骤顺序不清晰 | 调整正文章节顺序,先步骤后细节 |
| 脚本执行后输出无人解析 | 返回结构非 JSON | 统一为固定 JSON Schema |
| 文件路径频繁出错 | 相对路径与执行目录不一致 | 脚本内统一使用绝对路径 |
| 模型反复读文档导致超时 | 正文过长、资源过多 | 简化正文,拆分 reference 按需读取 |
这个表基本覆盖了我踩过的大部分结构层问题。如果你的技能表现不稳定,建议先对着表逐条排查,大部分问题都能在这里找到影子。
6. 主流 Skills 结构设计模式总结
6.1 标准工具型模式
这是最常用的模式,也是我前文脚手架示例中用到的类型。特点是一个 SKILL.md 加一个核心脚本,模型读取文档后按步骤调用脚本完成全流程。适合任务链路短、确定性高的场景,比如格式转换、字段抽取、批量处理。
6.2 资源依赖型模式
有些技能必须依赖外部模板或查询表才能工作。此时 assets 目录变成主角,SKILL.md 的重要任务是指明“先读哪个资源、按什么规则使用”。比如生成定制报表,SKILL.md 只写流程,真正的字段定义全在 assets 的模板里。这种模式注意控制资源体积,能拆就别整。
6.3 组合编排型模式
这是 Skill 结构设计的天花板。一个 Skill 本身不做具体执行,而是编排多个子 Skill 或其他工具按顺序协作。SKILL.md 的正文写的是“流程编排逻辑”,脚本里的动作变成编排代码。这种模式能覆盖最复杂的业务场景,但对设计者的整体架构能力要求也比较高。我建议循序渐进,先把简单模式跑稳,再思考编排型。
6.4 模式选择决策逻辑
选择哪种模式,核心看两个维度:任务确定性高不高,资源耦合重不重。任务明确、结果可预期,选标准工具型;任务依赖外部资料,选资源依赖型;任务横跨多个能力域、需要动态判断路径,选组合编排型。没有万能模式,只有适不适合当前场景。
结尾
说实话,Skill 结构设计这件事入门门槛不算高,官方规范本身就是一页纸的事。但真正把它用好,靠的还是反复打磨和踩坑。我个人经验里最值钱的一条是:每次技能在实测中表现不佳,先别急着改描述文字,而是退回结构层面看看——是不是目录乱了?是不是正文顺序不对?是不是脚本反馈不够结构化?绝大多数问题在结构层面就能解决。如果你正在给项目设计技能封装,我的建议是从最小的标准工具型模式做起,吃透一套规范,再逐步叠加复杂度。这个路径我走过,走得通,相信你也能。