深入理解Hermes Agent Skill机制的核心原理与实现方法详解
时间:2026-07-17 | 作者:实验室老王 | 阅读:0Hermes Agent 的 Skill 机制,到底是怎么一回事?
Hermes Agent 的 Skill 系统本质上是一套完整的知识注入机制。它不是简单的文件读取,而是经历了一个从“找到它”到“用上它”的完整流程。具体来说,这个流程包含五个阶段:发现索引、触发加载、预处理、Prompt注入,最后才是LLM响应。核心的载体是 SKILL.md 文件,通过YAML frontmatter声明元数据,支持条件激活、平台过滤、安全检测等一系列特性。
1. Skill 目录结构
先来看看它的目录组织方式,其实挺直观的:
~/.hermes/skills/ ├── category-a/ │ └── skill-name/ │ ├── SKILL.md # 必需:主文件 │ ├── references/ # 可选:参考资料 │ ├── templates/ # 可选:模板文件 │ ├── scripts/ # 可选:脚本文件 │ └── assets/ # 可选:资源文件 ├── category-b/ │ └── another-skill/ │ └── SKILL.md └── ...
几个关键点值得注意:
- 支持任意深度的子目录嵌套,系统通过
os.walk递归扫描,所以分类层级方面完全不用太担心。 - 子目录只用于分类组织,不影响索引结果。
- 有四个目录会被自动排除:
.git、.github、.hub、.archive。
2. 完整生命周期(5阶段)
Phase 1: 发现与索引(启动时)
当Agent启动时,它会按以下路径扫描所有Skill:
get_all_skills_dirs()
├── ~/.hermes/skills/ # 本地目录(始终在前)
└── skills.external_dirs # 外部目录(config.yaml配置)
↓
iter_skill_index_files() # 递归扫描所有 SKILL.md
↓
parse_frontmatter() # 解析 YAML 元数据
↓
过滤规则:
├── skill_matches_platform() # 平台兼容性检查
├── get_disabled_skill_names() # 禁用列表过滤
└── _skill_should_show() # 条件激活规则
↓
build_skills_system_prompt() # 生成分类索引 Prompt
这里有意思的是,它采用了两级缓存机制来提升效率。说白了,就是尽量减少重复扫描磁盘的负担:
- L1:进程内 LRU 缓存,容量8 entries,Key为
(skills_dir, external_dirs, tools, toolsets, platform, disabled)。 - L2:磁盘快照,持久化,Key为
.skills_prompt_snapshot.json(mtime/size验证)。
生成的System Prompt格式如下:
## Skills (mandatory) Before replying, scan the skills below. If a skill matches or is even partially relevant to your task, you MUST load it with skill_view(name) and follow its instructions. category-a: - skill-name: brief description - another-skill: another description Only proceed without loading a skill if genuinely none are relevant to the task.
Phase 2: 触发(3种方式)
这是整个机制中最关键的一环——Skill到底是怎么被激活的?有三种途径:
方式 A: LLM 自主调用(主要路径)
这是最核心的触发方式,也是设计上期望的主要路径:
System Prompt 引导:
"Before replying, scan the skills below... MUST load with skill_view(name)"
↓
LLM 判断任务与 skill 相关
↓
tool_call: skill_view(name="skill-name")
触发条件其实挺宽松的:
- Skill 名称或描述与用户请求匹配。
- Skill 的
description字段包含关键词。 - LLM 自主判断“部分相关”就应加载——这意味着描述写得好的Skill更容易被命中。
方式 B: Slash 命令(用户显式调用)
当用户想直接指定某个Skill时,可以这样操作:
用户输入: /skill-name some instruction
↓
scan_skill_commands() # 扫描所有 SKILL.md 生成命令映射
↓
匹配 /skill-name
↓
build_skill_invocation_message() # 构建触发消息
Skill 命令命名规则:名称会经过规范化处理——小写,空格/下划线转连字符,去除非法字符。例如 My Skill 就变成了 /my-skill。
方式 C: CLI 预加载(Session 启动时)
还有一种方式是在启动时直接指定:
hermes --skills skill-name
build_preloaded_skills_prompt()
↓
注入到 session prompt 开头
Phase 3: 加载与预处理
当Skill被触发后,就该进入实质性的加载阶段了。skill_view() 的执行流程相当严谨:
skill_view(name)
├── 解析 qualified name # plugin:skill → 路由到 plugin 系统
├── 目录搜索(first match wins) # local → external
│ ├── 直接路径: search_dir/name/SKILL.md
│ ├── 分类路径: search_dir/category/name/SKILL.md
│ └── 名称匹配: 遍历所有 SKILL.md 比对目录名
├── 安全检查
│ ├── 路径穿越检测(防止 .. 攻击)
│ └── prompt injection 模式扫描
├── 平台/禁用检查
├── 前置条件检查
│ ├── 环境变量(prerequisites.env)
│ └── 凭证文件(prerequisites.credential_files)
├── preprocess_skill_content()
│ ├── 模板变量替换: ${HERMES_SKILL_DIR} → 绝对路径
│ └── inline shell 展开: !`cmd` → 执行结果
├── 收集 linked_files
│ ├── references/*.md
│ ├── templates/*.yaml
│ ├── scripts/*.py
│ └── assets/*
└── 返回 JSON:
{
"success": true,
"name": "skill-name",
"content": "",
"linked_files": {"references": [...], "templates": [...]},
"skill_dir": "/path/to/skill",
"setup_needed": false,
"readiness_status": "a vailable"
}
预处理机制有两个亮点值得关注:
模板变量替换:
${HERMES_SKILL_DIR} → skill 的绝对路径
${HERMES_SESSION_ID} → 当前会话 ID
Inline Shell 展开(需配置启用):
!`ls -la ${HERMES_SKILL_DIR}/scripts/`
→ 替换为命令执行结果
Phase 4: Prompt 注入
加载完成后,Skill内容需要以合适的方式注入到对话上下文中。根据触发方式不同,注入方式也有所区别:
方式 A: LLM tool call 返回
tool 返回 JSON
↓
作为 tool_result 注入 conversation history
↓
LLM 在下一轮看到完整 skill 内容
方式 B: Slash 命令消息构建
_build_skill_message() ├── [IMPORTANT: The user has invoked the "xxx" skill...] ├──├── [Skill directory: /path/to/skill] ├── [Skill config: key = value] # 配置变量注入 ├── [Skill setup note: ...] # 安装提示 ├── [This skill has supporting files:] # 支持文件列表 │ ├── references/api.md → /path/to/references/api.md │ └── scripts/run.py → /path/to/scripts/run.py └── The user has provided the following instruction: ... ↓ 作为 user message 注入 → LLM 响应
方式 C: CLI 预加载
[IMPORTANT: The user launched this CLI session with "xxx" ...]↓ 追加到 system prompt 的 prompt_parts
Phase 5: LLM 响应与执行
最后,LLM开始基于Skill内容进行响应:
LLM 接收包含 skill 内容的 message ├── 遵循 skill 中的 instructions ├── 可通过 skill_view(name, file_path) 加载 supporting files ├── 执行 skill 中的 scripts(通过 skill_dir 绝对路径) ├── 使用 skill 声明的配置变量 └── 任务完成后可选:skill_manage(action='patch') 更新 skill
3. Skill 元数据(YAML Frontmatter)
每个 SKILL.md 文件的开头,都会有一段YAML frontmatter来声明元数据。这里面的字段配置直接决定了Skill的行为:
---
name: skill-name
description: "简短描述(≤1024字符)"
version: 1.0.0
author: Author Name
license: MIT
platforms: [macos, linux] # 可选:平台限制
metadata:
hermes:
tags: [tag1, tag2]
related_skills: [skill-a, skill-b]
fallback_for_toolsets: [web] # 当 web toolset 可用时隐藏
fallback_for_tools: [web_fetch] # 当 web_fetch tool 可用时隐藏
requires_toolsets: [browser] # 当 browser toolset 不可用时隐藏
requires_tools: [browser_click] # 当 browser_click tool 不可用时隐藏
config: # 配置变量声明
- key: api_endpoint
description: API endpoint URL
default: "https://api.example.com"
prompt: Enter API endpoint
prerequisites:
env:
- name: API_KEY
description: API key for authentication
credential_files:
- path: ~/.config/skill/credentials.json
description: Credentials file
---
4. 条件激活规则
这个机制是Skill灵活性的核心所在。通过几个字段,可以精确控制Skill在什么条件下出现,什么条件下隐藏:
- fallback_for_toolsets:当指定 toolset 可用时隐藏此 skill。例如有 web toolset 时不需要 web-fallback skill。
- fallback_for_tools:当指定 tool 可用时隐藏此 skill。例如有 web_fetch tool 时不需要备用方案。
- requires_toolsets:当指定 toolset 不可用时隐藏。例如没有 browser toolset 时浏览器 skill 不可用。
- requires_tools:当指定 tool 不可用时隐藏。例如没有 git tool 时 git 相关 skill 不可用。
5. 安全机制
安全这根弦得时刻绷紧,尤其是在处理外部注入的内容时。
Prompt Injection 检测
系统会扫描以下常见攻击模式:
ignore previous instructionsdisregard your instructionsyou are nowsystem prompt:
处理方式上,系统区分了两种场景:
- Context 文件注入:拒绝加载并警告。
- Skill 内容注入:记录警告但仍加载(因为Skill被视为可信来源)。
路径安全
- 防止路径穿越攻击(
..)。 - 验证解析路径仍在 skill 目录内。
- 禁止访问 skill 目录外的文件。
6. 关键文件职责
整个Skill机制的实现分散在多个文件中,各司其职:
- hermes_constants.py:
get_skills_dir()→~/.hermes/skills/路径解析。 - agent/skill_utils.py:核心工具:frontmatter 解析、平台匹配、禁用列表、外部目录、条件提取、文件迭代。
- agent/prompt_builder.py:
build_skills_system_prompt()生成分类索引,两级缓存,_skill_should_show()条件过滤。 - agent/skill_commands.py:Slash 命令扫描、消息构建、CLI 预加载。
- agent/skill_preprocessing.py:模板变量替换、inline shell 展开。
- tools/skills_tool.py:Tool 注册(skills_list, skill_view)、skill 加载、安全检查、linked_files 发现。
- model_tools.py:Tool 注册触发、toolset 过滤。
- tools/registry.py:Tool 注册机制,
registry.register()统一注册 schema + handler。 - run_agent.py:Agent 循环中调用
build_skills_system_prompt(),注入 system prompt。
7. 优化与最佳实践
Skill 设计原则
- 描述清晰:
description字段是LLM判断是否加载的主要依据,应包含关键词。 - 触发词明确:在 description 中列出典型触发场景。
- 条件激活合理使用:避免与内置 tool 冲突,使用
fallback_for_*声明备选关系。 - 支持文件组织:将参考资料、模板、脚本放在对应子目录中。
- 配置变量声明:需要用户配置的参数应在 frontmatter 中声明。
性能优化
- 两级缓存:避免重复扫描文件系统。
- 条件过滤前置:在索引阶段就过滤掉不兼容的 skill。
- 延迟加载:只加载与当前任务相关的 skill 内容。
说到底,这套Skill机制的设计思路很清晰:通过明确定义的生命周期和灵活的触发方式,让知识注入既有章可循,又不会显得死板。理解了这个流程,再去开发或优化自己的Skill,心里就有底了。
免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。
相关文章
更多-
- 阿里千问开放第三方Agent与Skill接入,瑞幸东航首批测试
- 时间:2026-08-21
-
- 将老员工经验沉淀为Agent可调用资产:Skill与MCP治理实践
- 时间:2026-08-21
-
- Microsoft Agent Framework 1.0发布:Agent开发迈入工程化时代
- 时间:2026-08-21
-
- 郑州GEO源码推荐指南:核心要点与靠谱选择技巧
- 时间:2026-08-18
-
- OpenSkill智能体自进化新范式:孙立超团队刷新多项基准SOTA
- 时间:2026-08-18
-
- 小红书上线RED Skill功能:AI应用深度嵌入社区笔记场景
- 时间:2026-08-18
-
- AI简历优化工具怎么选:校招社招ATS兼容与数据安全指南
- 时间:2026-08-17
-
- AI简历工具推荐:国内与海外及ATS和全流程能力区别
- 时间:2026-08-17
精选合集
更多大家都在玩
大家都在看
更多-
- 以下哪种食材被称为“地下苹果” 蚂蚁庄园今日答案9.18
- 时间:2026-09-17
-
- 蚂蚁庄园今天答题答案2026年9月18日
- 时间:2026-09-17
-
- 蚂蚁庄园答题今日答案2026年9月18日
- 时间:2026-09-17
-
- 蚂蚁庄园小课堂2026年9月18日最新题目答案
- 时间:2026-09-17
-
- 小鸡答题今天的答案是什么2026年9月18日
- 时间:2026-09-17
-
- 蚂蚁庄园每日答题答案2026年9月18日
- 时间:2026-09-17
-
- 蔬菜洗完掉色,说明是被染色了,是真的吗 蚂蚁庄园今日答案9月18日
- 时间:2026-09-17
-
- 满襟蜡绘花纹巧染就花纹当绣裳说的是哪种传统技艺 蚂蚁新村今日答案2026.9.17
- 时间:2026-09-17