把技能钉进每个会话:skills.auto_load 让 Agent 永远记得你的流程


周一早上你开了一个新会话,第一件事是粘贴三行:按我们的内部模板写、发版前跑那个 QA 脚本、别用 emoji 当小标题。周三你换了个模型,Agent 又把模板忘了。周五你压缩过上下文之后,它开始用完全不同的结构写东西——而你只是想让那套流程一直在那儿,不用每次重申。

技能系统原本的设计是“按需”:Agent 平时只读技能的短描述,任务真的需要时才加载正文。这个设计省钱,但有个前提——任务得“看起来像”需要那个技能。当你的流程是一条贯穿始终的约束(写作风格、审查清单、发布步骤),按需加载经常赶不上。

auto_load 改变的就是“加载”这一步

在 profile 的 config.yaml 里写:

skills:
  auto_load:
    - release-notes
    - qa-multilingual

这两个技能会在每个新会话开始时被完整加载(作为已加载技能注入系统提示),而不只是列在技能目录里。它覆盖所有 agent 表面:CLI、TUI、网关、cron 任务、API agent。默认值是空列表,也就是维持原来的按需行为。

和同类设计的对应关系很清楚——Cursor 把这个模式叫 Custom Modes(选一个技能、钉住、保持 playbook);Hermes 这边是 profile 级的一份配置列表:不管你今天用什么界面、什么模型,这套技能都在。

一个细节值得单独说:auto_load 里的技能与显式 --skills 请求会按规范名去重,并且享受和 --skills 相同的门禁——被禁用的技能不会被塞进来,加载了会照常计入 Curator 的使用统计(这样长时间没人用的技能才会被清理,而不是因为被钉住就永远“热门”)。

它和另外三种“让技能生效”的方式有什么不同

方式 什么时候生效 适用场景
技能描述索引(默认) 常驻,但只是短描述 大多数技能:Agent 自己判断需不需要
skills.auto_load 每个新会话,正文完整加载 贯穿全局的约束:写作风格、审查清单、发布流程
显式 --skills(命令行) 本次调用 一次性任务,或临时试一个技能
项目级技能目录 会随触发条件被发现 仓库自己的约定,跟着代码走

四者可以叠用:auto_load 负责“底线”,--skills 负责“这次额外要什么”,项目级技能负责“这个仓库的规矩”。

为什么它不会把 prompt 成本打爆

这是这个功能实现里最讲究的部分,也是它值得信任的原因。钉住技能意味着每个会话都多一段固定的系统提示内容——如果实现得糙,它会同时打破两件事:请求体积,以及 prompt 缓存。

实际实现是每个 agent 只在系统提示第一次构建时解析一次,之后模型切换、上下文压缩、静态前缀恢复都复用完全相同的那段渲染字节。换句话说,它变成缓存前缀的一部分,而不是每次都重新拼的可变内容。官方验证里专门测了这条:在磁盘上的技能文件被改动之后,同一 agent 的 auto-load 渲染结果仍然是字节稳定的(否则缓存会立刻失效)。

同一批验证还覆盖了另外两条行为:缺失的技能警告并跳过,不会让会话起不来;--ignore-rules(或环境变量 HERMES_IGNORE_RULES=1)会连同其余自动注入的上下文一起抑制 auto-load。

什么时候不该用

  • 别钉一打技能。 每个被钉住的技能都占常驻上下文,钉十来个之后你会开始为“我根本没用到的流程”付 token。两三个真正全局的约束就够了。
  • 别钉你正在迭代的技能。 正因为渲染是解析一次、字节稳定,你在会话中途改技能文件不会影响正在跑的会话——这是特性,但也意味着“改完立刻生效”要开新会话。
  • 临时要干净的运行:HERMES_IGNORE_RULES=1 hermes chat -q "...",或者 --ignore-rules;CI 里想完全隔离再加 --ignore-user-config。

一个真实用法:把发布流程钉进每个会话

假设你有一套固定的发布步骤(版本号怎么取、要跑哪个 QA 脚本、章节顺序是什么)。做法是把它写成一个技能,然后钉住:

skills:
  auto_load:
    - release-notes
    - qa-multilingual

写完这样验证三件事:

hermes config get skills.auto_load          # 确认 profile 里的值
hermes session new                          # 开一个新会话
hermes skills list                          # 看它是否已被视为已加载

然后在会话里直接让它按流程做事,看它是否第一次就用了你的模板——不用你先说“按我们的模板来”。如果它没有,先检查技能名是否写对(名字错了只会得到一条警告并被跳过),再检查有没有用 --ignore-rules 起会话。

想让它换模型也稳定(比如便宜模型跑日常、强模型做大事),这条特性正好补上:模型换了,钉住的技能还在,而且因为渲染字节没变,缓存前缀也还在。如果你还要把同样的流程带进无人值守的运行,可以配合 技能总是先加载 之外的另两件事——用 stream-json 让 CI 能判断结果,用 项目级技能 让仓库自己的规矩跟着代码走。

小结

skills.auto_load 是那种“看起来只是省了几句话、实际上改变可靠性”的小功能:它把“每次都要重申的约束”变成“会话默认状态”。代价是常驻上下文,收益是行为一致性——特别是当你换模型、压缩上下文、或者把任务交给 cron 跑的时候,Agent 依然按你的流程办事。想先看它随哪个版本发布、同窗口还有什么,读 v0.21.4 都带了什么;技能系统的整体说明见 hermes skills 命令参考。