2026年7月16日 周四晚上19:30,报名腾讯会议了解“如何构建自进化的动态知识库(Brain)”(限30人)
免费POC, 零成本试错
FDE知识库

FDE知识库

学习大模型的前沿技术与行业落地应用


收藏

Hermes Skill Runtime 架构拆解:三层加载如何压住 Agent 上下文成本

发布日期:2026-07-10 10:40:27 浏览次数: 1543
作者:AI 小老六

微信搜一搜,关注“AI 小老六”

推荐语

通过分层披露技能信息,Hermes巧妙控制了Agent的上下文成本,避免一次性加载所有细节,提升了运行效率。

核心内容:
1. Hermes技能系统的三层加载架构设计原理
2. 主目录与外部目录的边界划分与工程取舍
3. 运行时扫描与分层披露机制如何优化token使用

杨芳贤
53AI创始人/腾讯云(TVP)最具价值专家

Hermes 用 Level 0/1/2 分层披露,把技能发现、完整说明和参考文件拆开,降低 Agent 上下文成本。

Hermes 的 Skill System 看起来只是一个“按名字加载 Markdown 文件”的工具,但真正有意思的地方不在读取文件本身,而在它怎样控制上下文成本、怎样处理本地技能和外部技能的边界、怎样让插件技能进入同一套解析链路,又不把用户会话一开始就塞满。

这套设计的核心判断很明确:技能系统不能像传统插件市场一样,把所有内容预先索引、预先展开、预先注入。Agent 会话里的上下文窗口太贵,技能越多,越不能一次性把所有细节暴露给模型。Hermes 选择了一条更朴素的路:运行时扫描,分层披露,只有在真正用到某个技能时才付出更多 token。

图:模型先看到技能地图,而不是一次性读完整手册

Skill Runtime 的基本边界:主目录、外部目录与命名空间

Hermes 把 ~/.hermes/skills/ 视为技能的主目录。它是默认读写位置,也是本地技能的单一真实来源。外部目录通过 external_dirs 接入,更多承担扩展和共享的角色,默认不会改变本地主目录的权威性。

典型目录长这样:

~/.hermes/skills/
├── category/
│   └── skill-name/
│       └── SKILL.md
├── .hub/
│   ├── lock.json
│   ├── quarantine/
│   └── audit.log
├── .bundled_manifest
└── .archive/

这里有几个工程取舍。SKILL.md 是技能入口;.hub 保存 Hub 相关的本地状态;.archive 和 .bundled_manifest 属于维护层数据,不应该参与正常技能扫描。Hermes 在遍历时会主动排除这些目录,也会跳过 .gitnode_modules、虚拟环境、缓存目录等高噪声路径。

EXCLUDED_SKILL_DIRS = frozenset((
    ".git"
, ".github", ".hub", ".archive",
    ".venv"
, "venv", "node_modules", "site-packages",
    "__pycache__"
, ".tox", ".nox", ".pytest_cache",
    ".mypy_cache"
, ".ruff_cache"
))

命名空间是另一条边界。普通技能用 skill-name 解析,插件技能用 namespace:skill 解析。这个冒号并不是装饰,它告诉运行时先拆出插件命名空间,再去插件目录里找对应技能。没有这个规则,插件生态很快会撞名。

def parse_qualified_name(name: str) -> Tuple[Optional[str], str]:
    if
 ":" not in name:
        return
 None, name
    return
 tuple(name.split(":", 1))

本地优先也很关键。同名技能出现时,Hermes 不会让外部目录悄悄覆盖用户本地版本;真正发生多候选冲突时,它会返回明确错误和所有匹配路径,让用户改用完整相对路径。这个决定减少了“为什么今天调用的不是昨天那个技能”的排查成本。

Level 0:skills_list 只给模型一张轻量地图

会话启动时,Hermes 不会把每个技能的正文都塞进上下文。skills_list() 只返回技能元数据,大约是一个固定的 token 成本。原文估算 Level 0 约为 3k tokens,这笔成本会在会话启动时支付;后面的完整技能内容和参考文件,只有在触发时才成为边际成本。

Level 0: skills_list()              -> 仅技能元数据,约 3k tokens
Level 1: skill_view(name)           -> 完整 SKILL.md,通常 10-100k tokens
Level 2: skill_view(name, path)     -> 技能目录内的某个参考文件

Level 0 的目标不是“让模型读懂所有技能”,而是让模型知道有哪些技能、每个技能大概负责什么、是否适合当前平台和环境。它更像一张地图,不是一本手册。

图:Level 0 从目录扫描到条件激活过滤的完整链路

返回值只保留必要字段:

{
  "name"
: "skill-name",
  "description"
: "Brief description...",
  "category"
: "category-name",
  "tags"
: ["tag1", "tag2"]
}

