乐于分享
好东西不私藏

深挖Hermes源码(三):你的Agent为什么越用越笨

深挖Hermes源码(三):你的Agent为什么越用越笨
 这是Hermes源码解读系列第三篇,每篇都从源码级别解决一个使用Agent中遇到的实际问题。前两篇分别拆解了ReAct循环和SKILL加载机制,解决了SKILL怎么写才能保障被Agent触发的问题。这一篇讲如何在自更新的时候,让Hermes的效果不退化,也是我觉得设计含量最高的部分。建议关注、收藏,推荐给使用Hermes或建设Agent的朋友。 

太长不看版

如果你也在用Hermes,发现它越用越笨、Skill越来越多但效果越来越差,下面是你今天就能做的事:

📌 使用者操作清单

• 纠正Agent时要精确,不要说「这不对」,要说「处理X类问题时用Y方法,不要用Z」——你的抱怨会被直接写进Skill

• 每周跑一次 hermes curator run --dry-run,看看系统打算合并/归档什么

• 对你在意的Skill执行 hermes curator pin skill-xxx,防止被误合并

• 在 config.yaml 里把 stale_after_days 从30调到60(如果你觉得Skill被清理得太快)

📌 Agent建设者设计清单

如果你在设计自己的Agent,可以参考Hermes的设计思路,从下面几个方面进行优化,让你的Agent聪明好用。

• 不同类型学习用不同触发维度(Memory按聊天轮数 / Skill按任务完成次数 / 整合按日历)

• 后台学习绝不阻塞前台,失败用warning不抛异常

• 学习信号分级,越激进门槛越高(补充>修改>创建)

• 必须有整合机制,核心是用对的方式提问(后面源码里会展开)

• LLM驱动的学习模块必须防递归(interval=0 + 迭代上限)

• 知识要有过期机制,但别一刀切删除,要能被重新激活

下面是源码级的解释,为什么这些建议有效。

———

故事是这样的

我之前写过一篇从Hermes和OpenClaw的竞争,看Agent进化论:Skill适者生存,从生物进化论视角看Agent自进化。

Hermes是具备自进化能力Agent的典范。

然而,我用Hermes一段时间后,最近明显感觉它变笨了。

不是那种突然变笨,是一种温水煮青蛙式的退化。响应变慢,经常选错Skill,有时候明明应该用A方案,它非要用一个我两周前临时创建的B方案。

翻了一下 ~/.hermes/skills/,好家伙,攒了快200个Skill。一大半是某次对话里临时产生的,名字类似 skill-fix-timeout-errorskill-debug-env-var,互相重叠,根本分不清谁是谁。

我把马养死了。

然后我去翻它的源码,想搞明白这套自更新机制到底是怎么运作的,有没有什么我能做的事来挽救局面。结果发现,Hermes在自更新这件事上的设计其实非常精细,但它需要使用者配合才能跑好。

全貌:三层学习架构

Hermes的自更新不是一个机制,是三个机制叠在一起跑的。

Layer 1:即时学习(热信号)  对话中 LLM 直接调用 skill_manage → 立即生效  触发:每次 Agent 判断需要时Layer 2:后台反思(温信号)  用户收到响应后,后台线程异步运行 Review Agent  触发:Memory 每 10 个 turn / Skill 每 5 个 iterationLayer 3:Curator 维护(冷信号)  独立进程,大规模知识整合  触发:每 7 天,且用户空闲 > 2小时

解释一下两个术语:turn 是一次用户发消息+Agent回复的完整来回,聊10轮就是10个turn。iteration 是Agent内部执行一次完整动作(思考-调用工具-得到结果)的循环,一个turn里可能包含多个iteration(比如Agent连续调了3次工具才给你回复,就是3个iteration)。

三层用不同的时间维度触发,因为学习对象的性质不同。Memory是「你是谁」的信息,变化慢,用聊天轮数衡量就够了。Skill是「怎么做复杂事」的信息,跟具体执行动作相关,用iteration数更精确。大规模知识整合是低频长期任务,用日历时间。

我之前的问题就出在这里:Layer 1太勤快地创建新Skill,而Layer 3的Curator整合不够及时(默认7天才跑一次),中间的积累期知识库就失控了。

下面逐层看源码。

源码拆解 Layer 2:后台Review怎么跑的

