Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

技能系统:从经验中学习的闭环

本章核心源码agent/skill_utils.py(442 行)、tools/skills_tool.py(1376 行)、tools/skill_manager_tool.py(742 行)

定位:本章分析 Hermes "self-improving" 理念的核心实现——技能系统。技能不是静态文档,而是 agent 从工作中提炼、在使用中改进、按条件加载的过程性知识。 前置依赖:第 5 章(提示词系统)、第 6 章(工具系统)。适用场景:想理解"self-improving agent"如何在工程上实现。

为什么技能系统是 Hermes 的核心差异

大多数 agent 框架有工具系统("agent 能做什么")和 prompt 系统("agent 知道什么")。Hermes 多了第三个系统——技能系统("agent 学到了什么")。

三者的关系:

系统内容类型变化频率来源
工具可执行的函数低(开发者添加)代码
Prompt身份和规则低(配置/硬编码)配置文件
技能过程性知识高(agent 自主创建/改进)工作经验

技能填补了一个空白:agent 在解决一个复杂问题后,如果没有技能系统,下次遇到同类问题需要从头探索。有了技能系统,agent 可以把解决过程提炼为可复用的技能——下次直接检索使用。

这就是 Learning Loop 赌注的工程实现。

技能的数据模型

每个技能是一个 Markdown 文件,带有 YAML frontmatter:

---
metadata:
  hermes:
    fallback_for_toolsets: [web]
    tags: [automation, workflow]
platforms: [macos, linux]
---

# 使用 Exa API 搜索学术论文

## 问题
标准 web_search 对学术论文的检索效果不佳...

## 方案
使用 Exa 的 neural search 模式,配合 category=research...

## 示例
```python
result = web_search(query="transformer attention mechanism", ...)

### Frontmatter 解析

`parse_frontmatter()`(`agent/skill_utils.py:52`)负责解析 YAML frontmatter:

```python
# agent/skill_utils.py:52-86
def parse_frontmatter(content: str) -> Tuple[Dict[str, Any], str]:
    if not content.startswith("---"):
        return {}, content
    end_match = re.search(r"\n---\s*\n", content[3:])
    yaml_content = content[3 : end_match.start() + 3]
    try:
        parsed = yaml_load(yaml_content)  # CSafeLoader(快速)+ fallback
    except Exception:
        # Fallback: simple key:value parsing for malformed YAML
        for line in yaml_content.strip().split("\n"):
            key, value = line.split(":", 1)
            frontmatter[key.strip()] = value.strip()
    return frontmatter, body

设计选择:优先使用 CSafeLoader(C 实现,快);如果 YAML 格式有问题,fallback 到逐行 key: value 解析。这让系统对格式不完美的技能文件保持鲁棒。

条件加载

Frontmatter 支持多种条件字段:

平台过滤agent/skill_utils.py:92):

platforms: [macos, linux]  # 只在 macOS 和 Linux 上加载

skill_matches_platform()platforms 列表与 sys.platform 比较。缺失或空表示兼容所有平台。

工具依赖agent/skill_utils.py:240):

metadata:
  hermes:
    fallback_for_toolsets: [web]     # 当 web toolset 不可用时激活
    requires_toolsets: [terminal]     # 需要 terminal toolset 才加载
    requires_tools: [web_search]     # 需要特定工具才加载

extract_skill_conditions() 提取这些条件,由 build_skills_system_prompt() 在构建技能索引时评估。

禁用列表agent/skill_utils.py:121):

# config.yaml
skills:
  disabled: [deprecated-skill]
  platform_disabled:
    telegram: [desktop-only-skill]

get_disabled_skill_names() 支持全局禁用和按平台禁用。Gateway 的 Telegram 平台可以禁用只在桌面端有意义的技能。

技能的生命周期

graph LR
    A["发现<br/>扫描 skills/ 目录"] --> B["索引<br/>提取 name + description"]
    B --> C["注入<br/>写入 system prompt"]
    C --> D["检索<br/>skill_view 按需加载"]
    D --> E["使用<br/>模型根据内容执行"]
    E --> F["创建<br/>skill_manage create"]
    F --> G["改进<br/>skill_manage patch"]
    G --> D

阶段 1:发现

get_all_skills_dirs()agent/skill_utils.py:226)返回技能搜索路径:

# agent/skill_utils.py:226-234
def get_all_skills_dirs() -> List[Path]:
    dirs = [get_hermes_home() / "skills"]   # 当前 HERMES_HOME/skills/(总是第一位)
    dirs.extend(get_external_skills_dirs())  # config.yaml 中的 external_dirs
    return dirs

阶段 2:索引

build_skills_system_prompt()agent/prompt_builder.py:529)扫描所有技能目录,为每个技能提取名称和一句话描述,生成索引列表注入 system prompt。

