Hermes Agent 自进化架构的源码级拆解
大家好,我是玄姐。
PS:
SDD AI 编程干货直播,欢迎点击预约,直播见。
当大多数 AI Agent 还在"干完就忘"时,Hermes 做了一件架构层面的事:它让 Agent 具备了"事后复盘"的能力。本文从源码层面拆解其 Memory、Skill、Nudge Engine 三大子系统,并探讨这套机制在企业场景中的落地思路。

一、问题的本质:为什么 Agent 总是"金鱼记忆"?
当前主流 AI Agent 有一个共同痛点:会话隔离。每次对话结束,Agent 对用户的认知归零:你的代码风格、项目约定、环境怪癖,下次见面全部重来。
更深层的问题是:Agent 不会从失败中学习。今天踩过的坑,明天照踩不误。你纠正过十次的做法,第十一次它依然按老路子来。
这不是模型能力问题,是架构设计问题。大多数 Agent 框架把"记忆"当成一个外挂的向量数据库,只存不整理;把"技能"当成静态的配置文件,只读不写。
Hermes Agent 的核心设计哲学是:Agent 应该像人一样,干完活后主动复盘,把经验沉淀为可复用的资产。
二、总览:三个子系统构成的自进化闭环
Hermes 在内部搭建了一套"学习闭环",由三个子系统协同支撑:
|
子系统 |
职责 |
类比 |
|---|---|---|
| Memory |
记住事实(你是谁、环境什么样) |
助理的随身笔记本 |
| Skills |
记住怎么做(操作流程、踩坑经验) |
助理的操作手册 |
| Nudge Engine |
定时触发复盘 |
提醒助理"回头看看"的闹钟 |
用户的每一次对话,都会同时流入 Memory 和 Skill 两条线;Nudge Engine 则按固定节奏触发后台审查,决定哪些该记、哪些该存、哪些该修。
三、Memory 子系统:在容量限制下做信息压缩

3.1 极简存储:两个文本文件
Hermes 的 Memory 设计非常克制:只有两个纯文本文件,用§分隔条目:
~/.hermes/memories/├── MEMORY.md #环境事实、项目约定、工具怪癖└── USER.md # 用户偏好、沟通风格、工作习惯
关键设计:硬性容量上限
MEMORY.md 限制2200 字符
USER.md 限制1375 字符
这个设计看似反直觉,为什么不给更多空间?因为容量有限会倒逼 Agent 做信息压缩。过时的、低价值的记忆自然被挤掉,留下的都是高密度事实。相比之下,纯追加模式的记忆文件用几个月就会膨胀成几万行,检索效率极低。
3.2 超限处理:让模型自己决定取舍
当新增内容超出上限时,Hermes 不会静默丢弃,而是让操作失败,并把当前所有条目返回给模型:
Memory at 1,800/2,200 chars. Adding this entry (500 chars) would exceed the limit. Replace or remove existing entries first.
模型收到错误后,会主动调用 replace 或 remove 操作,自己判断哪些过时、哪些可以合并。这本身就是一次"自我反思"。
3.3 冻结快照:省钱的工程智慧
每次会话启动时,Memory 加载后会立即捕获一份快照,之后系统提示词里用的都是这份冻结版本:
def load_from_disk(self): self.memory_entries = self._read_file(...) self.user_entries = self._read_file(...) 会话开始时冻结,之后不再变动 self._system_prompt_snapshot = { "memory": self._render_block(...), "user": self._render_block(...), }
为什么冻结而不是实时更新? 因为系统提示词会话内不变,就能共享前缀缓存(Prefix Cache),避免每轮 API 调用重复计费。新写入的内容只改磁盘,下一个会话才刷新,用延迟一致性换成本优化。
3.4 记忆的内容规范
系统提示词中对 Memory 有明确的写入引导:
"Write memories as declarative facts, not instructions to yourself.'User prefers concise responses' ✓'Always respond concisely' ✗"
声明式事实("用户喜欢简洁回复")vs 命令式指令("永远简洁回复")的区别在于:前者是偏好,可以被当前上下文覆盖;后者是死命令,会限制 Agent 的灵活性。
同时,Tool Schema 里有一句关键边界规则:
"If you've discovered a new way to do something, save it as a skill."
Memory 不存操作步骤,操作步骤归 Skill 管。一句话划清了两个系统的职责边界。
四、Skill 子系统:把踩过的坑变成组织能力

