ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

Agent Skills 架构解析:从 SKILL.md 到 AI 智能体能力工程实践

Agent Skills 架构解析:从 SKILL.md 到 AI 智能体能力工程实践

1. Agent Skills 到底是什么,为什么突然被反复提起

Agent Skills 这个词最近在 AI 工程圈里出现的频率非常高,尤其是 Claude 生态的开发者社区。简单来说,它是 Anthropic 在 Claude 平台上推出的一套让 AI 智能体获得可复用、可组合、可版本管理的专项能力的机制。你可以把它理解成给 AI 装"技能包"——每个技能包定义了 AI 在特定场景下应该怎么做事、按什么流程做、需要调用哪些工具、输出什么格式。

它解决的问题非常实际:过去我们用 Claude 或者别的 AI 助手,每次都要在对话里反复交代"你要先做 A 再做 B,注意 C,输出格式是 D"。这些指令散落在对话历史里,不可复用、不可维护、不可测试。Agent Skills 把这些"怎么做"的知识从对话中抽出来,变成一个独立的、有结构的文件——核心就是SKILL.md,放在指定目录下,AI 在需要的时候自动加载并遵循。

适合谁来了解这个东西?三类人最应该关注:一是正在用 Claude Code 做开发自动化的工程师,二是想把团队内部流程沉淀成 AI 可执行规范的 Tech Lead,三是正在构建 AI Agent 产品、需要一套标准化能力扩展机制的产品和架构同学。哪怕你目前只是用 Claude 做日常问答,理解 Skills 的设计思路也能帮你更好地组织提示词和上下文。

我自己的感受是,Agent Skills 本质上是在回答一个问题:当 AI 从"聊天工具"变成"执行体"之后,它的能力边界怎么定义、怎么扩展、怎么复用?这不是一个纯粹的提示词技巧,而是一套工程化的能力管理方案。下面我从架构原理开始,一层层拆开讲。

2. Agent Skills 的架构原理拆解

2.1 从"提示词工程"到"能力工程"的范式转变

要理解 Agent Skills 的架构,得先理解它跟传统提示词工程的区别。传统做法是把所有指令塞进 system prompt 或者对话上下文,问题是:上下文窗口有限、指令之间互相干扰、无法按需加载、改一处要动全身。这就像你把所有工具都堆在一张桌子上,用的时候翻半天,还容易拿错。

Agent Skills 的思路是按需加载 + 结构化描述 + 渐进式披露。每个 Skill 是一个独立目录,里面至少有一个SKILL.md文件,包含元数据(名称、描述、触发条件)和正文指令。AI 在启动时只加载所有 Skill 的元数据(很轻量),当判断当前任务匹配某个 Skill 的描述时,才把该 Skill 的完整内容读进上下文。这个设计非常关键——它让 AI 可以拥有几十上百个技能,但每次实际占用的上下文只有当前需要的那几个。

提示:这种"元数据常驻、正文按需加载"的模式,是 Agent Skills 能规模化的核心原因。如果你自己设计类似的系统,一定要把"索引"和"内容"分开。

2.2 SKILL.md 的结构与字段含义

SKILL.md是整个机制的核心载体。它采用 Markdown + YAML frontmatter 的格式,frontmatter 里定义元数据,正文里写具体指令。一个典型的SKILL.md长这样:

--- name: pdf-form-filler description: 当用户需要填写 PDF 表单、提取表单字段或批量处理 PDF 表单时使用此技能。支持 AcroForm 和 XFA 两种表单类型。 --- # PDF 表单填写技能 ## 使用场景 当任务涉及 PDF 表单的读取、填写或批量生成时,按以下流程操作。 ## 操作步骤 1. 先用 pdfplumber 读取表单字段结构,确认字段名和类型 2. 根据用户提供的数据映射到对应字段 3. 用 pypdf 的 update_page_form_field_values 写入 4. 输出前用 pdfplumber 重新读取验证 ## 注意事项 - XFA 表单需要先 flatten 再处理 - 中文字段名要做编码兼容处理

frontmatter 里的name是技能的唯一标识,description是最关键的字段——AI 就是靠它来判断"当前任务要不要用这个技能"。所以 description 写得准不准,直接决定技能会不会被正确触发。正文部分则是给 AI 看的"操作手册",可以包含步骤、示例、边界条件、错误处理。

2.3 技能加载与触发的完整链路

