编程 Hermes Agent 深度拆解:自进化 AI Agent 架构全解析——从闭环学习到持久记忆的工程真相

2026-07-20 15:48:15 +0800 CST views 17

Hermes Agent 深度拆解:自进化 AI Agent 架构全解析——从闭环学习到持久记忆的工程真相

前言:为什么 Hermes Agent 值得你花时间理解

2026 年 2 月 25 日,AI 研究实验室 Nous Research 在 GitHub 上发布了一个名为 Hermes Agent 的开源项目。没有发布会,没有新闻通稿,上线六周后 Star 数从零飙升至 4.7 万,单日新增超过 6400 颗——这个速度仅次于 OpenClaw,被中文开发者社区戏称为"爱马仕"。

但 Star 数从来不能说明一切。真正让我花时间研究这个项目的,是它的核心定位:self-improving AI agent——一个真正能"越用越聪明"的 AI Agent,而不是一个简单的前端套壳或聊天机器人。

在翻完它的源码库、issue 区、贡献者文档和官方 Discord 之后,我的判断是:这个项目在架构层面有真正值得工程人员学习的东西。尤其是它把"闭环学习"(Closed Learning Loop)做成了原生能力,而不是事后打补丁——这一点对所有做 AI Agent 开发的工程师都有参考价值。

本文将从一个工程师的视角,完整拆解 Hermes Agent 的架构设计、核心机制、自进化学习循环的实现细节,并提供部署实战和代码示例。


一、背景与问题:为什么现有 Agent 框架都在"吃老本"

在聊 Hermes Agent 之前,我们需要先理解它试图解决的根本问题。

传统 Agent 框架的通病:几乎所有主流 Agent 框架——无论是 LangChain Agents、AutoGPT 还是各种"RAG + Tool Calling"方案——都有一个共同缺陷:它们是静态的

你配置好工具链、设定好 Prompt,Agent 就能工作。但当它遇到一个新的任务类型,完成之后,这个经验就消失了。下次遇到类似的场景,它还得从头推理,不会自动把"上次是怎么做的"沉淀下来。

这就好像一个员工,每天完成工作但从不复盘、不做笔记、不积累 SOP——永远在重复发明轮子。

三条技术路线在试图解决这个问题:

  1. Prompt Engineering 路线:不断优化 Prompt,让模型"记住"更多模式。治标不治本。
  2. 知识库 RAG 路线:把文档塞进去,希望模型检索到。但它解决的是"知识查询"问题,不是"能力增长"问题。
  3. Hermes 的路线:让 Agent 自主把执行经验封装成可执行技能(Skill),并在后续任务中复用和优化。

第三条路线的核心工程挑战是:如何在没有人工干预的情况下,让 AI Agent 可靠地把"成功经验"变成"可复用代码/Skill",而不是变成一堆无效的 Prompt 修改?

这就是 Hermes Agent 要回答的问题。


二、核心架构:五大模块如何协同工作

Hermes Agent 的技术架构由五个核心模块组成,这五个模块不是简单拼凑,而是经过深思熟虑的协同设计:

┌─────────────────────────────────────────────────────────────────┐
│                        Hermes Agent Architecture                  │
│                                                                  │
│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐       │
│  │ Self-Evolving│    │   Hierarchical│    │ Multi-Platform│     │
│  │ Learning Loop │◄──►│ Memory System │◄──►│ Gateway       │     │
│  │              │    │              │    │               │     │
│  └──────┬───────┘    └──────┬───────┘    └──────┬───────┘     │
│         │                   │                    │              │
│         └───────────────────┼────────────────────┘              │
│                             ▼                                    │
│              ┌──────────────────────────┐                        │
│              │   Universal Model Layer   │                       │
│              │  (OpenAI/Claude/Gemini/   │                       │
│              │   Ollama/本地模型)        │                        │
│              └──────────────────────────┘                        │
│                             ▼                                    │
│              ┌──────────────────────────┐                        │
│              │   Security Guardrails     │                        │
│              │   (命令执行控制/内容过滤)  │                       │
│              └──────────────────────────┘                        │
└─────────────────────────────────────────────────────────────────┘