这个阶段的扫描没有依赖 SQLite 或预构建 JSON 索引。Hermes 每次执行 skills_list() 都会重新扫文件系统:

def iter_skill_index_files(skills_dir: Path, filename: str):
    for
 root, dirs, files in os.walk(skills_dir, followlinks=True):
        dirs[:] = [d for d in dirs if d not in EXCLUDED_SKILL_DIRS]
        if
 filename in files:
            yield
 Path(root) / filename

dirs[:] 的原地修改是一个小但实用的优化。它不是在遍历后过滤结果,而是在 os.walk() 继续递归之前剪掉不该进入的目录。技能数量少于千级时,这种按需扫描足够简单,维护成本也比额外索引低。

Level 0 还会处理平台和环境匹配。platforms 为空时默认通过;macos 会映射到 darwinlinuxwindows 也有对应映射。Termux 需要特殊处理,因为它跑在 Android 上,却经常要兼容 Linux 技能。

PLATFORM_MAP = {
    "macos"
: "darwin",
    "linux"
: "linux",
    "windows"
: "win32"
}

环境字段也在这个阶段过滤。Hermes 内置识别 kanbandockers6,未知环境默认通过。这个默认值有点宽松,但它避免了一个更糟的问题:新环境还没被运行时认识时,技能全部消失。

_KNOWN_ENVIRONMENTS = frozenset({"kanban", "docker", "s6"})

条件激活是 Level 0 里更像 Agent 的部分。技能可以声明 requires_toolsetsrequires_tools,也可以声明 fallback_for_toolsetsfallback_for_tools。前者表示依赖不可用就隐藏;后者表示主工具可用时自己退场。比如一个 DuckDuckGo 搜索技能可以只在正式 Web 工具不可用时出现。

图:依赖工具与 fallback 工具共同决定技能是否显示

这样做的好处是,模型看到的不是“所有可能工具”,而是当前会话真正有意义的工具。对 Agent 来说,这比单纯减少 token 更重要,因为候选越乱,错误调用的概率越高。

Level 1:skill_view 的难点在名字解析,而不是读文件

当模型决定使用某个技能时,才进入 Level 1。skill_view(name) 会读取完整 SKILL.md,执行必要的前置处理,然后把完整技能说明交给模型。

图:Level 1 的命名解析、冲突检查与内容预处理

四层名称解析策略体现了兼容性优先级:

# 策略 1:直接路径
direct_path = search_dir / name
if
 direct_path.is_dir() and (direct_path / "SKILL.md").exists():
    return
 direct_path / "SKILL.md"

# 策略 2:递归按目录名匹配

for
 found_skill_md in iter_skill_index_files(search_dir, "SKILL.md"):
    if
 found_skill_md.parent.name == name:
        return
 found_skill_md

# 策略 3:按 frontmatter 的 name 字段匹配

fm, _ = _parse_frontmatter(fm_content)
if
 fm.get("name") == name:
    return
 found_skill_md

# 策略 4:兼容旧式扁平 .md 文件

for
 found_md in search_dir.rglob(f"{name}.md"):
    if
 found_md.name != "SKILL.md":
        return
 found_md

直接路径优先,说明 Hermes 鼓励用户在冲突时显式指定位置。目录名匹配符合大多数人的直觉;frontmatter 名称匹配给重命名目录留下空间;legacy .md 负责兼容旧技能。

真正撞名时,运行时不会装作没事:

if len(candidates) > 1:
    return
 json.dumps({
        "success"
: False,
        "error"
: f"Ambiguous skill name '{name}': {len(candidates)} skills match",
        "matches"
: [str(smd) for _, smd in candidates],
        "hint"
: "Use full relative path instead"
    })

这比“按某个顺序静默选第一个”可靠得多。技能是会执行命令、写文件、访问外部系统的,名称解析上的模糊不该被吞掉。

插件技能在 Level 1 里走一条相似但带命名空间的链路。skill_view("plugin:skill") 会先定位插件,再找插件内的技能。如果插件存在但技能不存在,运行时可以列出可用技能;如果找到了,会在返回内容前附加上下文横幅,提醒模型这是哪个插件的一部分,以及有哪些 sibling skills 可以用限定名调用。

[Bundle context: This skill is part of the 'plugin' plugin.
Sibling skills: skill1, skill2.
Use qualified form to invoke siblings (e.g. plugin:skill1).]

Level 1 的后半段是技能内容预处理。Hermes 支持模板变量:

${HERMES_SKILL_DIR}  -> 当前技能目录的绝对路径
${HERMES_SESSION_ID} -> 当前会话 ID

如果配置允许,还可以执行内联 shell:

