Hermes Agent 核心功能与 Skill 自进化机制
一句话定位
Hermes Agent 是 MemTensor 出品的一个 Python AI agent 外壳,它自己不带记忆和进化逻辑,而是通过一个无状态的 JSON-RPC 适配层,接入 MemOS 的 @memtensor/memos-local-plugin 共享算法核心——从而拥有「会自己长出可调用 skill」的记忆引擎。
它的「智能」刻意分布在两个进程里:Python 侧只负责会话生命周期(建会话、检索注入、落盘、反馈、收尾),Node/TypeScript 侧负责所有重活(四层记忆、奖励回传、skill 结晶与生命周期)。这种切分让 agent 本体保持极薄,而算法可以跨多个 agent 复用。
架构:Python 外壳 + TypeScript 记忆引擎
Hermes 的 Python 进程本身是完全无状态的——每一个 MemoryProvider 方法都只是一个薄代理,把调用翻译成 JSON-RPC。所有算法逻辑(L1/L2/L3、skill、检索、反馈、决策修复)都住在 TS 写的 core/ 里。两者通过 stdio JSON-RPC 2.0 通信:
┌────────────────────┐ stdio JSON-RPC 2.0 ┌─────────────────────┐│ Hermes Python 进程 │ ─────────────────────▶ │ node bridge.cts ││ MemTensorProvider │ ◀── events.notify ──── │ → MemoryCore(core/)│└────────────────────┘ └─────────────────────┘为什么用子进程 stdio 而非常驻 HTTP daemon: 端口协商、过期进程回收、Python↔Node 鉴权、重复日志管道——这些问题全部从 OS 进程模型里「免费」得到。Hermes 会话本来就有界,每次会话 spawn 一个 node 子进程的代价可以忽略;会话结束时 stdin 关闭,子进程自动退出,生命周期干净。
核心功能:四层记忆 + 奖励回传
Hermes agent 实现了一个 MemoryProvider 接口,每个 hook 映射到 core 的一个方法——这张表就是它的完整功能面:
| Hermes hook | 映射方法 | 作用 |
|---|---|---|
initialize(session_id) | session.open + episode.open | 开会话 + 开默认 episode |
prefetch(query) | turn.start | 模型调用前拉取要注入的上下文(三层检索) |
sync_turn(user, assistant) | turn.end(延迟异步 flush) | 持久化已完成的一轮 |
handle_tool_call("memory_*") | memory.search / memory.timeline | 暴露给模型的显式记忆工具 |
submit_feedback(...) | feedback.submit | 记录用户显式反馈 |
on_session_end | episode.close + session.close | 关闭并 flush |
shutdown | 关闭 transport | 干净杀掉 node 子进程 |
把 core 那一层算进来,Hermes agent 实际拥有 四层记忆 + 一个反馈驱动的自进化闭环:
- L1 trace — 步骤级落地记录(action + observation + reflection + value V)
- L2 policy — 跨任务归纳出的「子任务策略」,带
gain(比基线好多少) - L3 world model — 从 L2+L1 压缩出的环境认知
- Skill — 可被 agent 直接调用的「结晶能力」(这正是自进化的产物)
奖励回传是驱动进化的燃料:用 reflection 加权的 R_human ∈ [-1,1](rubric LLM 三轴打分 + 启发式兜底),沿 trace 反向传播:
V_T = R_humanV_t = α_t · R + (1 − α_t) · γ · V_{t+1}推理时,一个三层检索器(Tier-1 skill → Tier-2 trace/episode → Tier-3 world model)在模型调用前,用 RRF 融合 + MMR 去重,把「对的上下文」注入到「对的时刻」。
Skill 自进化:一个闭环
这是 Hermes agent 最有意思的部分。实现位于 core/skill/,对应规范 Reflect2Evolve V7 §2.5,是一个事件驱动、闭环的过程:
L1 traces ──reward回传──▶ L2 policy (induced/updated) │ 触发事件: l2.policy.induced / updated(active) / reward.updated ▼ ① 资格判定 evaluateEligibility → skip / crystallize / rebuild ▼ ② 收集证据 gatherEvidence (0.7·value + 0.3·cosine 排序, char-cap) ▼ ③ LLM 结晶 crystallizeDraft (skill.crystallize prompt → 结构化草稿) ▼ ④ 启发式校验 verifyDraft (覆盖率≥50% + 共振≥minResonance, 无LLM) ▼ ⑤ 打包 buildSkillRow (procedureJson + invocationGuide + eta + vec) ▼ status 永远 = probationary(试用态) ⑥ 生命周期 applyFeedback (η + trials + status 迁移) ▼ Tier-1 检索只取 status∈{probationary,active} 且 η≥minEtaForRetrieval 的 skill → 把它的 invocationGuide 注入下一轮 system prompt ▼ 改变 agent 行为 → 产生新的 L1 trace ……(闭环)一个 Skill 的形式定义:
Skill = (name, invocationGuide, procedure, parameters, examples, η, trialsAttempted, trialsPassed, sourcePolicyIds, status)η ∈ [0,1]—— 可靠度。同时控制检索过滤(minEtaForRetrieval,默认 0.5)和生命周期迁移(retireEta,默认 0.25)。status ∈ {probationary, active, retired}—— 检索可见性;只有active(部分路径含probationary)才会被注入到 prompt。
闭环的六个阶段:资格判定(L2 policy 变 active 且 gain/support 达标,且没有更新鲜的 skill 引用它)→ 收集证据(给 L1 trace 打分排序、char-cap 截断)→ LLM 结晶(产出结构化草稿)→ 启发式校验(命令型 token 覆盖率 + 证据共振,纯字符串匹配)→ 打包(生成结构化过程 + 调用指南 + η + 向量)→ 生命周期(由 applyFeedback 驱动 η 和 status 迁移)。
三条让自进化「不崩」的设计
自进化最大的风险是:一次 LLM 幻觉,或一次噪声 reward,就把垃圾 skill 固化进检索池。Hermes 用三条规则守住底线。
① 结晶靠 LLM,但晋升绝不靠 LLM。
verifyDraft 只做两件确定性检查:草稿里的命令型 token(如 `apk add`、docker.build、rg)在证据 trace 里的覆盖率 ≥ 50%;以及证据共振(≥ minResonance 比例的 trace 与草摘要有 ≥2 个 token 重叠)≥ 0.5。即便校验过了,新 skill 永远是 probationary,必须靠真实 trial 攒 η 才能转正。一条 LLM 幻觉不可能绕过 trial 直接变成永久工具——校验是「第一道防线防幻觉工具名」,trial 才是「最终防意图错误」。
② η 用 Beta(1,1) 后验,单次噪声杀不死好 skill。
trial.pass/fail : η' = clamp01( (trialsPassed + 1) / (trialsAttempted + 2) ) # Beta(1,1) 后验reward 漂移 : η' = clamp01( 0.7·η + 0.3·gain ) # 混合而非覆盖user 点赞/踩 : η' = clamp01( η ± etaDelta ) # etaDelta 默认 0.1Beta(1,1) 先验让早期 trial 不至于把 η 在 0 和 1 之间甩来甩去——2/3 passes 得 η ≈ 0.6 而非 0.67,0/3 passes 得 η = 0.2 而非 0。而 reward 漂移刻意「混合」而非「覆盖」,就是为了一次嘈杂的 reward 不能扳倒一个经过多次 trial 的 skill。
③ 生命周期是一张清晰的状态机。
| 信号 | 对 η 的影响 | 可能的状态迁移 |
|---|---|---|
trial.pass | Beta 后验 | probationary → active(达阈值) |
trial.fail | Beta 后验 | probationary → retired(未达阈值) |
user.positive | η += 0.1 | retired → probationary(复活) |
user.negative | η -= 0.1 | 任意 → retired(跌破 retireEta) |
reward.updated | 0.7η + 0.3gain | 任意 → retired(跌破 retireEta) |
还有一条 rebuild 机制:当 policy 发生漂移(policy.updatedAt > skill.updatedAt),会在原地用同一个 id 重建 skill,η 结转、不重复造轮子。而 retired skill 不阻塞重新结晶——它被视为「该 policy 暂无 skill」,可以被全新 skill 完全替换。
工程取舍:什么时候值得借鉴
这套设计的工程鲁棒性体现在三个层面,也是判断「要不要抄」的依据:
- 全程异步、事件驱动——订阅挂在
attachSkillSubscriber上,监听l2.policy.induced/l2.policy.updated(active)/reward.updated,绝不阻塞 reward / L2 pipeline。一个慢的下游消费者不能拖垮主流程。 - 故障隔离——批次里某一个 policy 失败只会发
skill.failed {stage, reason}事件,不抛异常、不影响其它 policy。运行级取消从不使用,编排器返回rejected/warnings计数让调用方断言。 - 审计可观测——每个
skill.crystallized/skill.retired都进永不被删的logs/audit.jsonl,并在 viewer 的 Skills 视图里实时可见(status、η、trial 计数)。
适合借鉴的场景:你的 agent 需要从自己的历史经验里持续沉淀可复用能力,且不能容忍「一次坏运气毁掉好工具」。不适合的场景:一次性脚本、无反馈通道的单轮工具调用——没有 reward 回传,闭环就断了,整套机制退化成空转。
两个叫 Hermes 的东西别搞混
本地生态里还有另一个叫 Hermes 的东西(ECC 插件 everything-claude-code 文档里的 operator shell),定位是「终端原生的运营者外壳」,把重复工作流蒸馏成 skill。但它只是人工/半自动地把工作流导入成 skill,没有 η、没有 Beta 后验、没有 probationary→active 的状态机——换句话说,没有算法闭环。
判断依据很简单:你问的「核心功能 + skill 自进化」明确对应 MemTensor 的 hermes-agent。看到「Reflect2Evolve V7」「η 可靠度」「Trial 攒分晋升」这些词,就是它;只看到「把工作流 sanitize 后导入」的,是另一个。