恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

深入源码:Hermes Agent 的 Self-Improving 机制如何驱动 Skill 自动进化

  • 首页
  • 资讯中心
  • /
  • 深入源码:Hermes Agent 的 Self-Improving 机制如何驱动 Skill 自动进化

相关资讯

开源实时3D地球引擎WorldWideView:如何在浏览器里可视化全球飞机、船舶与冲突事件 2026/10/10 22:46:33
十年混战复盘:从「四大金刚」到「三国杀」,TensorFlow 亲历的框架江湖 2026/10/10 22:46:33
基于 Application Insights 与 OpenTelemetry 构建 MCP Server 生产级监控与可观测性 2026/10/10 22:46:33

最新资讯

人员状态检测数据集实战:7z解压、格式校验与YOLOv8训练
室内定位超宽带算法MATLAB实现:从脉冲生成到TOA/TDOA解算
Python情感分析源码实战:53k对话清洗、SnowNLP训练与Flask接口全链路
预测分析表自动生成:结构化决策证据链实战方案
CVND人脸关键点检测实战:从数据增强到OKS评估的完整避坑指南
Selenium自动化测试:抽奖系统概率、库存与UI回归实战

今日推荐

Codex 总用英文回答?从 AGENTS.md 到 config.toml 的中文输出调优指南
OpenClaw 自定义插件开发完整指南(2026最新版):从 TypeScript 到 npm 发布
基于Spark的电影推荐系统全链路实战:从爬虫到Web展示

本周热门

MR25H40CDF + PIC18F65K40:工业记录仪高可靠存储实战
基于STM32的数控恒压恒流电源设计:从硬件到PID调参全解析
LT9211 MIPI重定时器原理与双路扇出实战指南

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

深入源码:Hermes Agent 的 Self-Improving 机制如何驱动 Skill 自动进化

