把技能钉进每个会话: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 命令参考。