Hermes Agent 自进化架构的源码级拆解
- 人工智能
- -123分钟前
- 6热度
- 0评论
一、问题的本质:为什么 Agent 总是"金鱼记忆"?
二、总览:三个子系统构成的自进化闭环
|
|
|
|
|---|---|---|
| Memory |
|
|
| Skills |
|
|
| Nudge Engine |
|
|
三、Memory 子系统:在容量限制下做信息压缩
3.1 极简存储:两个文本文件
~/.hermes/memories/├── MEMORY.md #环境事实、项目约定、工具怪癖└── USER.md # 用户偏好、沟通风格、工作习惯
关键设计:硬性容量上限
MEMORY.md 限制2200 字符
USER.md 限制1375 字符
3.2 超限处理:让模型自己决定取舍
Memory at 1,800/2,200 chars.Adding this entry (500 chars) would exceed the limit.Replace or remove existing entries first.
3.3 冻结快照:省钱的工程智慧
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(...), }
3.4 记忆的内容规范
"Write memories as declarative facts, not instructions to yourself.'User prefers concise responses' ✓'Always respond concisely' ✗"
"If you've discovered a new way to do something, save it as a skill."
四、Skill 子系统:把踩过的坑变成组织能力
4.1 Skill 的结构
~/.hermes/skills/├── devops/│ └── flask-k8s-deploy/│ ├── SKILL.md主指令(YAML frontmatter + Markdown)│ ├── references/ # 参考文档│ └── templates/ # 模板文件
---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
4.2 自动创建:什么值得记?
"Create when: complex task succeeded (5+ calls), errors overcome, user-corrected approach worked, non-trivial workflow discovered..."
-
工具调用超过 5 次(简单任务不记)
-
踩过坑并修复过(有教训才有价值)
-
用户纠正过的做法(人的反馈是最宝贵的信号)
4.3 自我修补:局部更新而非全量重写
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 渐进式加载:解决上下文膨胀
Available skills:devops:- flask-k8s-deploy: Deploy a Flask app to Kubernetes- nginx-reverse-proxy: Configure Nginx with SSLsoftware-development:- fix-pytest-fixtures: Debug pytest fixture scope issues
五、Nudge Engine:谁来触发"复盘"?
5.1 两个计数器,两种粒度
# Memory 计数器:按用户回合self._memory_nudge_interval = 10 # 每 10 个用户回合触发一次# Skill 计数器:按工具迭代self._skill_nudge_interval = 10 # 每 10 次工具调用触发一次
粒度不同是有道理的:
-
Memory 的信息来自用户输入 → 按回合计
-
Skill 的经验来自工具使用过程 → 按迭代计
5.2 后台 fork:不打扰用户的静默审查
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."
六、完整案例:K8s 部署的三次会话演进
第一次会话:冷启动
用户:帮我把这个 Flask 应用部署到 K8s 集群
|
|
|
|
|---|---|---|
|
|
|
|
|
|
kubectl apply |
|
|
|
|
|
|
|
|
|
|
|
kubectl get pods |
|
|
|
|
|
第二次会话:Skill 复用 + 自我修补
用户:帮我再部署一个 Django 应用到 K8s
|
|
|
|
|---|---|---|
|
|
skill_view("flask-k8s-deploy") |
|
|
|
|
|
|
|
kubectl apply |
|
|
|
|
|
第三次会话:零错误,一次搞定
用户:帮我部署一个新的 FastAPI 微服务
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
七、安全机制:进化必须有约束
7.1 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"),]
7.2 Skill 安全扫描 + 自动回滚
scan_error = _security_scan_skill(skill_dir)if scan_error:_atomic_write_text(target, original_content)不通过就回滚 return {"success": False, "error": scan_error}
八、设计取舍:源码背后的架构思考
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
九、企业落地思考:从"个人工具"到"组织能力"
9.1 冷启动问题
9.2 团队共享问题
9.3 密钥安全问题
9.4 审计与治理
十、总结
-
Memory 记住你是谁:在容量限制下做高密度信息压缩
-
Skill 记住怎么做事:把踩坑经验自动沉淀为可复用资产
-
Nudge Engine 保证循环不停转:后台静默触发复盘,不打扰用户
PS:
SDD AI 编程干货直播,欢迎点击预约,直播见。