整个链路可以拆成四个阶段。第一阶段是发现:Claude 启动时扫描技能目录,读取所有SKILL.md的 frontmatter,构建一个技能索引。第二阶段是匹配:用户发起任务后,模型根据任务语义和每个技能的 description 做相关性判断。第三阶段是加载:匹配成功的技能,其完整正文被注入当前上下文。第四阶段是执行:模型按照技能正文的指令调用工具、执行步骤、产出结果。

这里有个容易被忽略的细节:匹配是模型自己做的,不是关键词硬匹配。这意味着 description 的语义质量比关键词堆砌重要得多。我见过有人把 description 写成"处理PDF、PDF处理、表单、form、fill、填写"这种关键词列表,效果反而不如一句自然语言描述。

2.4 与 MCP 的关系:能力层与连接层的分工

很多人会把 Agent Skills 和 MCP 搞混,其实两者是不同层次的东西。MCP 解决的是连接问题——让 AI 能访问外部工具、数据源、服务,它是一个协议层,定义了 AI 和外部系统之间怎么通信。Agent Skills 解决的是能力问题——告诉 AI 在拿到工具之后,具体该怎么组合使用、按什么流程做、注意什么。

打个比方:MCP 像是给 AI 装上了手和脚(能操作外部世界),Agent Skills 像是给 AI 一本操作手册(知道怎么用这些手脚完成特定任务)。一个 Skill 可以调用多个 MCP 工具,一个 MCP 工具也可以被多个 Skill 使用。两者是正交的、互补的。

维度Agent SkillsMCP
解决的问题怎么做(流程、规范、知识)能连什么(工具、数据、服务)
载体SKILL.md 文件协议 + Server
加载方式按需注入上下文运行时调用
复用粒度任务级工具级
典型场景表单填写流程、代码审查规范数据库查询、浏览器操作

理解这个分工,对后面做架构设计非常关键。你不能指望用 Skill 去解决连接问题,也不该用 MCP 去承载流程知识。

3. 全系列 Agent Skills 速览与分类

3.1 官方内置技能系列

Claude 平台内置了一批官方技能,覆盖最常见的办公和开发场景。文档处理类包括 PDF 处理、Word 文档生成、Excel 表格操作、PPT 制作;开发类包括代码审查、测试生成、Git 操作规范;数据类包括 CSV 分析、图表生成、数据清洗。这些内置技能的特点是开箱即用、经过充分测试、边界处理比较完善。

我实际用下来,PDF 和 Excel 这两个内置技能的质量最高,基本能覆盖 80% 的日常需求。代码审查技能偏保守,适合做第一轮筛查,但深度审查还是得靠人工或者自定义技能。

3.2 自定义技能:从零写一个 SKILL.md

自定义技能才是 Agent Skills 真正发挥价值的地方。写一个自定义技能,核心是把"你脑子里那套做事方法"翻译成 AI 能执行的指令。我的经验是分四步走:

  1. 明确触发边界:这个技能在什么情况下该被用?description 要写清楚"什么时候用"和"什么时候不用"。
  2. 拆解操作流程:把任务拆成有序步骤,每步说清楚输入、动作、输出。
  3. 补充边界条件:哪些情况会出错?出错了怎么处理?有哪些坑要避开?
  4. 给出输出规范:最终产出什么格式?有没有必须包含的字段?

举个我实际写的例子,一个"周报生成"技能:

--- name: weekly-report-generator description: 当用户需要根据 Git 提交记录、任务清单或工作日志生成结构化周报时使用。不适用于月报或项目总结。 --- # 周报生成技能 ## 输入要求 - Git 仓库路径或提交记录文本 - 本周主要任务清单(可选) - 输出格式偏好(默认 Markdown) ## 生成流程 1. 用 git log --since="7 days ago" --pretty=format:"%h %s" 拉取提交 2. 按 feat/fix/docs/refactor 分类聚合 3. 合并任务清单,去重 4. 按"本周完成 / 进行中 / 下周计划 / 风险"四段输出 ## 输出规范 - 每条不超过 50 字 - 动词开头 - 涉及数据要带具体数字

这个技能写完之后,我每周只需要说一句"生成本周周报",AI 就自动跑完整个流程。这就是 Skills 的威力——把重复性认知劳动固化下来。

3.3 社区技能生态与典型分类

社区里已经涌现出大量第三方技能,大致可以分成几类。开发工具类:Git 工作流、代码格式化、依赖升级、CI 配置生成。数据处理类:日志分析、指标计算、报表生成。内容创作类:技术文档撰写、API 文档生成、变更日志整理。运维类:部署脚本生成、配置检查、故障排查流程。