2.1 自进化学习循环(Self-Evolving Learning Loop)

这是 Hermes 区别于所有其他 Agent 框架的核心模块,也是工程实现上最有难度的部分。

一个完整的学习闭环包含五个环节:

任务执行 → 评估触发 → 技能抽象 → 技能优化 → 持久化存储
    ↑                                              │
    └────────────── FTS5 召回 ←────────────────────┘

第一阶段:任务执行

Agent 接收用户任务,自主规划并执行。执行过程中会调用工具(终端、文件系统、浏览器、API 等),并记录完整的执行轨迹(trajectory)。

第二阶段:评估触发

每完成 15 次工具调用,或者一个复杂任务结束,系统自动触发自评估。这里的关键是不需要人工介入——评估逻辑由 LLM 本身完成,但有结构化的评估框架引导:

评估维度:
- 任务完成度:目标是否达成?
- 效率评分:步骤是否冗余?
- 错误恢复:从失败中恢复的能力如何?
- 可复用性:这次执行模式以后还能用吗?

第三阶段:技能抽象(Skill Creation)

如果评估认为这次执行模式值得复用,Agent 会自动将工作流封装为 Markdown 格式的 Skill 文件:

# Skill: 自动化 GitHub Issue 创建与标签分类

## 触发条件
当用户提供以下任意一种表达时触发:
- "帮我创建一个 issue"
- "提交一个 bug"
- "新建 issue"

## 执行步骤
1. 使用 `gh issue create` 创建 issue
2. 调用 GitHub API 获取当前仓库标签列表
3. 根据 issue 内容关键词(bug/feature/docs/test)自动匹配标签
4. 使用 `gh issue edit` 更新标签

## 参数
- repo: 仓库名(格式:owner/repo)
- title: issue 标题
- body: issue 正文(支持 Markdown)
- type: 类型推断(自动从内容中提取)

## 依赖工具
- gh CLI
- GitHub API

## 版本历史
- v1.0: 初始版本,基于 2026-06-15 的执行经验生成
- v1.1: 增加自动标签分类,2026-07-02 优化

这就是 Hermes 的关键设计:Skill 是 Markdown 文件,不是代码文件。这意味着任何人都可以阅读、编辑和复用,不需要编程知识。Skill 的可访问性被最大化了。

第四阶段:技能优化(Skill Self-Improvement)

当已有 Skill 在执行过程中失败,Agent 会自动分析失败原因,并对 Skill 进行优化:

失败分析流程:
1. 捕获错误类型和上下文
2. 判断是 Skill 本身的问题还是环境变化
3. 如果是 Skill 问题 → 生成优化方案
4. 验证优化方案(用 test case)
5. 更新 Skill 文件

第五阶段:持久化存储

所有 Skill 文件存储在 ~/.hermes/skills/ 目录下,以 Markdown 格式保存,文件名即 Skill 名称:

~/.hermes/skills/
├── github-issue-creator.md
├── docker-log-analyzer.md
├── api-response-cache.md
├── cron-job-manager.md
└── ...

2.2 分层持久记忆系统(Hierarchical Memory System)

Hermes 的记忆系统借鉴了认知科学的三种记忆类型,设计了一套分层架构:

记忆类型存储内容持久化方式召回方式
情景记忆(Episodic)会话历史、对话轨迹SQLite(JSON 序列化)时间范围检索
语义记忆(Semantic)MEMORY.md 文件文件系统全文关键词检索
程序性记忆(Procedural)Skill 文件(技能流程)Markdown 文件FTS5 索引召回

语义记忆的工程实现

MEMORY.md 是用户和 Agent 共建的知识文件。当 Agent 判断某个事实"值得长期记住"时,会追加到这个文件:

# MEMORY.md - 用户知识库

## 用户偏好
- 编程语言:Go > Python > TypeScript
- 数据库偏好:PostgreSQL(上线项目),SQLite(轻量工具)
- 不喜欢:过度封装,复杂的依赖链

## 技术栈
- 主要开发:macOS + VSCode + iTerm2
- 部署环境:阿里云 ECS + Docker
- CI/CD:GitHub Actions