索引只包含标题和描述——完整内容在模型需要时通过工具按需加载。这个设计控制了 system prompt 的 token 开销:26 个技能类别的索引只占几百 token,但完整内容可能超过 50K token。

阶段 3-4:检索与使用

模型通过 skill_view 工具按名称检索技能的完整内容:

# tools/skills_tool.py:787
def skill_view(name: str, file_path: str = None, task_id: str = None) -> str:
    # 在所有 skills 目录中搜索匹配的技能文件
    # 返回完整的 Markdown 内容

阶段 5-6:创建与改进

这是 Learning Loop 的核心。模型通过 skill_manage 工具创建和改进技能:

# tools/skill_manager_tool.py:569
def skill_manage(action: str, name: str = None, content: str = None,
                 patch: str = None, ...):
    # action = "create": 创建新技能
    # action = "patch": 改进现有技能
    # action = "delete": 删除技能

SKILLS_GUIDANCEagent/prompt_builder.py:164)引导模型的行为:

"After completing a complex task (5+ tool calls), fixing a tricky error, or discovering a non-trivial workflow, save the approach as a skill... When using a skill and finding it outdated, incomplete, or wrong, patch it immediately with skill_manage(action='patch') — don't wait to be asked."

两个关键指令:

  1. 自主创建:完成复杂任务后主动保存为技能
  2. 使用时改进:发现技能过时或不准确时立即 patch

这让技能系统形成了一个正反馈循环:使用越多 → 发现越多问题 → 改进越多 → 质量越高 → 使用越有效。

Nudge 机制:主动触发学习

agent 不会"忘记"创建技能——AIAgent 中的 nudge 机制会定期提醒:

# run_agent.py:1072-1076
self._skill_nudge_interval = 10  # 每 10 个 tool iteration 检查
self._iters_since_skill = 0

当模型在一次对话中使用了 10+ 个工具调用但没有触碰 skill_manage,编排器会在 _spawn_background_review() 中启动一个后台 agent 审查对话内容,判断是否值得创建技能(详见第 4 章)。

与 agentskills.io 的对接

Hermes 的技能格式兼容 agentskills.io 开放标准。这意味着:

  • 社区创建的技能可以直接放入当前 HERMES_HOME/skills/(默认 profile 下表现为 ~/.hermes/skills/
  • Hermes 创建的技能可以分享到 Skills Hub
  • 不同 agent 框架之间的技能可以互通

设计哲学:基于来源的信任分级(Source-based credibility)

并非所有技能享有同等信任。Hermes 实现了一套信任分级机制(tools/skills_guard.py:41-49),根据技能的来源决定如何解读其安全性发现:builtin 技能(Hermes 团队编写)即使触发"dangerous"级发现也被允许执行;trusted-source 技能允许"caution"但拦截"dangerous";community-sourced 技能连"caution"级发现也会被拦截。同一个安全发现,因为编写者不同,处理策略完全不同——这是来源即信誉的设计原则。

技能 vs 工具 vs Prompt:三种知识的区分

维度工具Prompt技能
形式Python 函数文本块Markdown 文件
变更频率低(版本发布)低(配置修改)高(agent 自主创建)
作者开发者开发者/用户Agent 自身
加载方式模块导入构建时注入 system prompt索引注入 + 按需检索
可改进否(需改代码)手动Agent 自动 patch

这个区分不是学术分类,而是有工程后果的:如果技能被实现为工具,每次添加技能就需要修改代码;如果技能被实现为 prompt,所有技能内容都会占用 system prompt token。Markdown + 按需检索的方案既让 agent 自主管理,又控制了 token 开销。

设计启示

技能系统的设计展示了 "self-improving" 的工程实现路径:

  1. 低成本创建:Markdown 文件 + YAML frontmatter,没有 schema 验证、没有编译、没有注册步骤
  2. 渐进式加载:索引在 system prompt,完整内容按需检索——控制基础 token 开销
  3. 正反馈循环:使用时发现问题 → 立即 patch → 下次使用时更好
  4. Nudge 而非强制:通过 background review 提醒,不强制每次都创建技能

第 9 章将分析子代理与委托机制——另一种扩展 agent 能力的方式。


设计赌注回扣:本章是 Learning Loop 赌注的核心实现。技能系统让 Hermes 从"能用工具做事的 agent"升级为"能从经验中学习的 agent"。SKILLS_GUIDANCE 的"使用时立即 patch"指令和 _spawn_background_review 的自动审查构成了完整的学习闭环。


版本演化说明

本章核心分析基于 Hermes Agent v0.8.0(2026 年 4 月)。 技能文件发现、skill_manage 和基础 skills 目录迁移,在 v0.3.0 发布窗口之前就已出现;v0.4.0 发布窗口又加入了 background review 驱动的自动审查。之后 v0.5.0-v0.8.0 之间继续补足条件加载、展示层和 agentskills.io 兼容细节。