深度解析 · 19 分钟阅读 · 2天前

Hermes Agent 自动学习与成长原理深度解读

# Hermes Agent 自动学习与成长原理深度解读 > Nous Research 推出的 Hermes Agent 是 2026 年增长最快的开源 AI Agent(14.8 万 GitHub Stars),其核心差异化能力是**内置学习循环(Learning Loop)**——它能从经验中自动创建技能、在使用中自我改进、主动持久化知识,实现跨 Session 的能力累积。本文从源码层面

Hermes Agent 自动学习与成长原理深度解读

Nous Research 推出的 Hermes Agent 是 2026 年增长最快的开源 AI Agent(14.8 万 GitHub Stars),其核心差异化能力是内置学习循环(Learning Loop)——它能从经验中自动创建技能、在使用中自我改进、主动持久化知识,实现跨 Session 的能力累积。本文从源码层面深度拆解其原理。


一、架构总览:学习循环的四阶段

Hermes Agent 的学习循环遵循 Observe → Distill → Reuse → Refine 四个阶段,运行在 agent loop 的主循环之上:

code
User Message
    │
    ▼
┌─────────────────────────────────┐
│   Agent Loop                    │
│   (run_conversation)            │
│                                 │
│   while budget_remaining:       │
│     response = LLM.call(...)    │
│     if tool_calls:              │
│       execute tools             │
│       append results            │
│     else:                       │
│       return response           │
│                                 │
│   ┌─────────────────────────┐   │
│   │ Self-Evaluation         │   │
│   │ Checkpoint              │   │
│   │ (每 15 次 tool call)     │   │
│   └─────────┬───────────────┘   │
│             ▼                   │
│   ┌─────────────────────────┐   │
│   │ Skill Creation / Update │   │
│   │ Memory Nudge            │   │
│   └─────────────────────────┘   │
└─────────────────────────────────┘

核心洞察:这不是模型权重层面的训练,而是结构化的经验记录与检索系统。LLM 的权重从未被改变,改变的是围绕 LLM 的"知识层"——提示词、技能文档、记忆文件。


二、主线 Agent Loop:`run_conversation()`

Hermes 的核心驱动在 run_agent.py 中的 AIAgent 类(约 13,700 行)。其主循环逻辑如下:

python
# run_agent.py - AIAgent.run_conversation() 核心循环(简化)
def run_conversation(self):
    while (api_call_count < self.max_iterations
           and self.iteration_budget.remaining > 0) \
           or self._budget_grace_call:

        if self._interrupt_requested:
            break

        # 1. 构建系统提示(含 skills 索引、记忆、上下文文件)
        system_prompt = self._build_system_prompt()

        # 2. 调用 LLM(支持多种 provider 和 API mode)
        response = client.chat.completions.create(
            model=model,
            messages=messages,
            tools=tool_schemas
        )

        # 3. 解析响应
        if response.tool_calls:
            for tool_call in response.tool_calls:
                # 执行工具调用(支持 ThreadPoolExecutor 并发)
                result = handle_function_call(
                    tool_call.name,
                    tool_call.args,
                    task_id
                )
                messages.append(tool_result_message(result))

                # ★ 自评价检查点:每 15 次 tool call 触发
                if self._should_evaluate():
                    self._learning_checkpoint(messages)

            api_call_count += 1
        else:
            # 纯文本响应 → 持久化记忆后返回
            self._flush_memory()
            return response.content

关键设计:

  • self.iteration_budget:追踪父子 agent 的预算消耗,防止无限循环
  • should_evaluate():基于 tool call 计数判断是否需要触发学习检查点
  • _flush_memory():在上下文丢失前将关键信息写入持久化文件

三、技能系统:学习循环的核心载体

3.1 SKILL.md 格式(agentskills.io 标准)

技能以 Markdown 文件形式存储在 ~/.hermes/skills/ 下,通过 YAML frontmatter 声明元数据:

