从Hermes cli的源代码中学习skill

skill定义

结合anthropic,microsoft的前沿定义,可以将Skill总结如下:

Agent Skill 是一种可复用、可发现、可组合的能力单元,它将领域知识、执行流程(Workflow)、工具调用策略和资源封装在一起,使 Agent 能够在特定任务场景下稳定地复现专家级行为。

写成公式可以表示为

其中Skill正在成为Agent stack中独立于tool和memory的第4层抽象

其中的resource包含的类别很多,可以是独立的python脚本,专家知识,配置及依赖环境,比如第三方api或者mcp服务配置

Skill内部处理逻辑

从具体的Hermes agent的源码看skill部分的具体逻辑

Skill文件夹的结构

在Hermes的路径/.hermes/skills中可以找到hermes的skill包

常见skill文件夹中结构如下

html 复制代码
~/.hermes/skills/
└── <category>/
    └── <skill-name>/
        ├── SKILL.md          ← 必须,主文件
        ├── references/       ← 可选,按需加载的深度文档
        ├── templates/        ← 可选,模板文件(LaTeX、YAML 等)
        ├── scripts/          ← 可选,辅助脚本
        └── assets/           ← 可选,图片等资源

这个skill的文件夹设计和一般的文件夹设计不同,其中包含的reference文件夹是一般skill不具备的,框架会自动发现 references/templates/assets/scripts/ 四个目录,并在 skill_view() 返回值的 linked_files 字段中列出,供 LLM 按需调用。

Skill文件结构

以YAML Frontmatter作为文件开头的,作为描述skill的元数据,被两个---包围,作为LLM在系统提示词中看到的skill元描述内容,复合渐进式披露的原则

通常内容如下:

正文结构

顺序 章节 作用
1 # 标题 skill 名称
2 ## When to Use 触发条件,最关键
3 ## Overview / Key Concepts 核心概念速查
4 ## Steps / Workflow 具体操作步骤
5 ## Examples 可运行的代码示例
6 ## Common Pitfalls / Red Flags 反面教材
7 ## Checklist / Verification 收尾核查清单
8 ## References 指向 references/ 子文件

示例

以市场预测的Polymarket Skill为例子,他的文件夹结构如下

XML 复制代码
skill/
├── SKILL.md          ← 2.9KB:概念、典型流程、3个API、注意事项
├── references/
│   └── api-endpoints.md  ← API 细节(按需加载)
└── scripts/
    └── polymarket.py

Polymarket 是一个预测市场平台,用户可以用真实金钱对未来事件的结果下注,比如"特朗普会赢得2028年大选吗?"、"比特币年底会超过10万美元吗?"。市场价格本身就代表概率------某个结果的价格是 0.65,就意味着市场认为这件事发生的概率是 65%。

其中SKILL.md内容为背景知识和操作规范

api-endpoints.md保存实际api的请求使用方式,是对SKILL.md中的补充

scripts/polymarket.py是一个可以直接运行的命令行工具,零依赖,全程用 Python 标准库。LLM可以直接进行调用

python 复制代码
python3 polymarket.py search "bitcoin"      # 搜索比特币相关市场
python3 polymarket.py trending              # 看今天交易量最大的事件
python3 polymarket.py history 0xabc...     # 看某个市场的价格历史
python3 polymarket.py book TOKEN_ID        # 看 orderbook 深度

Hermes agent中代码逻辑

1.提取skill元数据

/.hermes/hermes-agent/agent/skill_utils.py

python 复制代码
# skill_utils.py L532-544
def iter_skill_index_files(skills_dir: Path, filename: str):
    """Walk skills_dir yielding sorted paths matching *filename*."""
    matches = []
    for root, dirs, files in os.walk(skills_dir, followlinks=True):
        # 剔除 .git / venv / node_modules / __pycache__ 等
        dirs[:] = [d for d in dirs if d not in EXCLUDED_SKILL_DIRS]
        if filename in files:
            matches.append(Path(root) / filename)
    # 按相对路径字典序排列,保证结果稳定
    for path in sorted(matches, key=lambda p: str(p.relative_to(skills_dir))):
        yield path

