Skip to content

技能系统 Skills

源码版本v2026.7.20

职责

Skill 是比 Tool 更高阶的能力单元:一段可复用的、带 frontmatter 的流程(类似 agentskills.io 规范),按领域归类在 skills/<category>/ 下。与工具的「静态函数」不同,技能可被学习闭环创建、改写、精炼,是 agent「越用越聪明」的载体。技能通过 skills_tool 暴露给主循环调用。

设计动机

为什么 skill 要按 category 分目录而不是平铺?技能数量会随使用增长(用户加的、hub 同步的、学习循环生成的都在 ~/.hermes/skills/),平铺后 skills_list 返回的列表很快变成噪音。category 让 progressive disclosure 第一层只暴露「这有一组 research 技能」而不是 50 条具体技能名。每个 SKILL.md 是单文件即定义(带 frontmatter),配合 skills/<category>/<skill>/references/ 的子文件做按需加载,token 不会一次性爆。

bundle 是另一层封装:把多个技能用一个 slash 命令加载,因为「后端开发」这种场景要同时挂上 code review、TDD、PR 三个技能,逐个 /skill 太碎。

关键文件

  • skills/ 目录 — 按领域分组(apple、computer-use、research、software-development、yuanbao…),每个技能长这样:
skills/
├── my-skill/
│   ├── SKILL.md           # 主指令(必需)
│   ├── references/        # 支撑文档
│   │   ├── api.md
│   │   └── examples.md
│   ├── templates/         # 输出模板
│   └── assets/            # 附件(agentskills.io 标准)
└── category/
    └── another-skill/
        └── SKILL.md

SKILL.md 顶部是 YAML frontmatter(name/description/version/platforms/prerequisites…),下面是正文指令。name 限 64 字符、description 限 1024,这两个字段是 progressive disclosure 第一层 skills_list 唯一返回的内容,保 token。

  • skills_tool — 把技能作为工具暴露给主循环。它注册了两个工具:
python
registry.register(
    name="skills_list",
    toolset="skills",
    schema=SKILLS_LIST_SCHEMA,
    handler=lambda args, **kw: skills_list(
        category=args.get("category"), task_id=kw.get("task_id")
    ),
    check_fn=check_skills_requirements,
    emoji="📚",
)

registry.register(
    name="skill_view",
    toolset="skills",
    schema=SKILL_VIEW_SCHEMA,
    handler=_skill_view_with_bump,
    check_fn=check_skills_requirements,
    emoji="📚",
)

skills_list 只返回 name + description + category(第一层 progressive disclosure);skill_view 加载完整 SKILL.md(第二层);reference/template 等支撑文件按需 skill_view(name, file_path="references/api.md") 拉(第三层)。_skill_view_with_bump 在成功后调 bump_view / bump_use 更新使用计数,curator 的 stale 计时器据此清理没人用的技能。

  • skill_manager_tool — 技能管理(列表/查看/启用)
  • skills_hub — 技能中心同步(agentskills.io 兼容)
  • skills_sync — 本地与远端技能同步
  • skill_bundles — 技能束打包,注入到提示。bundle 是 ~/.hermes/skill-bundles/*.yaml 里的小文件:
yaml
name: backend-dev
description: Backend feature work — code review, testing, PR workflow.
skills:
  - github-code-review
  - test-driven-development
  - github-pr-workflow
instruction: |
  Optional extra guidance to inject above the skill bodies.

/<bundle-name> 调用 build_bundle_invocation_message 把所有成员技能的 SKILL.md 拼进一条 user message。bundle 与 skill 同名时 bundle 优先——用户显式起了同名就是想覆盖那条碰巧撞名的技能。缺失的成员技能不报错,只在结果里附「哪些被跳过」的提示。

  • skill_preprocessing — 技能内容预处理。负责替换 ${HERMES_SKILL_DIR} / ${HERMES_SESSION_ID} 模板变量,以及执行 !date +%Y-%m-%d`` 这种内联 shell snippet。内联 shell 失败返回 [inline-shell error: ...] 标记而不是抛异常,一个坏 snippet 不会拖垮整条技能消息。
  • 技能节点与边:125-193build_skill_nodes / build_edges,把技能组织成学习图

数据流

  1. 启动期 skill_preprocessing(agent/skill_preprocessing.py)扫描 skills/<category>/,读 frontmatter。
  2. skill_bundles(agent/skill_bundles.py)把相关技能打包,经 build_turn_context:268 注入本轮提示。
  3. provider 决定调用某技能 → tool_call skillstools/skills_tool.py 加载并执行该技能的流程。
  4. 执行结果回填主循环。
  5. 学习闭环在后台审视本轮,可能:

边界与失败

  • 路径穿越:skill name 会被拼接到 ~/.hermes/skills/ 上找文件,_skill_lookup_path_error 拒绝 .. 段、绝对路径、Windows 盘符。否则 name="../outside" 能读到 skills 目录之外的文件。
  • prompt 注入:SKILL.md 内容里有「ignore previous instructions」「system prompt:」「]]>」等模式会被 _INJECTION_PATTERNS 标记。第三方技能(从 hub 同步的)是不可信内容,主循环加载时要 sanitize。
  • bundle 缺成员:build_bundle_invocation_message 对缺失/禁用的成员技能只记到 missing / disabled 列表里,不报错——bundle 是宽容加载,少几个不影响其余技能。
  • 缓存陈旧:扫描 skills/ 是 O(#dirs) stat,签名包含目录 mtime + disabled 集合 + 平台。但单文件 SKILL.md 的就地编辑只 bump 自身 mtime,目录签名看不到,所以额外加了 30s TTL 兜底。

小结

技能 = 可演化的高阶流程,frontmatter 描述、文件即定义、学习闭环可改写。它与工具的关系:工具是技能流程里调用的原子,技能是「怎么组合工具完成一类任务」的知识。技能的演化机制见学习闭环

非官方社区学习站,内容以 MIT 许可的 NousResearch/hermes-agent 源码为依据。