## 项目上下文
- 当前项目:内部监控告警系统
- 技术选型:Go + Prometheus + Grafana
- 主要痛点:告警风暴,需要去重聚合逻辑

## 最后更新时间
2026-07-15 14:23:07

FTS5 全文索引:Hermes 使用 SQLite 的 FTS5(Full-Text Search 5)扩展对对话历史建立全文索引。这是一个工程上非常聪明的选择:

  • 零外部依赖:SQLite 是 Python 内置库,不需要额外安装 Elasticsearch 或 Meilisearch
  • 高性能:FTS5 专为全文检索优化,支持 BM25 排序算法
  • 本地化:所有数据存在本地,不上云,满足隐私需求
  • 持久化:数据库文件存放在 ~/.hermes/memory.db,重启不丢失
# FTS5 索引的工程价值——代码示例
# Hermes 使用 FTS5 实现跨会话记忆召回的内部逻辑

import sqlite3
import json
import os

def search_memory(query: str, top_k: int = 5):
    """
    基于 FTS5 的对话历史召回
    使用 BM25 算法排序,相关性最高的对话优先返回
    """
    conn = sqlite3.connect(os.path.expanduser("~/.hermes/memory.db"))
    cursor = conn.cursor()
    
    # FTS5 MATCH 查询,支持 AND/OR/NOT 逻辑
    sql = """
        SELECT session_id, timestamp, 
               snippet(history_content, 1, '**', '**', '...', 32) as snippet,
               bm25(memory_fts) as rank
        FROM memory_fts
        WHERE memory_fts MATCH ?
        ORDER BY rank
        LIMIT ?
    """
    
    # query 会自动进行词干提取(stemming)
    cursor.execute(sql, (query, top_k))
    results = cursor.fetchall()
    conn.close()
    
    return [
        {"session_id": r[0], "timestamp": r[1], "snippet": r[2], "rank": r[3]}
        for r in results
    ]

# 使用示例:召回所有涉及"Docker 容器"的历史对话
results = search_memory("Docker 容器 排查 内存")
for r in results:
    print(f"[{r['session_id']}] {r['snippet']}")

2.3 全模型兼容层(Universal Model Layer)

Hermes Agent 不绑定任何一家模型厂商,这是它区别于 OpenAI Agent SDK 或 Claude Agent 的关键策略。

# hermes 配置文件 ~/.hermes/config.yaml 示例

model_providers:
  # OpenAI 系列(GPT-4o、GPT-5 等)
  openai:
    api_base: "https://api.openai.com/v1"
    default_model: "gpt-4o"
    
  # Anthropic 系列(Claude 4 系列)
  anthropic:
    api_base: "https://api.anthropic.com"
    default_model: "claude-sonnet-4-20250514"
    
  # Google Gemini
  google:
    api_base: "https://generativelanguage.googleapis.com/v1"
    default_model: "gemini-2.5-pro"
    
  # 本地 Ollama(完全离线)
  ollama:
    api_base: "http://localhost:11434/v1"
    default_model: "qwen2.5:14b"
    
  # OpenRouter(聚合 200+ 模型)
  openrouter:
    api_base: "https://openrouter.ai/v1"
    default_model: "anthropic/claude-sonnet-4"
    
  # 国内模型(阿里千问、智谱 GLM、月之暗面 Kimi)
  chinese:
    qwen:
      api_base: "https://dashscope.aliyuncs.com/compatible-mode/v1"
      default_model: "qwen3-8B"
    zhipu:
      api_base: "https://open.bigmodel.cn/api/paas/v4"
      default_model: "glm-4-flash"

# 模型路由策略
routing:
  default: "openrouter/claude-sonnet-4"
  coding: "openrouter/claude-sonnet-4"
  research: "openrouter/openai/o3-mini-high"
  local_fallback: "ollama/qwen2.5:14b"  # 网络故障时自动切换到本地模型

这个设计的工程价值在于:当某个模型 API 出现故障或限流时,Hermes 可以自动切换到备用模型,整个执行过程不会中断。

2.4 多平台消息网关(Multi-Platform Gateway)

Hermes 统一了 15+ 消息平台的接入,通过一个 gateway 进程管理所有平台的连接:

