深入源码:Hermes Agent 如何实现 "Self-Improving"
深入源码:Hermes Agent 如何实现 "Self-Improving"
来源类型: 微信公众号文章
日期: 2026-06-02
标签: AI, OpenClaw, 记忆系统, 网络安全, 编程
原文链接: https://mp.weixin.qq.com/s/Qi68ptxQRyiA932JU49SYQ
摘要
背景 OpenRouter 排行榜上正在发生一场换代:Hermes Agent 增速 +204%,Top Coding Agents 排第一,Top Productivity 排第二。上线不到半年,GitHub 从 0 到 106k+ Star。开发者在用数据说话——选的不是"另一个 OpenClaw",是一种完全不同的东西。 区别在哪?OpenClaw 的 Skill 是手写的 Markdown 文件——你写多少它会多少,你不写它就不会。Hermes 做了一件 OpenClaw 架构上做不了的事:Agent 干完活之后,会自动把踩坑经验提炼成可复用的 Skill,下次遇到同类问题直接调用...
核心内容
背景
OpenRouter 排行榜上正在发生一场换代:Hermes Agent 增速 +204%,Top Coding Agents 排第一,Top Productivity 排第二。上线不到半年,GitHub 从 0 到 106k+ Star。开发者在用数据说话——选的不是"另一个 OpenClaw",是一种完全不同的东西。
区别在哪?OpenClaw 的 Skill 是手写的 Markdown 文件——你写多少它会多少,你不写它就不会。Hermes 做了一件 OpenClaw 架构上做不了的事:Agent 干完活之后,会自动把踩坑经验提炼成可复用的 Skill,下次遇到同类问题直接调用。用得越久,能力越强。这不是功能差异,是设计哲学的分野——一个靠人喂,一个自己长。
这篇文章拆开 Hermes 的源码,看看这个 Self-Improving 闭环到底怎么跑的。文末也会聊聊 RDSHermes 怎么把这套能力搬给不写代码的人用。
仓库地址:
github.com/NousResearch/hermes-agent
总览:三个子系统,一个闭环
大多数 Agent 每次会话结束后就"失忆"了。Hermes 在内部搭了一套学习闭环,由三个子系统撑起来:
打个比方:Memory 是助理随身带的小本子,记着"老板喜欢喝美式"这些事实;Skill 是助理积累的操作手册——"部署 K8s 第 2 步一定要先推镜像";Nudge Engine 是定时响的闹钟,提醒助理回头想想有没有什么值得记的。
Memory:越用越懂你
两个文件,就是 Agent 对你的全部认知
Memory 系统设计得很克制——两个纯文本文件,用 § 分隔条目:
-
- ~/.hermes/memories/├── MEMORY.md # Agent 的个人笔记(环境事实、项目约定、工具怪癖)└── USER.md # Agent 对用户的认知(偏好、沟通风格、工作习惯)
字符上限故意设得很紧:MEMORY 限 2200 chars,USER 限 1375 chars。容量有限就迫使 Agent 挑重要的记,不重要的自然被挤掉。对比 OpenClaw——它的 MEMORY.md 是纯追加模式,用几个月就膨胀成几万行的怪兽文件,找几个月前的一句话只能笨拙地通读全文。Hermes 的做法反过来:容量有限就倒逼 Agent 做信息压缩,过时的自然被挤掉,留下的都是高密度事实。
具体实现上,MemoryStore 维护两组平行状态——实时可写的条目列表,和会话开始时冻结的快照:
-
-
-
-
tools/memory_tool.py:116-122class MemoryStore: def init(self, memory_char_limit=2200, user_char_limit=1375): self.memory_entries: List[str] = [ ] self.user_entries: List[str] = [ ] self.memory_char_limit = memory_char_limit self.user_char_limit = user_char_limit self._system_prompt_snapshot: Dict[str, str] =
但"设了上限"只是第一步,关键是超限之后怎么处理。Hermes 不会静默丢弃旧条目,也不会自动压缩——它选择让 add 直接失败,然后把当前所有条目返回给模型:
-
-
-
-
-
-
tools/memory_tool.py:248-259if new_total > limit: current = self._char_count(target) return { "success": False, "error": ( f"Memory at {current:,}/{limit:,} chars. " f"Adding this entry ({len(content)} chars) would exceed the limit. " f"Replace or remove existing entries first." ), "current_entries": entries, "usage": f"{current:,}/{limit:,}", }
错误信息里一句 "Replace or remove existing entries first" 就把模型引导到了 replace 和 remove 操作上。同时返回 current_entries,让模型能看到现有的所有条目,自己决定哪些过时了该删、哪些可以合并压缩。模型不是被动地执行淘汰规则,而是主动做信息整理——这本身就是一次"自我反思"。
冻结快照机制
每次会话启动时,Memory 加载后立刻捕获一份快照,之后系统提示词里用的都是这份快照:
-
-
-
-
-
tools/memory_tool.py:124-140def load_from_disk(self): mem_dir = get_memory_dir() self.memory_entries = self._read_file(mem_dir / "MEMORY.md") self.user_entries = self._read_file(mem_dir / "USER.md") # 会话开始时冻结快照,之后不再变动 self._system_prompt_snapshot = { "memory": self._render_block("memory", self.memory_entries), "user": self._render_block("user", self.user_entries), }快照注入系统提示词后,Agent 还没看到用户消息就已经知道你的环境和偏好了。为什么"冻结"而不是实时更新?因为系统提示词会话内不变就能共享前缀缓存(Prefix Cache),省掉重复计费。新写入的内容只改磁盘,下一个会话才刷新进来。
提示词引导:什么该记、什么不该记
Agent 怎么知道什么时候该往 Memory 里写东西?靠 Prompt 引导。系统提示词中的 MEMORY_GUIDANCE:
-
-
-
-
-
agent/prompt_builder.py:1
...(内容截断,完整内容请查看原文)
本页由自动化脚本生成,待人工审核补充