昨天我用 Agent 处理一个棘手的部署任务。它第一次跑的时候踩了个坑——少了一步 docker login,推送镜像时报错了。Agent 发现问题,自己补上登录步骤,重试后跑通了。
但最让我惊讶的不是它跑通了,而是它默默更新了自己的操作手册。
下一次我再让它做同样的任务时,它直接带上了 docker login,一步到位。
它自己"长记性"了。
这不是魔法,是 Hermes Agent 的 Skill 自进化机制。它把一次性的试错经验,固化成了可复用的程序化记忆。
记忆 vs 技能:两种不同的知识
在 Agent 系统中,记忆(Memory)和技能(Skills)是两种截然不同的存在。
Memory(声明式记忆) 是"我知道什么":
- “我的博客在
~/Projects/blog2” - “用户喜欢中文写作”
- “Qwen 有 1M 上下文窗口”
Skill(程序化记忆) 是"我会做什么":
- “写博客的 5 步流程”
- “遇到
permission denied时先检查权限再重试” - “Rust 项目用
cargo build,不要用make”
Memory 是静态的,而 Skill 是活的。它会随着 Agent 的使用而生长、修补、进化。
技能是如何诞生的?(自动生成)
Skill 的创建不是预先写好所有可能用到的技能,而是按需生成。
System Prompt 中有一段 SKILLS_GUIDANCE 明确指导 Agent 何时创建技能:
After completing a complex task (5+ tool calls),
fixing a tricky error,
or discovering a non-trivial workflow,
save the approach as a skill with skill_manage so you can reuse it next time.
触发条件总结为三点:
- 复杂任务成功(5+ 次工具调用)——说明这是一个值得沉淀的流程。
- 克服了一个棘手错误——这个排错过程极其宝贵。
- 发现了非平凡的工作流——即使没有错误,如果发现了一条更优路径,也值得记录。
例如,Agent 成功写了一篇复杂的博客文章后,可能会调用:
skill_manage(
action='create',
name='hugo-blog-post',
content='...',
category='writing'
)
# generated by hugo AI
这样,下次它再写博客时,直接加载这个 skill,按标准流程执行,不需要从头摸索。
技能是如何进化的?(热修补)
这是整个机制最精彩的部分——发现即修补(Patch on Discovery)。
很多 Agent 系统有 skill,但它们是静态的。如果 skill 过时了,agent 还是会傻傻地照着做,或者默默忍受错误。
Hermes 的设计哲学是:“Skills that aren’t maintained become liabilities”(不维护的技能比没有更糟)。
当 Agent 使用一个 skill 时,如果发现:
- 步骤报错了
- 缺少了关键信息
- 有更好的实现方式
它会 立即 调用 patch 修正,不等待用户反馈,不等待定期检查:
skill_manage(
action='patch',
name='deploy-api',
old_string='docker push $IMAGE',
new_string='docker login # 必须先登录\n'
'docker push $IMAGE',
file_path=None # 直接修补 SKILL.md
)
# generated by hugo AI
模糊匹配:修补成功率的关键
LLM 不擅长精确字符串匹配。如果旧文本里有几个空格的变化,传统的 str.replace 就会失败。
_patch_skill 内部使用了模糊匹配引擎(Fuzzy Matching),能容忍:
- 空白字符差异(空格 vs 制表符)
- 缩进层级变化
- 转义字符差异
这意味着 Agent 不需要精确复制粘贴旧文本,只要提供"大致内容",系统就能找到并替换。这大大提高了自我修正的成功率。
技能是如何巩固的?(后台审查)
除了 Agent 在对话中的主动保存,系统还有一个无感的后台审查机制。
每次对话结束时,系统会检查距离上次 skill 操作是否已经过了 10 次对话(_skill_nudge_interval)。如果是,它会在后台启动一个审查 Agent:
用户对话结束
│
▼
_iters_since_skill >= 10?
│
▼ (是)
启动后台线程 (不影响用户)
│
▼
注入审查 Prompt:
"Review the conversation...
was a non-trivial approach used...
If a relevant skill already exists, update it..."
│
▼
审查 Agent 扫描历史
│
├── 发现有价值的流程 → 创建新 skill
├── 发现现有 skill 的不足 → 更新 skill
└── 没有值得保存的 → 结束
为什么用后台线程? 因为审查过程需要额外的 LLM 调用(最多 8 次迭代),如果在主线程执行会阻塞用户响应。后台执行让用户感知不到延迟,但 Agent 却在悄悄进化。
审查成功后,主会话会打印一行小字:
💾 Skill 'deploy-api' updated
安全防线:如何防止 Agent 乱改技能?
Agent 自己改自己的指令库,听起来有点危险。系统设计了多层防护:
1. 安全扫描(Security Scan)
每次 skill 写入后,运行 skills_guard 扫描器,检查是否包含:
- Prompt 注入攻击(如
ignore previous instructions) - 恶意命令(如
rm -rf /) - 越权访问指令
如果扫描不通过,自动回滚到修改前的状态。
2. 原子写入(Atomic Writes)
使用 tempfile + os.replace() 确保写入是原子的。即使在写入过程中系统崩溃,也不会留下半损坏的文件。
3. Frontmatter 校验
修改后的 SKILL.md 必须仍然包含有效的 YAML 头(name, description 等)。如果 patch 破坏了结构,拒绝保存。
4. 大小限制
Skill 内容限制在 100K 字符以内,防止技能无限膨胀。如果太大,提示 Agent 拆分技能。
框架总结:Agent 技能自进化模型
┌──────────────────────────────────────────────────┐
│ 技能自进化模型 │
├──────────────────────────────────────────────────┤
│ │
│ 1. 触发 (Trigger) │
│ - 复杂任务完成 │
│ - 错误修复 │
│ - 用户纠正 │
│ - 后台审查 (每 10 次对话) │
│ │
│ 2. 决策 (Decision) │
│ - 创建新技能 (Create) │
│ - 修补旧技能 (Patch) │
│ - 废弃无用技能 (Delete) │
│ │
│ 3. 执行 (Execution) │
│ - skill_manage 工具调用 │
│ - 模糊匹配定位旧内容 │
│ - 原子写入新内容 │
│ │
│ 4. 防御 (Defense) │
│ - 安全扫描 │
│ - 自动回滚 │
│ - 结构校验 │
│ │
└──────────────────────────────────────────────────┘
升维思考:从静态 Prompt 到动态 Skill
传统的 LLM 应用开发中,Prompt 是硬编码的。开发者写好 Prompt,部署,然后祈祷它能覆盖所有边缘情况。如果遇到问题,开发者手动修改 Prompt,重新部署。
Agent 的 Skill 机制把这个过程内化了。Agent 不再是一个静态的执行器,而是一个自我优化的系统。
- 它从经验中学习,而不是从代码中学习。
- 它自己修补错误,而不是等待开发者发版。
- 它按需进化,而不是预先设计所有路径。
这才是 Agent 真正区别于 Chatbot 的地方:它不是在执行你的指令,它在根据你的使用习惯,进化出更适合你的工作方式。
你在构建 Agent 系统时,有考虑过这种"自我进化"的机制吗?还是更倾向于手动维护 Prompt?欢迎留言讨论。