19 KiB
Agent Skills 文档
概述
Agent Skills 是一种让 Agent 通过阅读"使用说明书"来学习新能力的扩展机制。与传统的硬编码工具不同,Skills 通过注入到 System Prompt 来扩展 Agent 的能力,遵循 Progressive Disclosure(渐进式披露) 的设计理念。 目前仅支持带智能推理能力的智能体使用。前端可在智能体的编辑页面找到相关配置
核心特性
- 非侵入式扩展:不影响原有 Agent ReAct 流程
- 按需加载:三级渐进式加载,优化 Token 使用
- 沙箱执行:脚本在隔离环境中安全执行
- 灵活配置:支持多目录、白名单过滤
设计理念
Progressive Disclosure(渐进式披露)
Skills 采用三级加载机制,确保只在需要时才向 LLM 提供详细信息:
┌─────────────────────────────────────────────────────────────────┐
│ Level 1: 元数据 (Metadata) │
│ • 始终加载到 System Prompt │
│ • 约 100 tokens/skill │
│ • 包含:技能名称 + 简短描述 │
└─────────────────────────────────────────────────────────────────┘
↓ 用户请求匹配时
┌─────────────────────────────────────────────────────────────────┐
│ Level 2: 指令 (Instructions) │
│ • 通过 read_skill 工具按需加载 │
│ • SKILL.md 的指令内容 │
│ • 包含:详细指令、代码示例、使用方法 │
└─────────────────────────────────────────────────────────────────┘
↓ 需要更多信息时
┌─────────────────────────────────────────────────────────────────┐
│ Level 3: 附加资源 (Resources) │
│ • 通过 read_skill 工具加载特定文件 │
│ • 补充文档、配置模板、脚本文件 │
│ • 通过 execute_skill_script 执行脚本 │
└─────────────────────────────────────────────────────────────────┘
Skill 目录结构
每个 Skill 是一个目录,包含 SKILL.md 主文件和可选的附加资源:
my-skill/
├── SKILL.md # 必需:主文件(含 YAML frontmatter)
├── REFERENCE.md # 可选:补充文档
├── templates/ # 可选:模板文件
│ └── config.yaml
└── scripts/ # 可选:可执行脚本
├── analyze.py
└── generate.sh
SKILL.md 格式
YAML Frontmatter
每个 SKILL.md 必须以 YAML frontmatter 开头,定义元数据:
---
name: pdf-processing
description: Extract text and tables from PDF files, fill forms, merge documents. Use when working with PDF files or when the user mentions PDFs, forms, or document extraction.
---
# PDF Processing
This skill provides utilities for working with PDF documents.
## Quick Start
Use pdfplumber to extract text from PDFs:
```python
import pdfplumber
with pdfplumber.open("document.pdf") as pdf:
text = pdf.pages[0].extract_text()
print(text)
元数据验证规则
| 字段 | 要求 |
|---|---|
name |
1-50 字符,仅允许汉字、英文字母、数字,不能是保留词 |
description |
1-500 字符,描述技能用途和触发条件 |
保留词:system, default, internal, core, base, root, admin
配置
AgentConfig 配置项
type AgentConfig struct {
// ... 其他配置 ...
// Skills 相关配置
SkillsEnabled bool `json:"skills_enabled"` // 是否启用 Skills
SkillDirs []string `json:"skill_dirs"` // Skill 目录列表
AllowedSkills []string `json:"allowed_skills"` // 白名单(空=全部允许)
}
配置示例
{
"skills_enabled": true,
"skill_dirs": [
"/path/to/project/skills",
"/home/user/.agent-skills"
],
"allowed_skills": ["pdf-processing", "code-review"]
}
Sandbox 配置(环境变量)
Sandbox 相关配置通过环境变量设置:
| 环境变量 | 说明 | 默认值 |
|---|---|---|
WEKNORA_SANDBOX_MODE |
sandbox 模式: docker, local, disabled |
disabled |
WEKNORA_SANDBOX_TIMEOUT |
脚本执行超时(秒) | 60 |
WEKNORA_SANDBOX_DOCKER_IMAGE |
自定义 Docker 镜像 | wechatopenai/weknora-sandbox:latest |
Sandbox 模式
| 模式 | 说明 |
|---|---|
docker |
使用 Docker 容器隔离(推荐) |
local |
本地进程执行(基础安全限制) |
disabled |
禁用脚本执行 |
Agent 工具
Skills 功能通过两个工具与 Agent 交互:
read_skill
读取技能内容或特定文件。
参数:
{
"skill_name": "pdf-processing", // 必需:技能名称
"file_path": "FORMS.md" // 可选:相对路径
}
使用场景:
- 加载 Level 2 内容:仅传
skill_name - 加载 Level 3 资源:同时传
skill_name和file_path
示例调用:
// 加载技能主内容
{"skill_name": "pdf-processing"}
// 加载补充文档
{"skill_name": "pdf-processing", "file_path": "FORMS.md"}
// 查看脚本内容
{"skill_name": "pdf-processing", "file_path": "scripts/analyze.py"}
execute_skill_script
在沙箱中执行技能脚本。
参数:
{
"skill_name": "pdf-processing", // 必需:技能名称
"script_path": "scripts/analyze.py", // 必需:脚本相对路径
"args": ["input.pdf", "--format", "json"] // 可选:命令行参数
}
支持的脚本类型:
- Python (
.py) - Shell (
.sh) - JavaScript/Node.js (
.js) - Ruby (
.rb) - Go (
.go)
预加载技能(Preloaded Skills)
系统内置了以下 5 个预加载技能,用于增强知识库问答和文档处理能力:
1. citation-generator - 引用生成器
用途:自动生成规范引用格式
触发场景:
- 需要生成参考文献
- 标注知识库内容出处
- 要求提供引用信息
核心能力:
| 功能 | 说明 |
|---|---|
| 来源标注 | 为回答中使用的每个知识点标注来源 |
| 格式化引用 | 支持 APA、MLA、Chicago、简化格式 |
| 参考文献列表 | 在回答末尾生成完整的参考文献列表 |
简化引用格式示例:
根据公司政策[员工手册2024.pdf, 第15页],年假申请需提前...
2. data-processor - 数据处理器
用途:数据处理与分析
触发场景:
- "分析这些数据"、"统计一下"、"计算总数/平均值"
- "转换为 JSON/CSV 格式"
- "提取关键信息"、"整理成表格"
- "生成报告"、"数据汇总"
核心能力:
| 功能 | 说明 |
|---|---|
| 数据分析 | 对检索到的文档数据进行统计分析 |
| 格式转换 | JSON/CSV/Markdown 等格式相互转换 |
| 数据提取 | 从非结构化文本中提取结构化信息 |
| 报告生成 | 生成数据分析报告和摘要 |
可用脚本:
scripts/analyze.py- 数据分析脚本scripts/format_converter.py- 格式转换脚本scripts/extract_info.py- 信息提取脚本
脚本使用示例:
# 数据分析
echo '{"items": [1, 2, 3, 4, 5]}' | python scripts/analyze.py
# 格式转换(JSON 转 CSV)
echo '[{"name": "A", "value": 1}]' | python scripts/format_converter.py --to csv
# 信息提取
echo "2024年销售额为100万元" | python scripts/extract_info.py
3. doc-coauthoring - 文档协作 (源于Claude官方Skill)
用途:引导用户完成结构化文档创作
触发场景:
- 编写文档:"write a doc"、"draft a proposal"、"create a spec"
- 文档类型:PRD、设计文档、决策文档、RFC
工作流程:
Stage 1: 上下文收集 (Context Gathering)
↓
Stage 2: 细化与结构 (Refinement & Structure)
↓
Stage 3: 读者测试 (Reader Testing)
三阶段说明:
| 阶段 | 目标 | 关键活动 |
|---|---|---|
| Stage 1 | 缩小用户与 Claude 之间的信息差 | 元信息提问、上下文收集、澄清问题 |
| Stage 2 | 逐节构建文档 | 头脑风暴、筛选整理、迭代修改 |
| Stage 3 | 测试文档对读者的效果 | 预测读者问题、子代理测试、修复盲点 |
4. document-analyzer - 文档分析器
用途:深度分析文档结构和内容
触发场景:
- 分析文档结构
- 提取关键信息
- 识别文档类型
- 进行内容质量评估
核心能力:
| 功能 | 说明 |
|---|---|
| 结构分析 | 识别文档的章节层级、组织架构 |
| 关键信息提取 | 提取核心论点、关键数据、重要结论 |
| 文档类型识别 | 判断文档类型(报告、手册、论文、合同等) |
| 内容质量评估 | 评估文档的完整性、一致性、可读性 |
分析流程:
- 文档概览 - 获取文档基本信息
- 结构分析 - 识别标题层级、章节组织
- 内容提取 - 提取核心主题、关键论点、支撑数据
- 质量评估 - 评估完整性、一致性、清晰度
技能目录结构
预加载技能位于 skills/preloaded/ 目录下:
skills/preloaded/
├── citation-generator/
│ └── SKILL.md
├── data-processor/
│ ├── SKILL.md
│ └── scripts/
│ ├── analyze.py
│ ├── format_converter.py
│ └── extract_info.py
├── doc-coauthoring/
│ └── SKILL.md
├── document-analyzer/
│ └── SKILL.md
└── summary-generator/
└── SKILL.md
创建自定义 Skill
暂时不支持用户自主创建自定义 Skill
沙箱安全机制
脚本安全校验(Script Validator)
在脚本执行前,系统会进行多层安全校验,拦截潜在的恶意操作:
校验类型
| 类型 | 说明 | 示例 |
|---|---|---|
| 危险命令检测 | 检测可能破坏系统的命令 | rm -rf /, mkfs, shutdown, fork bombs |
| 危险模式匹配 | 正则匹配高危操作模式 | curl | bash, base64 -d, eval() |
| 网络访问检测 | 检测网络请求尝试 | curl, wget, socket.connect, requests.get |
| 反向 Shell 检测 | 检测远程控制后门 | /dev/tcp/, bash -i, nc -e |
| 参数注入检测 | 检测命令行参数中的注入 | &&, |, $(), 反引号 |
| Stdin 注入检测 | 检测标准输入中的嵌入命令 | 嵌入的命令替换语法 |
拦截的危险命令
系统破坏类:
rm -rf /,rm -rf /*- 递归删除根目录mkfs,dd if=/dev/zero- 文件系统/磁盘操作- Fork bombs:
:(){ :|:& };:
系统控制类:
shutdown,reboot,halt,poweroffkillall,pkillsystemctl,service
权限提升类:
chmod 777 /,chown rootsetuid,setgid,passwd- 访问
/etc/passwd,/etc/shadow,/etc/sudoers
凭证窃取类:
- 访问
.ssh/,id_rsa,id_ed25519 - 读取敏感配置文件
容器逃逸类:
docker,kubectl,nsenterunshare,capsh
拦截的危险模式
代码注入:
# 以下模式会被拦截
curl ... | bash # 下载并执行
wget ... | sh # 下载并执行
eval() # 动态代码执行
exec() # 命令执行
os.system() # 系统命令执行
subprocess.Popen(shell=True) # Shell 命令执行
编码绕过尝试:
# 以下模式会被拦截
base64 -d # Base64 解码执行
echo ... | base64 -d # 管道解码
xxd -r # Hex 解码
Python 特有风险:
# 以下模式会被拦截
__import__() # 动态导入
pickle.load() # 反序列化(可执行任意代码)
yaml.load() # 不安全的 YAML 加载
yaml.unsafe_load() # 显式不安全加载
Shell 操作符拦截
参数中包含以下操作符时会被拦截:
| 操作符 | 说明 |
|---|---|
&&, || |
命令链接 |
; |
命令分隔 |
| |
管道 |
$(), ` |
命令替换 |
>, >>, < |
重定向 |
2>, &> |
错误/组合重定向 |
\n, \r |
换行注入 |
校验结果
校验失败时返回详细的错误信息:
type ValidationError struct {
Type string // 错误类型:dangerous_command, dangerous_pattern, arg_injection 等
Pattern string // 匹配到的模式
Context string // 上下文信息
Message string // 人类可读的描述
}
示例错误:
security validation failed [dangerous_command]: Script contains dangerous command: rm -rf / (pattern: rm -rf /, context: ...cleanup && rm -rf / && echo done...)
使用示例
// 创建校验器
validator := sandbox.NewScriptValidator()
// 校验脚本内容
result := validator.ValidateScript(scriptContent)
if !result.Valid {
for _, err := range result.Errors {
log.Printf("Security error: %s", err.Error())
}
return errors.New("script validation failed")
}
// 校验命令行参数
argsResult := validator.ValidateArgs(args)
// 校验标准输入
stdinResult := validator.ValidateStdin(stdin)
// 或一次性校验全部
fullResult := validator.ValidateAll(scriptContent, args, stdin)
Docker 沙箱
Docker 模式提供最强的隔离:
- 非 root 用户:容器内以普通用户运行
- Capability 限制:移除所有 Linux capabilities
- 只读文件系统:根文件系统只读
- 资源限制:内存 256MB,CPU 限制
- 网络隔离:默认无网络访问
- 临时挂载:Skill 目录只读挂载
- 脚本预校验:执行前进行安全校验
沙箱镜像
系统使用专用的沙箱镜像 wechatopenai/weknora-sandbox,预装了 Python 3.11、Node.js 20、常用 CLI 工具和 Python 库,无需在执行时临时安装依赖。
预拉取镜像(推荐在首次部署时执行,避免首次执行脚本时等待下载):
# 方式一:直接拉取
docker pull wechatopenai/weknora-sandbox:latest
# 方式二:本地构建
sh scripts/build_images.sh -s
如果未预拉取,应用启动时会自动异步拉取镜像(
EnsureImage),但首次执行可能需要等待下载完成。
镜像内置环境:
- Python 3.11 + pip(requests、pyyaml、pandas、beautifulsoup4)
- Node.js 20 + npm
- CLI 工具:jq、curl、bash、grep、sed、awk 等
# Docker 执行示例
docker run --rm \
--user 1000:1000 \
--cap-drop ALL \
--read-only \
--memory=256m \
--network=none \
-v /path/to/skill:/skill:ro \
-w /skill \
wechatopenai/weknora-sandbox:latest \
python scripts/analyze.py input.pdf
Local 沙箱
Local 模式提供基础保护:
- 命令白名单:仅允许特定解释器
- 工作目录限制:限定在 Skill 目录
- 环境变量过滤:仅传递安全变量
- 超时控制:默认 30 秒超时
- 路径遍历防护:防止访问 Skill 目录外文件
- 脚本预校验:执行前进行安全校验
允许的命令:
python,python3node,nodejsbash,shrubygo run
API 参考
SkillManager
type Manager interface {
// 初始化,发现所有 Skills
Initialize(ctx context.Context) error
// 获取所有 Skill 元数据(Level 1)
GetAllMetadata() []*SkillMetadata
// 加载 Skill 指令(Level 2)
LoadSkill(ctx context.Context, skillName string) (*Skill, error)
// 读取 Skill 文件内容(Level 3)
ReadSkillFile(ctx context.Context, skillName, filePath string) (string, error)
// 列出 Skill 中的所有文件
ListSkillFiles(ctx context.Context, skillName string) ([]string, error)
// 执行 Skill 脚本
ExecuteScript(ctx context.Context, skillName, scriptPath string, args []string) (*sandbox.ExecuteResult, error)
// 检查是否启用
IsEnabled() bool
}
Skill 结构
type Skill struct {
Name string // 技能名称
Description string // 技能描述
BasePath string // 目录绝对路径
FilePath string // SKILL.md 绝对路径
Instructions string // SKILL.md 主体指令内容
Loaded bool // 是否已加载 Level 2
}
type SkillMetadata struct {
Name string // 技能名称
Description string // 技能描述
BasePath string // 目录路径
}
ExecuteResult 结构
type ExecuteResult struct {
ExitCode int // 退出码
Stdout string // 标准输出
Stderr string // 标准错误
Duration time.Duration // 执行时长
Error error // 执行错误
}
示例:完整工作流
以下是 Agent 处理用户请求的完整流程:
用户: "帮我从 report.pdf 提取表格数据"
Agent 思考:
→ 查看 System Prompt 中的 Skills 列表
→ 发现 "pdf-processing" 技能匹配
Agent 行动 1: 调用 read_skill
→ {"skill_name": "pdf-processing"}
→ 获取 SKILL.md 指令内容
→ 学习如何使用 pdfplumber
Agent 行动 2: 调用 execute_skill_script
→ {"skill_name": "pdf-processing",
"script_path": "scripts/extract_text.py",
"args": ["report.pdf"]}
→ 脚本在沙箱中执行,返回提取的表格数据
Agent 回复:
→ 向用户展示提取的表格数据
→ 提供数据使用建议
故障排查
Skill 未被发现
- 检查
skill_dirs配置是否正确 - 确认目录中存在
SKILL.md文件 - 验证 YAML frontmatter 格式
# 运行 demo 验证
go run ./cmd/skills-demo/main.go
脚本执行失败
- 检查
sandbox_mode配置 - Docker 模式:确认 Docker 服务运行中
- Local 模式:确认解释器已安装
- 检查脚本权限和语法
元数据验证错误
常见错误:
skill name too long: 名称超过 50 字符skill name contains invalid characters: 包含非法字符skill name is reserved: 使用了保留词skill description too long: 描述超过 500 字符