Layer 1(即时学习)没什么好说的,就是对话中Agent觉得该记就调 skill_manage 记了。精髓在Layer 2和Layer 3。

📄 run_agent.py 第14121-14146行

_should_review_skills = Falseif (self._skill_nudge_interval > 0andself._iters_since_skill >= self._skill_nudge_interval  # 默认5and"skill_manage"inself.valid_tool_names):_should_review_skills = Trueif final_response and not interrupted and (_should_review_memory or _should_review_skills):self._spawn_background_review(        messages_snapshot=list(messages),        review_memory=_should_review_memory,        review_skills=_should_review_skills,    )

_spawn_background_review fork一个新的AIAgent在后台线程跑,只给memory和skills两个toolset。

📄 run_agent.py 第3674-3675行 — 防递归

review_agent._memory_nudge_interval = 0# 禁止Review Agent再触发Reviewreview_agent._skill_nudge_interval = 0

同时 max_iterations=16 兜底。两道锁,防止学习模块无限递归触发自己——Review Agent自己学到东西了,不会再触发一个新的Review Agent去反思这次学习。

后台执行时所有输出重定向到 /dev/null,失败了用warning不抛异常。用户看到的只是一行「💾 Skill updated · Memory saved」,主对话完全不受影响。

源码拆解 Layer 3:Curator怎么防止知识爆炸

Layer 3是我翻源码后最想了解的部分,也是解决我「马养死了」问题的关键。

📄 agent/curator.py 第56-59行

DEFAULT_INTERVAL_HOURS = 24 * 7# 7天DEFAULT_MIN_IDLE_HOURS = 2# 空闲2小时才跑DEFAULT_STALE_AFTER_DAYS = 30# 30天没用 → STALEDEFAULT_ARCHIVE_AFTER_DAYS = 90# 90天没用 → 归档

Curator做两件事。

第一件:自动淘汰过期知识(纯规则,不需要LLM)

📄 curator.py 第255-295行 — 自动生命周期

defapply_automatic_transitions(now):    stale_cutoff = now - timedelta(days=30)    archive_cutoff = now - timedelta(days=90)for skill in all_agent_created_skills:if skill.last_activity <= archive_cutoff:            archive_skill(skill)elif skill.last_activity <= stale_cutoff:            mark_as_stale(skill)elif skill.was_stale and skill.last_activity > stale_cutoff:            reactivate_skill(skill)  # 重新用到了,自动激活

30天没用标记STALE(降权,不参与匹配),90天归档(彻底移出)。但如果某个STALE的Skill又被用到了,自动复活。不是一刀切删除,是可逆的退化。

第二件:LLM驱动的「伞状合并」(精髓)

📄 curator.py 第359-399行 — 伞状合并Prompt

"For each cluster with 2+ members, do NOT ask 'are these pairsoverlapping?' — ask 'what is the UMBRELLA CLASS these skills allserve? Would a maintainer name that class and write one skill forit?' If yes, pick (or create) the umbrella and absorb the siblings."

注意这个提问方式。不问「这两个Skill是否重叠」(这么问太容易答是,导致过度合并把有用的也合没了),而是问「这些Skill共同服务的类别是什么?如果你是一个维护者,你会给这个类别起名字、写一个统一的Skill吗?」只有真正属于同一类的才会被合并。

📄 run_agent.py 第3462-3467行 — 命名强制类级

"The name MUST be at the class level.The name MUST NOT be a specific PR number, error string, featurecodename, library-alone name, or 'fix-X / debug-Y / audit-Z-today'session artifact."

不允许创建 skill-fix-bug-1234 这种只对今天有意义的名字。从命名层面就杜绝碎片化。

源码拆解:学习信号的四级优先级(贯穿Layer 1和Layer 2)

这个优先级同时约束Layer 1的即时学习和Layer 2的后台反思。

📄 run_agent.py 第3434-3467行

1️⃣ UPDATE A CURRENTLY-LOADED SKILL     ← 最热,直接改当前在用的2️⃣ UPDATE AN EXISTING UMBRELLA         ← 中等,扩展已有类别3️⃣ ADD A SUPPORT FILE (references/)    ← 低成本,补充参考细节4️⃣ CREATE A NEW CLASS-LEVEL UMBRELLA   ← 最冷,创建全新知识单元门槛最高

越激进的改动门槛越高。优先补充已有知识,尽量不创建新的。这样知识库就不会爆炸式增长。

我之前的问题就是Layer 1在即时学习时没有严格遵循这个优先级,太容易创建新Skill了。

源码拆解:你的不满是第一等级信号(Layer 1的输入)

📄 run_agent.py 第3417-3423行

"Frustration signals like 'stop doing X', 'this is too verbose','don't format like this', 'why are you explaining', 'just give methe answer', 'you always do Y and I hate it' are FIRST-CLASS skillsignals, not just memory signals."

一句抱怨不只是修正当前回答,而是直接改写未来所有类似场景的行为模式。Agent的行为改变不需要你说「记住这个」,从日常摩擦中自动捕获。

所以你纠正它的方式,直接决定了它进化的方向。说得越精确,它沉淀出来的知识越干净。

使用者怎么操作,不把马养死

翻完源码之后,我总结出来这几个操作要点:

第一,纠正要精确、要结构化。 不要说「这不对」,要说「处理超时问题时应该先检查DNS再看连接池,不要一上来就建议加timeout」。因为你的不满会直接进Skill(上面那段源码),说得越精确,沉淀出来的知识质量越高。

第二,定期跑 hermes curator run --dry-run 这个命令只预览不执行,让你看到Curator打算合并什么、归档什么。有不同意的,pin住那个Skill。

第三,pin住你在意的Skill。hermes curator pin skill-xxx,被pin的Skill永远不会被自动动。适用于你花了很多时间调教出来的关键Skill。

第四,如果你是重度用户,调Curator频率。 在 config.yaml 里把 curator.interval_hours 从168(7天)减到72-120(3-5天),让整理更频繁,不给垃圾积累的机会。

第五,清理已有的垃圾。 去 ~/.hermes/skills/ 看一眼,把那些 skill-fix-xxx-today 的直接删了。或者等Curator跑的时候,审核它的合并提案。

Agent建设者的抄作业清单

如果你不只是用Hermes,还在自己做Agent系统,可以参考Hermes的思路,从下面几个方面来设计,让你的Agent持续变聪明而不是越用越笨:

① 不同类型的学习,用不同的触发维度。 Memory按聊天轮数,Skill按执行动作数,大规模整合按日历。用错维度要么浪费token要么延迟学习。

② 后台学习绝不阻塞前台。 失败了用warning不抛异常,主对话不受影响。

③ 学习信号分级,越激进门槛越高。 补充已有知识是低门槛,创建全新知识单元是高门槛。

④ 必须有整合机制,而且提问方式很关键。 不要问「这两条知识重不重叠」,要问「它们共同服务的是什么场景?一个人类维护者会把它们归到同一类吗?」前者太容易误合并,后者才能做出正确判断。

⑤ LLM驱动的学习模块必须防递归。 interval设为0 + 迭代上限,两道锁。

⑥ 每条学习带元数据。 谁写的、什么session、什么时间。错了能追踪,能回滚。

⑦ 知识要有过期机制,但必须可逆。 设一个「冷却期」而不是直接删除。冷却期内如果又被用到了,自动恢复。用户也可以手动pin住不想被动的知识。

一句话收尾

Hermes的自更新不是一个feature,是一套生态。它设计得很精细,但不是「设置好就不用管」的东西。

如果你的Agent只有「学」没有「忘」和「整理」,那它迟早会被自己学到的垃圾淹死。使用者也是这个生态的一部分,你纠正它的方式、你审核它的频率,直接决定了它是越来越聪明还是越来越笨。

关注「熵息茶馆」,回复进群,加入Agent技术交流群:

推荐阅读
Hermes是怎么实现ReAct的?源码级拆解Agent推理引擎
从 Hermes 源码看,怎样写出 Agent 真能用的 SKILL
一文搞懂:DeepSeek V1到V4核心技术全解
深度长文 | DeepSeek的七道坎:一家量化基金如何用穷人思维重写AI规则
重磅!DeepSeek V4 官方技术报告核心亮点全解析
从Hermes和OpenClaw的竞争,看Agent进化论:Skill适者生存

觉得有用的话,随手点个赞、在看、转发三连吧,如果想第一时间收到推送,也可以给我个星标⭐~