AI Agent Skill 系统架构全解析:SKILL 规范与框架实现

0 阅读9分钟

一个 skill 跑得好,靠的是三件事

最近刚好需要自己实现一套完整的 Skills 运行框架,所以把官方协议、源码、实现方案都啃了一遍。写这篇文章,就是想把自己踩的坑、悟出来的门道记录下来。对做 Agent 开发、做 skill 开发,或者单纯想搞懂 "我的 skill 为什么效果不稳定" 的人,应该都有帮助。

道理很简单,一个 skill 的强大,从来不是单点优势决定的。它靠三件事:

  • skill 本身写得好不好
  • 模型理解得对不对
  • 框架支撑得稳不稳

三者缺一不可,尤其是框架对于 skill 能力的支撑,常常容易被忽略

你见过这样的场景吗?同一个技能,在 A 框架上跑得很顺,换到 B 框架上就崩了;甚至同一个模型,换到不同 Agent 里,能力表现也天差地别。

这玩意儿不是玄学,是 Runtime Architecture 的锅。

请添加图片描述

skill 是什么?它长什么样

先说 skill 本身的结构。一个完整的 skill,通常由两部分组成:SKILL.md配套文件夹

SKILL.md 是技能的 "说明书"。它告诉模型:

  • "我能干什么"
  • “什么时候该用我”
  • “具体怎么干”

配套文件夹是技能的 "工具箱",它存放:

  • 脚本
  • 模板
  • API 文档
  • 配置文件
  • 数据文件
  • 静态资源

这些配套文件,才是模型执行任务时真正会依赖的东西。

SKILL.md 是必须的,配套的文件夹可以没有。有些 Skill 只是行为引导,不提供任何脚本和资源文件,这类 Skill 本质上更接近 “高级 Prompt 模块”。

SKILL.md 的角色定义

你可以把 SKILL.md 理解成三个东西的合集:

  • 身份证
  • 操作手册
  • 路由提示器

文件的开头是一段 YAML 格式的Front Matter,负责定义技能的身份信息:

---
name: hermes-agent
description: Configure, extend, or contribute to Hermes Agent.
category: devops
---

Front Matter 部分的字段,根据 Agent Skills 开放标准,有以下几个。

字段必填说明
name技能名称,只能用小写字母、数字、连字符,不能以连字符开头或结尾
description技能描述,告诉模型"这玩意儿能干嘛,什么时候用"
license许可证信息,可以放许可证名称或引用
compatibility环境要求,比如"需要 macOS"或"需要 Docker"
metadata自定义元数据,随便填
allowed-tools技能能用的工具列表,比如 ["terminal", "file"]

其中 description 的作用,不单单只是 “技能介绍”,同时也是 Semantic Routing(语义路由)。

从某种意义上来说,description 更像是一个 “隐式分类器”,所以 description 写得差,Skill 甚至可能永远不会被调用。

Front Matter 下面是正文部分,也就是技能的具体执行内容。这部分没有固定格式,Markdown、纯文本、甚至伪代码都行,只要模型能读懂。

比如一个 "写周报" 的技能,完整的结构应该是:

---
name: weekly-report-generator
description: 自动生成标准规范的每周工作周报,涵盖本周工作总结、工作遇到的问题、下周工作计划、需要协调支持的事项四大核心模块,输出格式统一整洁,无需人工整理排版,可直接复用或微调。
---

# 写周报技能

## 功能
帮助模型生成每周工作周报,包含:
- 本周工作总结
- 遇到的问题
- 下周计划
- 需要支持的事项

## 输入
无(模型自行收集信息)

## 输出
Markdown 格式的周报

## 示例
### 本周工作总结
1. 完成了 XXX 功能开发
2. 修复了 YYY 问题

这段内容就是模型调用技能时看到的 "操作指南"。模型根据这个指南,决定怎么组织周报、怎么写措辞、要不要调用其他工具。

这里还有一个容易忽略的问题, 模型并不会像人一样 “认真阅读文档”。

所以真正工业级 Skill,往往会大量使用:

  • checklist
  • step-by-step
  • XML tags
  • hard constraints
  • examples
  • retry instruction
  • structured output

配套文件夹:标准化 + 开放度

协议规定了三个标准文件夹:

scripts/ — 可执行脚本库

放脚本文件,比如analyze.py、run.sh、process.js。语言不限,由框架实现决定支持什么脚本语言。这个目录的设计非常灵活,用 Python、Bash、Node.js 都行。

references/ — 补充文档库

放额外的说明文档。官方不强制 .md 后缀,也不强制有哪些文件。你可以放 API 文档、流程图、表格、FAQ,一切靠约定。

assets/ — 静态资源库

用于存放资源文件:模板、图片、数据文件等。比如:

assets/demo.html —— 样式模板
assets/logo.png —— Logo
assets/sample.csv —— 示例数据

重点:允许自定义扩展

除了这三个标准文件夹,框架允许你自由添加。这也是协议真正聪明的地方,只规定 “最低公共结构”,不限制扩展。

比如很多 Agent 框架会添加:

templates/ —— 专门放模板文件
cache/ —— 缓存中间结果
logs/ —— 运行日志

这也是为什么不同 Agent 虽然都有 Skill System,但运行方式差异会非常大。

框架层:让 skill 真正跑起来的引擎

光有 skill 是不行的,还必须有 Runtime Framework

框架对 skill 的处理,分三步:启动加载、动态召回、动态执行。

请添加图片描述

第一步:启动加载

Agent 启动时,框架会扫描所有 skill 目录,提取 Front Matter 中的 name 和 description,拼成一个 "技能菜单",塞进 system prompt。