支持的平台:
├── 即时通讯:Telegram、Discord、Slack、WhatsApp、Signal、Matrix
├── 邮件:Email(IMAP/SMTP)
├── 国产平台:微信(企业版)、飞书、钉钉
├── 物联网:Home Assistant
└── 开发工具:CLI(本地终端)、SSH(远程服务器)

网关架构设计(Python asyncio 实现):

# gateway 架构简化版

import asyncio
from abc import ABC, abstractmethod

class PlatformAdapter(ABC):
    """各平台的统一适配器接口"""
    
    @abstractmethod
    async def connect(self):
        pass
    
    @abstractmethod
    async def send_message(self, message: str, target: str):
        pass
    
    @abstractmethod
    async def receive_message(self) -> tuple[str, str]:
        """返回 (sender_id, message_content)"""
        pass

class HermesGateway:
    """
    统一网关:管理所有平台连接,运行单一进程
    消息统一格式:{"platform": "telegram", "from": "user123", "content": "..."}
    """
    
    def __init__(self):
        self.platforms: dict[str, PlatformAdapter] = {}
        self.message_queue: asyncio.Queue = asyncio.Queue()
    
    async def register(self, platform_name: str, adapter: PlatformAdapter):
        """注册新的平台适配器"""
        await adapter.connect()
        self.platforms[platform_name] = adapter
        # 启动该平台的接收循环
        asyncio.create_task(self._receive_loop(platform_name, adapter))
    
    async def _receive_loop(self, platform: str, adapter: PlatformAdapter):
        """每个平台独立接收循环,互不阻塞"""
        while True:
            try:
                sender, content = await adapter.receive_message()
                await self.message_queue.put({
                    "platform": platform,
                    "sender": sender,
                    "content": content,
                    "timestamp": asyncio.get_event_loop().time()
                })
            except Exception as e:
                # 单平台故障不影响其他平台
                await asyncio.sleep(5)  # 5秒后重试
    
    async def broadcast(self, message: str, target_platforms: list[str] = None):
        """向指定平台(或全部平台)广播消息"""
        targets = target_platforms or list(self.platforms.keys())
        await asyncio.gather(
            *[self.platforms[p].send_message(message, "broadcast") 
              for p in targets if p in self.platforms]
        )

这个架构的设计亮点是事件驱动:所有平台的消息进入统一队列后,由 Hermes Agent 的核心推理引擎处理,响应逻辑与平台无关。

2.5 安全护栏体系(Security Guardrails)

由于 Hermes Agent 能够执行终端命令,安全设计至关重要。Hermes 采用多层安全机制:

# ~/.hermes/security.yaml

security:
  # 命令执行白名单(明确允许的命令)
  allowed_commands:
    - git
    - docker
    - npm
    - pip
    - curl
    - kubectl
    - gh
    - cat
    - ls
    - grep
    - find
    - tar
    - zip
    
  # 危险命令黑名单(绝对禁止)
  blocked_commands:
    - rm -rf /       # 递归删除根目录
    - :(){ :|:& };:  # Fork 炸弹
    - dd if=/dev/zero
    - mkfs
    - shutdown
    - reboot
    - chmod -R 000
    
  # 文件系统访问限制(沙盒目录)
  filesystem:
    sandbox_root: "~/.hermes/sandbox"
    allow_beyond_sandbox: false  # 是否允许访问沙盒外文件
    dangerous_extensions:
      - .exe
      - .dmg
      - .bat
      - .ps1
    
  # 网络访问限制
  network:
    allowed_domains:
      - "*.github.com"
      - "api.openai.com"
      - "api.anthropic.com"
    blocked_ports:
      - 22    # SSH(防止远程隧道)
      - 3306  # MySQL
      - 5432  # PostgreSQL
      - 6379  # Redis(防止未授权访问)
    max_request_size_mb: 10

三、自进化循环的工程实现:代码级拆解

光有架构描述不够,我们来看一个真实的自进化循环执行流程,用代码说明它到底是怎么工作的。

3.1 任务执行与轨迹记录

# hermes-agent/core/loop.py(概念代码,基于官方架构文档重构)