发布时间:2026/10/10 22:51:33
深入源码:Hermes Agent 的 Self-Improving 机制如何驱动 Skill 自动进化 1. 从一次 K8s 部署翻车说起Hermes Agent 的 Self-Improving 到底在解决什么如果你用过 OpenClaw 这类 Agent 框架大概率经历过这样的场景第一次让它部署一个 Flask 应用到 K8s它踩了 ImagePullBackOff 的坑你手动纠正了第二次换个项目再部署它把同样的坑又踩了一遍。Skill 是手写的 Markdown 文件你不写它就不会你写了它也不会自己更新。Hermes Agent 在 OpenRouter 排行榜上增速 204%Top Coding Agents 排第一GitHub 从 0 到 106k Star靠的不是功能堆叠而是设计哲学上的分水岭——它让 Agent 干完活之后自动把踩坑经验提炼成可复用的 Skill下次遇到同类问题直接调用。用得越久能力越强。这篇文章拆解 Hermes Agent 源码中 Self-Improving 与 Skill 模块的协作链路给出可复制的源码阅读路径和关键函数调用链并演示一次完整的 Skill 迭代验证动作。适合想理解 Agent 自进化原理的开发者也适合正在选型 Agent 框架的技术负责人。三个子系统撑起一个闭环Memory 是助手随身带的小本子记着老板喜欢喝美式这些事实Skill 是助手积累的操作手册——部署 K8s 第 2 步一定要先推镜像Nudge Engine 是定时响的闹钟提醒助手回头想想有没有什么值得记的。三者协作构成一个完整的反馈回路。源码仓库地址github.com/NousResearch/hermes-agent。下面按模块拆解每一步都给出文件路径和行号区间你可以直接对照阅读。2. Memory 系统源码拆解两个文件如何定义 Agent 对你的全部认知Memory 系统设计得很克制——两个纯文本文件用§分隔条目~/.hermes/memories/ ├── MEMORY.md # Agent 的个人笔记环境事实、项目约定、工具怪癖 └── USER.md # Agent 对用户的认知偏好、沟通风格、工作习惯字符上限故意设得很紧MEMORY 限 2200 charsUSER 限 1375 chars。容量有限就迫使 Agent 挑重要的记不重要的自然被挤掉。对比 OpenClaw——它的 MEMORY.md 是纯追加模式用几个月就膨胀成几万行的怪兽文件找几个月前的一句话只能笨拙地通读全文。Hermes 的做法反过来容量有限就倒逼 Agent 做信息压缩过时的自然被挤掉留下的都是高密度事实。具体实现上MemoryStore维护两组平行状态——实时可写的条目列表和会话开始时冻结的快照# tools/memory_tool.py:116-122 class MemoryStore: def __init__(self, memory_char_limit2200, user_char_limit1375): 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] {memory: , user: }但设了上限只是第一步关键是超限之后怎么处理。Hermes 不会静默丢弃旧条目也不会自动压缩——它选择让add直接失败然后把当前所有条目返回给模型# tools/memory_tool.py:248-259 if new_total limit: current self._char_count(target) return { success: False, error: ( fMemory at {current:,}/{limit:,} chars. fAdding this entry ({len(content)} chars) would exceed the limit. fReplace 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-140 def 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省掉重复计费。新写入的内容只改磁盘下一个会话才刷新进来。提示词引导方面系统提示词中的MEMORY_GUIDANCE明确了什么该记、什么不该记# agent/prompt_builder.py:144-162 MEMORY_GUIDANCE ( You have persistent memory across sessions. 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 or remind you again.\n Write memories as declarative facts, not instructions to yourself. User prefers concise responses ✓ — Always respond concisely ✗. Project uses pytest with xdist ✓ — Run tests with pytest -n 4 ✗. )注意这里的区别Memory 要求写成声明式事实User prefers concise responses而不是命令式指令Always respond concisely。前者是偏好可以被当前上下文覆盖后者是死命令会限制 Agent 的灵活性。Tool Schema 里还有一句关键的边界规则If youve discovered a new way to do something, save it as a skill. —— Memory 不存操作步骤操作步骤归 Skill 管。这一句话把两个系统的分工画清了。3. Skill 模块源码拆解从 SKILL.md 结构到自动创建触发条件Memory 是我知道什么Skill 是我会做什么。每个 Skill 是一个目录核心是 SKILL.md 文件~/.hermes/skills/ ├── devops/ │ └── flask-k8s-deploy/ │ ├── SKILL.md # 主指令 │ ├── references/ # 参考文档 │ └── templates/ # 模板文件 └── software-development/ └── fix-pytest-fixtures/ └── SKILL.md一个典型的 SKILL.md--- name: flask-k8s-deploy description: Deploy a Flask app to Kubernetes with health checks version: 1.0.0 --- # Flask K8s Deployment ## When to use - User wants to deploy a Flask/Python app to Kubernetes - User mentions K8s, kubectl, or container deployment ## Steps 1. Create Dockerfile with gunicorn (not dev server) 2. Build and push image to registry BEFORE creating deployment 3. Write deployment.yaml with livenessProbe pointing to /health 4. Write service.yaml with correct port mapping 5. kubectl apply both files 6. Verify with kubectl get pods and kubectl logs ## Pitfalls - MUST push image to registry before kubectl apply, otherwise ImagePullBackOff - Flask 默认没有 /health 端点需要手动添加 - Django 需要额外设置 ALLOWED_HOSTS 环境变量 - livenessProbe path 必须返回 200不能用需要认证的路径Pitfalls 这一节不是预先写好的而是 Agent 踩坑后追加的——这就是 Skill 层面的self-improving。Agent 不需要用户说帮我创建一个 Skill。驱动力来自skill_manage工具的 schema# tools/skill_manager_tool.py:681-701 SKILL_MANAGE_SCHEMA { name: skill_manage, description: ( Manage skills (create, update, delete). Skills are your procedural memory — reusable approaches for recurring task types.\n\n Create when: complex task succeeded (5 calls), errors overcome, user-corrected approach worked, non-trivial workflow discovered, or user asks you to remember a procedure.\n Update when: instructions stale/wrong, OS-specific failures, missing steps or pitfalls found during use. If you used a skill and hit issues not covered by it, patch it immediately with skill_manage(actionpatch) — dont wait to be asked.\n\n After difficult/iterative tasks, offer to save as a skill. Skip for simple one-offs. ), }创建的门槛设得比较清晰工具调用超过 5 次才值得创建简单任务不记、踩过坑再修复的经验才有价值、用户纠正过的做法要铭记。OpenClaw 也有 Skill 系统也是 SKILL.md YAML frontmatter但 Skill 要么是你手写的要么是从社区装的。手写的成本高懒得维护社区装的不是针对你的环境。关键问题是Agent 本身不会从工作中学到任何东西——干了一百次部署第一百零一次犯的错跟第一次一模一样。HN 上有个帖子叫 Data Is the Final Moat——当模型智能被商品化、Agent 框架被开源真正的护城河是 Agent 在工作中积累的领域知识。OpenClaw 的 Skill 是手写的配置文件用了一年还是那份手写的配置文件Hermes 的 Skill 是越用越厚的经验资产——每一次踩坑都在加固护城河。这不是 OpenClaw 团队不想做而是它的架构没有为Agent 自主学习预留通路——没有创建触发、没有 patch 机制、没有 review agent。要补这一课是要重写核心架构。Hermes 这边Agent 踩了坑、修了 bug、用了 12 次工具调用才搞定一个部署——这些经验被自动提炼成 Skill下次再遇到同类任务就是 6 次调用零错误。系统提示词里还有一句 Skills that arent maintained become liabilities——通过提示词给 Agent 灌输责任感防止它只管创建不管维护。当 Agent 按照已有 Skill 执行但中途发现步骤有遗漏或者踩了新坑时它会在完成任务后回头修补 Skill。不是全量重写而是做精确的局部 patch# tools/skill_manager_tool.py:397-485 def _patch_skill(name, old_string, new_string, file_pathNone, replace_allFalse): Targeted find-and-replace within a skill file. from tools.fuzzy_match import fuzzy_find_and_replace new_content, match_count, _strategy, match_error fuzzy_find_and_replace( content, old_string, new_string, replace_all ) if match_error: return {success: False, error: match_error, file_preview: content[:500]} # ...省略 _validate_content_size、_validate_frontmatter 等校验 # 修改前备份原内容 original_content content _atomic_write_text(target, new_content) # 修改后重新做安全扫描 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可能跟原文有格式差异模糊匹配能容忍这些差异。每次修改后还要跑一遍_security_scan_skill()不通过就自动回滚。Agent 在踩完坑的当场就把 Pitfalls 补上了下次同事遇到同样的场景直接绕过去。Skill 多了以后不能全塞进系统提示词——这也是 OpenClaw 的一个痛点它采用全量背包模式每次会话把 SOUL.md、IDENTITY.md 和各种设定一股脑塞进上下文设定越多背包越沉Token 浪费严重模型注意力也被稀释。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 issuesAgent 判断某个 Skill 跟当前任务相关时才通过skill_view加载完整内容。先看目录再翻全文按需加载。4. Nudge Engine 与后台 fork反馈回路如何自动触发 Skill 迭代Memory 和 Skill 都是存储系统写入需要有人触发。Nudge Engine 就是这个触发器——运行时维护两个计数器定时提醒 Agent 该停下来想想了。两个计数器两种粒度# run_agent.py:1328-1331 — Memory 计数器 self._memory_nudge_interval 10 # 每 10 个用户回合触发一次 self._turns_since_memory 0 # run_agent.py:1428-1431 — Skill 计数器从配置读取默认 10 self._skill_nudge_interval int(skills_config.get(creation_nudge_interval, 10)) self._iters_since_skill 0粒度不同是有道理的Memory 的信息来自用户输入按回合计Skill 的经验来自工具使用过程按迭代计。计数器到阈值就触发审查Agent 主动调用了 memory 或 skill_manage 则重置——已经在做了就不用催。Nudge 触发后怎么处理它不会在主对话中插一条让我想想有没有什么该记的——那样太打扰用户了。而是在后台 fork 一个独立的 Agent 实例拿着主对话的快照去做审查# run_agent.py:2665-2711 def _spawn_background_review(self, messages_snapshot, review_memoryFalse, review_skillsFalse): def _run_review(): with open(os.devnull, w) as _devnull, \ contextlib.redirect_stdout(_devnull), \ contextlib.redirect_stderr(_devnull): review_agent AIAgent( modelself.model, max_iterations8, quiet_modeTrue, ) review_agent._memory_store self._memory_store review_agent._memory_enabled self._memory_enabled review_agent._user_profile_enabled self._user_profile_enabled # 禁用 review agent 自身的 nudge否则会无限递归 review_agent._memory_nudge_interval 0 review_agent._skill_nudge_interval 0 review_agent.run_conversation( user_messageprompt, conversation_historymessages_snapshot, ) thread threading.Thread(target_run_review, daemonTrue) thread.start()几个细节输出重定向到/dev/null用户完全无感知最多 8 次工具调用不会无限消耗 APIreview agent 自身的 nudge 被禁用避免无限递归和主 agent 共享同一份 Memory写入直接生效。干活和反思拆成两个实例互不干扰。Review Agent 靠两套审查提示词决定做什么Memory Review 关注用户偏好和个人信息Skill Review 关注非平凡的解题过程。每个 prompt 都以 If nothing is worth saving, just say Nothing to save. and stop. 收尾——防止 review agent 每次都往里塞东西来交差。审查在响应发送给用户之前才触发用户收到回复后该干嘛干嘛Agent 在后台默默复盘。完整案例从不会到精通的三次会话。用一个 K8s 部署场景串一下三个子系统的协同。第 1 次会话冷启动。用户说帮我把这个 Flask 应用部署到 K8s 集群。Memory 和 Skills 都是空的Agent 靠基座知识摸索12 次工具调用踩了两个坑iter1: terminal(kubectl version) → 确认集群版本 iter2: read_file(app.py) → 读取应用代码 iter3: write_file(Dockerfile) → 创建 Dockerfile iter4: terminal(docker build -t myapp .) → 构建镜像 iter5: write_file(deployment.yaml) → 编写 K8s 部署文件 iter6: terminal(kubectl apply -f deployment.yaml) → ImagePullBackOff忘记推镜像到 registry iter7: terminal(docker push myregistry.azurecr.io/myapp) iter8: terminal(kubectl apply -f deployment.yaml) → 重新部署 iter9: write_file(service.yaml) → 编写 Service iter10: terminal(kubectl apply -f service.yaml) iter11: terminal(kubectl get pods) → CrashLoopBackOfflivenessProbe 路径不对 iter12: 修改 deployment.yaml → 重新部署 → 成功12 次迭代触发 Skill ReviewReview Agent 看到两次报错和修复过程创建了一个 SkillReview Agent 执行: → skill_manage(actioncreate, nameflask-k8s-deploy, categorydevops, content --- name: flask-k8s-deploy description: Deploy a Flask app to Kubernetes with health checks --- ## Steps 1. Create Dockerfile with gunicorn 2. Build and push image to registry BEFORE kubectl apply 3. Write deployment.yaml with livenessProbe → /health ... ## Pitfalls - MUST push image to registry first, otherwise ImagePullBackOff - Flask 默认没有 /health 端点需手动添加 - livenessProbe path 必须返回 200 )安全扫描通过后写入磁盘用户对这一切毫不知情。第 2 次会话Skill 复用 自我修补。用户说帮我再部署一个 Django 应用到 K8s。系统提示词里多了 Skills 索引Agent 加载flask-k8s-deploy后照着步骤做iter1: skill_view(flask-k8s-deploy) → 加载完整 Skill iter2: read_file(manage.py) → 确认 Django 项目结构 iter3: write_file(Dockerfile) → 用 gunicornSkill 指示 iter4: 添加 /health 端点Skill Pitfalls 提醒 iter5: terminal(docker build docker push) → 先 push 再 applySkill Steps 第2步 iter6: write_file(deployment.yaml) → livenessProbe → /health iter7: terminal(kubectl apply) → DisallowedHost 错误Django 特有的问题Skill 没覆盖 iter8: 修改 deployment.yaml 添加 ALLOWED_HOSTS env iter9: terminal(kubectl apply) → 成功从 12 次调用降到 9 次已知坑被绕过但遇到 Django 特有的新坑。Review Agent 一口气做了三件事写入用户画像、记住 registry 地址、patch Skill 补上 ALLOWED_HOSTS 坑。第 3 次会话零错误一次搞定。用户说帮我部署一个新的 FastAPI 微服务。Agent 已经知道你是谁、registry 在哪、集群在哪Skill 里也包含了 ALLOWED_HOSTS 的坑——6 次调用零错误。三次对比维度会话 1 (冷启动)会话 2 (Skill 复用)会话 3 (全自愈)工具调用12 次9 次6 次错误数210Memory无触发写入系统提示词注入Skill触发创建复用 自我修补复用已修补版本在开源 Hermes 中这些经验积累在单个用户的~/.hermes/目录下。RDSHermes 把 Skill 存储从本地磁盘搬到了云端——一个 DBA 踩过的坑团队里所有人的 Agent 都能绕过。自我进化不再是单点的而是组织级的。5. 常见报错排查401、local proxy failed、reading choices 与 OAuth 失效在跑通 Hermes Agent 的 Self-Improving 链路之前接入层的问题往往先卡住你。下面按真实报错对照排查。401 Unauthorized / invalid_api_key。最常见的原因是 Base URL 和 Key 不匹配。如果你用的是 TaoToken 的 API 网关Base URL 必须写成https://taotoken.net/apiKey 从控制台的 API Keys 页面生成。检查配置文件里base_url和api_key是否成对出现以及 Key 是否带了多余空格。用 curl 快速验证curl https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d {model:claude-sonnet-4-20250514,messages:[{role:user,content:ping}]}返回 200 且 choices 数组非空说明 Key 和 Base URL 都没问题。local proxy failed / connection refused。这个报错通常出现在你配置了本地代理端口但代理进程没起来。检查config.yaml里是否残留了proxy: http://127.0.0.1:xxxx这类配置。如果你不需要本地代理直接删掉这一行。Hermes 默认走直连不需要额外代理层。reading choices 报错 / KeyError: choices。这通常意味着上游返回的不是标准 OpenAI 格式的响应。可能原因模型 ID 写错了网关返回了错误 JSON或者 Base URL 少了/v1路径。确认你的 Model ID 跟网关支持的列表一致比如claude-sonnet-4-20250514、gpt-4o这类。用模型对话页面先手动测一次确认模型可用再写进配置。OAuth token expired / Claude Code 认证失败。如果你在用 Claude Code 接入认证走的是 Anthropic 的 OAuth 流程。token 过期后需要重新走一遍授权。检查~/.claude/下的凭证文件是否还在有效期内。如果频繁过期考虑改用 API Key 方式接入稳定性更好。CC Switch / Cline MCP / Codex auth.json 三件套配置。如果你在 Hermes 里挂 MCP Server 或者用 CC Switch 管理多套配置记住每个接入点都需要三样东西Base URL、API Key、Model ID。以 Codex 的auth.json为例{ base_url: https://taotoken.net/api, api_key: sk-xxxxxxxx, model: claude-sonnet-4-20250514 }Cline 的 MCP 配置在settings.json里{ mcpServers: { hermes: { command: npx, args: [-y, hermes/mcp-server], env: { HERMES_BASE_URL: https://taotoken.net/api, HERMES_API_KEY: sk-xxxxxxxx, HERMES_MODEL: claude-sonnet-4-20250514 } } } }CC Switch 的配置文件里同样需要这三项对齐。任何一项缺失或写错都会导致 401 或 reading choices 报错。Skill 创建后不生效。检查~/.hermes/skills/目录下是否有对应的 SKILL.md 文件以及 YAML frontmatter 里的name和description是否完整。如果安全扫描没通过文件会被回滚磁盘上不会留下痕迹。查看日志里有没有Security scan blocked this skill的输出。Nudge 不触发。确认config.yaml里creation_nudge_interval的值默认是 10。如果你把值设得太大比如 100短时间内不会触发审查。另外如果 Agent 在会话中已经主动调用了skill_manage计数器会重置不会重复触发。6. 把 Self-Improving 能力接进你的工作流Hermes Agent 的 Self-Improving 就是三件事的配合Memory 记住你是谁Skill 记住怎么做Nudge Engine 保证这个循环不停转。用得越久Agent 帮你干活就越快、踩坑就越少。如果你想在自己的项目里复现这套机制源码阅读路径建议按这个顺序先看tools/memory_tool.py理解存储和上限控制再看tools/skill_manager_tool.py理解创建和 patch 流程最后看run_agent.py里的 nudge 计数器和后台 fork 逻辑。三个文件加起来不到 2000 行一个下午能读完。接入层用 TaoToken 的 API 网关Base URL 写https://taotoken.net/apiKey 在控制台的 API Keys 页面生成。模型 ID 根据你的任务选编码类任务用claude-sonnet-4-20250514通用任务用gpt-4o。配置写好后先用模型对话页面手动验证一次确认返回正常再写进 Hermes 的config.yaml。如果你需要长期跑编码 Agent 或者多 Agent 协作Coding Plan 的额度更划算适合持续迭代的场景。接入文档里有完整的配置示例和排错指南遇到 401 或 reading choices 报错先对照文档检查 Base URL、Key、Model ID 三件套是否对齐。自我进化不是魔法是一套设计良好的反馈回路在持续运转。理解了这个回路你就能在自己的 Agent 项目里复现它。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号