AI Agent技能实战: 从 SKILL.md 到 MCP Server 的完整实现
本文介绍了Agent Skills的设计理念与SkillLite实现。Agent Skills作为AI Agent的核心能力单元,通过标准化封装解决传统Tool调用的局限性。SkillLite是一个轻量级Rust执行引擎,主要实现三个功能: 基于SKILL.md的标准化能力定义格式 系统级沙箱的安全执行环境 通过MCP协议暴露技能接口 文章详细解析了SKILL.md的结构设计,包括三种技能类型(脚
本文基于开源项目 SkillLite 的实战经验,深入解析 Agent Skills 的设计哲学、SKILL.md 规范、智能 Schema 推断、MCP 协议暴露、以及两阶段安全确认机制的 Rust 实现。
一、Skills 是什么?为什么说它是 2026 年 AI Agent 的核心议题
2025 年,MCP(Model Context Protocol)让 AI Agent 有了"标准化的工具调用接口",解决了 协议层 的问题。但进入 2026 年,行业关注的焦点已经转移到一个更本质的问题:
Agent 到底应该"会"什么?它的能力从哪里来?怎么安全地扩展?
这就是 Agent Skills 要回答的问题。
如果说 MCP 是 Agent 的"USB 接口",那 Skills 就是"U盘里的软件"。MCP 定义了通信协议,而 Skills 定义了 能力本身 —— 包括能做什么、怎么做、需要什么权限、输入输出是什么格式。
1.1 从 Tool 到 Skill 的演进
传统 LLM Tool 调用存在三个根本问题:
| 问题 | 传统 Tool | Agent Skills |
|---|---|---|
| 能力定义 | 硬编码在框架内 | 自描述、可热加载 |
| 安全边界 | 无隔离,信任一切 | 沙箱执行 + 安全扫描 |
| 可复用性 | 框架绑定,无法跨平台 | 标准化格式,跨框架共享 |
| 参数发现 | 手动编写 Schema | 从代码自动推断 |
Skills 的核心理念:把 Agent 的能力封装成标准化、自描述、安全隔离的可复用包。 一个 Skill 写好后,可以同时在 Cursor、Claude Desktop、OpenCode、LangChain 等任意框架中使用。
1.2 SkillLite 的定位
SkillLite 是一个轻量级 AI Agent Skills 执行引擎,用 Rust 实现,核心解决三件事:
- 定义 Skills:基于 SKILL.md 的标准化格式
- 安全执行 Skills:原生系统级沙箱(macOS Seatbelt / Linux Namespace + Seccomp)
- 暴露 Skills:通过 MCP Server 让任意 AI IDE 调用
整体架构如下:
┌─────────────────────────────────────────────────────┐
│ AI IDE (Cursor / Claude Desktop / OpenCode) │
│ ↕ MCP (JSON-RPC 2.0 over stdio) │
├─────────────────────────────────────────────────────┤
│ SkillLite MCP Server │
│ ┌───────────┬──────────────┬──────────────────┐ │
│ │list_skills│ get_skill_info│ run_skill │ │
│ └───────────┴──────────────┴────────┬─────────┘ │
│ ↓ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Skills Engine (Rust Core) │ │
│ │ ┌────────────┐ ┌──────────┐ ┌────────────┐ │ │
│ │ │ SKILL.md │ │ Schema │ │ Security │ │ │
│ │ │ Parser │ │ Inferrer │ │ Scanner │ │ │
│ │ └────────────┘ └──────────┘ └────────────┘ │ │
│ │ ┌────────────────────────────────────────┐ │ │
│ │ │ Sandbox Runner (Seatbelt/Namespace) │ │ │
│ │ └────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────┤
│ .skills/ │
│ ├── weather/ (Python Skill) │
│ ├── agent-browser/ (Bash-Tool Skill) │
│ ├── data-analysis/ (Python Skill) │
│ └── ... │
└─────────────────────────────────────────────────────┘
二、SKILL.md:一个文件定义一个能力
Skills 的核心设计哲学是 “一个 SKILL.md 文件定义 Agent 的一个能力”,借鉴了 Anthropic Claude Code 的 Agent Skills 规范并做了安全增强。
2.1 SKILL.md 结构
---
name: weather
description: 查询城市天气信息。当用户询问某个城市的天气、温度、湿度等信息时使用。
license: MIT
compatibility: Requires Python 3.x, network access
metadata:
author: skillLite
version: "3.0"
---
# Weather Skill
查询指定城市的**真实天气**信息。**开箱即用,无需配置任何 API Key!**
## 示例
输入: `{"city": "深圳"}`
输出: `{"city": "深圳", "temperature": "18°C", ...}`
一个 Skill 的完整目录结构:
weather/
├── SKILL.md # 能力定义(必需)
├── scripts/
│ └── main.py # 执行脚本
├── references/ # 参考文档(按需加载)
├── assets/ # 资源文件
└── .skilllite.lock # 依赖锁定
关键设计决策:YAML front matter 中的 description 字段是 唯一的触发机制。AI Agent 通过这段描述来决定"什么时候该用这个 Skill"。因此描述必须精确、全面,包含所有触发场景。
2.2 三种 Skill 类型
SkillLite 支持三种 Skill 类型,覆盖不同的使用场景:
类型一:脚本 Skill(有入口脚本)
最常见的类型,包含 scripts/main.py 等可执行脚本。Agent 通过 JSON 传参,脚本执行后返回结果。
---
name: data-analysis
description: 分析数据集并生成报告
compatibility: Requires Python 3.x
---
类型二:Bash-Tool Skill(命令行工具封装)
没有脚本目录,只有 SKILL.md 中的 allowed-tools 字段声明允许执行哪些命令。AI Agent 读取文档后自行组装 bash 命令。
---
name: agent-browser
description: Browser automation CLI for AI agents...
allowed-tools: Bash(agent-browser:*)
---
这种设计特别适合封装 CLI 工具。allowed-tools: Bash(agent-browser:*) 声明后,SkillLite 会:
- 将该 Skill 注册为一个接受
command参数的 Tool - 执行前用 Bash 命令验证器 检查命令是否匹配允许的 pattern
- 在沙箱中执行命令
类型三:多脚本 Skill(一个 Skill 多个工具)
scripts/ 目录下有多个脚本时,每个脚本自动注册为独立的 Tool,命名规则为 skill_name__script_name(双下划线分隔)。
skill-creator/
├── SKILL.md
└── scripts/
├── init_skill.py → tool: skill_creator__init_skill
├── package_skill.py → tool: skill_creator__package_skill
└── quick_validate.py → tool: skill_creator__quick_validate
这个设计让一个 Skill 可以提供一组相关的工具,避免了"一个工具一个 Skill"的碎片化问题。
2.3 Metadata 解析的工程实现
SKILL.md 的解析在 Rust 中实现(skill/metadata.rs),有几个值得分享的工程细节:
智能语言检测:系统不要求用户显式声明语言。当 language 字段为空时,通过 compatibility 字段关键词匹配 + 入口脚本扩展名推断:
// 从 compatibility 字段推断语言
fn parse_compatibility_for_language(compatibility: Option<&str>) -> Option<String> {
let compat_lower = compat.to_lowercase();
if compat_lower.contains("python") {
Some("python".to_string())
} else if compat_lower.contains("node") {
Some("node".to_string())
} else { None }
}
网络策略推断:compatibility: Requires Python 3.x, network access 中的 “network” 关键词会被自动提取,支持中英文(“网络”、“联网”、"在线"等):
let needs_network = compat_lower.contains("network")
|| compat_lower.contains("internet")
|| compat_lower.contains("网络")
|| compat_lower.contains("联网");
依赖解析:从 compatibility 字段智能提取 pip 包名(如 requests, pandas),自动创建虚拟环境并安装,结果缓存在 .skilllite.lock 中避免重复安装。
三、从代码自动推断 Schema:让 LLM 精确调用
传统做法需要开发者手写 JSON Schema 来描述 Tool 的参数。SkillLite 做了一个关键创新:从 Python 脚本的 argparse 代码中自动推断参数 Schema。
3.1 Argparse Schema 推断
当 Skill 的入口脚本是 Python 文件时,SkillLite 会通过正则表达式解析 add_argument 调用,自动生成符合 OpenAI function calling 规范的 JSON Schema。
例如这段 Python 代码:
parser.add_argument('city', help='要查询天气的城市名称')
parser.add_argument('--format', type=str, choices=['json', 'text'], default='json',
help='输出格式')
parser.add_argument('--detailed', action='store_true', help='是否输出详细信息')
SkillLite 自动推断出:
{
"type": "object",
"properties": {
"city": { "type": "string", "description": "要查询天气的城市名称" },
"format": { "type": "string", "enum": ["json", "text"], "default": "json",
"description": "输出格式" },
"detailed": { "type": "boolean", "description": "是否输出详细信息" }
},
"required": ["city"]
}
3.2 推断规则
核心推断逻辑在 agent/skills.rs 的 parse_argparse_schema 函数中实现,支持以下映射:
| Python argparse | JSON Schema |
|---|---|
| 位置参数 | required: true |
--flag 参数 |
required: false |
type=int |
"type": "integer" |
type=float |
"type": "number" |
action='store_true' |
"type": "boolean" |
choices=[...] |
"enum": [...] |
nargs='*' / nargs='+' |
"type": "array" |
help='...' |
"description": "..." |
default=... |
"default": ... |
这个设计的好处在于 Skill 开发者只需要写标准的 Python 脚本,不需要额外维护 Schema 定义,也不需要学习新的 DSL。argparse 本身就是参数声明的最佳实践。
四、MCP Server:让 Skills 被任意 AI IDE 调用
有了 Skills 定义和 Schema 推断,下一步是 把 Skills 暴露给外部 AI IDE。这就是 MCP Server 的职责。
4.1 协议设计
SkillLite 的 MCP Server 实现了 JSON-RPC 2.0 over stdio 协议,提供 5 个工具:
| 工具 | 功能 | 典型调用者 |
|---|---|---|
list_skills |
列出所有可用 Skill | AI IDE 初始化时调用 |
get_skill_info |
获取 Skill 详细信息和 Schema | AI Agent 决策前调用 |
run_skill |
执行 Skill | AI Agent 行动时调用 |
scan_code |
代码安全扫描 | 执行前安全检查 |
execute_code |
执行临时代码 | 快速代码执行 |
协议交互流程:
Client SkillLite MCP Server
│ │
│──── initialize ──────────────────→ │
│←─── capabilities + serverInfo ─── │
│ │
│──── tools/list ──────────────────→ │
│←─── 5 tool definitions ───────── │
│ │
│──── tools/call: list_skills ────→ │
│←─── [{name, description, lang}]── │
│ │
│──── tools/call: run_skill ──────→ │
│←─── scan report (需确认) ──────── │ ← 两阶段确认第一阶段
│ │
│──── tools/call: run_skill ──────→ │
│ (confirmed=true, scan_id) │
│←─── execution result ─────────── │ ← 第二阶段:确认后执行
4.2 在 Cursor 中接入
在 Cursor 的 MCP 配置中添加:
{
"mcpServers": {
"skilllite": {
"command": "skilllite",
"args": ["mcp-serve", "--skills-dir", ".skills"]
}
}
}
配置后,Cursor 的 AI Agent 自动获得所有 Skills 的能力。当用户说"帮我查一下深圳天气",Agent 会:
- 在工具列表中找到
weatherskill(通过 description 匹配) - 调用
run_skill执行 - 将结果返回给用户
五、核心创新:两阶段安全确认机制
MCP 标准定义了工具调用协议,但 没有定义"谁来确认代码是否安全"。这是 SkillLite 的核心创新点。
5.1 问题
在 Agent 自动化场景下,一个 Skill 可能包含任意代码。如果 AI Agent 不经检查直接执行,存在严重安全风险。但如果每次都弹窗让用户确认,又会严重影响效率。
5.2 解决方案:scan_id + confirmed
SkillLite 设计了两阶段安全确认:
第一阶段:自动扫描,返回 scan_id
当 AI Agent 调用 run_skill 时(未携带 confirmed=true),系统自动执行安全扫描:
// 1. 计算代码哈希
let code_hash = McpServer::generate_code_hash(language, code);
// 2. 执行静态安全扫描
let scan_result = do_scan(language, code)?;
// 3. 生成 scan_id 并缓存结果(TTL 300秒)
let scan_id = McpServer::generate_scan_id(&code_hash);
server.scan_cache.insert(scan_id.clone(), CachedScan {
scan_result, code_hash, language, code,
created_at: Instant::now(),
});
如果扫描发现 High 级别以上的问题,返回安全报告给 AI Agent,要求展示给用户确认:
📋 Security Scan: 2 issue(s) found
#1 [High] CodeInjection - Line 15: Use of eval() detected
#2 [Medium] ProcessExecution - Line 23: subprocess.run usage
⚠️ High-severity issues found. User confirmation is required.
{"scan_id": "a3f8b1c2d4e5f6a7", "requires_confirmation": true}
第二阶段:用户确认后执行
AI Agent 展示安全报告给用户,获得确认后,携带 scan_id 和 confirmed=true 再次调用:
{
"name": "run_skill",
"arguments": {
"skill_name": "data-analysis",
"confirmed": true,
"scan_id": "a3f8b1c2d4e5f6a7"
}
}
系统验证:
- scan_id 是否有效且未过期(TTL 300 秒)
- 代码是否在扫描后被篡改(比对 code_hash)
- Critical 级别问题 无法覆盖,即使用户确认也会被硬阻断
5.3 会话级缓存:避免重复打扰
同一个 Skill 在同一个会话中确认一次后,只要代码没有变化,后续调用不再重复扫描:
// 计算 Skill 代码哈希
let code_hash = compute_skill_hash(skill_dir, metadata);
// 检查会话缓存
let already_confirmed = server.confirmed_skills
.get(skill_name)
.map_or(false, |c| c.code_hash == code_hash);
if already_confirmed {
// 跳过扫描,直接执行
}
5.4 Fail-Secure 设计
当扫描过程本身出错时(临时文件创建失败、扫描器异常等),系统遵循 Fail-Secure 原则:
fn scan_error_result(err: &str) -> ScanResult {
ScanResult {
is_safe: false,
issues: vec![SecurityIssue {
severity: SecuritySeverity::High, // 扫描失败 = 需要确认
description: format!("Security scan failed: {}. Manual review required.", err),
...
}],
}
}
扫描失败不会导致自动执行,而是返回 High 级别报告,要求用户人工审核。这与 Python 版本的行为保持一致。
5.5 三层安全等级
两阶段确认只是安全体系的一部分。SkillLite 提供三层可选安全等级:
| 等级 | 能力 | 适用场景 |
|---|---|---|
| Level 1 | 无沙箱,直接执行 | 受信任的内部 Skill |
| Level 2 | 沙箱隔离(文件/网络/进程) | 一般 Skill |
| Level 3(默认) | 沙箱 + 静态代码扫描 + 两阶段确认 | 不受信任的 Skill |
六、Skills 生态:从 GitHub 到 ClawHub
有了标准格式,自然就有了生态。SkillLite 支持三种 Skill 来源:
6.1 从 GitHub 安装
# 从 GitHub 仓库安装
skilllite add owner/repo
# 安装仓库中的特定 Skill
skilllite add owner/repo --skill weather
6.2 从 ClawHub 安装
ClawHub 是 Agent Skills 的专属分发平台,类似于 npm 之于 Node.js:
# 一键安装
skilllite add clawhub:weather
skilllite add clawhub:agent-browser
SkillLite 通过 ClawHub API 下载 Skill 的 zip 包,自动解压到 .skills/ 目录:
⬇ Downloading from ClawHub (weather) ...
✓ Download complete
📦 Installing weather...
✓ Installed weather → .skills/weather
6.3 本地开发
# 使用 skill-creator 创建新 Skill
skilllite add clawhub:skill-creator
# 在 chat 中创建
skilllite chat
> 帮我创建一个翻译 Skill
skill-creator 本身就是一个 Skill,它教 AI Agent 如何正确创建 Skill —— 这是一种优雅的"Skills 自举"。
七、完整调用链路:从用户输入到结果返回
以"帮我查一下深圳天气"为例,完整调用链路:
1. 用户输入: "帮我查一下深圳天气"
↓
2. AI IDE (Cursor) 通过 MCP 调用 SkillLite
↓
3. MCP Server 收到 tools/call: run_skill
├── skill_name: "weather"
└── input: {"city": "深圳"}
↓
4. Skills Engine 处理
├── 4.1 解析 SKILL.md → SkillMetadata
├── 4.2 安全扫描 → 检查 scripts/main.py
│ └── 无安全问题,跳过确认
├── 4.3 环境准备
│ ├── 检查 .skilllite.lock → 依赖已缓存
│ └── 复用已有 venv
└── 4.4 构建 SandboxConfig
├── language: "python"
├── network_enabled: true ← 从 compatibility 推断
└── network_outbound: ["*"]
↓
5. Sandbox Runner 执行
├── macOS: sandbox-exec + Seatbelt profile
├── 文件系统: 仅可读 skill 目录 + 可写临时目录
├── 网络: 允许(weather API 需要)
└── 资源限制: 512MB 内存, 30s 超时
↓
6. 脚本输出 → JSON 结果
{"city":"深圳","temperature":"18°C","weather":"多云",...}
↓
7. MCP Server 封装响应 → AI IDE 展示给用户
八、与现有方案的对比
| 维度 | SkillLite Skills | OpenAI GPT Actions | LangChain Tools | Claude MCP |
|---|---|---|---|---|
| 能力定义 | SKILL.md(自描述) | API Schema | Python 函数 | Tool Schema |
| 执行位置 | 本地沙箱 | 云端 | 本地无隔离 | 取决于 Server |
| 安全机制 | 三层安全 + 扫描 | 平台审核 | 无 | 无内置 |
| Schema 来源 | 自动推断 | 手写 | 手写 | 手写 |
| 跨框架复用 | 是(MCP + SDK) | 否 | 否 | 是(MCP) |
| 离线可用 | 是 | 否 | 是 | 取决于 Server |
| 包管理 | ClawHub + GitHub | GPT Store | pip | 无标准 |
九、最佳实践与踩坑经验
9.1 SKILL.md 编写建议
描述要穷举触发场景:
# ❌ 太模糊
description: 处理浏览器相关任务
# ✅ 穷举触发词
description: Browser automation CLI for AI agents. Use when the user needs
to interact with websites, including navigating pages, filling forms,
clicking buttons, taking screenshots, extracting data, testing web apps,
or automating any browser task.
善用 Progressive Disclosure:SKILL.md 只放核心流程,详细文档放 references/。AI Agent 按需读取,节省上下文窗口。
9.2 多脚本 Skill 的命名陷阱
LLM 有时会用原始 Skill 名称(含连字符)调用工具,而非标准化后的名称(下划线)。SkillLite 通过模糊匹配解决:
pub fn find_skill_by_tool_name(skills: &[LoadedSkill], tool_name: &str)
-> Option<&LoadedSkill>
{
// 精确匹配优先
if let Some(skill) = skills.iter().find(|s|
s.tool_definitions.iter().any(|td| td.function.name == tool_name)
) {
return Some(skill);
}
// 标准化匹配:frontend-design → frontend_design
let normalized = sanitize_tool_name(tool_name);
skills.iter().find(|s|
s.tool_definitions.iter().any(|td| td.function.name == normalized)
)
}
9.3 Bash-Tool Skill 的输出路径问题
很多 CLI 工具不尊重 shell 的 cwd,导致输出文件位置不可预测。SkillLite 通过 路径重写 解决:
// 将 "agent-browser screenshot shot.png"
// 重写为 "agent-browser screenshot /abs/path/to/output/shot.png"
fn rewrite_output_paths(command: &str, output_dir: &Path) -> String {
// 检测文件名后缀,将相对路径替换为绝对路径
for part in command.split_whitespace() {
if has_output_ext && !is_absolute && !has_env_var && !is_url {
let abs = output_dir.join(part);
// 替换为绝对路径
}
}
}
十、总结与展望
Agent Skills 代表了 AI Agent 能力扩展的一个重要范式转变:
- 标准化:SKILL.md 提供了跨框架的能力描述格式
- 安全性:两阶段确认 + 系统级沙箱,让不受信任的代码也能安全执行
- 智能化:Schema 自动推断,开发者零额外负担
- 生态化:从 GitHub 到 ClawHub,Skills 可以像 npm 包一样分享
如果说 2025 年 MCP 解决了"Agent 怎么调用工具"的协议问题,那 2026 年 Agent Skills 要解决的是"Agent 的能力从哪里来、怎么安全地获取和使用"的根本问题。
SkillLite 正在构建的,不仅是一个执行引擎,更是一个 让 AI Agent 能力可组合、可共享、可信任 的基础设施。
项目地址:github.com/EXboys/skilllite
如果你对 Agent Skills 的设计有自己的想法,或者在实际使用中遇到了问题,欢迎在评论区交流讨论。你更看好哪种 Agent 能力扩展方案?
更多推荐
所有评论(0)