选社区技能的时候要注意两点:一是看 description 写得是否清晰,二是看正文有没有边界处理。很多社区技能只写了 happy path,遇到异常就抓瞎。我一般会先读一遍SKILL.md全文,确认它的假设跟我的环境一致再用。

3.4 技能组合:多技能协同的工作流

单个技能解决单点问题,多个技能组合起来才能解决复杂工作流。比如一个"发布新版本"的完整流程,可以拆成:变更日志生成技能 → 版本号更新技能 → 构建脚本生成技能 → 发布说明撰写技能。Claude 会根据任务进展自动切换加载不同技能。

这里有个实操技巧:在技能正文里显式引用其他技能。比如在发布技能里写"变更日志部分请参考 changelog-generator 技能的输出规范",这样模型在加载发布技能时,会知道去关联另一个技能,协同效果更好。

4. 实操:从安装到跑通第一个自定义技能

4.1 环境准备与目录结构

Agent Skills 的目录结构有约定。以 Claude Code 为例,技能通常放在项目根目录的.claude/skills/下,每个技能一个子目录:

项目根目录/ ├── .claude/ │ └── skills/ │ ├── weekly-report-generator/ │ │ └── SKILL.md │ ├── pdf-form-filler/ │ │ ├── SKILL.md │ │ └── scripts/ │ │ └── fill_form.py │ └── code-reviewer/ │ └── SKILL.md

注意技能目录里除了SKILL.md,还可以放辅助脚本、模板文件、参考数据。技能正文里可以引用这些文件,模型在执行时会去读取。这个设计让技能可以携带"资产",而不只是纯文本指令。

注意:目录名和 frontmatter 里的 name 最好保持一致,避免模型在匹配时产生歧义。我踩过一次坑,目录叫report-gen但 name 写的是weekly-report,结果触发时好时坏。

4.2 编写第一个 SKILL.md 的完整过程

我拿一个真实场景来演示:自动生成 API 变更文档。假设我们有个后端项目,每次接口变更都要写变更说明,很烦。写个技能固化它。

第一步,想清楚触发条件。这个技能应该在"用户提到 API 变更、接口修改、需要生成变更文档"时触发。description 写成:

当用户需要根据代码 diff、接口定义文件或提交记录生成 API 变更文档时使用。适用于 REST 和 GraphQL 接口。不适用于内部函数变更。

第二步,拆解流程。读 diff → 识别接口变更 → 分类(新增/修改/删除/废弃)→ 提取参数变化 → 生成文档。

第三步,写正文:

--- name: api-changelog-generator description: 当用户需要根据代码 diff、接口定义文件或提交记录生成 API 变更文档时使用。适用于 REST 和 GraphQL 接口。不适用于内部函数变更。 --- # API 变更文档生成技能 ## 触发后第一步 确认变更来源:是 git diff、OpenAPI 文件对比,还是提交记录文本。 如果用户没说明,默认用 git diff HEAD~1。 ## 识别接口变更 - 扫描路由定义文件(routes/、controllers/、api/) - 对比新旧版本的路径、方法、参数、返回结构 - 分类:新增接口、参数变更、返回变更、废弃接口、删除接口 ## 输出格式 按以下结构输出 Markdown: ### 新增接口 - `POST /api/v2/users` — 创建用户,参数:name, email, role ### 参数变更 - `GET /api/v2/orders` — 新增 `status` 查询参数,可选值:pending/paid/cancelled ### 废弃接口 - `GET /api/v1/users` — 将于下个版本移除,请迁移到 `/api/v2/users` ## 注意事项 - 破坏性变更必须用 **加粗** 标注 - 每个变更要给出迁移建议 - 如果 diff 里没有接口相关文件,明确告知用户"未检测到接口变更"

第四步,测试。我拿一个真实的 commit 试了一下,模型正确识别出了三个接口变更,分类准确,迁移建议也合理。唯一的问题是它把内部 service 方法的改动也列进去了,我在正文里补了一句"只关注 HTTP 路由层,忽略 service 和 repository 层",问题解决。

4.3 调试技能触发的三个关键参数

技能不触发或者乱触发,是新手最常见的问题。三个关键点:

description 的语义精度。太宽泛会误触发,太窄会不触发。判断标准是:把 description 单独拿出来给一个人看,他能不能准确说出"什么时候该用"。如果他说不准,模型也说不准。

name 的唯一性。多个技能 name 冲突或者语义重叠,会导致匹配混乱。我建议 name 用"领域-动作"的格式,比如pdf-fill、git-commit-format、api-changelog。