Current date: !`date -u +%Y-%m-%d`
Git branch: !`git -C ${HERMES_SKILL_DIR} rev-parse --abbrev-ref HEAD`

这个能力很锋利,所以它应该被视为受控扩展,而不是普通 Markdown 特性。技能内容一旦能执行命令,路径安全和注入检测就必须跟上。Hermes 对技能名做了绝对路径、Windows drive、.. 路径穿越检查,也内置了一批 prompt injection 模式,例如 ignore previous instructionssystem prompt:

Hub 安装技能还有额外安全扫描,重点检查数据渗出、破坏性命令、Shell 注入和 prompt 注入。它不能证明技能一定安全,但能挡住一批低成本攻击。

配置注入也发生在 Level 1。技能可以在 frontmatter 里声明自己需要的配置项:

metadata:
  hermes:

    config:

      -
 key: wiki.path
        description:
 Path to wiki directory
        default:
 ~/wiki
        prompt:
 Wiki directory path

运行时会从配置文件读取 skills.config.,没有值就用默认值,再展开 ~ 和环境变量。最后把结果追加到技能内容里:

[Skill config (from ~/.hermes/config.yaml):
  wiki.path = /Users/erik/wiki
]

这里可以看出 Hermes 对“技能加载”和“技能管理”分得很清楚。加载是按需读取和注入;管理则走 skill_manage,支持 createpatcheditdeletewrite_fileremove_file。如果开启 skills.write_approval,写入不会直接落盘,而是进入 ~/.hermes/pending/skills/,等待用户 review、diff、approve 或 reject。

Level 2:参考文件把长技能拆成可控切片

图:低频细节被延后到参考文件,按需进入上下文

很多技能的主文件不应该无限膨胀。Hermes 的 Level 2 允许按路径读取技能目录内的参考文件:

skill_view("skill-name", "references/api.md")

这一步解决的是另一个 token 问题:有些知识只在特定分支下需要,比如 API 细节、样式规范、平台适配说明。把这些内容全塞进 SKILL.md,会让每次技能加载都变重;拆到 references/ 以后,主技能只负责路由和原则,细节按需进入上下文。

可以把三层加载理解成这张表:

层级
入口
模型拿到什么
主要成本
适合放什么
Level 0
skills_list()
名称、描述、分类、标签
会话启动固定成本
技能发现与选择信号
Level 1
skill_view(name)
完整 SKILL.md
使用技能时的边际成本
工作流、边界、关键规则
Level 2skill_view(name, path)
某个参考文件
分支触发成本
API 细节、模板、长规范

原文尾部提到的性能优化、安全机制、平台环境匹配,其实都应该放回这三层里看。Level 0 负责过滤和候选控制;Level 1 负责解析、预处理和安全检查;Level 2 负责把低频细节延后。这样理解后,Hermes Skill System 就不是“技能列表 + 技能详情”的二段式接口,而是一套围绕上下文窗口设计的运行时。

一次完整调用:从会话启动到技能内容进入上下文

会话启动时,Hermes 读取配置,解析外部目录,然后扫描技能元数据:

图:会话启动时只注入精简技能元数据

用户触发技能后,完整内容才进入模型上下文:

图:技能被触发后才读取完整说明进入上下文

如果技能再请求 references/api.md,才进入 Level 2。这个顺序让技能系统可以支持很多技能,又不会在每次会话里一次性支付全部成本。

这个设计真正解决的问题

Hermes 的选择并不复杂。它没有上来做一套重索引系统,也没有把技能包管理做成独立数据库。它依赖文件系统、frontmatter、运行时扫描和少量缓存,换来的好处是透明、容易调试、容易迁移。

我更认可这套系统的一点,是它把 Agent 运行时最稀缺的资源放在了设计中心。技能不是越完整越好,也不是越早暴露越好。Level 0 让模型知道“有什么”,Level 1 让模型知道“这个技能怎么用”,Level 2 只在需要时补上“具体细节”。这是一个很适合 Agent 时代的插件系统思路:能力可以很多,但上下文必须克制。

如果后续要继续演进,真正值得加强的可能不是复杂索引,而是两个方向:一是更好的冲突解释和推荐限定路径,二是对 references/ 的结构化摘要,让模型在进入 Level 2 前就能判断该读哪个文件。前者减少用户困惑,后者继续压低 token 成本。至于数据库化索引,除非技能数量和外部目录规模真的上来了,否则它未必比现在的按需扫描更划算。

53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询

扫码登录
登录即表示您同意《53AI网站服务协议》
服务协议

欢迎您使用【53AI 官方网站】(以下简称“本网站”或“我们”)。本《会员服务协议》(以下简称“本协议”)是您(以下简称“会员”或“用户”)与【深圳市博思协创网络科技有限公司】之间关于注册、登录及使用本网站会员服务所订立的法律协议。