from dataclasses import dataclass, field
from typing import Callable
import json
from datetime import datetime

@dataclass
class ToolCall:
    """单次工具调用记录"""
    tool_name: str
    arguments: dict
    result: str
    duration_ms: float
    success: bool
    timestamp: datetime = field(default_factory=datetime.now)

@dataclass
class ExecutionTrace:
    """完整执行轨迹"""
    task_id: str
    user_prompt: str
    tool_calls: list[ToolCall] = field(default_factory=list)
    final_output: str = ""
    evaluation_score: float = 0.0
    skills_created: list[str] = field(default_factory=list)
    
    @property
    def total_calls(self) -> int:
        return len(self.tool_calls)
    
    @property
    def success_rate(self) -> float:
        if not self.tool_calls:
            return 0.0
        return sum(1 for tc in self.tool_calls if tc.success) / len(self.tool_calls)
    
    def add_tool_call(self, tool_name: str, args: dict, 
                      result: str, duration: float, success: bool):
        self.tool_calls.append(ToolCall(
            tool_name=tool_name,
            arguments=args,
            result=result,
            duration_ms=duration,
            success=success
        ))


class SelfEvolvingLoop:
    """
    自进化学习循环核心逻辑
    触发条件:每 15 次工具调用 或 任务完成
    """
    
    def __init__(self, memory_system, llm_client, skill_manager):
        self.memory = memory_system
        self.llm = llm_client
        self.skills = skill_manager
        self.call_counter = 0
        self.eval_threshold = 15  # 每 15 次调用触发评估
    
    async def execute_task(self, user_prompt: str) -> ExecutionTrace:
        trace = ExecutionTrace(
            task_id=f"task_{datetime.now().timestamp()}",
            user_prompt=user_prompt
        )
        
        while not self.is_task_complete(trace):
            # 1. LLM 决定下一步行动
            decision = await self.llm.decide_next_action(
                prompt=user_prompt,
                trace=trace,
                available_tools=self.get_available_tools()
            )
            
            if decision.type == "tool_call":
                # 2. 执行工具调用并记录
                start = datetime.now()
                result = await self.execute_tool(decision.tool_name, decision.args)
                duration = (datetime.now() - start).total_seconds() * 1000
                
                trace.add_tool_call(
                    tool_name=decision.tool_name,
                    args=decision.args,
                    result=str(result),
                    duration=duration,
                    success=not result.get("error")
                )
                
                self.call_counter += 1
                
                # 3. 检查是否需要触发自评估
                if self.call_counter >= self.eval_threshold:
                    await self._trigger_self_evaluation(trace)
                    self.call_counter = 0
                    
            elif decision.type == "response":
                trace.final_output = decision.text
        
        # 任务完成后再次评估(最终评估)
        await self._trigger_self_evaluation(trace)
        await self._consider_skill_creation(trace)
        
        return trace
    
    async def _trigger_self_evaluation(self, trace: ExecutionTrace):
        """触发自评估:LLM 对当前轨迹进行复盘"""
        
        eval_prompt = f"""
        请对以下执行轨迹进行自评估:

        用户任务:{trace.user_prompt}
        工具调用次数:{trace.total_calls}
        成功率:{trace.success_rate:.1%}
        
        评估维度(0-10分):
        1. 任务完成度:结果是否达到了用户目标?
        2. 执行效率:步骤是否冗余?有无更短路径?
        3. 错误处理:失败后恢复得如何?
        4. 可复用性:这个执行模式以后还能用吗?
        
        请给出结构化的 JSON 评估结果。
        """
        
        evaluation = await self.llm.generate_structured(
            eval_prompt,
            schema={
                "task_completion": "float 0-10",
                "efficiency": "float 0-10", 
                "error_recovery": "float 0-10",
                "reusability": "float 0-10",
                "summary": "string 评估总结",
                "lessons_learned": "list 经验教训"
            }
        )
        
        trace.evaluation_score = (
            evaluation["task_completion"] * 0.4 +
            evaluation["efficiency"] * 0.2 +
            evaluation["error_recovery"] * 0.2 +
            evaluation["reusability"] * 0.2
        )
        
        await self.memory.store_evaluation(trace, evaluation)
    
    async def _consider_skill_creation(self, trace: ExecutionTrace):
        """
        判断是否值得创建 Skill
        核心逻辑:可复用性得分 >= 7/10 时创建
        """
        
        if trace.evaluation_score < 7.0:
            return  # 质量不够,不创建
        
        existing = await self.skills.find_similar(trace.user_prompt)
        if existing:
            # 已有类似 Skill → 优化它
            await self.skills.improve(existing, trace)
        else:
            # 没有类似 Skill → 创建新的
            skill_path = await self.skills.create_from_trace(trace)
            trace.skills_created.append(skill_path)

