Hermes-Agent Skill 自进化


总览(一句话结论)

hermes-agent 确实实现了 skill 自进化,且体系完整:它设计了“运行时本地 skill + 远程 Skills Hub”两层 skill 系统,通过“渐进式加载”让大语言模型(LLM)自主发现并加载 skill;同时靠“即时学习(background_review)、周期整理(curator)”两条自动回路,加上“人工提炼(/learn)”一条人工入口,驱动 skill 自进化。一个 skill 从创建、使用、修正、合并到归档的全生命周期,都有对应的机制支撑。

核心设计原则:自动回路仅执行“小修、标记、归档”这类可逆操作,不可逆动作(如合并重写、删除)需手动触发或由人工确认。


目录

  1. Skill 发现(Discovery)
  2. Skill 加载(Loading)—— 三种模式
  3. Skill 执行(Execution)—— 三个工具各做什么
  4. 问题发现与自进化——双回路 + 人工入口
  5. 一个 skill 的完整修改生命史(全景)
  6. 常见疑问解答
  7. 借鉴价值

一、Skill 发现(Discovery)

1.1 先分清两套系统(读代码最大的坑)

hermes-agent 的 skill 系统分“远程”和“本地”两套,作用和核心文件完全不同,先理清这一点能避免理解偏差:

