第 18 章:Skills 系统 — 程序化记忆
核心问题:Agent 如何积累和复用”怎么做”的知识?78 个内置 Skill 如何按需加载而不撑爆上下文窗口?
18.1 Skills 系统解决什么问题
第 17 章的 Memory 系统存储的是声明性知识——“用户偏好 Python 类型注解”、“这台机器有 CUDA 12.4”。但有一类知识无法用简短条目表达:程序化知识。如何用 Axolotl 微调一个 7B 模型?如何在 Modal 上启动一个 vLLM 推理服务?如何用 Playwright 自动化网页测试?这些知识有明确的步骤、前提条件、代码片段和参数模板。
Skills 就是 Hermes 的程序化记忆系统。一个 Skill 不是一条事实,而是一段可复用的经验单元——一个目录,核心是 SKILL.md 文件(YAML 元数据 + Markdown 指令),可选附带参考文档、模板和脚本。所有 Skills 存储在 ~/.hermes/skills/,当前版本附带 78 个内置 Skill,分布在 26 个分类中。
核心挑战:上下文窗口管理
78 个 Skill 的全文不可能同时放进上下文窗口——即使是 200K token 的窗口也会被挤占。Hermes 借鉴 Anthropic 的 Claude Skills 系统,实现了三级渐进式披露:
| 层级 | API | 返回内容 | token 成本 |
|---|---|---|---|
| Tier 0 | skills_categories() | 分类名称 + 描述 | 极低 |
| Tier 1 | skills_list() | 所有 Skill 的 name + description | 低 |
| Tier 2 | skill_view(name) | 完整 SKILL.md 内容 | 中 |
| Tier 3 | skill_view(name, file) | 链接的参考文档/模板 | 按需 |
Agent 按需逐层加载——先看分类目录知道有哪些能力域,再看列表找到具体 Skill,最后才加载完整指令。
Skill 发现→加载→使用全流程
点击下方的 “播放流程” 按钮观看 Skill 从发现到使用的完整链路,或点击任意阶段查看详情:
本章结构
| 部分 | 节 | 内容 | 重要度 |
|---|---|---|---|
| 一、核心:Skill 的定义与加载 | §18.2–18.4 | SKILL.md 格式 → 渐进式披露 → 发现与过滤 | ⭐⭐⭐ 必读 |
| 二、使用:Slash 命令与配置 | §18.5–18.6 | Slash 命令系统 → 配置变量与条件激活 | ⭐⭐ 理解 Skill 如何被调用 |
| 三、安全与内置 Skill 概览 | §18.7–18.8 | 安全检查 → 78 个内置 Skill 的组织 | ⭐ 按需查阅 |
一、核心:Skill 的定义与加载
这部分回答三个基本问题:一个 Skill 长什么样?怎么被 Agent 发现?怎么按需加载而不浪费 token?
18.2 SKILL.md 格式
每个 Skill 是一个目录,核心是 SKILL.md 文件,使用 YAML frontmatter + Markdown body 的组合格式:
---name: axolotl # Required, max 64 charsdescription: Fine-tune LLMs # Required, max 1024 charsversion: 1.0.0 # Optionalplatforms: [macos, linux] # Optional — restrict to specific OSprerequisites: # Optional env_vars: [HF_TOKEN] commands: [python3, pip]metadata: # Optional (agentskills.io) hermes: tags: [fine-tuning, llm] related_skills: [peft, lora]---
# Axolotl Fine-Tuning Guide
Full instructions here...可选的子目录提供补充材料:references/ 放 API 文档,templates/ 放配置模板,assets/ 放补充文件(遵循 agentskills.io 开放标准),scripts/ 放可执行脚本。
Frontmatter 解析通过 agent/skill_utils.py 的 parse_frontmatter() 实现,有一个务实的容错设计:如果 YAML 解析失败(用户手写的 YAML 经常有格式问题),它会回退到简单的 key: value 逐行解析。宁可拿到不完美的元数据,也不要因为格式问题丢掉整个 Skill:
# agent/skill_utils.py:52-86def parse_frontmatter(content: str) -> Tuple[Dict[str, Any], str]: frontmatter: Dict[str, Any] = {} body = content
if not content.startswith("---"): return frontmatter, body
end_match = re.search(r"\n---\s*\n", content[3:]) if not end_match: return frontmatter, body
yaml_content = content[3 : end_match.start() + 3] body = content[end_match.end() + 3 :]
try: parsed = yaml_load(yaml_content) if isinstance(parsed, dict): frontmatter = parsed except Exception: # Fallback: simple key:value parsing for malformed YAML for line in yaml_content.strip().split("\n"): if ":" not in line: continue key, value = line.split(":", 1) frontmatter[key.strip()] = value.strip()
return frontmatter, body18.3 渐进式披露(Progressive Disclosure)
渐进式披露是 Skills 系统最重要的设计——它解决了”丰富知识库 vs 有限上下文窗口”的根本矛盾。
Tier 0 — 分类目录(skills_categories)。仅返回分类名称和描述,让 Agent 在最低成本下了解有哪些能力域。分类信息来自目录结构和可选的 DESCRIPTION.md 文件。
Tier 1 — 元数据列表(skills_list)。返回所有 Skill 的名称和描述(受 MAX_NAME_LENGTH = 64 和 MAX_DESCRIPTION_LENGTH = 1024 限制),不加载 body 内容。Agent 知道自己”能做什么”,但不消耗 token 去加载”怎么做”。
Tier 2/3 — 完整内容(skill_view)。当 Agent 决定需要某个 Skill 的详细指导时,调用 skill_view(name) 加载完整 SKILL.md(Tier 2)。如果 Skill 有链接文件,可用 skill_view(name, file_path) 加载特定参考文档或模板(Tier 3)。
这个分层不是任意的——它是上下文窗口管理的必然结果。在第 1 章讨论的设计哲学中,Hermes 选择了”Skills 而非规则”,本章展示了这个选择的实现代价:需要一个精细的加载策略来平衡知识可用性和 token 消耗。
18.4 Skill 发现与平台过滤
_find_all_skills() 递归扫描 Skills 目录及配置的外部目录,收集所有可用的 Skill 元数据。扫描过程中有三个重要的过滤步骤。
平台过滤。Skill 可以在 frontmatter 中声明支持的操作系统。PLATFORM_MAP 将人类友好的名称映射到 sys.platform 前缀:"macos" → "darwin"、"linux" → "linux"、"windows" → "win32"。声明 platforms: [macos, linux] 的 Skill,Windows 用户不会看到。
禁用过滤。用户可在 config.yaml 中禁用特定 Skill,支持全局禁用和平台特定禁用。一个 Skill 可能在 CLI 中启用但在 Telegram 上禁用(比如不适合移动端的复杂工作流)。
外部目录。除默认的 ~/.hermes/skills/,用户可通过 skills.external_dirs 配置额外的 Skill 目录。
二、使用:Slash 命令与配置
Skill 被发现后,用户如何调用它?Skill 如何声明自己需要的环境变量和配置项?
18.5 Slash 命令系统
每个 Skill 自动成为一个 slash 命令。scan_skill_commands() 将 Skill 名称转换为 /skill-name 格式:
# agent/skill_commands.py:200-262def scan_skill_commands() -> Dict[str, Dict[str, Any]]: ... for skill_md in scan_dir.rglob("SKILL.md"): ... name = frontmatter.get('name', skill_md.parent.name) cmd_name = name.lower().replace(' ', '-').replace('_', '-') cmd_name = _SKILL_INVALID_CHARS.sub('', cmd_name) cmd_name = _SKILL_MULTI_HYPHEN.sub('-', cmd_name).strip('-') _skill_commands[f"/{cmd_name}"] = { "name": name, "description": description or f"Invoke the {name} skill", "skill_md_path": str(skill_md), "skill_dir": str(skill_md.parent), }当用户输入 /axolotl fine-tune my model 时,build_skill_invocation_message() 加载 Skill 内容并构建一条包含完整指令的消息,附带 [SYSTEM: The user has invoked the "axolotl" skill...] 激活注释。
CLI 还支持 --skill 参数预加载——hermes --skill axolotl 会在会话开始时将 Skill 注入 system prompt(全程有效),而非作为单条用户消息。
18.6 配置变量与条件激活
配置变量。Skills 可以通过 frontmatter 的 metadata.hermes.config 声明需要的配置项,存储在 config.yaml 的 skills.config.* 命名空间下。加载时自动解析并注入 Skill 消息,Agent 无需自己读取 config.yaml。
条件激活。Skills 可以声明在特定工具集可用或不可用时才激活:
# agent/skill_utils.py:240-255def extract_skill_conditions(frontmatter: Dict[str, Any]) -> Dict[str, List]: hermes = metadata.get("hermes") or {} return { "fallback_for_toolsets": hermes.get("fallback_for_toolsets", []), "requires_toolsets": hermes.get("requires_toolsets", []), "fallback_for_tools": hermes.get("fallback_for_tools", []), "requires_tools": hermes.get("requires_tools", []), }requires_toolsets 表示 Skill 需要某些工具集才有意义(如 requires_toolsets: [browser])。fallback_for_toolsets 表示 Skill 是某个工具集不可用时的替代方案。这让 Skills 能适应不同的部署环境——第 12 章讨论的终端后端差异直接影响可用的工具集。
环境变量捕获。Skill 可在 frontmatter 中声明所需的环境变量。加载时检查缺失项,通过 _secret_capture_callback 提示用户在终端中安全输入,捕获后通过 register_env_passthrough 注册到沙盒执行环境。Gateway 模式下安全输入不可用,会提示用户在 CLI 中设置或手动添加到 .env 文件。
三、安全与内置 Skill 概览
Skill 内容会被注入上下文——它可能来自外部目录或社区分享,因此需要安全检查。本部分也概览了 Hermes 附带的 78 个内置 Skill 的组织方式。
18.7 安全检查
skill_view 在加载 Skill 时执行两层安全检查。
注入模式检测。扫描 9 种 prompt injection 模式(“ignore previous instructions”、“you are now” 等)。与第 17 章的记忆注入检测不同,Skill 的检测是警告而非阻止——因为 Skill 内容可能合法地讨论 prompt injection(如 red-teaming/godmode Skill):
# tools/skills_tool.py:871-907_INJECTION_PATTERNS = [ "ignore previous instructions", "ignore all previous", "you are now", "disregard your", "forget your instructions", "new instructions:", "system prompt:", "<system>", "]]>",]路径遍历防护。对链接文件的访问进行严格控制——has_traversal_component 检测 .. 路径组件,validate_within_dir 验证解析后的绝对路径仍在 Skill 目录内。双重检查防止 symlink 和 Unicode 规范化攻击。
18.8 78 个内置 Skills 的组织
Hermes v0.8.0 附带 78 个 SKILL.md 文件,分布在 26 个分类目录中:
skills/├── apple/ # macOS 原生应用集成│ ├── apple-notes/│ ├── apple-reminders/│ ├── findmy/│ └── imessage/├── autonomous-ai-agents/ # 其他 AI Agent 的使用指南│ ├── claude-code/│ ├── codex/│ └── hermes-agent/ # Hermes 自己的 dogfood Skill├── creative/ # 创意工具│ ├── ascii-art/│ ├── manim-video/│ ├── p5js/│ └── popular-web-designs/├── mlops/ # 机器学习运维(最大的分类)│ ├── training/ # Axolotl, PEFT, PyTorch FSDP, etc.│ ├── inference/ # vLLM, llama-cpp, GGUF, etc.│ ├── evaluation/ # LM Evaluation Harness, W&B│ ├── models/ # Stable Diffusion, Whisper, CLIP│ └── cloud/ # Modal 部署├── software-development/ # 开发工作流│ ├── plan/│ ├── systematic-debugging/│ ├── test-driven-development/│ └── subagent-driven-development/├── red-teaming/ # 安全测试│ └── godmode/└── ...这个分类反映了 Hermes 的定位——不是一个编程专精工具,而是一个通用 Agent。从 Apple Notes 到 Minecraft Mod Server,从 ArXiv 论文检索到 Polymarket 预测市场,覆盖范围远超传统 AI 编程助手。
18.9 与其他章节的连接
Skills 系统和第 17 章的 Memory 系统形成了 Hermes 知识持久层的两半。Memory 存储声明性知识(事实、偏好),Skills 存储程序性知识(步骤、模板、脚本)。Memory 的 schema 描述明确指引”如果你发现了新的做事方式,用 skill 工具保存”。
第 20 章将展示 Skill 自动创建和改进的 nudge 机制——Agent 完成复杂任务后,影子 Agent 审查对话历史,决定是否创建新 Skill 或更新已有的。第 6 章的 system prompt 构建过程中,预加载的 Skills 会作为 system prompt 的一部分注入。
速查表
| 文件 | 角色 |
|---|---|
tools/skills_tool.py | Skills 系统主逻辑(发现、加载、安全检查) |
agent/skill_utils.py | 轻量级元数据工具(解析、平台匹配、配置提取) |
agent/skill_commands.py | Slash 命令系统(扫描、构建、预加载) |
~/.hermes/skills/ | Skill 存储目录(26 个分类,78 个 Skill) |
SKILL.md | Skill 定义文件(YAML frontmatter + Markdown body) |
skills_categories() | Tier 0 — 分类目录 |
skills_list() | Tier 1 — 元数据列表(name + description) |
skill_view() | Tier 2/3 — 完整内容 + 链接文件 |
_parse_frontmatter() | YAML 解析(带 key:value 回退) |
skill_matches_platform() | 平台兼容性过滤 |
_INJECTION_PATTERNS | Skill 内容安全检测(9 种模式) |
register_env_passthrough() | 环境变量透传到沙盒执行环境 |