markdown
---
name: code-review
description: 执行标准代码审查工作流,检查 CI 状态、生成 diff 摘要、标记风格违规
version: 1.2.0
platforms: [macos, linux]
metadata:
  hermes:
    tags: [code-review, github, ci]
    related_skills: [github-pr-workflow, github-issues]
    config:
      - key: review.strictness
        description: 审查严格程度 (low/medium/high)
        default: "medium"
        prompt: 代码审查严格等级
---

# 代码审查技能

## 触发条件
当用户说"审查这个 PR"或"review PR #xxx"时自动加载。

## 步骤
1. 读取 PR 的变更文件列表
2. 对每个文件运行 linter 检查
3. 生成变更摘要报告
4. 发布审查评论到 PR

## 已知陷阱
- 超过 500 行变更的 PR,先要求作者拆分
- 确保仅审查变更行,不要审查整个文件

3.2 渐进式加载(Progressive Disclosure)

prompt_builder.py 实现了三层缓存加载策略,确保即使有数百个技能,上下文开销仍然可控:

python
# agent/prompt_builder.py
def build_skills_system_prompt(
    available_tools=None,
    available_toolsets=None,
) -> str:
    """构建紧凑的技能索引,注入 system prompt。

    三层缓存:
      1. 进程内 LRU 字典(keyed by skills_dir + tools + toolsets)
      2. 磁盘快照 .skills_prompt_snapshot.json(跨进程重启)
      3. 完整文件系统扫描(缓存未命中时的回退)
    """

    # 索引行:仅包含技能名称 + 简短描述
    # 每行约 60-80 字符,100 个技能仅约 3K tokens
    index_lines = []
    for category in sorted(skills_by_category):
        for name, desc in sorted(...):
            if desc:
                index_lines.append(f"    - {name}: {desc}")
            else:
                index_lines.append(f"    - {name}")

    result = (
        "## Skills (mandatory)\n"
        "Before replying, scan the skills below. "
        "If a skill matches your task, you MUST load it with skill_view(name) "
        "and follow its instructions.\n"
        "<available_skills>\n"
        + "\n".join(index_lines) + "\n"
        "</available_skills>\n"
    )
    return result

三层加载模型:

层级 内容 Token 开销 触发时机
L0 技能名称 + 描述索引 ~3K(总) Session 启动(自动注入 system prompt)
L1 完整 SKILL.md 内容 按需加载 Agent 判断与任务相关,调用 skill_view(name)
L2 附属文件(references/templates/scripts) 按需加载 Agent 调用 skill_view(name, file_path)

3.3 Agent 自管理技能:`skill_manage` 工具

这是学习循环的关键工具——Agent 可以通过 skill_manage 在运行时 创建、更新、删除 自己的技能文件。

python
# tools/skill_manager_tool.py
def skill_manage(action, name, content=None, category=None,
                 old_string=None, new_string=None, replace_all=False,
                 file_path=None, file_content=None):
    """
    Agent 管理自己的技能(过程性记忆)。

    Actions:
      create     - 创建新技能(完整 SKILL.md)
      patch      - 定向修补(old_string → new_string,首选方式)
      edit       - 整体重写(替换整个 SKILL.md)
      delete     - 删除技能
      write_file - 添加/更新附属文件
      remove_file - 删除附属文件
    """
    if action == "create":
        return _create_skill(name, content, category)
    elif action == "patch":
        return _patch_skill(name, old_string, new_string,
                            replace_all, file_path)
    elif action == "edit":
        return _edit_skill(name, content)
    elif action == "delete":
        return _delete_skill(name)
    elif action == "write_file":
        return _write_file(name, file_path, file_content)
    elif action == "remove_file":
        return _remove_file(name, file_path)

`_patch_skill` 的模糊匹配引擎

patch 操作使用了与文件编辑工具相同的 8 策略模糊匹配引擎:

python
# tools/skill_manager_tool.py
def _patch_skill(name, old_string, new_string,
                 replace_all=False, file_path=None):
    # ... 定位技能文件 ...

    content = target.read_text(encoding="utf-8")

    # 使用 8 策略模糊匹配引擎
    # 处理:空白标准化、缩进差异、转义序列、块锚点匹配
    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:
        # 返回文件预览以便模型自纠正
        preview = content[:500] + ("..." if len(content) > 500 else "")
        return {
            "success": False,
            "error": match_error,
            "file_preview": preview,
        }

    # 安全检查:注入检测 + 大小限制
    err = _validate_content_size(new_content)
    if err:
        return {"success": False, "error": err}

    # 原子写入(失败时回滚)
    _atomic_write_text(target, new_content)

    return {
        "success": True,
        "message": f"Patched skill '{name}' ({match_count} replacements).",
    }