4.1 Skill 的结构
每个 Skill 是一个目录,核心是SKILL.md文件:
~/.hermes/skills/├── devops/│ └── flask-k8s-deploy/│ ├── SKILL.md 主指令(YAML frontmatter + Markdown)│ ├── references/ # 参考文档│ └── templates/ # 模板文件
一个典型的 SKILL.md 结构:
---name: flask-k8s-deploydescription: Deploy a Flask app to Kubernetes with health checksversion: 1.0.0---
Flask K8s Deployment
## When to use- User wants to deploy a Flask/Python app to Kubernetes
## Steps1. Create Dockerfile with gunicorn (not dev server)2. Build and push image to registry BEFORE creating deployment3. Write deployment.yaml with livenessProbe pointing to /health...
## Pitfalls- MUST push image to registry before kubectl apply- Flask 默认没有 /health 端点,需要手动添加- livenessProbe path 必须返回 200
注意 Pitfalls 这一节不是预先写好的,而是 Agent 踩坑后自动追加的。这就是 Skill 层面的"自我进化"。
4.2 自动创建:什么值得记?
Agent 不需要用户说"帮我创建一个 Skill"。skill_manage 工具的 Schema 里写明了创建门槛:
"Create when: complex task succeeded (5+ calls), errors overcome, user-corrected approach worked, non-trivial workflow discovered..."
只有满足以下条件才值得创建:
-
工具调用超过 5 次(简单任务不记)
-
踩过坑并修复过(有教训才有价值)
-
用户纠正过的做法(人的反馈是最宝贵的信号)
4.3 自我修补:局部更新而非全量重写
当 Agent 按 Skill 执行但发现步骤遗漏或新坑时,完成任务后会回头修补。采用模糊匹配做局部 patch:
def _patch_skill(name, old_string, new_string, ...): new_content, match_count, strategy, error = fuzzy_find_and_replace( content, old_string, new_string, replace_all ) if error: return {"success": False, "error": error}
修改前备份 original = content _atomic_write_text(target, new_content)
# 安全扫描,不通过就回滚 if _security_scan_skill(skill_dir): _atomic_write_text(target, original) return {"success": False, "error": "Security scan failed"}
几个工程细节:
-
模糊匹配:容忍 Agent 给出的 old_string 与原文有格式差异
-
原子写入:先写备份,再替换,失败可回滚
-
安全扫描:每次修改后自动跑安全检测,不通过就撤销
4.4 渐进式加载:解决上下文膨胀
Skills 多了不能全塞进系统提示词。Hermes 采用"动态图书馆"模式:
默认只放一个轻量索引,每个 Skills 的名字和一句话描述:
Available skills: devops: - flask-k8s-deploy: Deploy a Flask app to Kubernetes - nginx-reverse-proxy: Configure Nginx with SSL software-development: - fix-pytest-fixtures: Debug pytest fixture scope issues
Agent 判断某个 Skills 与当前任务相关时,才通过 skill_view 加载完整内容。"先看目录再翻全书",按需加载,避免上下文膨胀。
五、Nudge Engine:谁来触发"复盘"?

