Hermes Agent 自进化架构的源码级拆解

来源: Hermes Agent 自进化架构的源码级拆解

当大多数 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 编程干货直播,欢迎点击预约,直播见。