3.2 Skill 创建:从轨迹到可执行技能

# hermes-agent/core/skill_manager.py(概念代码)

import os
import re
from pathlib import Path
from datetime import datetime

SKILLS_DIR = Path.home() / ".hermes" / "skills"

class SkillManager:
    """Skill 的创建、优化和召回管理"""
    
    async def create_from_trace(self, trace: ExecutionTrace) -> str:
        """从执行轨迹自动生成 Skill Markdown 文件"""
        
        skill_content = await self._llm_generate_skill_markdown(trace)
        
        skill_name = self._infer_skill_name(trace.user_prompt)
        safe_name = re.sub(r'[^\w\s-]', '', skill_name).strip().replace(' ', '-').lower()
        
        file_path = SKILLS_DIR / f"{safe_name}.md"
        file_path.parent.mkdir(parents=True, exist_ok=True)
        
        file_path.write_text(skill_content)
        await self._index_skill(file_path, skill_content)
        
        return str(file_path)
    
    async def _llm_generate_skill_markdown(self, trace: ExecutionTrace) -> str:
        """使用 LLM 生成结构化的 Skill Markdown"""
        
        prompt = f"""
        基于以下执行轨迹,生成一个可复用的 Skill Markdown 文件。

        用户任务:{trace.user_prompt}
        工具调用序列:{[tc.tool_name for tc in trace.tool_calls]}
        最终输出:{trace.final_output}
        
        请生成符合以下格式的 Markdown:
        
        # Skill: <从任务推断的名称>
        
        ## 触发条件
        <什么情况下应该调用这个 Skill>
        
        ## 执行步骤
        <步骤化的执行流程,每步对应一个工具调用>
        
        ## 参数定义
        <Skill 的输入参数>
        
        ## 依赖环境
        <需要哪些工具/权限>
        
        ## 边界情况
        <常见错误和应对方式>
        
        ## 版本信息
        - v1.0: 初始版本,基于 {datetime.now().strftime('%Y-%m-%d')} 执行经验生成
        """
        
        return await self.llm.generate(prompt)
    
    async def improve(self, existing_skill_path: str, new_trace: ExecutionTrace):
        """对已有 Skill 进行增量优化"""
        
        existing_content = Path(existing_skill_path).read_text()
        
        improvement_prompt = f"""
        当前 Skill 内容:
        {existing_content}
        
        新增执行经验(这次执行有什么改进点?):
        工具调用:{[tc.tool_name for tc in new_trace.tool_calls]}
        
        请在保留现有内容的基础上,补充:
        1. 新的边界情况处理
        2. 优化后的执行步骤(如果有更优路径)
        3. 新增版本记录条目
        """
        
        improved = await self.llm.generate(improvement_prompt)
        Path(existing_skill_path).write_text(improved)

四、部署实战:从零到生产级别的完整指南

4.1 快速安装(Linux/macOS/WSL2)

# 一键安装脚本(推荐)
curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash

# 验证安装
hermes --version

# 查看帮助
hermes --help

4.2 Docker 部署(生产推荐)

# docker-compose.yml
version: '3.8'