_create_skill 的完整流程

python
def _create_skill(name, content, category=None):
    # 1. 从 content 解析 YAML frontmatter
    frontmatter, body = _parse_frontmatter(content)
    skill_name = frontmatter.get("name", name)

    # 2. 安全检查
    #    - 注入模式检测
    #    - 内容大小限制(默认 100K chars / 1 MiB)
    #    - 名称冲突检测
    if _detect_injection(content):
        return {"success": False, "error": "Potential prompt injection detected"}

    err = _validate_content_size(content)
    if err:
        return {"success": False, "error": err}

    # 3. 确定目标路径
    if category:
        skill_dir = SKILLS_DIR / category / skill_name
    else:
        skill_dir = SKILLS_DIR / skill_name
    skill_dir.mkdir(parents=True, exist_ok=True)

    # 4. 写入 SKILL.md
    target = skill_dir / "SKILL.md"
    _atomic_write_text(target, content)

    return {
        "success": True,
        "message": f"Skill '{skill_name}' created.",
        "path": str(target),
    }

内容大小限制逻辑(来自 PR #4414):

python
_CONTENT_SIZE_LIMIT = 100_000       # 100K 字符
_CONTENT_BYTE_LIMIT = 1_048_576     # 1 MiB

def _validate_content_size(content: str, label="SKILL.md"):
    if len(content) > _CONTENT_SIZE_LIMIT:
        return (
            f"{label} content is {len(content):,} characters "
            f"(limit: {_CONTENT_SIZE_LIMIT:,}). Consider splitting "
            f"into a smaller SKILL.md with supporting files "
            f"in references/ or templates/."
        )
    if len(content.encode("utf-8")) > _CONTENT_BYTE_LIMIT:
        return f"{label} exceeds 1 MiB."
    return None  # OK

3.4 System Prompt 中的技能引导

prompt_builder.py 中的 SKILLS_GUIDANCE 常量告诉 Agent 何时以及如何创建技能:

python
# agent/prompt_builder.py
SKILLS_GUIDANCE = (
    "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.\n"
    "When using a skill and finding it outdated, incomplete, or wrong, "
    "patch it immediately with skill_manage(action='patch') — "
    "don't wait to be asked. "
    "Skills that aren't maintained become liabilities."
)

这不是硬编码的 if-else 逻辑,而是通过 System Prompt 引导 LLM 自主决策:

  1. 5+ 次 tool call → 判定为"复杂任务"
  2. 成功完成 → 创建技能
  3. 发现更好的方法 → patch 更新技能
  4. 用户纠正 → 更新技能

这意味着学习能力来自于 LLM 自身的推理能力,而非预设规则。


四、技能生命周期管理:Curator

Curator 是 Hermes 的"技能管家",负责技能的自动生命周期管理:

python
# agent/curator.py(核心逻辑)
class SkillCurator:
    def run(self):
        """Curator 运行循环"""
        # 1. 加载使用统计数据
        usage = self._load_usage_stats()  # ~/.hermes/skills/.usage.json

        for skill in self._get_agent_skills():
            state = usage.get(skill.name, {})

            # 2. 根据使用频率判断状态转移
            if self._is_stale(skill, state):
                # 超过 30 天未使用 → 归档
                self._archive_skill(skill)
            elif self._is_frequently_used(skill, state):
                # 高频使用 → 固定(pin)
                self._pin_skill(skill)

            # 3. 对活跃技能进行 LLM 质量审查
            if self._needs_review(skill, state):
                review = self._llm_review_skill(skill)
                if review.suggested_improvements:
                    self._apply_review(skill, review)

    def _archive_skill(self, skill):
        """将技能移到 .archive/ 目录,永不删除"""
        archive_dir = SKILLS_DIR / ".archive"
        shutil.move(str(skill.dir), str(archive_dir / skill.name))

Curator 的不变量

  • 仅操作 created_by: "agent" 的技能,内置 + Hub 安装技能不受影响
  • 永不删除,最多归档到 .archive/
  • 被 Pin(固定)的技能豁免所有自动操作
  • skill_manage(action="delete") 拒绝删除 pinned 技能

五、记忆系统:跨 Session 知识持久化

Hermes 有三层记忆,使用不同的存储和检索策略:

5.1 提示记忆(Prompt Memory):MEMORY.md + USER.md

python
# agent/memory_manager.py
class MemoryManager:
    def flush(self, conversation_history):
        """将当前会话的关键信息持久化到记忆文件"""
        memory_path = HERMES_HOME / "MEMORY.md"
        user_path = HERMES_HOME / "USER.md"

        # 提取关键事实、用户偏好、工作约定
        insights = self._extract_insights(conversation_history)

        # MEMORY.md:工作相关的记忆(API 端点、项目结构、密码等)
        with open(memory_path, "a") as f:
            for insight in insights.work_memories:
                f.write(f"- {insight}\n")

        # USER.md:用户画像(偏好、风格、约束)
        with open(user_path, "a") as f:
            for insight in insights.user_insights:
                f.write(f"- {insight}\n")

5.2 情节记忆(Episodic Memory):SQLite FTS5 全文搜索

每个会话的轨迹被索引到 SQLite 数据库,支持跨会话上下文检索:

sql
-- 会话历史索引表(简化)
CREATE VIRTUAL TABLE session_history USING fts5(
    content,          -- 会话内容
    metadata,         -- JSON 元数据(时间、平台、模型等)
    tokenize='porter' -- 词干分析器
);

-- 查询:10ms 内跨 10,000+ 文档检索
SELECT snippet(session_history, 1, '<b>', '</b>', '...', 32)
FROM session_history
WHERE session_history MATCH ?
ORDER BY rank
LIMIT 5;

5.3 Honcho 用户建模

Honcho 是 Hermes 的辩证主义用户建模引擎。不同于静态用户画像,它通过持续对话维护一个不断演化的用户模型:

python
# Honcho 用户建模(概念简化)
class HonchoModel:
    def evolve(self, interaction):
        """基于新交互更新用户模型"""

        # 1. 更新用户画像
        self.profile.update({
            "preferences": self._extract_preferences(interaction),
            "style": self._detect_communication_style(interaction),
            "constraints": self._extract_constraints(interaction),
        })

        # 2. 模式检测
        if self._detect_pattern(self.history[-3:]):
            # 发现重复模式 → 创建模式洞察
            self.insights.append(
                self._synthesize_pattern(self.history[-3:])
            )

        # 3. 洞察综合
        self.history.append(interaction)

5.4 Memory Nudge:主动记忆

每 10 次交互或会话结束时,Hermes 会问自己:"这次对话中有哪些值得记住的信息?"

Nudge 类型 触发条件 目的
会话结束 对话关闭 总结关键收获
模式检测 3+ 次类似请求 持久化偏好
用户声明 用户说"记住这个" 立即存储
周期检查 每 10 轮交互 检查是否有价值信息

六、完整的技能自改进循环

现在让我们追踪一个完整的示例——看看 Hermes 如何从一次代码审查中学习和成长:

第一次请求:"帮我审查这个 PR"

code
1. Agent 收到请求
2. 扫描 skills_list(从 system prompt 中读取技能索引)
3. 没有匹配的 code-review 技能 → 从头推理
4. 执行 7 次 tool call:
   - gh pr view #42
   - gh pr diff
   - 对每个文件运行 lint
   - 总结变更
   - 发布评论
5. 成功完成 ✓
6. ★ 自评价检查点触发(7 > 5)
7. Agent 判断这是可复用的工作流
8. 调用 skill_manage(action='create', name='code-review', content=...)
9. 文件写入 ~/.hermes/skills/code-review/SKILL.md

第二次请求:"再审查 PR #58"

code
1. Agent 收到请求
2. 扫描 skills_list → 发现 code-review 技能匹配
3. ★ 使用触发条件匹配!调用 skill_view("code-review")
4. 加载完整 SKILL.md → 按步骤执行
5. 遇到新问题:PR 包含二进制文件
6. Agent 发现技能中没有处理二进制文件的步骤
7. 完成审查后:
   → skill_manage(action='patch', name='code-review',
                  old_string='## 步骤\n1. 读取 PR 的变更文件列表',
                  new_string='## 步骤\n1. 读取 PR 的变更文件列表\n'
                             '2. 过滤二进制文件(.png, .ico 等),仅审查文本文件')
8. 技能从 5 步变成了 6 步,增加了边界条件处理

第 N 次:技能成熟

经过 20-30 次使用后,技能文档已从简单的指令集演化为经过实战锤炼的操作手册:

  • 初始:5 行步骤
  • 一个月后:30+ 行,包含已知陷阱、验证步骤、边界情况
  • 原始未处理的边缘情况已通过 patch 逐步补充
  • 不再使用的步骤通过 edit 移除
  • 用户的偏好和组织的规范已固化到技能中

性能对比

指标 第 1 周 第 6 周
每次审查的 tool call 数 25 8-10
错误率 高(经常遗漏步骤) 低(边界情况已被覆盖)
需要的人工干预 频繁 几乎不需要

七、RL 强化学习管道:Atropos 集成

除了技能级的程序性学习,Hermes 还集成了 Atropos RL 管道进行更深层的行为优化:

python
# rl_cli.py - Atropos RL 训练入口
class AtroposRLPipeline:
    def train_from_trajectories(self, trajectories_dir):
        """从交互轨迹进行强化学习训练"""

        # 1. 批量轨迹生成
        trajectories = self._load_trajectories(trajectories_dir)

        # 2. 轨迹压缩(减少 token 开销)
        compressed = trajectory_compressor.compress(trajectories)

        # 3. 支持 RLHF / DPO 训练
        #    用户评分、纠正标记、自动评估
        for trajectory in compressed:
            reward = self._compute_reward(trajectory)
            # RLHF: 用户反馈作为奖励信号
            # DPO: 偏好对比训练
            self._training_step(trajectory, reward)

        # 4. 导出为 ShareGPT 格式
        self._export_for_finetuning(compressed)

但需要强调:RL 管道是可选的、离线的。日常的学习循环(技能创建 → 修补 → 记忆)不需要权重更新,在用户使用过程中实时发生。


八、"自改进"的真实含义

理解 Hermes 的学习机制,必须明确一个关键区分:

维度 Hermes 的学习 传统 ML 训练
作用对象 提示词、技能文档、记忆文件 模型权重
范围 特定用户的工作流 全局能力
频率 实时(每次任务后) 周期性(训练阶段)
存储 文件系统(明文 Markdown) 模型参数(二进制)
可解释性 完全透明(可读可编辑) 黑盒
回滚 简单(删文件或 git revert) 需要重新训练

结论:Hermes 的"自改进"不是模型变聪明了,而是围绕模型的辅助层——过程性记忆(Skills)和陈述性记忆(MEMORY.md/USER.md)——在持续累积经验。但这恰恰是实用层面最重要的改进:一个更了解你工作流的 Agent,比一个参数更多的通用模型更有价值。


九、代码学习:完整的最小学习循环实现

为了帮助理解,这里是一个极简版的学习循环实现(非 Hermes 源码,而是原理演示):

python
"""极简学习循环演示"""
import json
from pathlib import Path

SKILLS_DIR = Path.home() / ".demo-skills"
TOOL_CALL_THRESHOLD = 3  # 3+ 次 tool call 后触发学习

class LearningAgent:
    def __init__(self):
        self.tool_call_count = 0
        self.conversation_history = []
        SKILLS_DIR.mkdir(exist_ok=True)

    def run(self, user_input):
        self.conversation_history.append({"role": "user", "content": user_input})

        # 1. 构建提示词(含技能索引)
        prompt = self._build_prompt()

        # 2. 调用 LLM
        response = self._call_llm(prompt)

        # 3. 执行工具调用
        if response.get("tool_calls"):
            for tc in response["tool_calls"]:
                result = self._execute_tool(tc)
                self.conversation_history.append({
                    "role": "tool",
                    "content": result
                })
                self.tool_call_count += 1

            # ★ 自评价检查点
            if self.tool_call_count >= TOOL_CALL_THRESHOLD:
                self._learning_checkpoint()

            # 继续循环...
            return self.run(user_input)
        else:
            return response["content"]

    def _learning_checkpoint(self):
        """自评价:判断是否需要创建/更新技能"""
        # 提取本次任务的步骤
        steps = self._extract_steps()

        if not steps:
            return

        # 检测任务类型
        task_type = self._classify_task(steps)

        existing_skill = self._find_skill(task_type)

        if existing_skill:
            # 比较现有技能和实际执行步骤的差异
            new_steps = self._find_new_steps(existing_skill, steps)
            if new_steps:
                # Patch 技能:添加新发现的步骤
                self._patch_skill(existing_skill, new_steps)
                print(f"  → 技能 '{task_type}' 已更新 (+{len(new_steps)} steps)")
        else:
            # 创建新技能
            self._create_skill(task_type, steps)
            print(f"  → 新技能 '{task_type}' 已创建 ({len(steps)} steps)")

    def _create_skill(self, name, steps):
        """创建 SKILL.md 文件"""
        content = f"""---
name: {name}
description: 自动创建的技能
created_by: agent
---

# {name}

## 步骤
"""
        for i, step in enumerate(steps, 1):
            content += f"{i}. {step}\n"

        skill_dir = SKILLS_DIR / name
        skill_dir.mkdir(exist_ok=True)
        (skill_dir / "SKILL.md").write_text(content)

    def _patch_skill(self, name, new_steps):
        """修补技能:添加新步骤"""
        skill_file = SKILLS_DIR / name / "SKILL.md"
        content = skill_file.read_text()

        # 在 ## 步骤 部分追加新步骤
        old = "## 步骤\n"
        new = old + "\n".join(
            f"{i}. {step}" for i, step in enumerate(new_steps, 1)
        ) + "\n"
        content = content.replace(old, new, 1)

        skill_file.write_text(content)

运行示例:

python
agent = LearningAgent()
agent.run("帮我设置 CI/CD 流水线")
# 执行了 5 次 tool call
# → 自评价触发
# → 创建技能 'ci-cd-pipeline' (8 steps)

agent.run("再设置一个前端项目的 CI/CD")
# 技能匹配!加载 ci-cd-pipeline 技能
# 执行中发现缺少 npm install 步骤
# → 自动 patch 技能
# → 技能更新为 9 steps

十、总结

机制 技术实现 学习效果
技能创建 将复杂任务的执行轨迹抽象为 SKILL.md 从"不知道怎么做"到"有标准方法"
技能修补 使用模糊匹配引擎 patch 技能文件 从"有标准方法"到"方法越来越完善"
技能渐进加载 L0 索引 + L1 内容 + L2 附属文件 数百技能不增加 token 开销
记忆持久化 MEMORY.md / USER.md + SQLite FTS5 跨 Session 知识不丢失
Curator 生命周期 自动归档 + LLM 审查 技能库保持健康、无过期技能
Honcho 用户建模 辩证主义演进式用户画像 Agent 越来越了解你
Atropos RL 轨迹压缩 + DPO/RLHF 训练 可选深度优化模型行为

Hermes 的学习循环本质上是将 LLM 的推理能力与文件系统的持久性结合:LLM 负责判断"什么值得学"和"如何改进",文件系统负责"记住"和"检索"。这种架构让 Agent 在使用中不断累积领域知识,从第 1 天的通用助手,进化为第 30 天的专属工作伙伴。

正如 Nous Research 所说:"这不是一个更聪明的模型,这是一个更聪明的包装器。"(The LLM is a replaceable component; the real engineering work happens in the layers around it.


本文基于 Hermes Agent v2026.5.7 (v0.13.0) 源码分析,GitHub: https://github.com/NousResearch/hermes-agent