<available_skills>
name: hermes-agent
description: Configure, extend, or contribute to Hermes Agent.
category: devops
---
name: youtube-content
description: YouTube transcripts to summaries, threads, blogs.
category: media
---
name: article-writing-style
description: 写作规范:篇幅、结构、语气、禁忌
category: productivity
---
</available_skills>

这玩意儿就是模型的 "能力菜单"。模型启动时就看到 "我手里有哪些家伙"。

为什么要只加载 Front Matter?

因为技能内容太多。假设你有 30 个技能,每个技能正文平均 3k token,那就是 9k token,不仅浪费,也容易导致模型注意力不集中。

所以只加载 name 和 description,大概每个技能 100-200 字符,可以大大减少 token 消耗,同时保证模型运行效果。

环境过滤:有些技能有环境限制,比如 "只在 macOS 运行" 或 "需要 Docker"。框架会读取 Front Matter 的 compatibility 字段,在启动时排除不可用的技能。比如 Agent 部署在 Windows 下,所有 compatibility: macOS 的技能直接跳过。

这样保证模型看到的菜单,都是"当前环境真正能用的"。

第二步:动态召回

模型启动后,如果需要用某个技能,但它的具体内容不在 system prompt 里,这时候就要 动态召回

skill 框架一般提供两个工具 skills_listskill_view

tool 1: skills_list(category?)

这个工具返回某个目录下的所有技能,只有 name 和 description:

{
  "skills": [
    {"name": "hermes-agent", "description": "Configure, extend, or contribute to Hermes Agent."},
    {"name": "youtube-content", "description": "YouTube transcripts to summaries, threads, blogs."}
  ]
}

这个工具更多是一个兜底策略。假设 model 的上下文被其他任务挤占,导致 system prompt 里的技能菜单丢失,它可以通过这个工具 "重新查一遍" 自己有哪些能力。

但实际上,这个工具很少被调用。正常情况,模型直接看 system prompt 里的菜单就够了。它更多是 健壮性设计,防止极端情况下的信息丢失。

tool 2: skill_view(skill_name, file_path?)

这个工具用于查看 skill 详情,分两种情况,是否传 file_path

第一种:只传 skill_name,不传 file_path

skill_view(skill_name='hermes-agent')

返回:

{
  "success": true,
  "name": "hermes-agent",
  "description": "Configure, extend, or contribute to Hermes Agent.",
  "content": "正文内容(Markdown)...",
  "path": "/home/laowang/.hermes/skills/hermes-agent/SKILL.md",
  "skill_dir": "/home/laowang/.hermes/skills/hermes-agent",
  "linked_files": ["scripts/config.py", "scripts/validate.sh", "references/api.md"]
}

此时工具返回的 skill 信息会略多,其中三个信息最关键:

  • content —— 技能的正文,也就是具体执行内容
  • skill_dir —— 技能的根目录,告诉模型 "如果需要执行脚本,从这里开始找"
  • linked_files —— 关联文件列表,告诉模型 "技能目录下有哪些配套文件"

第二种:skill_name + file_path

skill_view(skill_name='hermes-agent', file_path='scripts/config.py')

返回:

{
  "success": true,
  "name": "hermes-agent",
  "file": "scripts/config.py",
  "content": "#!/usr/bin/env python3\n...",
  "file_type": ".py"
}

返回内容变简单了,只剩下了 content 一个关键信息,包含了文件的完整代码或文本。

skill 的动态召回体现了一个非常关键的 设计哲学:先概览、再细节。

模型先知道 "这个技能有哪些文件",再决定 "要不要看某个文件的细节",最后决定 "看了之后要不要修改或执行"。

这种渐进式加载,既节省上下文,又保持灵活性。也是整个 Agent Runtime 最重要的 Context Management 技术之一。

第三步:动态执行

在这里插入图片描述

SKILL.md 和文件夹里的文件,光有 "说明书" 和 "素材" 还不行,还得有执行工具

因为 SKILL.md 本身不会执行任何东西。

比如技能里有 scripts/analyze.py,模型要执行它,就得有一个 python_execute() 工具;如果技能里是scripts/run.sh,那得有一个bash_execute() 工具。

执行工具的作用:

  • 提供执行环境:隔离的沙箱,防止模型乱来
  • 安全校验:比如检查脚本路径是否在允许范围内
  • 权限控制:比如限制脚本能访问哪些文件、能调哪些 API

其他执行工具

除了脚本执行工具外,如果 skill system 支持自定义文件夹(例如 figures/图片.png,video/视频.mp4),框架还得提供相应的文件访问工具,比如 read_image()、download_file() 等。

如果光有对应的文件,没有配套的工具,那模型就只能假装用自然语言模拟代码逻辑。这时候 Skill 就退化成了 “纸上谈兵”。

Skill 系统的真正价值

在这里插入图片描述

Skills 系统不是 "多几个 Function Call 那么简单"。

它的本质是 知识层和执行层的分离。SKILL.md 负责知识层(告诉模型"干什么"),文件夹负责执行层(提供"怎么干"的材料),框架负责把两者串联起来。

它的核心价值是 渐进式披露。模型启动时只看到 name+description,用的时候再按需查看详情,避免上下文爆炸。

它的 开放度 也是关键。协议规定了三个标准文件夹,但允许自定义扩展。skill 框架的实现者可以按自己的场景添加响应的支持工具。

回到开头那个问题:技能强大 = 技能本身 × 模型能力 × 框架能力

很多时候不是 Skill 写的有问题,也不是模型变蠢了。

而是 Agent 的 Skill 框架根本没把 Skill 真正跑起来。