services:
  hermes-agent:
    image: nousresearch/hermes-agent:latest
    container_name: hermes-agent
    restart: unless-stopped
    environment:
      # 模型配置
      - HERMES_DEFAULT_MODEL=openrouter/anthropic/claude-sonnet-4
      - OPENROUTER_API_KEY=${OPENROUTER_API_KEY}
      
      # 安全配置
      - HERMES_SECURITY_MODE=strict
      - HERMES_ALLOW_SUDO=false
      
      # 记忆持久化(关键!)
      - HERMES_MEMORY_DIR=/data/memory
      - HERMES_SKILLS_DIR=/data/skills
      
      # 日志级别
      - RUST_LOG=info
    
    volumes:
      # 持久化记忆和技能(数据不丢失)
      - hermes-data:/data
      - /var/run/docker.sock:/var/run/docker.sock:ro  # 按需
    
    ports:
      - "8000:8000"   # REST API
      - "8001:8001"   # WebSocket(实时消息)
    
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 10s
      retries: 3

volumes:
  hermes-data:
    driver: local
# 启动
docker compose up -d

# 查看日志
docker compose logs -f hermes-agent

4.3 本地模型部署(Ollama,完全离线运行)

# docker-compose.local.yml(使用 Ollama 本地模型)

services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    restart: unless-stopped
    environment:
      - OLLAMA_HOST=0.0.0.0:11434
    volumes:
      - ollama-data:/root/.ollama
    ports:
      - "11434:11434"
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]
    
  hermes-agent:
    image: nousresearch/hermes-agent:latest
    environment:
      - HERMES_DEFAULT_MODEL=ollama/qwen2.5:14b
      - OLLAMA_API_BASE=http://ollama:11434/v1
    depends_on:
      - ollama

volumes:
  ollama-data:
# 先拉取模型
docker exec -it ollama ollama pull qwen2.5:14b
docker exec -it ollama ollama pull nomic-embed-text

# 启动完整栈
docker compose -f docker-compose.local.yml up -d

4.4 多模型路由配置

# ~/.hermes/config.yaml

model_routing:
  rules:
    - trigger: "写代码|编程|debug|重构"
      model: "openrouter/anthropic/claude-sonnet-4"
      
    - trigger: "搜索|调研|分析"
      model: "openrouter/openai/gpt-4o"
      
    - trigger: "快速回答|简单问题"
      model: "ollama/qwen2.5:7b"
    
    - trigger: "私密内容|内部数据"
      model: "ollama/qwen2.5:14b"

  fallback_chain:
    - "openrouter/anthropic/claude-sonnet-4"
    - "openrouter/openai/gpt-4o"
    - "ollama/qwen2.5:14b"

五、MCP 协议集成:Hermes Agent 的工具扩展能力

5.1 MCP 是什么

MCP(Model Context Protocol)是 2026 年 AI Agent 领域最重要的协议之一,Hermes 对 MCP 的原生支持使其工具能力可以无限扩展。

没有 MCP:
Agent 需要为每个工具写独立的适配代码
├── Slack 集成 → SlackAdapter
├── GitHub 集成 → GitHubAdapter  
├── 数据库 → DBAdapter
└── 文件系统 → FileSystemAdapter

有了 MCP:
Agent 只需要实现 MCP Client
所有工具按统一协议接入
├── MCP Server: Slack
├── MCP Server: GitHub
├── MCP Server: PostgreSQL
└── MCP Server: File System

5.2 Hermes 中的 MCP 集成配置

# ~/.hermes/config.yaml

mcp:
  servers:
    # GitHub MCP Server——直接在对话中操作 GitHub
    github:
      command: "npx"
      args: ["-y", "@modelcontextprotocol/server-github"]
      env:
        GITHUB_PERSONAL_ACCESS_TOKEN: "${GITHUB_TOKEN}"
    
    # 文件系统 MCP Server——安全的文件操作
    filesystem:
      command: "npx"
      args: ["-y", "@modelcontextprotocol/server-filesystem"]
      env:
        ALLOWED_DIRECTORY: "/home/user/projects"
    
    # PostgreSQL MCP Server——数据库查询
    postgres:
      command: "npx"
      args: ["-y", "@modelcontextprotocol/server-postgres"]
      env:
        DATABASE_URL: "postgresql://user:pass@localhost:5432/mydb"
    
    # Brave Search MCP Server——网络搜索
    brave-search:
      command: "npx"
      args: ["-y", "@modelcontextprotocol/server-brave-search"]
      env:
        BRAVE_API_KEY: "${BRAVE_SEARCH_API_KEY}"