提取每个skill的元数据,并在60字符处截断

python 复制代码
# prompt_builder.py L990-1006
def _parse_skill_file(skill_file: Path) -> tuple[bool, dict, str]:
    raw = skill_file.read_text(encoding="utf-8")
    frontmatter, _ = parse_frontmatter(raw)    # ← 解析 YAML frontmatter

    if not skill_matches_platform(frontmatter):
        return False, frontmatter, ""          # ← 平台过滤(macos/linux/windows)

    return True, frontmatter, extract_skill_description(frontmatter)

# skill_utils.py L518-526
def extract_skill_description(frontmatter: Dict[str, Any]) -> str:
    raw_desc = frontmatter.get("description", "")
    desc = str(raw_desc).strip().strip("'\"")
    if len(desc) > 60:
        return desc[:57] + "..."   # ← 这就是系统提示词里看到的内容
    return desc

2.检查两级缓存

/.hermes/hermes-agent/agent/prompt_builder.py

第一层(进程内 LRU)

_SKILLS_PROMPT_CACHE: OrderedDict 最多 8 个 entry

cache_key = (skills_dir, external_dirs, tools, toolsets, platform, disabled_skills)

第二层(磁盘 snapshot)

~/.hermes/.skills_prompt_snapshot.json

含 manifest(每个 SKILL.md 的 mtime + size),用于校验缓存是否过期

校验snapshot逻辑,如果命中则直接复用,而非重新扫描skill

python 复制代码
# prompt_builder.py L919-934
def _load_skills_snapshot(skills_dir: Path) -> Optional[dict]:
    snapshot = json.loads(snapshot_path.read_text(encoding="utf-8"))

    # 版本号不匹配(代码升级后)→ 缓存失效
    if snapshot.get("version") != _SKILLS_SNAPSHOT_VERSION:
        return None

    # manifest 不匹配(有 SKILL.md 文件被修改)→ 缓存失效,重新扫描
    if snapshot.get("manifest") != _build_skills_manifest(skills_dir):
        return None

    return snapshot  # 命中:直接用预解析的 metadata,跳过全量扫描

snapshot内容

3.组装系统提示词

/.hermes/hermes-agent/agent/system_prompt.py

python 复制代码
# system_prompt.py L179-195
has_skills_tools = any(
    name in agent.valid_tool_names
    for name in ['skills_list', 'skill_view', 'skill_manage']
)
if has_skills_tools:
    skills_prompt = _r.build_skills_system_prompt(
        available_tools=agent.valid_tool_names,
        available_toolsets=avail_toolsets,
    )
if skills_prompt:
    stable_parts.append(skills_prompt)  # 加入系统提示词的 stable 层

stable层属于系统提示词的一部分,并且系统提示词不参与上下文压缩,以保持kv缓存的命中率,

系统提示词被分成三层:

stable = 身份 + 工具指引 + skills 索引 ← 本会话不变,prefix cache 保持有效

context = AGENTS.md 等项目上下文 ← 按 cwd 变化

volatile = 记忆 + 时间戳 ← 每次对话都可能变

skills 索引放在 stable 层,意味着一旦 LLM API 缓存了这个 prefix,后续每轮对话不用重新计算这些 token,显著降低成本和延迟。这也是为什么 description 只截断到 60 字符而不是完整加载所有 SKILL.md 内容------索引要尽量短,以便 prefix cache 命中率更高。

最终注入格式

python 复制代码
# prompt_builder.py L1235-1262
result = (
    "## Skills (mandatory)\n"
    "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. ...\n"
    "\n"
    "<available_skills>\n"
    "  research:\n"
    "    - polymarket: Query Polymarket: markets, prices, orderbooks...\n"
    "    - research-paper-writing: End-to-end academic paper writing ...\n"
    "  software-development:\n"
    "    - spike: Run a time-boxed experiment to validate a technolog...\n"
    "    ...\n"
    "</available_skills>\n"
    "\n"
    "Only proceed without loading a skill if genuinely none are relevant."
)

