13 · 技能系统

81 个 SKILL.md 文件,分布在 15 个类别里。skills_hub.py 有 4,956 行。这一章讲怎么用纯文本教会智能体做一件它本来不会的事

13.1 技能是什么

一个技能就是一个 Markdown 文件。没有代码,没有编译,没有注册。

---
name: deploy-to-staging
description: 把当前分支部署到预发布环境并验证健康检查
version: 1.2.0
author: platform-team
license: MIT
platforms: [slack, cli]
metadata:
  hermes:
    tags: [deploy, ci, infra]
related_skills: [rollback-deploy, check-service-health]
---

# 部署到预发布环境

## 前置检查
1. 确认当前分支的 CI 全绿:`gh pr checks`
2. 确认没有未提交的改动:`git status --porcelain`

## 部署步骤
1. 打 tag:`git tag staging-$(date +%Y%m%d-%H%M%S)`
2. 推送:`git push origin --tags`
3. 等待部署流水线:`gh run watch`

## 验证
- 访问 https://staging.example.com/health,应返回 200
- 如果 5 分钟内没有变绿,执行 rollback-deploy 技能

为什么这有用?

模型知道 git、知道 gh、知道怎么发 HTTP 请求。它不知道的是「在你们团队,部署是这么做的」 —— 用哪个命令、按什么顺序、验证什么、出错了找谁。

技能填补的正是这个缺口:不是教模型新能力,而是告诉它「在这个具体环境下,正确的做法是什么」。

13.2 前置元数据逐字段解释

文件开头 --- 之间的部分叫「前置元数据」(front matter),是 YAML 格式的结构化信息。