正文的指令明确度。正文里如果出现"可以""建议""视情况"这类模糊词,模型执行时会摇摆。改成"必须""禁止""如果 X 则 Y"这种确定性表述,执行稳定性会明显提升。

4.4 技能与 MCP 工具联调的实操记录

技能本身不直接操作外部系统,它通过调用 MCP 工具来干活。我做过一个"数据库变更审查"技能,流程是:读 migration 文件 → 用 MCP 连数据库查当前 schema → 对比 → 生成审查报告。

实操中遇到两个问题。一是 MCP 工具调用失败时,技能没有定义降级路径,模型直接卡住。后来我在正文里加了"如果数据库连接失败,改为静态分析 migration 文件,并在报告里标注'未做实际 schema 对比'"。二是工具返回的数据量太大,塞爆上下文。解决办法是在技能里规定"只查询涉及变更的表,不要全库扫描"。

这两个坑很典型:技能设计必须考虑工具失败和数据量控制,否则再好的流程也会在真实环境里翻车。

5. 常见问题与排查技巧实录

5.1 技能不触发或错误触发的排查思路

技能不触发,按这个顺序排查:先确认技能目录位置对不对(.claude/skills/还是其他约定路径),再确认SKILL.md的 frontmatter 格式有没有语法错误(YAML 对缩进敏感),然后检查 description 是否跟当前任务语义匹配。我遇到过一次是 frontmatter 里多了个空格导致整个文件解析失败,技能静默不加载,排查了半天。

错误触发通常是 description 太宽泛。比如你写"处理文档相关任务",那所有涉及文档的任务都会触发。改成"当用户需要填写 PDF 表单字段时使用"就精确多了。

5.2 SKILL.md 编写中的高频错误

错误类型典型表现修正方法
frontmatter 语法错误技能完全不加载用 YAML 校验工具检查缩进和引号
description 太宽泛频繁误触发加入"不适用于..."的排除条件
正文指令模糊执行结果不稳定用"必须/禁止/如果...则..."替换"可以/建议"
缺少边界处理遇到异常就卡住为每个关键步骤补充失败降级路径
步骤粒度过粗模型自由发挥拆到"读什么文件、调什么工具、输出什么"级别
引用文件路径错误找不到辅助脚本用相对技能目录的路径,不要用绝对路径

5.3 上下文占用与性能优化

技能多了之后,上下文管理就成了问题。虽然元数据很轻,但如果一次任务触发了五六个技能,正文全加载进来也会挤占空间。优化手段有三个:一是把大段参考资料拆成独立文件,正文里只写"需要时读取 references/xxx.md";二是技能正文尽量精炼,把"为什么"删掉只留"怎么做";三是定期清理不再使用的技能,保持技能库精简。

我实测下来,一个设计良好的技能,正文控制在 500 到 1500 字之间比较合适。超过 2000 字就要考虑拆分或者外置参考资料了。

5.4 团队协作中的技能版本管理

团队共用技能库时,版本管理很重要。我的做法是把.claude/skills/纳入 Git 管理,每个技能目录独立演进,变更走 PR 流程。技能正文里可以加一个version字段,方便追踪。另外建议给技能写测试用例——准备几个典型输入,验证技能触发和执行结果是否符合预期,避免改一处坏一片。

提示:技能库的 PR 审查重点看两件事——description 有没有变宽泛,正文有没有引入模糊指令。这两个是技能退化的主要来源。

6. 我对 Agent Skills 的几点实际体会

用了一段时间 Agent Skills,最大的感受是它把"隐性知识显性化"这件事变得可操作了。以前团队里老员工的那套做事方法,只能靠口口相传,现在可以写成SKILL.md,让 AI 和新人一起遵循。这个价值比单纯提升 AI 效率要大得多。

另一个体会是,技能的质量取决于你对任务的理解深度,而不是提示词技巧。一个连你自己都说不清楚流程的任务,写成技能也是一团乱麻。所以写技能之前,先问自己:这个任务的标准流程是什么?哪些步骤容易出错?输出应该长什么样?想清楚了再动笔,比边写边改效率高得多。

最后分享一个小技巧:新写一个技能时,先别急着写正文,先用自然语言跟 AI 对话跑一遍完整流程,把对话记录里有效的指令抽出来,整理成SKILL.md。这样写出来的技能,触发率和执行稳定性都比凭空写的高。这个内容后续还可以往"技能市场"和"跨平台技能标准"方向扩展,等生态再成熟一些,我再补充。

RELATED READING

延伸阅读

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