4.LLM决策调用

如果LLM在这个用户输入的语句中满足某个skill的触发条件,LLM返回一个tool_call

bash 复制代码
{
  "tool": "skill_view",
  "arguments": {
    "name": "polymarket"
  }
}

agent后端接受到tool_call指令,解析并执行工具

python 复制代码
# tool_executor.py L542 / L110
def execute_tool_calls_sequential(agent, assistant_message, messages, ...):
    for tool_call in assistant_message.tool_calls:
        function_name = tool_call.function.name    # = "skill_view"
        function_args = json.loads(tool_call.function.arguments)

        # 安全门:guardrail 检查、plugin block 检查
        guardrail_decision = agent._tool_guardrails.before_call(function_name, function_args)
        if not guardrail_decision.allows_execution:
            ...  # 拦截,不执行

        # 最终分发执行
        result = agent._invoke_tool(function_name, function_args, task_id, ...)
        messages.append(make_tool_result_message(function_name, result, tool_call.id))

skill_view通过注册表连接到真实的工具函数

python 复制代码
# skills_tool.py L1517-1524
registry.register(
    name="skill_view",
    toolset="skills",
    schema=SKILL_VIEW_SCHEMA,
    handler=_skill_view_with_bump,   # ← 真正执行的函数
    check_fn=check_skills_requirements,
    emoji="📚",
)

LLM收到返回示例

python 复制代码
{
  "success": true,
  "name": "polymarket",
  "content": "---\nname: polymarket\n...(SKILL.md 全文 2.9KB)...",
  "linked_files": {
    "references": ["references/api-endpoints.md"],
    "scripts": ["scripts/polymarket.py"]
  },
  "usage_hint": "To view linked files, call skill_view(name, file_path=...)"
}

5.阅读SKIll

LLM 读完 SKILL.md 后,如果需要实际查询数据,会调用 terminal 工具直接运行脚本:

python 复制代码
# LLM 的 tool_call:
{
    "tool": "terminal",
    "arguments": {
        "command": "python3 ~/.hermes/skills/research/polymarket/scripts/polymarket.py search 'bitcoin'"
    }
}

如果需要查看api细节

python 复制代码
# LLM 的 tool_call:
{
    "tool": "skill_view",
    "arguments": {
        "name": "polymarket",
        "file_path": "references/api-endpoints.md"   // ← file_path 参数
    }
}

LLM获取足够信息后则会按照SKILL内容做下一步操作。

相关推荐
沉下去,苦磨练!几秒前
张量的形状操作以及拼接
人工智能
小黄人软件4 分钟前
Claude和Codex下载离线包 安装遇到问题:windows无法访问指定设备 路径 文件 应用无法打开也无法卸载,解决了
人工智能·microsoft·openai·codex
落叶无情4 分钟前
分析:不上传文档给AI上下文窗口,仅让Ai上网搜索icef认知框架的详情,可以获得比较完整的信息,并可直接进行基本推理的具体机制
人工智能
王小王-1235 分钟前
基于Python的车联网数据聚合与可视化分析平台设计与实现
python·车联网·新能源汽车·车联网聚合分析
Hector_zh7 分钟前
逐浪 · 第十一篇: Vibe Coding 下的效率定义与规范建设
人工智能·vibecoding
147API13 分钟前
Claude进入受监管系统前,接入层应该先怎么设计
人工智能
Szime14 分钟前
深智微:面向汽车电子与工业控制的电子元器件原装现货服务商
人工智能·汽车
gis分享者15 分钟前
Claude Code 接入蓝耘 GLM-5.1:终端 AI 编程助手配置实战
人工智能·ai·实战·claude·cc·接入glm
企学宝19 分钟前
央国企数字化培训升级路径:学分制+AI评卷的全新实践
人工智能·企业培训·公司内训
三更两点19 分钟前
AI拉呱-2026年06月12日AI技术洞察简报
人工智能