5.3 MCP 生态 2026 年最新数据

指标数据
官方 MCP Servers80+
社区 MCP Servers2000+
NPM 上的 MCP 包500+
支持 MCP 的 Agent 框架15+(含 Cursor、Claude Desktop、OpenClaw、Zed)
日均 MCP 调用量(社区)1000 万次以上
# 安装热门 MCP Server

# GitHub 操作(提 issue/PR/代码审查)
npx -y @modelcontextprotocol/server-github

# PostgreSQL 数据库(直接用自然语言查数据)
npx -y @modelcontextprotocol/server-postgres

# Brave 搜索(不依赖 Google)
npx -y @modelcontextprotocol/server-brave-search

# Puppeteer 浏览器自动化
npx -y @modelcontextprotocol/server-puppeteer

# Kubernetes 集群管理
npx -y @modelcontextprotocol/server-kubernetes

六、与主流 Agent 框架的横评

维度Hermes AgentOpenClawLangChain AgentsAutoGPT
自进化能力原生闭环内置记忆需要手动配置
Skill 系统Markdown 可编辑WorkflowLangChain Chain
记忆持久化FTS5+文件LCM 压缩需额外配置
多平台支持15+ 平台多渠道需定制
本地模型Ollama 原生支持支持支持
MCP 支持原生支持通过 LangChain MCP
部署难度简单简单复杂中等
GitHub Stars21.6 万+对比基线N/A16 万+

七、工程反思:自进化 Agent 的边界与挑战

7.1 Skill 质量失控风险

当 Agent 自主创建的 Skill 越来越多,如何保证 Skill 的质量不会随着版本迭代而退化

目前 Hermes 的机制是:每次失败的 Skill 调用都会触发优化,但如果优化方向错了(比如把一个本应被废弃的 Skill 修了又修),Skill 会变得越来越复杂、越来越难以理解。

这是一个 LLM 自动化的固有风险:自我改进的系统如果没有外部约束,可能会在局部最优解里越陷越深

7.2 记忆数据库的膨胀

FTS5 全文索引 + SQLite 会话存储,在长期运行后会产生大量数据。当记忆库达到 GB 级别时,检索延迟会显著上升。此外,目前的召回是基于关键词 FTS5 的,没有向量嵌入,在语义相似性召回上不如专门的向量数据库。

7.3 安全的自进化边界

这是最核心的哲学问题:如果 Agent 有权限修改自己的 Skill(行为逻辑),那么它的行为边界由谁来定义?

Hermes 的安全护栏(security.yaml)是静态配置的,Agent 本身无法修改它。但如果 Agent 学会了绕过安全限制,安全配置文件本身被损坏,系统的安全性就会完全失效。

这实际上是 2026 年整个 AI Agent 领域都在面对的核心问题:可审计性 + 可控性 + 自进化能力,这三者如何共存?


八、总结与展望

Hermes Agent 的出现,标志着 AI Agent 从"工具调用框架"时代,进入"持续学习系统"时代。

从工程实现的角度,Hermes 有几个值得所有 AI 开发者学习的点:

  1. Skill 即 Markdown:把执行经验用最通用的格式保存,最大化了可复用性
  2. FTS5 替代向量数据库:用 SQLite 解决 90% 的召回需求,不需要引入沉重的外部依赖
  3. 事件驱动的多平台网关:一个进程管所有平台,架构清晰,扩展容易
  4. 安全护栏与自进化并行:安全不是事后补救,而是和进化机制同步设计

展望未来:我认为 Hermes 的路线会启发更多框架采用"原生自进化"设计。但最终,决定 Agent 系统能走多远的,不是它的功能有多强大,而是它的可预测性可审计性——人类需要能够理解 Agent 为什么会做出某个决策,而不是只看到结果。

在这个意义上,Hermes Agent 是一个非常好的起点,但绝不是终点。


参考资源


本文首发于 程序员茄子,cid=1,tag: Hermes Agent|AI Agent|自进化|Nous Research|MCP|Python|2026

推荐文章

MySQL用命令行复制表的方法
2024-11-17 05:03:46 +0800 CST
程序员茄子在线接单