Memory 和 Skills 都是存储系统,写入需要触发器。Nudge Engine 就是这个计数内省触发器。
5.1 两个计数器,两种粒度
# Memory 计数器:按用户回合self._memory_nudge_interval = 10 # 每 10 个用户回合触发一次# Skill 计数器:按工具迭代self._skill_nudge_interval = 10 # 每 10 次工具调用触发一次
粒度不同是有道理的:
-
Memory 的信息来自用户输入 → 按回合计
-
Skill 的经验来自工具使用过程 → 按迭代计
5.2 后台 fork:不打扰用户的静默审查
Nudge 触发后,不会在主对话中插入"让我想想",而是在后台 fork 一个独立的 Agent 实例做审查:
def _spawn_background_review(self, messages_snapshot, review_memory=False, review_skills=False): def _run_review(): with open(os.devnull, "w") as devnull, \ contextlib.redirect_stdout(devnull), \ contextlib.redirect_stderr(devnull):
review_agent = AIAgent(model=self.model, max_iterations=8, quiet_mode=True) review_agent._memory_store = self._memory_store 共享 Memory review_agent._memory_nudge_interval = 0 # 禁用递归 review_agent._skill_nudge_interval = 0 review_agent.run_conversation(user_message=prompt, ...)
thread = threading.Thread(target=_run_review, daemon=True) thread.start()
设计要点:
-
输出重定向到/dev/null:用户完全无感知
-
最多 8 次工具调用:控制成本上限
-
禁用 review agent 自身的 nudge:避免无限递归
-
共享 Memory 存储:写入直接生效,无需同步
审查提示词以这句话收尾:
"If nothing is worth saving, just say 'Nothing to save.' and stop."
防止 review agent 为了"交差"而硬塞内容。
六、完整案例:K8s 部署的三次会话演进
用一个真实场景串起三个子系统的协同。
第一次会话:冷启动
用户:帮我把这个 Flask 应用部署到 K8s 集群
Memory 和 Skills 都是空的,Agent 靠基座知识摸索:
|
迭代 |
操作 |
结果 |
|---|---|---|
|
1-5 |
读代码、写 Dockerfile、写 deployment.yaml |
正常推进 |
|
6 |
kubectl apply |
💥 ImagePullBackOff(忘记推镜像) |
|
7-8 |
推镜像、重新 apply |
修复 |
|
9-10 |
写 service.yaml、apply |
正常推进 |
|
11 |
kubectl get pods |
💥 CrashLoopBackOff(livenessProbe 路径不对) |
|
12 |
修改 deployment.yaml、重新部署 |
✅ 成功 |
12 次调用,2 个错误。触发 Skill Review,后台 Agent 自动创建flask-k8s-deploySkill,把两个 Pitfalls 写进文件。用户对这一切毫不知情。
第二次会话:Skill 复用 + 自我修补
用户:帮我再部署一个 Django 应用到 K8s
Agent 加载已有 Skill,已知坑被绕过:
|
迭代 |
操作 |
结果 |
|---|---|---|
|
1 |
skill_view("flask-k8s-deploy") |
加载完整 Skill |
|
2-6 |
按 Skill 步骤执行 |
先 push 再 apply、加 /health 端点 |
|
7 |
kubectl apply |
💥 DisallowedHost(Django 特有,Skill 未覆盖) |
|
8-9 |
添加 ALLOWED_HOSTS 环境变量、重新 apply |
✅ 成功 |
从 12 次降到 9 次,已知坑被绕过,但遇到新坑。Review Agent 做三件事:写入用户画像、记住 registry 地址、patch Skill 补上 Django 的坑。
第三次会话:零错误,一次搞定
用户:帮我部署一个新的 FastAPI 微服务
Agent 已经知道你是谁、registry 在哪、集群在哪,Skill 里也包含了 ALLOWED_HOSTS 的教训:6 次调用,零错误。
三次演进对比:
|
维度 |
第一次 |
第二次 |
第三次 |
|---|---|---|---|
|
工具调用 |
12 次 |
9 次 |
6 次 |
|
错误数 |
2 |
1 |
0 |
|
Memory |
无 |
触发写入 |
系统提示词注入 |
|
Skill |
触发创建 |
复用 + 修补 |
复用已修补版本 |
七、安全机制:进化必须有约束
Agent 能往自己"脑子"里写东西,意味着攻击面扩大。Hermes 做了两层防护。
7.1 Memory 内容扫描
因为 Memory 最终会注入系统提示词,如果被诱导记住"ignore all previous instructions",下次会话就等于被劫持:
_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"),]
7.2 Skill 安全扫描 + 自动回滚
每次 Skill 创建或修改后,自动跑安全扫描,不通过就回滚到原版本:
scan_error = _security_scan_skill(skill_dir)if scan_error: _atomic_write_text(target, original_content) 不通过就回滚 return {"success": False, "error": scan_error}
八、设计取舍:源码背后的架构思考
|
设计决策 |
表面效果 |
深层考量 |
|---|---|---|
|
Memory 限 2200 字符 |
迫使 Agent 挑重点记 |
低质量 Memory 注入系统提示词 = 每次 API 调用都带噪声 |
|
声明式事实 vs 操作步骤分离 |
Memory 存事实,Skill 存步骤 |
更新频率、触发条件、安全风险完全不同 |
|
冻结快照模式 |
系统提示词会话内不变 |
保护前缀缓存,避免重复计费 |
|
后台 fork 审查 |
用户无感知 |
自省不应占用用户任务的 attention budget |
|
patch 优先于全量重写 |
局部修复 Skill |
保留已验证的稳定部分,只改需要改的 |
|
安全扫描 + 自动回滚 |
拒绝恶意写入 |
Memory/Skill 最终进入系统提示词,是一等安全边界 |
九、企业落地思考:从"个人工具"到"组织能力"
开源 Hermes 的自进化能力令人印象深刻,但在企业落地时,还需要解决几个关键问题:
9.1 冷启动问题
开源版 Skill 需要 Agent 从零积累。对于企业场景,预装领域 Skill 是更务实的路径,数据库巡检、慢 SQL 诊断、索引优化等通用技能,Agent 上线第一天就应具备。
9.2 团队共享问题
开源 Hermes 的经验积累在~/.hermes/本地目录。团队落地时,需要将 Skill 存储从本地磁盘搬到云端共享存储:一个 DBA 踩过的坑,全团队 Agent 都能绕过。自我进化不应是单点的,而应是组织级的能力沉淀。
9.3 密钥安全问题
Agent 有了终端权限后,API Key、数据库密码等凭证就暴露在攻击面上。企业级部署需要加密托管:AK/SK 由网关代理鉴权,密钥不落盘,不暴露给 Agent 也不暴露给用户。
9.4 审计与治理
Agent 能自我进化,但每一步操作都应在审计链路上可追溯。写操作需二次确认才执行,每一次会话可审计,Token 消耗可监控,安全事件可告警。
十、总结
Hermes Agent 的自进化架构,本质上是三件事的配合:
-
Memory 记住你是谁:在容量限制下做高密度信息压缩
-
Skill 记住怎么做事:把踩坑经验自动沉淀为可复用资产
-
Nudge Engine 保证循环不停转:后台静默触发复盘,不打扰用户
这套机制的价值不在于功能多复杂,而在于设计哲学的转变:从"人调教 Agent"到"Agent 自己学"。
对于正在构建或选型 Agent 平台的技术团队,Hermes 的源码值得仔细研读。它证明了:Agent 的护城河不是模型能力,不是框架功能,而是在真实工作中积累的组织记忆。
PS:
SDD AI 编程干货直播,欢迎点击预约,直播见。
好了,这就是我今天想分享的内容。如果你对构建企业级 AI 原生应用新架构设计和落地实践感兴趣,别忘了点赞、关注噢~
—1—
加我微信
扫码加我👇有很多不方便公开发公众号的我会直接分享在朋友圈,欢迎你扫码加我个人微信来看👇

加星标★,不错过每一次更新!
⬇戳”阅读原文“,立即预约!
更多推荐



所有评论(0)