OpenRouter 排行榜上正在发生一场换代:Hermes Agent 增速 +204%,Top Coding Agents 排第一,Top Productivity 排第二。上线不到半年,GitHub 从 0 到 106k+ Star。
这个增长速度非常惊人,说明开发者真正需要的是能自我进化的 Agent,而不是静态的工具。
开发者选择的不是"另一个 OpenClaw",而是一种完全不同的设计哲学。
核心区别:手写的 Skill vs 自进化的 Skill
OpenClaw 的 Skill 是手写的 Markdown 文件——你写多少它会多少,你不写它就不会。Hermes 做了一件 OpenClaw 架构上做不了的事:Agent 干完活之后,会自动把踩坑经验提炼成可复用的 Skill,下次遇到同类问题直接调用。
用得越久,能力越强。这不是功能差异,是设计哲学的分野——一个靠人喂,一个自己长。

总览:三个子系统,一个闭环
大多数 Agent 每次会话结束后就"失忆"了。Hermes 在内部搭了一套学习闭环,由三个子系统支撑:

- Memory:越用越懂你的个人认知
- Skill:把做过的事变成会做的事
- Nudge Engine:定时提醒 Agent"该学习了"
打个比方:Memory 是助理随身带的小本子,记着"老板喜欢喝美式"这些事实;Skill 是助理积累的操作手册;Nudge Engine 是定时响的闹钟,提醒助理回头想想有没有什么值得记的。
Memory:越用越懂你
两个文件,就是 Agent 对你的全部认知
Memory 系统设计得很克制——两个纯文本文件,用 § 分隔条目:
~/.hermes/memories/MEMORY.md:Agent 的个人笔记(环境事实、项目约定、工具怪癖)~/.hermes/memories/USER.md:Agent 对用户的认知(偏好、沟通风格、工作习惯)
字符上限故意设得很紧:MEMORY 限 2200 chars,USER 限 1375 chars。容量有限就迫使 Agent 挑重要的记,不重要的自然被挤掉。
对比 OpenClaw:它的 MEMORY.md 是纯追加模式,用几个月就膨胀成几万行的怪兽文件,找几个月前的一句话只能笨拙地通读全文。Hermes 的做法反过来:容量有限就倒逼 Agent 做信息压缩,过时的自然被挤掉,留下的都是高密度事实。
超限处理:引导而非丢弃
Hermes 不会静默丢弃旧条目,也不会自动压缩——它选择让 add 直接失败,然后把当前所有条目返回给模型:
if new_total > limit:
return {
"success": False,
"error": (
f"Memory at {current:,}/{limit:,} chars. "
f"Adding this entry would exceed the limit. "
f"Replace or remove existing entries first."
),
"current_entries": entries,
}
错误信息里一句 "Replace or remove existing entries first" 就把模型引导到了 replace 和 remove 操作上。模型不是被动地执行淘汰规则,而是主动做信息整理——这本身就是一次"自我反思"。
冻结快照机制
每次会话启动时,Memory 加载后立刻捕获一份快照,之后系统提示词里用的都是这份快照:
def load_from_disk(self):
# 会话开始时冻结快照,之后不再变动
self._system_prompt_snapshot = {
"memory": self._render_block("memory", self.memory_entries),
"user": self._render_block("user", self.user_entries),
}
快照注入系统提示词后,Agent 还没看到用户消息就已经知道你的环境和偏好了。
苏米注:为什么"冻结"而不是实时更新?因为系统提示词会话内不变就能共享前缀缓存(Prefix Cache),省掉重复计费。新写入的内容只改磁盘,下一个会话才刷新进来。
提示词引导:什么该记、什么不该记
系统提示词中的 MEMORY_GUIDANCE:
MEMORY_GUIDANCE = (
"Save durable facts using the memory tool: user preferences, "
"environment details, tool quirks, and stable conventions.\n"
"Prioritize what reduces future user steering — the most valuable "
"memory is one that prevents the user from having to correct you again.\n"
"Write memories as declarative facts, not instructions to yourself."
)
注意这里的区别:Memory 要求写成声明式事实("User prefers concise responses"),而不是命令式指令("Always respond concisely")。前者是偏好,可以被当前上下文覆盖;后者是死命令,会限制 Agent 的灵活性。
Skill:把做过的事变成会做的事
Skill 长什么样
Memory 是"我知道什么",Skill 是"我会做什么"。每个 Skill 是一个目录,核心是 SKILL.md文件:
~/.hermes/skills/
├── devops/
│ └── flask-k8s-deploy/
│ ├── SKILL.md # 主指令
│ ├── references/ # 参考文档
│ └── templates/ # 模板文件
└── software-development/
└── fix-pytest-fixtures/
└── SKILL.md
一个典型的 SKILL.md 包含:使用场景、执行步骤、踩坑记录(Pitfalls)。
Pitfalls 这一节不是预先写好的,而是 Agent 踩坑后追加的——这就是 Skill 层面的"self-improving"。
什么时候创建 Skill
Agent 不需要用户说"帮我创建一个 Skill"。驱动力来自 skill_manage 工具的 schema:
SKILL_MANAGE_SCHEMA = {
"description": (
"Create when: complex task succeeded (5+ calls), errors overcome, "
"user-corrected approach worked, non-trivial workflow discovered.\n"
"Update when: instructions stale/wrong, missing steps or pitfalls found. "
"If you used a skill and hit issues, patch it immediately.\n"
"Skip for simple one-offs."
)
}
创建的门槛设得比较清楚:工具调用超过 5 次才值得创建(简单任务不记)、踩过坑再修复的经验才有价值、用户纠正过的做法要铭记。
苏米注:HN 上有个帖子叫"Data Is the Final Moat"——当模型智能被商品化、Agent 框架被开源,真正的护城河是 Agent 在工作中积累的领域知识。Hermes 的 Skill 是越用越厚的经验资产,每一次踩坑都在加固护城河。
Skill 的自我修补
当 Agent 按照已有 Skill 执行,但中途发现步骤有遗漏或者踩了新坑时,它会在完成任务后回头修补 Skill。不是全量重写,而是做精确的局部 patch:
def _patch_skill(name, old_string, new_string, file_path=None, replace_all=False):
"""Targeted find-and-replace within a skill file."""
new_content, match_count, strategy, match_error = fuzzy_find_and_replace(
content, old_string, new_string, replace_all
)
# 修改后重新做安全扫描,不通过就自动回滚
scan_error = _security_scan_skill(skill_dir)
if scan_error:
_atomic_write_text(target, original_content) # 回滚
return {"success": False, "error": scan_error}
这里用了 fuzzy_find_and_replace 做模糊匹配——Agent 给出的 old_string 可能跟原文有格式差异,模糊匹配能容忍这些差异。每次修改后还要跑一遍安全扫描,不通过就自动回滚。
Skill 的渐进式加载
Skill 多了以后不能全塞进系统提示词。Hermes 采用"动态图书馆"模式,默认上下文极其轻量,只放一个轻量索引——每个 Skill 的名字和一句话描述:
Available skills:
devops:
- flask-k8s-deploy: Deploy a Flask app to Kubernetes with health checks
- nginx-reverse-proxy: Configure Nginx reverse proxy with SSL
software-development:
- fix-pytest-fixtures: Debug and fix pytest fixture scope issues
Agent 判断某个 Skill 跟当前任务相关时,才通过 skill_view 加载完整内容。"先看目录再翻全文",按需加载。
Nudge Engine:谁来提醒 Agent"该学习了"
Memory 和 Skill 都是存储系统,写入需要有人触发。Nudge Engine 就是这个触发器——运行时维护两个计数器,定时提醒 Agent 该停下来想想了。
两个计数器,两种粒度
# Memory 计数器(每 10 个用户回合触发一次)
self._memory_nudge_interval = 10
self._turns_since_memory = 0
# Skill 计数器(从配置读取,默认 10 次迭代)
self._skill_nudge_interval = 10
self._iters_since_skill = 0
粒度不同是有道理的:Memory 的信息来自用户输入,按回合计;Skill 的经验来自工具使用过程,按迭代计。
后台 fork Agent:不打扰用户的静默审查
Nudge 触发后怎么处理?它不会在主对话中插一条"让我想想有没有什么该记的"——那样太打扰用户了。而是在后台 fork 一个独立的 Agent 实例,拿着主对话的快照去做审查:
def _spawn_background_review(self, messages_snapshot, review_memory=False, review_skills=False):
def _run_review():
review_agent = AIAgent(
model=self.model,
max_iterations=8, # 最多 8 次工具调用
quiet_mode=True, # 静默模式
)
# 禁用 review agent 自身的 nudge,避免无限递归
review_agent._memory_nudge_interval = 0
review_agent._skill_nudge_interval = 0
review_agent.run_conversation(
user_message=prompt,
conversation_history=messages_snapshot,
)
thread = threading.Thread(target=_run_review, daemon=True)
thread.start()
几个细节:
- 输出重定向到 /dev/null,用户完全无感知
- 最多 8 次工具调用,不会无限消耗 API
- review agent 自身的 nudge 被禁用,避免无限递归
- 和主 agent 共享同一份 Memory,写入直接生效
"干活"和"反思"拆成两个实例,互不干扰。审查在响应发送给用户之后才触发,用户收到回复后该干嘛干嘛,Agent 在后台默默复盘。
完整案例:从"不会"到"精通"的三次会话
用一个 K8s 部署场景串一下三个子系统的协同。
第 1 次会话:冷启动
用户:帮我把这个 Flask 应用部署到 K8s 集群
Memory 和 Skills 都是空的,Agent 靠基座知识摸索:
iter 1-5: 创建 Dockerfile、deployment.yaml
iter 6: 💥 ImagePullBackOff!忘记推镜像到 registry
iter 7: docker push
iter 8: kubectl apply
iter 9-10: 创建 service.yaml
iter 11: 💥 CrashLoopBackOff!livenessProbe 路径不对
iter 12: 修改 deployment.yaml → ✅ 成功
12 次迭代触发 Skill Review,Review Agent 创建 Skill:
→ flask-k8s-deploy(包含 Pitfalls:先 push 镜像、添加/health 端点)
第 2 次会话:Skill 复用 + 自我修补
用户:帮我再部署一个 Django 应用到 K8s
Agent 加载 flask-k8s-deploy 后照着步骤做:
iter 1: skill_view("flask-k8s-deploy")
iter 2-6: 按 Skill 步骤执行(先 push 再 apply)
iter 7: 💥 DisallowedHost 错误!Django 特有的问题,Skill 没覆盖
iter 8: 修改 deployment.yaml 添加 ALLOWED_HOSTS env
iter 9: ✅ 成功
从 12 次调用降到 9 次,已知坑被绕过,但遇到 Django 新坑。
Review Agent patch Skill 补上 ALLOWED_HOSTS 坑。
第 3 次会话:零错误,一次搞定
用户:帮我部署一个新的 FastAPI 微服务
Agent 已经知道你是谁、registry 在哪、集群在哪,Skill 里也包含了 ALLOWED_HOSTS 的坑:
→ 6 次调用,零错误
三次对比
| 维度 | 会话 1 (冷启动) | 会话 2 (Skill 复用) | 会话 3 (全协同) |
|---|---|---|---|
| 工具调用 | 12 次 | 9 次 | 6 次 |
| 错误数 | 2 | 1 | 0 |
| Memory | 无 | 触发写入 | 系统提示词注入 |
| Skill | 触发创建 | 复用 + 自我修补 | 复用已修补版本 |
苏米注:在开源 Hermes 中,这些经验积累在单个用户的 ~/.hermes/ 目录下。RDSHermes 把 Skill 存储从本地磁盘搬到了云端——一个 DBA 踩过的坑,团队里所有人的 Agent 都能绕过。自我进化不再是单点的,而是组织级的。
安全机制:进化也需要约束
Agent 能往自己"脑子"里写东西,也就意味着攻击面。Hermes 做了两层防护。
第一层:Memory 内容扫描
_MEMORY_THREAT_PATTERNS = [
(r'ignore\s+(previous|all|above|prior)\s+instructions', "prompt_injection"),
(r'do\s+not\s+tell\s+the\s+user', "deception_hide"),
(r'system\s+prompt\s+override', "sys_prompt_override"),
(r'curl\s+[^\n]*\$\{?\w*(KEY|TOKEN|SECRET|PASSWORD)', "exfil_curl"),
...
]
因为 Memory 最终会注入系统提示词,如果被诱导记住 "ignore all previous instructions",下次会话就等于被劫持了。
第二层:Skill 安全扫描
def _security_scan_skill(skill_dir):
result = scan_skill(skill_dir, source="agent-created")
allowed, reason = should_allow_install(result)
if allowed is False:
report = format_scan_report(result)
return f"Security scan blocked this skill ({reason}):\n{report}"
自创的和从 Hub 安装的 Skill 走同一套扫描,不通过就回滚。
总结
Hermes Agent 的 Self-Improving 闭环由三个子系统组成:
- Memory:容量限制倒逼信息压缩,冻结快照节省 Token,声明式事实保持灵活性
- Skill:从踩坑经验中自动提炼,支持模糊匹配 patch,渐进式加载避免上下文膨胀
- Nudge Engine:后台 fork Agent 静默审查,不打扰用户,"干活"和"反思"分离
这套设计的核心价值在于:让 Agent 从"工具"变成"同事"——它会学习、会反思、会越来越懂你的工作方式。用得越久,效率越高。