字段作用
name技能的唯一标识。用户可以直接用它调用(/deploy-to-staging
description最重要的一个字段。它决定模型什么时候会想起来用这个技能。见下一节
version技能也会演进。团队的部署流程变了,技能要跟着改
author出问题时找谁
license技能可以被分享、被开源。需要明确许可
platforms限定在哪些平台可用。有的技能只在命令行里有意义(涉及本地文件),有的只在聊天工具里有意义(涉及发消息)
metadata.hermes.tags标签,用于分类和检索
related_skills技能之间的关系。上面的例子里,部署技能指向了回滚技能 —— 出问题时模型知道下一步该看哪个

13.3 渐进式披露:技能系统的核心机制

81 个技能全部展开是多少字?假设每个 3 KB,就是 243 KB ≈ 6 万 token

如果把 81 个技能全放进系统提示词: · 每一轮对话都要重新发送这 6 万 token · 就算这次任务只需要其中 1 个技能 · 输入成本 × 每一轮 × 每一天 更糟的是:模型的注意力被稀释了。 6 万 token 的无关内容里藏着 3 KB 的相关内容, 模型很可能"看漏"。

解法:只常驻「目录」,内容按需加载。

系统提示词里常驻的(每个技能约 1 行): deploy-to-staging —— 把当前分支部署到预发布环境并验证健康检查 rollback-deploy —— 回滚上一次部署 check-service-health—— 检查服务健康状态 ...(81 行,约 5 KB) 用户说:"帮我把这个分支发到 staging" ↓ 模型看到目录里 deploy-to-staging 的描述匹配 ↓ 模型调用 skill 工具:读取 deploy-to-staging 的完整内容 ↓ 3 KB 的详细步骤进入上下文 ↓ 模型按步骤执行 ★ 常驻 5 KB,而不是 243 KB。省了 98%。

这解释了为什么 description 是最重要的字段。

它是模型唯一能看到的、用来判断「这个技能跟当前任务有没有关系」的信息

写得好:「把当前分支部署到预发布环境并验证健康检查」→ 用户说「发到 staging」时能匹配上。
写得差:「部署工具」→ 太模糊,模型不知道是部署到哪、部署什么。

写技能描述的原则:写「什么时候该用它」,而不是「它是什么」。

13.4 技能的支撑设施

技能本身是纯文本,但围绕它有一整套工程设施:

skills_hub.py          4,956 行   技能的加载、检索、执行编排
skill_ledger.py                   ★ 技能台账
skill_provenance.py               ★ 来源追溯
skill_usage.py                    ★ 使用统计
skill_linter.py                   ★ 格式检查
skills_guard.py                   ★ 安全守卫
skills_sync.py                    ★ 同步

skill_provenance.py:来源追溯

「provenance」(来源、出处)在这里是一个安全概念。

一个技能文件里写的步骤,智能体会照着执行。所以:一个技能文件就是一段可执行的指令 —— 只不过它是用自然语言写的。

攻击场景:有人往你的技能目录里放了一个技能文件,描述写得很正常(「清理临时文件」),内容里却是把敏感数据发到外部。下次模型判断需要清理临时文件时,就会照做。

来源追溯就是回答:这个技能是谁写的?从哪来的?改过没有?

skills_guard.py:安全守卫

在技能被加载或执行前做安全检查。可能包括:

skill_linter.py:格式检查

「linter」是「代码风格检查器」的通称。技能的 linter 检查的是:

为什么需要 linter:因为技能是给人写的,而人会写错。一个 description 拼错了字段名,这个技能就永远不会被匹配到 —— 而且不会报错,只是「莫名其妙不生效」。Linter 把这类静默失败变成明确的错误。

skill_usage.py:使用统计

记录哪些技能被用了、用了多少次、成功率如何。用途:

skill_ledger.pyskills_sync.py

台账记录技能的完整清单和状态(启用/禁用、版本、来源)。同步负责在多个地方之间保持技能一致 —— 比如从一个共享仓库拉取团队的技能库。

13.5 技能 vs 工具 vs 插件

技能工具插件
是什么Markdown 文本Python 函数Python 包
教会模型怎么做(用已有能力)能做什么(新能力)能做什么 + 改变系统行为
写的人任何人,包括非程序员程序员程序员
出错的后果模型走了错路,通常能自己纠正工具报错可能影响整个系统
常驻成本1 行描述一份 JSON schema(几百 token)取决于它注册了什么
典型例子「我们团队的部署流程」「读文件」「跑命令」「接入 Slack」「换个记忆后端」

关键区分:技能不给模型新能力,只给它「在这个环境下的正确做法」。

部署技能里的每一条命令(git taggh run watch)模型本来就会执行 —— 它有 terminal 工具。技能提供的是顺序、参数、验证方式、失败时的退路

这就是为什么技能可以是纯文本:它编码的是知识,不是能力。

13.6 技能系统的一个隐含设计:可组合

related_skills 字段和技能内容里的「执行 rollback-deploy 技能」这样的引用,构成了一张技能之间的关系网。

deploy-to-staging ├─ 失败时 → rollback-deploy └─ 验证时 → check-service-health └─ 异常时 → escalate-to-oncall ★ 模型可以沿着这张网走。 它不需要一开始就知道整条链, 只需要在每一步知道"下一步看哪个"。

这和渐进式披露是同一个思想的延伸。

不是「一次性把所有相关知识都塞进上下文」,而是「在需要的那一刻,告诉它去哪里找下一块」。

上下文是有限的、昂贵的。一个好的知识组织方式,应该让智能体在任意时刻只持有它当前真正需要的那部分。

这个原则贯穿了整篇文章讲过的所有机制:技能目录、记忆预取、上下文引擎的选择、工具集的投放 —— 全都是同一件事的不同表现。

13.7 15 个技能类别

81 个技能分布在 15 个类别里。类别本身反映了智能体被期望承担的工作范围:

开发相关 —— 代码审查、重构、测试、调试 运维相关 —— 部署、监控、回滚、故障处理 数据相关 —— 查询、分析、报表 文档相关 —— 写作、翻译、格式化 协作相关 —— 会议纪要、任务分派、状态汇报 ...

这个分布说明技能系统的实际用途:把一个通用智能体特化成「这个团队的工程助手」。模型本身是通用的,技能库是团队特有的。同样的模型 + 不同的技能库 = 完全不同的助手。

13.8 全文回顾:Hermes 的整体形状

入口层 聊天工具 · 命令行 · webhook · 定时任务 (第 1、12 章) ↓ 身份层 Profile:模型 + 工具 + 记忆 + 人格 (第 2 章) ↓ ┌────────────────────────────────┐ │ 智能体循环 │ │ (第 3 章) │ │ 预算闸门 → 建上下文 → 调模型 │ │ → 执行工具 → 回到开头 │ └──┬──────────┬──────────┬────────┘ ↓ ↓ ↓ 工具层 上下文层 记忆层 (第 4 章) (第 7 章) (第 8 章) ↓ 审批层(第 5 章)—— 5,802 行红线 ↓ 执行环境(第 6 章)—— 唯一的硬边界 ↓ 模型供应商 + 凭据池(第 11 章) 横切:插件(第 9 章)· 委派(第 10 章)· 技能(第 13 章)
这套架构最值得学的三件事

① 一切扩展点都是抽象基类。平台、记忆、上下文引擎、模型供应商、执行环境、定时提供者 —— 全部是「定义契约,实现可替换」。而且区分了「可叠加能力」和「必须单选的策略」。

② 安全是分层的、fail-closed 的。工具收窄 × 审批红线 × 执行隔离 × 注入检测。每一层都不可靠,叠起来才够用。不确定的时候一律选择「不执行」。

③ 上下文是最稀缺的资源,一切设计围绕它。渐进式披露、委派分区、记忆预取、压缩策略 —— 表面上是七八个不同的机制,本质上都在回答同一个问题:「怎么让模型在任意时刻只持有它真正需要的那部分信息」。