在您注册或登录前,请务必审慎阅读、充分理解各条款内容,特别是免除或限制责任的条款、知识产权条款、争议解决条款等。此类条款将以加粗形式提示您注意。 当您通过微信公众号授权、手机验证码验证或其他方式成功登录本网站时,即视为您已完全理解并同意接受本协议的全部内容。

一、 定义

本网站:指由【深圳市博思协创网络科技有限公司】运营的,域名为【53ai.com】的网站及相关移动端页面。

会员服务:指本网站向注册会员提供的知识库文章查阅、内容检索及其他相关增值服务。

知识库内容:指本网站发布的包括但不限于文字、图表、数据、研究报告、行业分析等数字化内容资源。

二、 账号注册与登录

登录方式:本网站支持以下登录方式,您可根据实际情况选择:

微信公众号授权登录:您同意将您的微信OpenID信息授权给本网站,用于创建或关联会员账号。

手机验证码登录:您需提供真实有效的手机号码,并通过短信验证码完成身份验证与登录/注册。

账号安全:您的账号仅限您本人使用,禁止赠与、借用、租用、转让或售卖。因您保管不善导致的账号被盗、密码泄露等损失,由您自行承担。

实名认证:根据相关法律法规要求,我们可能要求您在特定功能下完成实名认证。如您拒绝提供,可能无法使用部分或全部服务。

未成年人保护:若您未满18周岁,请在法定监护人的陪同下阅读本协议,并在征得监护人同意后使用本服务。

三、 服务内容与规范

知识库查阅权限:会员登录后,有权按照其会员等级对应的权限范围,在线浏览、检索本网站知识库中的相关文章及内容。

服务变更:我们有权根据业务发展需要,调整、变更或终止部分服务内容,并将以网站公告、公众号消息等方式提前通知。

禁止行为:您在使用服务时不得实施以下行为:

利用技术手段批量爬取、下载、转存知识库内容;

将知识库内容用于商业目的或未经授权地向第三方传播;

干扰本网站正常运行或侵犯其他用户合法权益;

发布违法违规信息或从事违反公序良俗的活动。

四、 知识产权声明

权利归属:本网站知识库中的排版设计、软件代码等内容的知识产权均归【公司全称】或原权利人所有,受《中华人民共和国著作权法》等法律保护。

有限许可:本网站授予会员一项非独占、不可转让、不可转授权的普通许可,仅限于个人学习、研究之目的在线查阅知识库内容。

侵权追责:未经书面许可,任何单位或个人不得以任何形式复制、转载、摘编、镜像、汇编或以其他方式使用上述内容。一经发现,我们保留追究其法律责任的权利。

五、 个人信息保护

我们重视对您个人信息的保护。关于我们如何收集、使用、存储和保护您的个人信息,请单独阅读 《隐私政策》。

您通过微信公众号授权或手机号验证所提供的信息,我们将严格按照《个人信息保护法》的规定处理,仅用于身份识别、服务提供及安全验证等必要用途。

您可以随时通过网站设置或联系客服行使查阅、更正、删除个人信息及撤回授权同意的权利。

六、 免责声明

内容准确性:知识库内容仅供参考,不构成专业建议。我们不对其完整性、准确性、时效性作任何明示或暗示的保证,您应自行判断并承担使用风险。

不可抗力:因自然灾害、政策法规变化、网络故障、第三方平台接口异常(如微信接口维护、运营商短信通道故障)等不可抗力导致的服务中断或延迟,我们不承担违约责任。

第三方链接:本网站可能包含指向第三方网站的链接,该等网站的内容和服务不受我们控制,请您自行甄别风险。

七、 违约责任

如您违反本协议约定,我们有权视情节采取警告、限制功能、暂停服务、注销账号等措施,并保留要求赔偿损失的权利。

如因您的违约行为导致我们遭受行政处罚、第三方索赔或商誉损失,您应承担全部赔偿责任(包括但不限于罚款、赔偿金、律师费、公证费等)。

八、 法律适用与争议解决

本协议的订立、执行和解释均适用中华人民共和国大陆地区法律。

因本协议产生的或与本协议有关的任何争议,双方应友好协商解决;协商不成的,任何一方均可向【公司所在地】有管辖权的人民法院提起诉讼。

九、 其他

本协议构成双方就本服务达成的完整协议,取代此前任何口头或书面约定。

本协议任一条款被认定为无效或不可执行的,不影响其他条款的效力。

我们对本协议享有最终解释权,并在法律允许的范围内保留随时修改的权利。修改后的协议一经公布即生效,继续使用服务即视为同意修订内容。


已查阅