04 - 技能系统与自改进循环
学习目标
本章聚焦 Hermes Agent 的技能系统及其自改进能力。你将了解:
- Curator 后台系统如何自动归档过期技能
- 技能 Provenance(来源追踪)如何区分 Agent 创建和人工编写
- 可选技能分发(optional-skills/)如何避免启动时加载过多技能
- SKILL.md 的硬性写作标准
前置知识
本章涉及技能系统的通用原理,建议先阅读:
下文直接聚焦 Hermes 的自改进循环具体实现。
项目实践
Curator 后台技能维护
agent/curator.py 实现了后台自动技能维护系统:
状态转换管线:
关键不变量:
- 只处理
created_by: "agent"的技能 — 内置和用户安装的技能不受影响 - 永远不会删除,最大破坏操作是归档到
~/.hermes/skills/.archive/ - Pin 的技能不参与任何自动转换和 LLM 审查
- 归档的技能可随时通过
hermes curator restore恢复
使用统计 Sidecar:~/.hermes/skills/.usage.json 跟踪每个技能的:
| 字段 | 含义 |
|---|---|
use_count | 执行次数 |
view_count | 查看次数 |
patch_count | 修改次数 |
last_activity_at | 最后活动时间 |
state | active / stale / archived |
pinned | 是否固定 |
CLI 动词:status、run、pause、resume、pin、unpin、archive、restore、prune、backup、rollback。
技能 Provenance 追踪
tools/skill_provenance.py 使用 ContextVar 标记每次技能写入的来源:
set_current_write_origin("assistant_tool") # Agent 自主创建set_current_write_origin("human") # 人工编写后台审查线程运行在独立线程上,带有独立的 ContextVar,确保写入来源正确标记。这使得 Curator 可以安全地只管理 Agent 创建的技能,不触碰人类编写的技能。
可选技能分发
Hermes 有两层技能分发:
| 目录 | 默认加载 | 安装方式 | 内容 |
|---|---|---|---|
skills/ | 是 | 自动可用 | 核心技能(25 分类) |
optional-skills/ | 否 | hermes skills install official/<cat>/<skill> | 重型/小众技能 |
这种区分避免了启动时加载过多技能描述导致模型注意力分散。重型依赖(如需要特定 CLI 工具或大量参考文献的技能)放在 optional-skills/。
SKILL.md 硬性标准
Hermes 对技能文档有 CI 强制执行的写作标准:
| 标准 | 要求 |
|---|---|
description | ≤ 60 字符,一句话,以句号结尾 |
| 工具引用 | 必须用反引号标注 Hermes 工具名(如 `terminal`) |
platforms: 门控 | 必须与实际脚本导入一致 |
| Section 顺序 | 标题 → 简介 → When to Use → Prerequisites → How to Run → Quick Reference → Procedure → Pitfalls → Verification |
| 脚本位置 | scripts/ 目录,不在 SKILL.md 中内联 |
| 测试位置 | tests/skills/test_<skill>_skill.py |
背景审查(Background Review)
agent/background_review.py 实现后台技能自我改进:
- 守护线程在 Agent 空闲时启动
- Forked agent 使用工具白名单(仅 memory 和 skill 管理工具)
- 继承父 Agent 的运行时(provider、model、credentials、prefix cache)
- Review 提示包含详细的信号检测指南(用户偏好、工作流修正、新技术等)
问题与规避
Curator 误归档活跃技能
问题:技能在后台被使用(如 cron 任务调用),但 usage tracker 未记录,导致被误标为 stale。
对策:bump_use() 在所有技能执行路径调用,包括 cron 和 delegate。如果仍有遗漏,可 Pin 关键技能豁免审查。
Provenance 在线程间泄漏
问题:ContextVar 设置在线程 A,但线程 B 的写入读取了 A 的值。
对策:后台审查线程在自己的线程上运行,带有独立的 ContextVar 值。主线程的 _memory_write_origin 不会泄漏到审查线程。
可选技能的依赖缺失
问题:用户安装了可选技能但缺少所需的 CLI 工具或依赖。
对策:每个工具的 check_fn 在注册时检查环境要求(如 API key、CLI 工具是否存在)。不满足条件的技能不会暴露给模型。
设计取舍
自动归档 vs 永久保留
| 方案 | 优势 | 代价 |
|---|---|---|
| 自动归档(Hermes) | 技能目录保持精简,模型注意力集中在活跃技能 | 归档技能需要手动恢复 |
| 永久保留 | 所有技能始终可用 | 技能过多时模型注意力分散 |
Hermes 选择归档而非删除,保留了恢复的可能性。归档技能存放在 .archive/ 目录,不加载到模型上下文。
描述 ≤ 60 字符的硬限制
| 方案 | 优势 | 代价 |
|---|---|---|
| 严格限制(Hermes) | 技能列表紧凑,模型可同时加载更多技能 | 复杂技能难以用一句话描述清楚 |
| 宽松限制 | 描述更充分 | 技能列表膨胀,注意力分散 |
Hermes 的假设是:描述的目的是让模型判断”这个技能是否与当前任务相关”,而不是教会模型如何使用。详细使用说明在 SKILL.md 正文中,按需加载。
参考来源
- 源码验证:
agent/curator.py、tools/skill_usage.py、tools/skill_provenance.py、agent/background_review.py