系统 作用 关键文件
Skills Hub(远程注册中心) 相当于 skill 的“应用市场”,可通过 hermes skills search/install 命令,从 Anthropic、OpenAI 等第三方 marketplace 拉取现成 skill tools/skills_hub.py(核心逻辑)、skills/index-cache/*.json(HTTP 缓存)、scripts/build_skills_index.py(构建索引)
Runtime skills(本地运行时) Agent 实际运行时能调用的 skill 集合,是真正参与业务逻辑的 skill agent/skill_utils.py(发现/过滤)、agent/prompt_builder.py(构建清单)、tools/skills_tool.py(工具封装)

⚠️ 注意:skills/index-cache/*.json(比如 anthropics_skills_skills_.json)只是 Hub 抓取远程仓库时的 HTTP 缓存(缓存有效期 1 小时,见 skills_hub.py:60),并不是 Agent 运行时的 skill 清单。Agent 运行时找 skill,只看本地文件系统。

1.2 运行时发现机制:扫描本地文件系统

Agent 启动后,会遍历 ~/.hermes/skills/ 目录(加上配置的 external_dirs 外部目录)下所有名为 SKILL.md 的文件,这个遍历动作由 iter_skill_index_files() 函数完成(见 agent/skill_utils.py)。

之后,skills_list 工具(tools/skills_tool.py:689,内部调用 _find_all_skills:604)会解析每个 SKILL.md 文件开头的 YAML 配置块(frontmatter),最终返回结构化数据:

# 示例返回格式
{
    "skills": [
        {"name": "arxiv", "description": "Search arXiv papers by keyword...", "category": "research"},
        {"name": "test-driven-development", "description": "TDD: enforce RED-GREEN-REFACTOR...", "category": "software-development"}
    ],
    "categories": ["research", "software-development"],
    "count": 2
}

1.3 关键设计:匹配由 LLM 完成,过滤只做“剔除”不做“排序”

Python 代码只负责“过滤掉不该出现的 skill”,不会给 skill 打分、排序,也不会做语义匹配或向量检索——判断“哪个 skill 适配当前任务”,完全靠 LLM 读取过滤后的清单自主决策。

一个 skill 要进入最终清单,需依次通过五道“过滤门”,每道门只做“剔除”动作:

门 1:平台门控(硬兼容门)—— skill_matches_platformskill_utils.py:163

作用:判断 skill 是否适配当前操作系统(比如 macOS、Linux),是“硬门槛”——不兼容就直接剔除,没有例外。

  • 读取 SKILL.md frontmatter 里的 platforms: 列表(比如 [macos][macos, linux]);
  • 若字段缺省,默认兼容所有平台;
  • 特殊处理:Android 上的 Termux(Linux 用户态),无论 Python 识别的 sys.platformlinux 还是 android,都会判定 linux 标签的 skill 兼容(见 skill_utils.py:199),也支持显式的 termux/android 标签。
门 2:环境门控(软相关门,offer-time only)—— skill_matches_environmentskill_utils.py:268

先解释核心名词:

  • offer-time:指“向 LLM 推荐 skill 的时机”,也就是构建 skill 清单、自动补全列表、slash 命令列表的时机;
  • 清单:给 LLM 看的所有可用 skill 汇总(系统提示里的压缩清单),是 LLM 选 skill 的核心依据;
  • 自动补全列表:Agent 交互时,输入 /skill 等命令后弹出的“可选 skill 列表”,方便快速选择;
  • slash 列表:以 / 开头的快捷命令列表(比如 /arxiv/learn),本质是“skill 快捷调用入口”。

这道门的作用:根据 Agent 运行的环境,控制 skill 是否出现在“清单、自动补全、slash 列表”里(软门槛,可被绕开)。

  • 读取 frontmatter 的 environments: 列表,只识别三个固定标签(_KNOWN_ENVIRONMENTS,见 skill_utils.py:217):
标签 匹配条件 检测方式
kanban 看板调度器在运行(比如 dispatcher worker 启动,或 profile 开启了 kanban 工具集) 检查 HERMES_KANBAN_TASK/HERMES_KANBAN_BOARD 环境变量,或调用 _profile_has_kanban_toolset()skill_utils.py:239
docker Agent 运行在 Docker 容器内 调用 hermes_constants.is_container()skill_utils.py:252
s6 Agent 运行在 s6-overlay 监管的容器里(Hermes Docker 镜像的 PID 1 是 s6) 检查 /run/s6/package/admin/s6-overlay 目录是否存在(skill_utils.py:260
  • 关键规则:
    1. 这是“软门”——只控制“是否显示”,不影响显式加载:比如一个标记 environments: [kanban] 的 skill,在非看板环境下不会出现在清单里,但手动执行 skill_view(该skill名) 仍能读取;
    2. 语义为“或”:只要声明的环境有一个激活,就判定匹配;
    3. 未知标签“容错”:遇到不认识的标签,不会隐藏 skill(避免误屏蔽)。

代码注释(skill_utils.py:282)原话:“an explicit load is explicit consent”(显式加载就是显式同意),核心是“不限制用户主动选择,只优化默认推荐”。
【我应该与skill有关的背景、操作执行者、执行内容写清楚,应该把复杂步骤用代码案例展示出来,应该把文章写得更通俗易懂】

门 3:禁用门控 —— get_disabled_skill_namesskill_utils.py:353

作用:读取用户配置,剔除显式禁用的 skill。

  • 读取 config.yaml 里的 skills.disabled(全局禁用)和 skills.platform_disabled.<平台>(按平台禁用);
  • 只要在禁用列表里,直接剔除,是用户/配置层的显式关闭。
门 4:条件激活(随 toolset 自适应)—— _skill_should_showprompt_builder.py:1386

作用:让 skill 清单随当前会话激活的工具集(toolset)自动调整,避免显示“用不了的 skill”。

  • 读取 metadata.hermes 下的四个条件字段:
    1. fallback_for_toolsets/fallback_for_tools:“备用 skill”——当它兜底的主工具集/工具可用时,隐藏这个 skill(有正经工具就不用备用的);
    2. requires_toolsets/requires_tools:“依赖 skill”——当它依赖的工具集/工具不可用时,隐藏这个 skill(依赖缺失,用不了)。
  • 示例:若某 profile 没开浏览器工具,依赖浏览器的 skill 会自动从清单消失;若主工具齐全,备用的 fallback skill 不会显示。
  • 注意:这道门是“硬过滤”(清单里绝对不显示),但 skill_view 仍能绕过(只作用于清单构建,不影响显式读取)。
门 5:编码姿态降级(永不隐藏)—— compact_categoriesprompt_builder.py:1608

作用:在编码场景下,节省 token(模型上下文容量有限),但绝不隐藏 skill 名字。

  • 非编码类 skill:从“名字 + 描述”降级为“仅名字”(比如 research: arxiv),砍掉描述;
  • 核心原则:“可以省描述,绝不藏名字”——因为 Agent 自建的 skill 是项目记忆,名字消失后,模型基本不会再想起它。
1.3 小结

五道过滤门的核心逻辑:

  • 门 1(平台):真兼容,不兼容就剔除;
  • 门 2(环境):软相关,不匹配就不推荐,但可手动选;
  • 门 3(禁用):配置层,显式关就剔除;
  • 门 4(条件):随工具集自适应,用不了就不显示;
  • 门 5(降级):省 token,只砍描述不藏名。

所有过滤只做“剔除不该出现的”,“选哪个用”完全交给 LLM 决策。

1.4 SKILL.md frontmatter schema(实际解析的字段)

SKILL.md 开头的 YAML frontmatter 是 skill 的“配置说明书”,下面结合真实示例(skills/research/arxiv/SKILL.md),讲清楚每个字段的作用,重点解释易混淆的 metadata.hermes.config

---
name: arxiv                              # 必填,小写连字符格式,最长64字符,全局唯一
description: "Search arXiv papers by keyword, author, category..."    # 必填,核心说明
version: 1.0.0                           # 可选,版本号
author: Hermes Agent                     # 可选,作者
license: MIT                             # 可选,开源协议
platforms: [linux, macos, windows]       # 可选,门1平台门控(缺省=全平台)
environments: [kanban]                   # 可选,门2环境门控(仅kanban/docker/s6)
metadata:
  hermes:
    tags: [Research, Arxiv, Papers]      # 可选,搜索标签
    related_skills: [ocr-and-documents]  # 可选,关联skill(skill_view时展示)
    # 门4条件激活字段(四选零到多)
    fallback_for_toolsets: []            # 主工具集可用时,隐藏此备用skill
    requires_toolsets: []                # 依赖的工具集不可用时,隐藏此skill
    fallback_for_tools: []               # 同上,针对单个工具
    requires_tools: []                   # 同上,针对单个工具
    # 重点:metadata.hermes.config 字段
    config:
      - key: wiki.path                   # config.yaml 里的配置键(逻辑路径)
        description: Path to the wiki    # 给用户看的配置说明
        default: "~/wiki"                # 配置默认值
        prompt: Wiki directory path      # 引导用户配置的提示语
---
重点解释:metadata.hermes.config 的作用

这个字段的核心是“声明 skill 依赖的配置项,让模型不用手动查配置文件”,分两步理解:

  1. 声明依赖:告诉 Agent“这个 skill 要正常工作,需要用到 config.yaml 里的 wiki.path 配置”;
  2. 预加载注入:当用“预加载模式”(后文 2.4 模式 C)加载这个 skill 时,Agent 会自动读取 config.yamlwiki.path 的当前值,以 [Skill config: wiki.path = ~/wiki] 的格式注入到对话上下文里。

举个实际例子:

  • config.yaml 里写了 wiki: path: /Users/xxx/my-wiki
  • 预加载 arxiv skill 时,Agent 会自动在上下文里加一行:[Skill config: wiki.path = /Users/xxx/my-wiki]
  • LLM 看到这行,就知道“用 arxiv skill 时,wiki 路径是这个”,不用再调用 read_file 去翻 config.yaml,也不用问用户“wiki 路径在哪”。

简单说:这个字段是“skill 和配置文件的桥梁”,既明确 skill 依赖哪些配置,又能在预加载时自动把配置值塞给模型,提升效率。

其他关键字段说明
  • description 截断规则
    1. 系统提示的压缩清单里:截到 60 字符(超长则前 57 字符 + “…”,见 skill_utils.py:716),目的是省 token;
    2. skills_list 工具返回里:最长 1024 字符(MAX_DESCRIPTION_LENGTHskills_tool.py:98),能看完整描述。
  • name 唯一性_create_skill 创建时会跨所有目录查重(skill_manager_tool.py:724),重名直接拒绝,避免冲突;
  • 无 triggers 字段:触发条件写在 description 里(比如 “Use this when searching academic papers”),靠 LLM 阅读理解,而非关键词匹配;
  • 配套文件不算独立 skillreferences/templates/scripts/assets/ 子目录里的文件(比如 references/api.md),不会被当作独立 skill,而是通过 skill_view(name=arxiv, file_path=references/api.md) 按需读取。
    【我应该与skill有关的背景、操作执行者、执行内容写清楚,应该把复杂步骤用代码案例展示出来,应该把文章写得更通俗易懂】

二、Skill 加载(Loading)—— 三种模式

Skill 加载是 hermes-agent 的核心设计,核心逻辑是“渐进式加载”:不是“要么全加载,要么不加载”,而是“先给目录(压缩清单),再按需读详情(完整正文)”。下面从“何时加载、加载到哪、加载什么”三个维度,讲清楚三种加载模式。

2.1 核心逻辑:渐进式加载(Progressive Disclosure)

先明确两个核心概念:

  • 内容分层
    1. 压缩清单:只有“名字 + 60 字短描述”,轻量,每轮对话都在模型上下文里;
    2. 完整正文:整个 SKILL.md + 配套文件(references/templates 等),量大,仅按需加载。
  • 触发模式:分“常驻、按需、预加载”三种,覆盖“自动、模型主动、用户主动”三类场景。

2.2 模式 A:常驻模式(Resident)—— 自动加载,每轮都在

何时加载:会话启动时自动触发,且每轮对话都保留

Agent 启动一个新会话(比如执行 hermes chat)时,会立刻调用 build_skills_system_promptagent/prompt_builder.py:1417)构建压缩清单,之后每轮对话,这份清单都会留在系统提示里。

加载到哪:系统提示(System Prompt)

系统提示是 LLM 每轮都会读取的“基础指令集”,压缩清单会被注入到系统提示的固定位置(agent/system_prompt.py:282),比如:

# Available Skills
research:
  - arxiv: Search arXiv papers by keyword, author, category...
software-development:
  - test-driven-development: TDD: enforce RED-GREEN-REFACTOR...

系统提示里还会加强制指令:“回复前先扫一遍下面的 skill,如果有匹配的,必须用 skill_view(name) 加载它并遵循其指令。”

加载什么:所有通过过滤的 skill 的“名字 + 60 字描述”

加载内容是 1.3 节过滤后的 skill 清单,每个 skill 只保留名字和截断后的短描述,比如 arxiv skill 的描述只留前 60 字符。

优化:两层缓存保证效率

遍历目录构建清单可能慢,所以设计了两层缓存:

  1. 进程内 LRU 缓存:键包含“skills 目录、外部目录、可用工具集、平台、禁用列表”等,同进程内重复请求直接读缓存;
  2. 磁盘快照缓存~/.hermes/.skills_prompt_snapshot.json,靠每个 SKILL.md 的“修改时间 + 大小”校验——文件没改就读快照,改了才重扫。

衔接逻辑:当 skill_manage(修改 skill 的工具)成功修改 skill 后,会调用 clear_skills_system_prompt_cache(clear_snapshot=True)skill_manager_tool.py:1271)清空两层缓存,保证下一轮对话能看到最新清单。

2.3 模式 B:按需模式(On-demand)—— LLM 主动加载,对话中途触发

何时加载:LLM 看到常驻模式的压缩清单后,判断需要用某个 skill 时

比如用户问“怎么搜索 arXiv 论文”,LLM 扫到压缩清单里的 arxiv skill,会主动调用 skill_view(name=arxiv),触发按需加载。

加载到哪:工具调用结果(Tool Result)

skill_view 是一个工具函数(tools/skills_tool.py:864),调用后返回的完整内容,会以“工具执行结果”的形式注入到对话上下文里(不是系统提示),比如:

# Tool: skill_view
# Result:
content: [完整的 arxiv SKILL.md 内容]
tags: [Research, Arxiv, Papers]
related_skills: [ocr-and-documents]
linked_files:
  references: [api.md, usage-notes.md]
  templates: [search-query-template.txt]
readiness_status: ACTIVE
加载什么:单个 skill 的完整正文 + 配套文件清单
  • 第一次调用 skill_view(name=arxiv):返回 SKILL.md 全文(预处理后) + 配套文件清单(references/templates 等);
  • 若需要读配套文件:再调用 skill_view(name=arxiv, file_path=references/api.md),读取具体文件内容。
额外动作:更新使用计数

每次 skill_view 成功调用,会执行 _skill_view_with_bump 函数,更新这个 skill 的“查看/使用计数”——这些计数是后续自进化的核心依据(比如 curator 会根据使用次数判断是否归档)。

预处理规则

加载的正文会做简单预处理:

  • ${HERMES_SKILL_DIR} 模板变量:自动替换为实际的 skill 目录路径;
  • !`cmd` 内联 shell 命令:仅当 skills.inline_shell: true 时展开(最长 4000 字符),比如 !echo ~/wiki`` 会替换为实际路径。
    【我应该与skill有关的背景、操作执行者、执行内容写清楚,应该把复杂步骤用代码案例展示出来,应该把文章写得更通俗易懂】

2.4 模式 C:预加载模式(Preload)—— 用户主动加载,会话启动/中途触发

何时加载:用户明确指定时,分两种场景
  1. 会话启动时:执行 hermes --skills arxiv,test-driven-development,指定要预加载的 skill;
  2. 对话中途:输入 slash 命令(比如 /arxiv)或 bundle 命令(/bundle-name,见 agent/skill_bundles.py)。
加载到哪:标记为 IMPORTANT 的对话消息

预加载的 skill 内容,会以 [IMPORTANT: Preloaded Skill - arxiv] 为标记,作为一条独立消息注入到对话上下文里(build_preloaded_skills_promptskill_commands.py:564),比如:

[IMPORTANT: Preloaded Skill - arxiv]
content: [完整的 arxiv SKILL.md 内容]
[Skill config: wiki.path = /Users/xxx/my-wiki]
加载什么:完整正文 + 配置块(核心区别)

和按需模式相比,预加载模式多了“配置块注入”:

  1. 先调用 skill_view 读取完整正文(和模式 B 底层函数相同);
  2. 再调用 _inject_skill_configskill_commands.py:206),读取 metadata.hermes.config 声明的配置项,把 config.yaml 里的当前值以 [Skill config: key = value] 格式注入。

比如 arxiv skill 声明了 wiki.path,预加载时就会自动加 [Skill config: wiki.path = /Users/xxx/my-wiki],模型直接用,不用查配置。

2.5 三种模式对照表(清晰版)

维度 模式 A 常驻 模式 B 按需 模式 C 预加载
触发者 系统自动 LLM 自主决策 用户(命令/参数)
触发时机 会话启动,每轮保留 对话中途,LLM 调用 skill_view 会话启动(–skills)/ 对话中途(/skill)
加载位置 系统提示(全局) 工具结果(当前轮) 标记为 IMPORTANT 的消息(全局)
加载内容 名字 + 60 字描述(压缩清单) 完整正文 + 配套文件清单(预处理) 完整正文 + 配套文件清单 + 配置块
Token 代价 极小(每 skill 一行) 中等(单个 skill 正文) 较大(全程常驻,多 skill 更甚)
核心函数 build_skills_system_prompt skill_view skill_view + _inject_skill_config

2.6 常见误解澄清

  1. 误解一:skill 太多会爆上下文
    不会。模式 A 把每个 skill 压缩到一行,token 消耗极低;只有模式 B/C 会加载完整正文,且只加载“需要用的”,不会全量加载。
  2. 误解二:编码模式下非编码 skill 会被隐藏
    不会。非编码类 skill 只会被降级为“仅名字”(比如 research: arxiv),名字一定保留——因为名字消失后,模型就不会再想起这个 skill 了。
    【我应该与skill有关的背景、操作执行者、执行内容写清楚,应该把复杂步骤用代码案例展示出来,应该把文章写得更通俗易懂】

三、Skill 执行(Execution)—— 三个工具各做什么

3.1 本质:指令注入改变模型行为

hermes-agent 的 skill 不是“可执行代码”(虽然能带 scripts/ 脚本),核心作用方式是“指令注入”:

  1. skill_view 读取 SKILL.md 全文,作为工具结果进入对话上下文;
  2. 系统提示强制 LLM“加载了 skill 就必须遵循其指令”;
  3. LLM 后续的回答/操作,会被这份 SKILL.md 的步骤、命令、注意事项约束。

简单说:skill 是“结构化的操作手册”,通过“塞进上下文”改变模型行为。

3.2 三个核心工具(分工明确)

整个 skill 系统对外只暴露三个工具,都属于 skills 工具集,分工是“找得到 → 读得到 → 改得动”:

工具 1:skills_list —— 浏览/检索(只读)
  • 作用:列出当前可用的 skill,相当于“翻目录”;
  • 返回内容:{skills: [{name, description, category}], categories, count}(见 1.2 示例);
  • 关键区别:和系统提示的压缩清单同源,但 description 不截断(最长 1024 字符),还支持按 category 过滤(比如 skills_list(category=research));
  • 引导逻辑:返回结果里会明确提示“Use skill_view(name) to load full content”,引导 LLM 下一步调用 skill_view
工具 2:skill_view —— 读取完整内容(只读,触发遥测)
  • 作用:加载 skill 完整正文 + 配套文件,是“渐进式加载”的核心;
  • 两段式读取:先读 SKILL.md 正文 + 配套文件清单,再按需读具体配套文件;
  • 遥测动作:每次成功调用,更新 skill 的“查看/使用计数”(_skill_view_with_bump),为自进化提供数据。
工具 3:skill_manage —— 创建/修改/删除(写,自进化唯一写入口)
  • 作用:所有 skill 的变更(创建、修改、删除、写配套文件等),都通过这个工具完成;
  • 核心动作:create / patch / edit / delete / write_file / remove_file(后文第五节详细讲);
  • 关键设计:工具描述里直接写“自进化触发规则”,比如“如果用了一个 skill 遇到没覆盖的问题,立刻 patch 它”,让 LLM 知道“什么时候该改 skill”;
  • 后置动作:改完后清空清单缓存,保证模型下一轮能看到更新。

3.3 工具协作逻辑

skills_list 让 LLM 知道“有哪些 skill 可用” → skill_view 让 LLM 读到“具体 skill 的内容” → skill_manage 让 LLM/用户能“修改 skill 内容”。前两个工具支撑“加载”,后一个支撑“进化”。
【我应该与skill有关的背景、操作执行者、执行内容写清楚,应该把复杂步骤用代码案例展示出来,应该把文章写得更通俗易懂】


四、问题发现与自进化——双回路 + 人工入口

hermes-agent 的 skill 自进化,核心是“两条自动回路 + 一条人工入口”:自动回路负责“持续零碎学、定期整理”,人工入口负责“主动系统化提炼”。下面讲清楚每个回路的“执行时机、修改内容、核心名词”。

4.1 回路①:background_review(即时学习,每轮触发)

核心定位:每轮对话结束后,自动“复盘学习”的后台线程
何时执行:每个对话轮结束后立刻触发

具体逻辑:run_agent.py:1493_spawn_background_review 函数会启动一个守护线程,fork 一个独立的 AIAgent 进程,重放本轮对话的快照(agent/background_review.py:839)——简单说,每和 Agent 聊一轮,这个复盘线程就跑一次。

执行主体:background_review 分身(独立的 AIAgent 进程)

这个分身和主对话完全隔离,权限极低,避免“学错东西影响主对话”。

核心目标:问自己“这一轮有什么值得固化成 skill 的东西?”

prompt 里明确要求:“大部分对话都至少能提炼出一个小改动,什么都不做是错过的学习机会”——也就是“尽量学,别空过”。

关注的“学习信号”(命中任一就动手)
  1. 用户纠正了表达方式(比如“别啰嗦,直接给步骤”)→ 改进对应 skill 的正文;
  2. 用户纠正了做法/步骤(比如“先查 API 再写代码,不是反过来”)→ 补充到 skill 的步骤里;
  3. 出现值得记的技巧/坑位(比如“这个命令要加 --force 参数”)→ 记到 skill 的 Pitfalls 章节;
  4. 本轮用的 skill 有问题(写错、漏步骤、过时)→ 立刻修改。
优先级(从上到下选,尽量不新建)
  1. 优先改“本轮用过的 skill”(比如本轮用了 arxiv skill,就改它);
  2. 没有就改“同类现成 skill”(比如改 research 分类下的其他 skill);
  3. 再没有就“给现成 skill 加配套文件”(比如把技巧写到 references/notes.md);
  4. 实在没有才“新建 skill”(名字必须是“类级别”,比如 research-paper-search,不能是“修-PR-123”这种临时名字)。
改什么:只做“小修小补”,不做不可逆操作
  • 允许改:patch 正文、加配套文件、标记问题;
  • 禁止改:删除 skill、合并 skill、重写整篇 skill。
安全约束(避免闯祸)
  1. 与主对话隔离:改动直接写磁盘,不碰主对话的上下文/缓存;
  2. 工具白名单:只开放 memory + skill_manage(且仅允许小改),不能跑终端、发请求、改文件;
  3. 只改 Agent 自建的 skill:bundled(内置)、hub-installed(远程安装)的 skill 是“受保护的”,碰都不碰;
  4. 权限比前台低:比如 pinned(锁定)的 skill,前台能改内容,background_review 连改都不能改(后文第五节讲 pinned)。
一句话总结

background_review 是“每轮对话结束后,跑一个权限极低的后台学徒,从本轮对话里学小技巧,补到对应的 skill 里”。
【我应该与skill有关的背景、操作执行者、执行内容写清楚,应该把复杂步骤用代码案例展示出来,应该把文章写得更通俗易懂】

4.2 回路②:curator(周期整理,7 天一次)

核心定位:定期“整理 skill 库”的“图书管理员”,解决“skill 碎片化”问题
先解释核心名词
  • cron:Linux/UNIX 系统的定时任务工具,这里是“定时执行”的泛指(但 hermes-agent 不用 cron,靠空闲触发);
  • pin/pinned:“锁定”,给 skill 加“锁定标记”后,curator 不会删除/归档/合并这个 skill(但允许改内容);
  • protected:“受保护的”,指 bundled(内置)、hub-installed(远程安装)的 skill,curator 只读不写;
  • umbrella skill:“伞状 skill”,指“大类 skill”(比如 research),能容纳多个小技巧/小节,是 curator 整理的核心目标。
何时执行:满足两个条件才触发
  1. Agent 处于空闲状态(至少 2 小时没交互);
  2. 距离上次 curator 运行超过 7 天(DEFAULT_INTERVAL_HOURS=24*7,见 curator.py)。

触发函数:maybe_run_curatorcurator.py:1958),由 cli.py:12691 调用——不是靠 cron 定时,而是“Agent 闲了且到时间了”才跑。

执行主体:fork 出来的辅助模型进程

和 background_review 一样,curator 跑在独立进程里,不影响主对话,且权限更低。

核心目标:合并碎片化 skill,整理成“伞状 skill”

prompt 里明确要求:扫描 skill 库,找“前缀簇”(比如 pr-*security-*),判断“人类会写成 N 个独立 skill,还是 1 个带 N 小节的大 skill”——优先合并成大 skill。

具体做法(四种手法)
  1. 并进现成 umbrella:簇里有大类 skill,就把小 skill 的内容 patch 进去,然后归档小 skill;
  2. 新建 umbrella:簇里没大类 skill,就新建一个类级 skill,吸收所有小 skill,然后归档小 skill;
  3. 降级成配套文件:小 skill 有价值但没必要独立,就把内容挪到 umbrella 的 references//templates/ 里,归档原 skill;
  4. 保留:仅当 skill 已是类级 umbrella,且合并不改善使用体验时才保留。
额外动作:自动状态流转(生命周期管理)

curator 会执行 apply_automatic_transitionscurator.py:307),按“最后活动时间”给 skill 打状态,且状态机是“确定性逻辑”(默认开启):

90天以上没动 → ARCHIVED(归档,目录挪进 .archive/)
30~90天没动 → STALE(陈旧,只改状态标记,内容不动)
30天内动过 → ACTIVE(活跃,正常使用)

状态规则:

  • STALE → ACTIVE:只要 STALE 的 skill 被再用一次,自动变回 ACTIVE,倒计时重置;
  • 新建不到 30 天的 STALE skill(use=0):也拉回 ACTIVE(“还没等到使用场景”);
  • ARCHIVED 恢复:需手动执行 hermes curator restore <skill名>,不能自动恢复。
改什么:只做“合并、归档、标记状态”,不删内容
  • 允许做:合并小 skill 到 umbrella、归档 skill(挪目录)、改状态标记;
  • 禁止做:删除 skill(永不删除,只归档)、改 protected skill 的内容。
安全约束
  1. 只改 Agent 自建的 skill:protected skill 只读;
  2. 永不删除:归档可恢复,避免误删;
  3. pinned skill 跳过:锁定的 skill 不参与归档/合并;
  4. 支持 dry-run:执行 hermes curator --dry-run 可预览修改,不动实际文件。
一句话总结

curator 是“7 天跑一次的图书管理员,把碎片化的小 skill 合并成大类 skill,长期不用的 skill 归档,且永不删除内容”。
【我应该与skill有关的背景、操作执行者、执行内容写清楚,应该把复杂步骤用代码案例展示出来,应该把文章写得更通俗易懂】

4.3 自进化的核心入口:skill_manage

background_review 和 curator 的所有修改,最终都通过 skill_manage 工具落盘(tools/skill_manager_tool.py:1200),它支持六个核心动作:create / patch / edit / delete / write_file / remove_file

关键设计:工具描述自带“自进化规则”

工具的 description 里直接写:

“Create when: complex task succeeded (5+ calls), errors overcome, user-corrected approach worked… Update when: instructions stale/wrong, OS-specific failures, missing steps… If you used a skill and hit issues not covered by it, patch it immediately.”

翻译过来就是:“复杂任务成功了就创建 skill;指令过时/错了就更新;用 skill 遇到没覆盖的问题就立刻 patch”——把“什么时候该改 skill”直接教给 LLM。

改后记账(支撑生命周期管理)

每次成功修改,会记三笔账:

  1. bump_patch(name):修改计数 +1(patch/edit/write_file/remove_file 触发);
  2. forget(name):硬 delete 时销账(但归档只改状态,不销账);
  3. mark_agent_created:background_review 创建的 skill 打标记(用户建的不打,但仍算“Agent 自建”)。

加上 skill_viewuse_count(使用次数),每个 skill 有完整的“生命数据”:谁创建的、用了多少次、改了多少次、最后一次动是什么时候——这是 curator 决策的核心依据。

4.4 人工入口:/learn(人主导,单次提炼)

核心定位:用户主动触发,把“整块知识”做成规范的 skill
与自动回路的区别
  • 自动回路:系统自动触发,碎片化学习、整理;
  • /learn:用户主动按下,系统化提炼、规范创作。
核心逻辑:/learn 本身不干活,只是“给 Agent 派活”

/learn 没有独立的提炼引擎,只是调用 build_learn_promptlearn_prompt.py:99)拼一段严格的提示词,让 Agent 用已有工具(read_file/search_files)抓素材,再用 skill_manage(create) 写 skill。

比如:

  • 输入 /learn https://docs.python.org/3/library/os.html:Agent 会先调用 web_extract 抓取文档内容,再按规范写一个 python-os-module skill;
  • 输入 /learn(空参):Agent 会提炼本轮对话的步骤,做成 skill。
核心价值:强制套用“严格的写作规范”

/learn 的提示词里包含 _AUTHORING_STANDARDSlearn_prompt.py:30),强制 skill 满足:

  1. description 必须 60 字符(因为系统提示清单只截 60 字,多了白写);
  2. 正文固定 8 段:标题+简介 → When to Use → Prerequisites → How to Run → Quick Reference → Procedure → Pitfalls → Verification;
  3. 必须用 Hermes 工具名(比如写 read_file 不写 cat);
  4. author 填 Hermes(避免泄露主机用户名);
  5. 不准编造(命令/URL 必须和源材料一致)。
一句话总结

/learn 是“用户点一下,Agent 按严格规范把知识做成 skill”——自动回路负责“零碎学”,/learn 负责“系统建”。

4.5 问题发现的三个源头

发现时机 发现主体 发现内容 反馈速度
使用当场 LLM 自身 这个 skill 没覆盖当前场景 → 立刻 patch 即时
每轮结束 background_review 分身 本轮对话有值得学的技巧 → 补到 skill 里 每轮一次
定期全局 curator skill 库碎片化/长期不用 → 合并/归档 7 天一次
【我应该与skill有关的背景、操作执行者、执行内容写清楚,应该把复杂步骤用代码案例展示出来,应该把文章写得更通俗易懂】

五、一个 skill 的完整修改生命史(全景)

一个 skill 从创建到归档/删除,所有操作都收敛到 skill_manage 工具,核心区分维度是“谁在改(前台/后台)”和“改的粒度(小修/重写/归档)”。下面按“出生 → 打磨 → 收纳 → 合并 → 锁定/保护 → 删除/恢复”六站,讲清楚“为什么做、何时做、谁来做、怎么做、过哪些校验”。

第一站:出生 —— create(创建 skill)

为什么做:需要把“有用的知识/步骤”固化成 skill,方便后续复用
何时做:
  1. 用户主动:前台让模型创建(比如“帮我建一个查天气的 skill”),或用 /learn 提炼知识;
  2. 后台自动:background_review 复盘时,发现没有现成 skill 能承接本轮学到的内容;
  3. 周期整理:curator 合并时,发现某簇 skill 没有“伞状大类”,需要新建。
谁来做:
  • 前台执行者:用户 + 主对话的 LLM;
  • 后台执行者:background_review 分身 / curator 进程。
怎么做(核心流程 + 校验):

_create_skill 函数(skill_manager_tool.py:703)是创建的核心,流程如下:

  1. 参数校验
    • 名字:小写连字符、≤64 字符;
    • 类目:必须是合法类目(比如 research、software-development);
    • frontmatter:必须是合法 YAML;
    • 内容:大小不超上限;
      → 任一不通过,直接返回错误,不创建。
  2. 唯一性查重:遍历所有 skill 目录(本地 + external),检查名字是否重复 → 重名拒绝。
  3. 原子创建
    • 先创建 skill 目录(比如 ~/.hermes/skills/weather);
    • _atomic_write_textSKILL.md(先写临时文件,再 rename 成正式文件)→ 避免进程崩溃/断电导致文件残缺。
  4. 安全扫描:扫描新写的内容是否有恶意模式 → 命中则删除整个目录,回滚创建。
  5. 打标记:只有 background_review 发起的创建,才执行 mark_agent_created 打标(用户创建的不打,但仍算“Agent 自建”)。
  6. 清缓存:调用 clear_skills_system_prompt_cache,让下一轮对话能看到新 skill。
最终状态:新建的 skill 状态为 ACTIVE(活跃),30 天陈旧倒计时启动。

第二站:在用中打磨 —— patch / write_file / remove_file / edit(修改 skill)

为什么做:skill 内容有遗漏、错误,或需要补充配套文件(比如脚本、参考资料)
何时做:
  1. 前台:用户让模型改(比如“给天气 skill 加一个查未来 7 天的步骤”),或 LLM 用 skill 时发现问题,当场 patch;
  2. 后台:background_review 复盘时,发现 skill 有可优化的地方。
谁来做:
  • 前台执行者:用户 + 主对话的 LLM;
  • 后台执行者:background_review 分身(权限受限)。
核心操作详解:
操作 1:patch(局部小改,最常用)
  • 作用:找到 skill 里的某段文字,替换成新内容(比如把“查今天天气”改成“查今天/明天天气”);
  • 关键细节:
    1. 模糊匹配:调用 fuzzy_find_and_replaceskill_manager_tool.py:865),容忍空白、缩进、转义字符差异 → 避免“差一个空格就改失败”;
    2. 匹配失败兜底:返回文件前 500 字预览 + 自纠提示 → 让模型看到实际内容后重试;
    3. 结构校验:改完后检查 frontmatter 是否完整(比如没少 ---)→ 破坏结构则拒绝;
    4. 支持配套文件:带 file_path 参数可改 references/ 等目录下的文件(无需校验 frontmatter)。
操作 2:write_file(加配套文件)
  • 作用:往 skill 的 references//templates//scripts//assets/ 目录写新文件(比如给天气 skill 加 scripts/query_weather.sh);
  • 注意:改完后通常要 patch SKILL.md,加一行指向新文件(比如“参考脚本:scripts/query_weather.sh”),否则模型不知道有这个文件。
操作 3:remove_file(删配套文件)
  • 作用:删除配套文件,常和 write_file 配合(比如替换旧脚本)。
操作 4:edit(整篇重写)
  • 作用:用完整的新 SKILL.md 替换旧的 → 仅用于结构性大改(比如重排所有章节);
  • 注意:小修优先用 patch,edit 容易引入回归(比如漏写旧步骤)。
所有修改的“安全网”:
  1. 写前备份:把原文存到内存(original_content);
  2. 原子写入:新内容写临时文件,再 rename;
  3. 安全扫描:命中恶意内容则用备份回滚;
  4. 后置动作:清缓存 + bump_patch(修改计数 +1)。
关键守卫:前台 vs 后台的权限差

先解释“前台/后台”:

  • 前台:用户直接和 Agent 交互的会话(主会话),有用户在场授权;
  • 后台:background_review/curator 启动的独立进程,无人值守。

权限差异核心规则(_background_review_write_guardskill_manager_tool.py:238):

操作 前台权限 后台(background_review)权限
修改 pinned skill 允许(只挡删除,不挡编辑) 禁止(连 patch/edit 都不行)
修改 external_dirs 里的 skill 允许 禁止(外部目录,只读)
修改 protected skill(内置/远程安装) 允许(用户授权) 禁止(只读)
修改 Agent 自建的非 pinned skill 允许 允许
用户自建 skill 的修改规则:

用户手动创建的本地 skill,属于“Agent 自建 skill”:

  • 前台:可随意改(patch/edit/delete 都可以);
  • 后台:background_review 可改(非 pinned 情况下);
  • curator:可合并/归档(非 pinned 情况下)。
    【我应该与skill有关的背景、操作执行者、执行内容写清楚,应该把复杂步骤用代码案例展示出来,应该把文章写得更通俗易懂】

第三站:长期不用收纳 —— 状态流转 + 归档

为什么做:skill 长期不用,会占用清单空间,需要“收纳”(归档),但不删除内容
何时做:curator 运行时(7 天一次,Agent 空闲时),执行 apply_automatic_transitions 函数
谁来做:curator 进程(独立辅助模型)
怎么做:
  1. 判断最后活动时间
    • 90 天以上没动 → 标记为 ARCHIVED,目录挪进 .archive/(比如 ~/.hermes/skills/.archive/weather);
    • 30~90 天没动 → 标记为 STALE(仅改状态,不挪目录);
    • 30 天内动过 → 保持 ACTIVE。
  2. 特殊规则
    • STALE skill 被再用一次 → 自动变回 ACTIVE,倒计时重置;
    • 新建不到 30 天的 STALE skill(use=0)→ 拉回 ACTIVE。
  3. 校验
    • pinned skill:跳过归档/状态修改;
    • protected skill:只读,不修改状态/目录。
注意:归档只改“状态 + 目录位置”,不改 SKILL.md 内容,可恢复。

第四站:碎片化合并 —— curator 合并

为什么做:多个小 skill 内容重叠,合并成“伞状大类 skill”,提升复用效率
何时做:curator 运行时(7 天一次),扫描到“前缀簇”skill(比如 pr-checkpr-mergepr-review
谁来做:curator 进程
怎么做:
  1. 判断合并方式
    • 有现成 umbrella → 把小 skill 内容 patch 进 umbrella,然后归档小 skill;
    • 无现成 umbrella → 新建 umbrella skill,吸收小 skill,归档小 skill。
  2. 校验
    • pinned/protected skill:不参与合并;
    • 合并后写账本:记录 consolidations: from→into(比如 pr-check → pr-management),供后续追溯。

第五站:锁定/保护 —— pinned / protected / cron

先解释核心名词:
  • pinned(锁定):用户手动给 skill 加“锁定标记”(比如 hermes curator pin weather);
  • protected(保护):系统给“内置(bundled)、远程安装(hub-installed)”的 skill 加的标记;
  • cron:这里指“skill 配置里的 cron: yes”,表示这个 skill 用于定时任务,不能归档。
为什么做:
  • pinned:防止重要 skill 被 curator 归档/合并(比如核心业务 skill);
  • protected:防止系统级 skill 被误改/删除;
  • cron:防止定时任务用的 skill 被归档,导致定时任务失效。
何时做:
  • pinned:用户手动执行 hermes curator pin <skill名> 时;
  • protected:skill 被安装/内置时,系统自动标记;
  • cron:用户创建 skill 时,在 frontmatter 加 cron: yes
谁来做:
  • pinned:用户;
  • protected:系统(安装/内置时);
  • cron:用户(创建 skill 时配置)。
核心规则:
标记 能否改内容 能否删除 能否归档/合并
pinned 能(前台/后台都能 patch/edit) 不能 不能
protected 前台能改(用户授权),后台不能改 前台能删(用户授权),后台不能删 不能
cron: yes 不能(不会被归档)
【我应该与skill有关的背景、操作执行者、执行内容写清楚,应该把复杂步骤用代码案例展示出来,应该把文章写得更通俗易懂】

第六站:删除/恢复 —— delete / restore

子站 6.1:delete(删除)
为什么做:skill 完全没用,需要彻底移除
何时做:用户前台主动发起(比如“删除 weather skill”)
谁来做:用户 + 主对话的 LLM
怎么做 + 校验:
  1. 权限校验
    • pinned skill:拒绝删除;
    • protected skill:前台可删(用户授权),后台(background_review/curator)拒绝删;
  2. 执行删除
    • 调用 _delete_skillskill_manager_tool.py:950),删除 skill 目录及所有文件;
    • 执行 forget(name),销除该 skill 的所有遥测记录(use_count、patch_count 等);
  3. 清缓存:调用 clear_skills_system_prompt_cache,更新清单。

注意:curator 不会执行 delete,只会归档(ARCHIVED),delete 只能由用户前台发起。

子站 6.2:restore(恢复)
为什么做:误删/误归档的 skill,需要恢复使用
何时做:用户发现 skill 被删/归档后,手动发起
谁来做:用户
怎么做:
  1. 恢复归档的 skill:执行 hermes curator restore <skill名> → 把 .archive/ 里的目录挪回原位置,状态改回 ACTIVE;
  2. 恢复删除的 skill:无直接恢复功能(需重新创建,或从备份恢复)。

六站总结

一个 skill 的生命周期,核心是“创建后持续打磨,长期不用归档,碎片化则合并,重要的锁定/保护,没用的手动删除”:

  • 自动操作(background_review/curator):只做可逆的小修、归档、合并;
  • 手动操作(用户/前台):负责不可逆的删除、锁定、重写;
  • 所有操作都过“权限/结构校验”,避免误改/误删,且改后清缓存,保证模型能看到最新状态。
    【我应该与skill有关的背景、操作执行者、执行内容写清楚,应该把复杂步骤用代码案例展示出来,应该把文章写得更通俗易懂】

六、常见疑问解答

1. skill 太多会爆模型上下文吗?

不会。常驻模式的压缩清单把每个 skill 压到一行,token 消耗极低;只有按需/预加载模式会加载完整正文,且只加载“需要用的”,不会全量加载。

2. 编码模式下非编码 skill 会被隐藏吗?

不会。非编码类 skill 只会被降级为“仅名字”(比如 research: arxiv),名字一定保留——因为名字消失后,模型就不会再想起这个 skill 了。

3. 用户自建的 skill 会被后台自动修改吗?

非 pinned 的用户自建 skill,background_review 可小修,curator 可合并/归档;pinned 的用户自建 skill,后台只能改内容,不能归档/合并/删除。

4. curator 靠什么触发?

不靠 cron 定时,靠“Agent 空闲(≥2 小时) + 距上次运行≥7 天”触发,避免占用业务资源。

5. /learn 和 background_review 有什么区别?

  • /learn:用户主动触发,按严格规范提炼“整块知识”,创建/修改 skill;
  • background_review:每轮自动触发,碎片化学习“本轮对话的小技巧”,只做小修。

七、借鉴价值

  1. 渐进式加载:先给“目录”再给“详情”,平衡 token 消耗和使用体验,值得大模型工具加载借鉴;
  2. 可逆自动回路:自动操作只做小修、归档,不可逆操作留手动入口,避免自动进化“闯祸”;
  3. 状态化生命周期:ACTIVE/STALE/ARCHIVED 三态管理,既收纳闲置 skill,又不丢失内容;
  4. 权限分层:前台/后台权限差异,无人值守的后台进程权限最小化,提升安全性;
  5. 规范驱动创作:/learn 的严格写作规范,保证 skill 质量和一致性,避免碎片化。
Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