Hermes 自改进循环(Self-Improvement Loop)
Hermes 把会话知识沉淀到 MEMORY.md / USER.md / SKILL.md 有两个互不调用但共享落盘资产的通道:
| 通道 | 触发 | 执行者 | 用户在场 |
|---|---|---|---|
自动:/refine(background review) |
手动 /refine [focus] + 回合结束 nudge |
fork 独立 AIAgent(后台 daemon 线程) | ❌ 无(auto-deny 审批) |
| 手动:session-knowledge-capture 技能 | 用户显式触发("/收割/沉淀"等) | 主 agent 前台 | ✅ 有(dry-run/追问) |
自动通道:background review(/refine)机制
触发(两条路径)
- 手动:
/refine [focus]——三个入口,行为同构:- CLI 交互:
hermes_cli/cli_commands_mixin.py:2460(查self.agent) - Messaging gateway(Telegram/Discord/A2A):
gateway/slash_commands.py:2860(查_agent_cache,LRU cap 128 / idle TTL 1h / 内存压力淘汰) - 桌面端:主进程白名单
_LIVE_SESSION_DIRECT_COMMANDS+_format_live_refine_output(查session["agent"])——桌面端不能走 slash worker(worker 的 HermesCLI 从不构建 agent,cli.py:11383;修复见 hermes-desktop-internals/references/slash-worker-architecture.md)
- CLI 交互:
- 自动(回合结束,
agent/turn_finalizer.py:727-732):- 条件:
final_response非空 ∧ 未中断 ∧skip_background_review=False(cron 禁用)∧ nudge 到期 - memory nudge:每 10 轮(
turn_context.py:598-605,memory工具可用且_memory_store存在) - skill nudge:每 10 次工具迭代(
turn_finalizer.py:707-712,skill_manage可用)
- 条件:
执行(agent/background_review.py:_run_review_in_thread)
主 agent 回合结束
└─ agent._spawn_background_review(messages_snapshot, review_memory, review_skills, focus)
└─ spawn_background_review_thread → fork 独立 AIAgent(daemon 线程 "bg-review")
├─ 继承父 runtime:provider/model/凭据/OAuth 会话态(_resolve_review_runtime)
│ └─ 可配置 aux 模型:auxiliary.background_review.{provider,model,timeout,...}
│ (默认 auto=主模型;路由到不同模型时把完整转录压缩为 digest 再喂)
├─ skip_memory=True:不碰外部记忆插件(honcho/mem0),
│ 内置 MEMORY.md/USER.md 状态从父 agent 重绑定 → memory() 写入照常落盘
├─ 审批回调 = auto-deny(危险命令直接拒绝,防 input() 死锁)
├─ 静音执行(thread_scoped_silence,只静默本线程)
├─ prompt:按 flags 选 _MEMORY/_SKILL/_COMBINED_REVIEW_PROMPT;
│ focus 追加到 prompt 末尾(用户优先级覆盖)
└─ review agent 的 nudge 归零 → fork 不递归触发 review
写保护(后端强制,不依赖模型自觉)
- 记忆:仅内置 MEMORY.md/USER.md(外部记忆插件被 skip_memory 跳过)
- 技能:仅 curator-managed——bundled / hub / pinned / user-owned 技能全部禁写(
_SKILL_REVIEW_PROMPT明示 + skill_manage 后端拒绝)
汇报
background_review_callback → 各表面展示:桌面端 = review.summary 事件(💾 气泡,server.py:6683);CLI = 打印;gateway = 平台消息。
成本与边界
- 每次 review ≈ 一个新 AIAgent 实例(~30K tokens/事件)——cron 会话因此禁用(无人受益)
- 长会话快照 = 浅拷贝
list(messages);无用户确认环节 = 可能误写且无人纠正(结构性弱点)
fork 运行时能力边界(2026-08-08 实测白名单)
fork 的工具白名单 = {memory, skill_manage, skill_view, skills_list}(background_review.py:893-909,get_tool_definitions(['skills']+['memory']) 实测)。其余工具运行时硬拒("Only memory/skill tools are allowed")。
推论:
- fork 能
skill_view加载 session-knowledge-capture,但无法完整执行其管线:内容级 grep 查重(需 terminal)❌、.bak快照(需 write_file/cp)❌、--session <id>补历史(需 session_search)❌——只能降级 skills_list 名称比对 + skill_view 逐个读 - 这是设计性缺失而非疏忽:fork 是无用户在场的自主 actor,白名单就是安全边界。想融合收割规范 → prompt 注入(fork 用 4 工具执行"裁剪版"),不是扩白名单(无人值守 actor 拿到 shell/文件写权限 = 破坏 auto-deny 安全设计)
查重分工("先写后治" vs "先查后写")
/refine 自己的四道防线全部非内容级(tools/skill_manager_tool.py):
- 同名拒绝(create 时
_find_skill精确目录名,929-934) - 先读后写守卫(
_background_review_read_before_write_guard,424-451:修改前必须 skill_view 读过目标,防盲写覆盖) - 保护技能拒绝(bundled/hub/pinned/user-owned,后端判定)
- consolidation 删除守卫(delete 必须
absorbed_into=<umbrella>且存在,463-503)
内容级查重不在写时,在 curator 异步 consolidation(agent/curator.py:"duplicate-finder" + "Judge overlap on CONTENT")——LLM 事后判定重叠并合并。窗口期:从重复技能创建到 curator 下次 pass 之间,库中可能短暂存在内容重叠条目(stash 教训即此机制产物:名字不同 + 描述无关键词 = 四道防线全漏)。
对照:session-knowledge-capture 是写前 grep(先查后写,无窗口期)。判断"某知识能否被 /refine 捕获":先查 fork 白名单是否含所需工具;terminal/write_file/session_search 不在 = 该知识只能靠用户侧收割。
手动通道:session-knowledge-capture
六步管线(范围确定→候选提取→QUIET 分类→内容级去重→落盘→保真度审计报告),详见该技能本体。要点差异:
- 决策框架更精细:QUIET 五维、教训四要素(触发信号/判别维度/反例/解决方案)、内容级 grep 查重
- 必出收割报告(保真度三档:高保真/改进版/丢弃 + 理由)
- 用户在场:dry-run 提案、可追问、落盘前确认
Curator 运维实战(2026-08-08 实证)
curator = 技能库自动维护(合并重叠技能为 umbrella、归档 stale),官方入口 hermes curator(CLI 子命令与 /curator slash 共享 hermes_cli/curator.py:cli_main)。
命令矩阵
| 场景 | 命令 | 说明 |
|---|---|---|
| 预览 | hermes curator run --consolidate --dry-run |
LLM 只读分析,只写 REPORT.md,零技能改动 |
| 正式合并 | hermes curator run --consolidate |
实际执行合并/归档(实测 27 分钟 / 74 次工具调用) |
| 恢复 | hermes curator restore <name> |
从 skills/.archive/ 移回(provenance 保留;目录落 skills/ 顶层,需手动 mv 回原分类目录) |
| 保护 | hermes curator pin <name> |
curator 永不自动动它(patch/edit 不受限,unpin 可解除) |
| 状态 | hermes curator status |
runs / last summary / last report 路径 / 技能统计 |
| 回滚 | hermes curator rollback |
配合 run 前自动 snapshot(curator_backup.snapshot_skills) |
桌面端限制(slash worker 45s 超时,详见 hermes-desktop-internals curator 矩阵)
- ✅ 秒级:status / pause / resume / pin / unpin / archive / restore / adopt
<name>/run(consolidate 默认 OFF 时纯确定性 prune) - ❌
run --consolidate(LLM pass 分钟级)→ 撞_SLASH_WORKER_TIMEOUT_S=45;run --background的 daemon 线程会被回合结束的 worker 重启杀死 - 桌面端跑 LLM 合并 → 用 CLI 终端
hermes curator run --consolidate
⚠️ dry-run 漂移教训(四要素)
- 触发信号:跑
--consolidate前看 dry-run 报告并计划"按预览执行" - 判别维度:dry-run 只读分析(实测 31 次 skill_view);正式 run 证据面更大(实测 74 次调用,含 37 次 terminal 文件核查)——证据面不同 → 决策必然可能不同,dry-run 的"保留/归档"结论不是承诺
- 反例教训:2026-08-08 实战——dry-run 明确"保留"的 5 个技能(hermes-desktop-internals / windows-file-organization / windows-software-installation / hermes-external-skills / hermes-agent-internals)全部被正式 run 归档(13 计划 → 17 实际);dry-run 说"修剪"的 agent-teams-architecture 被合并进 claude-code-internals(内容有去处,更好)
- 解决方案:① 重要技能先 pin(不是依赖 dry-run 的保留结论);② 正式 run 后对照实际归档清单与预览的偏差,偏差项
restore拉回;③ 确定性优先时,把不想动的技能全部 pin 后再跑
内容保全机制(已验证)
- 合并 = 正文 → umbrella
references/abs-<name>.md+ 支持文件搬迁(文件名冲突自动改名,如freellmapi-deployment-{toolinstall,softinstall}) - bundled 技能后端拒绝归档(实证:hermes-desktop-plugins 尝试归档被拒,内容以
abs-plugins.md复制进 umbrella,原技能不动) - 恢复技能与 umbrella 的 abs-* 副本内容重复——无害,可后续清理
选择指引
| 场景 | 通道 |
|---|---|
| 无人值守持续学习(回合结束自动捕获、不打断主任务) | /refine(自动 nudge) |
随时补采当前会话(手动 /refine [focus] 定向聚焦) |
/refine |
用户在场的定向沉淀、指定窗口(--window N/--session <id>) |
session-knowledge-capture |
| 判别类知识、四要素教训(可靠性靠反复实例化) | session-knowledge-capture(dry-run 提案更稳) |
| 需要 dry-run 审查后再落盘 | session-knowledge-capture --dry-run |
Pitfalls
- ⚠️ 桌面端
/refine曾结构性 100% 失败:slash worker 的self.agent恒 None → "send a message first" 误导。2026-08-08 已修复(主进程白名单),完整链条见hermes-desktop-internals的references/slash-worker-architecture.md - ⚠️ messaging gateway 版 /refine 部分可用:
_agent_cache被 LRU/idle TTL/内存压力淘汰后同样假阴性——"缓存未命中" ≠ "会话无内容" - ⚠️ 不要给 review fork 配置会造成副作用的外部记忆插件:skip_memory 是刻意设计,防止 harness prompt 泄漏进用户真实记忆命名空间
- ⚠️ session-knowledge-capture 是 user-owned 技能(后台 curator 不可写);如需自动整合本技能内容,
hermes curator adopt session-knowledge-capture - ⚠️ curator dry-run ≠ 正式 run 决策:LLM 每次独立判断(证据面不同),正式 run 可能推翻 dry-run 的"保留"结论(2026-08-08 实战:13 计划 → 17 实际,5 个"保留"被归档后 restore 拉回)——重要技能先
pin,别依赖预览结论 - ⚠️ /refine 创建技能时 references 引用不落盘:review fork 生成的 SKILL.md 常含
references/xxx.md引用,但创建流程只写 SKILL.md 一个文件(日志只见 "Skill created · Patched SKILL.md")。2026-08-13 实测:dsh-ops 的 3 个 references 全缺;全库扫描 20+ 处同类缺失(hermes-agent、hermes-mcp-servers、memory-storage-management、session-knowledge-capture、web-search 等)——创建/接收 curator 技能后应 skill_view 验证 linked_files,缺失则补写内容或删掉正文引用,避免引用悬空 - ⚠️ curator 标记与 frontmatter author 脱节:技能被用户手动移动/改名(如
mv devops/deepseek-harness deepseek-harness/dsh-ops)后,后端created_by标记丢失 → 即使 SKILL.md frontmatter 写着author: hermes-curator,skill_manage patch 仍报not curator-managed (created_by=None)。2026-08-13 实测:dsh-ops / dsh-web-search-fallback / dsh-architecture 全部变 user-owned。对策:改名前先hermes curator adopt <name>保持托管,或改名后重新 adopt;patch 被拒时不要反复重试,直接 adopt 或走前台流程