编程 Hermes Agent 深度解析:当 AI 终于学会「从经验中自己长大」

2026-04-11 07:13:15 +0800 CST views 45

Hermes Agent 深度解析:当 AI 终于学会「从经验中自己长大」

前言:AI Agent 的「失忆症」终于有救了

你有没有这种感觉——跟 AI 聊了一百遍,它还是不认识你。每次都像在跟一个失忆症患者对话,同样的背景交代、同样的偏好说明、同样的工作习惯解释……一遍又一遍。

这不是模型不够聪明,是架构出了问题。

传统 AI Agent 的设计哲学是「无状态」的:每次对话从零开始,做完就忘。这种设计有其合理性——简单、可控、容易实现。但当我们把 AI 当成长期工作伙伴来用时,这种「金鱼记忆」就成了致命缺陷。

2026 年 4 月,一个叫 Hermes Agent 的开源项目给了这个问题一个漂亮的答案。两个月 4.7 万 Star,登顶 GitHub Trending 全站第一,背后是一套让 Agent 真正「长记性」的完整工程方案。

这篇文章不谈概念,不吹愿景,我们就把 Hermes Agent 拆开来看——它的四层记忆系统怎么实现的,它的「提示反向传播」机制到底在做什么,它的自动技能生成系统凭什么能让 Agent 越用越聪明。代码级分析,不留死角。


一、项目背景:做模型的人亲自下场做 Agent

1.1 Nous Research 是谁

Hermes Agent 的开发团队 Nous Research,在开源 LLM 社区其实早有名气。他们家的 Hermes 系列微调模型,在 function calling 和 tool use 方面一直是开源圈的标杆。

这次他们从「做模型」跨界到「做 Agent」,核心逻辑很清晰:模型能力再强,没有好的系统架构支撑,也发挥不出价值。与其等着别人来做,不如自己做。

1.2 核心定位

Hermes Agent 的定位很明确:部署在你服务器上的持久化个人智能体

注意这几个关键词:

  • 部署在你服务器上:数据不离机器,隐私可控
  • 持久化:跨会话保留记忆,越用越懂你
  • 个人智能体:不是聊天窗口,不是代码补全,是真正能执行任务的 Agent
维度说明
出品方Nous Research(美国开源 AI 研究实验室)
开源协议MIT(完全免费,可商用)
技术栈Python
支持系统Linux、macOS、WSL2
GitHub Stars47,000+(截至 2026 年 4 月)
贡献者240+ 人
迭代速度平均不到一周一个大版本

1.3 与其他 Agent 的本质区别

传统 Agent 的模式是:用户提问 → Agent 执行 → 任务完成 → 对话结束 → 记忆清空

Hermes 的模式是:用户提问 → Agent 执行 → 任务完成 → 自动提炼技能 → 存入记忆库 → 下次直接复用

这个「执行—学习—改进」的闭环,是 Hermes 与所有其他 Agent 拉开差距的核心。


二、核心机制一:KEPA——对「提示」做反向传播

2.1 什么是 KEPA

KEPA(Knowledge Evolution via Prompt Adaptation)是 Hermes Agent 的核心创新。用一句话概括:它把深度学习中的反向传播思想,移植到了 Prompt 工程上

先看传统深度学习的模式:

前向传播:输入 → 模型 → 输出
反向传播:计算损失 → 更新模型权重

Hermes 的模式:

前向传播:用户意图 → Hermes(LLM + 工具) → 执行序列(工具调用链、代码生成等)
反向传播:周期性回顾执行 → 检测失败点 → 生成改进提示/改进skill定义 → 更新记忆库、技能库

关键差异:不是更新「模型权重」,而是更新「如何使用模型」的策略——包括提示模板、调用工具的顺序和条件、技能拆解方式等。

2.2 KEPA 的工作流程

┌─────────────────────────────────────────────────────────────────┐
│                     KEPA 反向传播周期                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. 执行阶段:Agent 完成约 15 次工具调用                         │
│      ↓                                                          │
│  2. 记录阶段:保存完整的执行轨迹(工具、参数、结果)              │
│      ↓                                                          │
│  3. 回放阶段:LLM 逐条分析执行记录                               │
│      ↓                                                          │
│  4. 评估阶段:识别失败点、低效点、用户纠错                       │
│      ↓                                                          │
│  5. 改进阶段:生成新的提示模板 / 更新已有技能定义                │
│      ↓                                                          │
│  6. 固化阶段:写入记忆库和技能库                                 │
│      ↓                                                          │
│  7. 下一周期:使用改进后的配置继续执行                           │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

2.3 代码层面的实现思路

虽然 Hermes 的具体实现较为复杂,但我们可以用一个简化的 Python 示例来说明核心思想:

class KEPALoop:
    """简化版的 KEPA 反向传播机制"""
    
    def __init__(self, llm_client, skill_store, memory_store):
        self.llm = llm_client
        self.skills = skill_store
        self.memory = memory_store
        self.execution_trace = []
        self.call_counter = 0
    
    def record_execution(self, tool_name: str, params: dict, result: dict):
        """记录每次工具调用的完整轨迹"""
        self.execution_trace.append({
            "tool": tool_name,
            "params": params,
            "result": result,
            "timestamp": time.time()
        })
        self.call_counter += 1
        
        # 每 15 次调用触发一次反思
        if self.call_counter >= 15:
            self.reflect_and_improve()
            self.execution_trace = []
            self.call_counter = 0
    
    def reflect_and_improve(self):
        """KEPA 的核心:反思并改进"""
        
        # 1. 构建反思提示
        reflection_prompt = f"""
        分析以下执行轨迹,识别可以改进的地方:
        
        执行记录:
        {json.dumps(self.execution_trace, indent=2, ensure_ascii=False)}
        
        请分析:
        1. 哪些工具调用失败了?失败原因是什么?
        2. 哪些调用顺序可以优化?
        3. 是否发现了可复用的模式?
        4. 用户是否有明确的偏好?
        
        输出格式:
        - improvements: 改进建议列表
        - skill_candidate: 是否可以提取为新技能
        - skill_definition: 如果可以,定义技能
        """
        
        # 2. 调用 LLM 进行分析
        analysis = self.llm.chat(reflection_prompt)
        
        # 3. 解析并应用改进
        result = parse_analysis(analysis)
        
        if result.get("skill_candidate"):
            self.skills.create_or_update(
                name=result["skill_definition"]["name"],
                definition=result["skill_definition"]
            )
        
        for improvement in result.get("improvements", []):
            self.memory.add_learning(improvement)

2.4 为什么不用微调?

很多人会问:既然要学习,为什么不直接微调模型?

答案是:微调的成本太高,且不适合个人场景。

维度微调KEPA
计算成本需要 GPU 集群只需要 LLM API
数据需求大量标注数据自动从执行中学习
更新频率周/月级别实时/小时级别
可解释性黑盒每次改进都有记录
个人化需要单独微调每个用户独立配置

KEPA 的本质是把「学习」从模型层剥离出来,放到应用层。这样做的代价是学习深度不如微调,但好处是成本低、迭代快、可解释。


三、核心机制二:四层记忆系统架构

3.1 为什么记忆这么难

在 AI Agent 领域,记忆问题分为两类:

  1. 访问型记忆(Retrieval Memory):从外部知识库检索信息。这个相对简单,RAG 技术已经比较成熟。

  2. 内化型记忆(Integrated Memory):Agent 真正「记住」的东西——用户的偏好、过去的经验、学到的技能。这才是难点。

内化型记忆要解决几个核心问题:

  • 持久化:关机重启后记忆还在吗?
  • 整合性:新记忆怎么和旧记忆融合?
  • 检索效率:记忆多了之后怎么快速找到相关的?
  • 遗忘机制:不可能什么都记,什么该忘?

3.2 Hermes 的四层架构

Hermes Agent 采用了四层记忆系统架构:

┌─────────────────────────────────────────────────────────────────┐
│ Layer 4: 元记忆层 (Meta Memory)                                 │
│ ─────────────────────────────────────────────────────────────── │
│ 管理其他三层记忆的刷新、检索和整合策略                           │
│ 类似人类大脑的「元认知」能力                                     │
├─────────────────────────────────────────────────────────────────┤
│ Layer 3: 技能记忆层 (Skill Memory)                              │
│ ─────────────────────────────────────────────────────────────── │
│ 自动沉淀的可复用技能文档                                        │
│ 存储格式:Markdown(agentskills.io 标准)                       │
│ 存储位置:~/.hermes/skills/                                     │
├─────────────────────────────────────────────────────────────────┤
│ Layer 2: 持久记忆层 (Persistent Memory)                         │
│ ─────────────────────────────────────────────────────────────── │
│ 跨会话的事实、偏好、项目背景                                    │
│ 技术实现:SQLite + FTS5 全文检索                                │
│ 存储位置:~/.hermes/memories/                                   │
├─────────────────────────────────────────────────────────────────┤
│ Layer 1: 会话记忆层 (Session Memory)                            │
│ ─────────────────────────────────────────────────────────────── │
│ 当前对话的临时上下文                                            │
│ 技术实现:LLM 驱动的摘要生成                                    │
│ 生命周期:单次会话                                              │
└─────────────────────────────────────────────────────────────────┘

3.3 各层的技术实现细节

Layer 1: 会话记忆层

会话记忆层管理当前对话的上下文。它的核心挑战是:如何在有限的 Token 预算内保留最关键的信息?

Hermes 的方案是 LLM 驱动的动态摘要:

class SessionMemory:
    """会话记忆层实现"""
    
    def __init__(self, max_tokens=4000, llm_client=None):
        self.messages = []  # 原始消息列表
        self.summary = ""   # 当前摘要
        self.max_tokens = max_tokens
        self.llm = llm_client
    
    def add_message(self, role: str, content: str):
        """添加消息并检查是否需要摘要"""
        self.messages.append({"role": role, "content": content})
        
        if self._estimate_tokens() > self.max_tokens:
            self._compress_history()
    
    def _compress_history(self):
        """当 Token 超限时压缩历史"""
        # 保留最近的几条消息
        recent_messages = self.messages[-4:]
        
        # 对早期消息生成摘要
        old_messages = self.messages[:-4]
        if old_messages:
            new_summary = self._generate_summary(old_messages)
            self.summary = f"{self.summary}\n{new_summary}" if self.summary else new_summary
        
        self.messages = recent_messages
    
    def _generate_summary(self, messages: list) -> str:
        """使用 LLM 生成对话摘要"""
        prompt = f"""
        请将以下对话压缩成简洁的摘要,保留关键决策、结论和未完成的任务:
        
        {json.dumps(messages, ensure_ascii=False, indent=2)}
        """
        return self.llm.chat(prompt)
    
    def get_context(self) -> list:
        """获取当前会话的完整上下文"""
        context = []
        
        if self.summary:
            context.append({
                "role": "system",
                "content": f"[历史摘要]\n{self.summary}"
            })
        
        context.extend(self.messages)
        return context

Layer 2: 持久记忆层

持久记忆层是真正的「长期记忆」,使用 SQLite + FTS5 实现:

import sqlite3
import json
from datetime import datetime

class PersistentMemory:
    """持久记忆层实现"""
    
    def __init__(self, db_path: str = "~/.hermes/memories/memory.db"):
        self.db_path = os.path.expanduser(db_path)
        self._init_db()
    
    def _init_db(self):
        """初始化 SQLite + FTS5 全文检索"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        # 创建主表
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS memories (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                content TEXT NOT NULL,
                memory_type TEXT DEFAULT 'general',
                importance REAL DEFAULT 0.5,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                last_accessed TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                access_count INTEGER DEFAULT 0
            )
        """)
        
        # 创建 FTS5 全文检索虚拟表
        cursor.execute("""
            CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts 
            USING fts5(content, content='memories', content_rowid='id')
        """)
        
        # 创建触发器:插入时同步到 FTS
        cursor.execute("""
            CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories
            BEGIN
                INSERT INTO memories_fts(rowid, content) 
                VALUES (new.id, new.content);
            END
        """)
        
        conn.commit()
        conn.close()
    
    def store(self, content: str, memory_type: str = "general", importance: float = 0.5):
        """存储新的记忆"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        cursor.execute("""
            INSERT INTO memories (content, memory_type, importance)
            VALUES (?, ?, ?)
        """, (content, memory_type, importance))
        
        conn.commit()
        conn.close()
    
    def search(self, query: str, limit: int = 10) -> list:
        """全文检索相关记忆"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        # FTS5 检索,按相关度排序
        cursor.execute("""
            SELECT m.id, m.content, m.importance, m.access_count,
                   bm25(memories_fts) as relevance
            FROM memories m
            JOIN memories_fts fts ON m.id = fts.rowid
            WHERE memories_fts MATCH ?
            ORDER BY relevance, m.importance DESC
            LIMIT ?
        """, (query, limit))
        
        results = cursor.fetchall()
        
        # 更新访问记录
        for row in results:
            cursor.execute("""
                UPDATE memories 
                SET last_accessed = ?, access_count = access_count + 1
                WHERE id = ?
            """, (datetime.now(), row[0]))
        
        conn.commit()
        conn.close()
        
        return [{"content": r[1], "importance": r[2], "access_count": r[3]} for r in results]
    
    def get_user_preferences(self) -> dict:
        """提取用户偏好"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        cursor.execute("""
            SELECT content FROM memories 
            WHERE memory_type = 'preference'
            ORDER BY importance DESC, created_at DESC
        """)
        
        preferences = {}
        for row in cursor.fetchall():
            # 解析偏好格式 "key: value"
            if ":" in row[0]:
                key, value = row[0].split(":", 1)
                preferences[key.strip()] = value.strip()
        
        conn.close()
        return preferences

为什么用 SQLite 而不是向量数据库?

这是一个很实际的设计决策:

  1. 零依赖:不需要额外安装 Milvus、Pinecone 等服务
  2. 本地优先:所有数据在本地,不依赖网络
  3. 全文检索够用:对于短文本(偏好、事实),FTS5 的效果不比向量差
  4. 维护简单:一个文件,容易备份和迁移

Layer 3: 技能记忆层

技能记忆层存储 Agent 自动生成的可复用技能。技能文件遵循 agentskills.io 开放标准,本质是结构化的 Markdown:

---
name: github-trending-analysis
version: 2
trigger: "分析 GitHub trending"
tools_required: [web_search, web_fetch, file_write]
created_at: 2026-04-01
last_used: 2026-04-10
use_count: 23
success_rate: 0.91
---

# GitHub Trending 分析技能

## 适用场景
当用户要求分析 GitHub Trending、发现热门开源项目时触发。

## 执行步骤

1. 使用 `web_search` 搜索 GitHub Trending 页面
2. 使用 `web_fetch` 获取详细内容
3. 提取项目名称、Star 数、描述、主要语言
4. 按 Star 增速排序(优先 daily)
5. 生成结构化报告并写入文件

## 注意事项

- Trending 页面可能有反爬,优先用搜索引擎缓存
- 注意区分 daily/weekly/monthly 周期
- 如果用户指定语言,先过滤再排序

## 成功案例

- 2026-04-01: 成功分析了本周 Rust 项目趋势
- 2026-04-05: 成功识别出 3 个高增长 AI 项目

## 改进历史

- v2: 添加了语言过滤能力
- v1: 初始版本

技能的加载策略用了「渐进式披露」:

class SkillLoader:
    """技能加载器:渐进式披露策略"""
    
    def __init__(self, skills_dir: str = "~/.hermes/skills"):
        self.skills_dir = os.path.expanduser(skills_dir)
        self.skill_index = self._build_index()
    
    def _build_index(self) -> dict:
        """构建技能索引(Level 0:只加载元信息)"""
        index = {}
        for filename in os.listdir(self.skills_dir):
            if filename.endswith(".md"):
                skill_path = os.path.join(self.skills_dir, filename)
                metadata = self._parse_frontmatter(skill_path)
                index[metadata["name"]] = {
                    "path": skill_path,
                    "trigger": metadata.get("trigger", ""),
                    "tools_required": metadata.get("tools_required", [])
                }
        return index
    
    def get_skill_triggers(self) -> list:
        """获取所有技能触发词(用于匹配用户意图)"""
        return [(name, info["trigger"]) for name, info in self.skill_index.items()]
    
    def load_skill_full(self, skill_name: str) -> dict:
        """加载完整技能内容(Level 1:按需加载)"""
        if skill_name not in self.skill_index:
            return None
        
        skill_path = self.skill_index[skill_name]["path"]
        with open(skill_path, "r", encoding="utf-8") as f:
            content = f.read()
        
        return {
            "metadata": self._parse_frontmatter(skill_path),
            "content": content
        }

这种设计的目的是节约 Token:不需要每次都加载所有技能的完整内容,只需要一个轻量的索引来判断是否触发。

Layer 4: 元记忆层

元记忆层是整个系统的「大脑」,负责管理其他三层记忆的刷新、检索和整合:

class MetaMemory:
    """元记忆层:管理其他记忆层"""
    
    def __init__(self, session_mem, persistent_mem, skill_mem):
        self.session = session_mem
        self.persistent = persistent_mem
        self.skills = skill_mem
        
        # 遗忘曲线参数
        self.forgetting_threshold = 0.1  # 重要性低于此值的记忆可能被遗忘
        self.max_memories = 1000         # 最大记忆条数
    
    def consolidate(self):
        """记忆巩固:将短期记忆转化为长期记忆"""
        # 从会话记忆中提取重要信息
        session_summary = self.session.get_summary()
        
        # 判断哪些值得长期保存
        important_info = self._extract_important(session_summary)
        
        for info in important_info:
            self.persistent.store(
                content=info["content"],
                memory_type=info["type"],
                importance=info["importance"]
            )
    
    def forget(self):
        """遗忘机制:清理不重要的记忆"""
        # 基于遗忘曲线和访问频率
        memories = self.persistent.get_all()
        
        for mem in memories:
            # 计算记忆强度
            days_since_access = (datetime.now() - mem["last_accessed"]).days
            strength = mem["importance"] * (0.5 ** (days_since_access / 30))
            strength *= (1 + 0.1 * mem["access_count"])  # 访问越多越重要
            
            if strength < self.forgetting_threshold:
                self.persistent.delete(mem["id"])
    
    def retrieve_for_context(self, query: str) -> str:
        """为当前任务检索相关上下文"""
        context_parts = []
        
        # 1. 用户偏好(优先级最高)
        preferences = self.persistent.get_user_preferences()
        if preferences:
            context_parts.append(f"[用户偏好]\n{json.dumps(preferences, ensure_ascii=False)}")
        
        # 2. 相关历史记忆
        relevant_memories = self.persistent.search(query, limit=5)
        if relevant_memories:
            mem_text = "\n".join([m["content"] for m in relevant_memories])
            context_parts.append(f"[相关记忆]\n{mem_text}")
        
        # 3. 相关技能
        matched_skills = self.skills.match(query)
        if matched_skills:
            for skill_name in matched_skills[:2]:  # 最多加载 2 个技能
                skill = self.skills.load_skill_full(skill_name)
                context_parts.append(f"[技能: {skill_name}]\n{skill['content']}")
        
        return "\n\n".join(context_parts)

3.4 与 OpenClaw 的对比

特性Hermes AgentOpenClaw
记忆持续性✅ 完全支持⚠️ 依赖外部存储
记忆整合✅ 四层架构❌ 单一结构
动态更新✅ 自适应机制❌ 静态存储
技能来源✅ Agent 自动生成❌ 人工编写
技能迭代✅ Agent 自动更新❌ 社区 PR 维护

四、核心机制三:自动技能生成系统

4.1 触发条件

Hermes Agent 不会对所有任务都生成技能。触发条件是:

  • 复杂度阈值:涉及 5 个以上工具调用的任务
  • 成功率检查:任务必须成功完成
  • 模式识别:LLM 判断是否存在可复用的模式

4.2 生成流程

任务完成
    ↓
检查复杂度(≥5 个工具调用?)
    ↓ 是
LLM 分析执行过程
    ↓
提取可复用模式
    ↓
生成结构化技能文档
    ↓
存储到 ~/.hermes/skills/
    ↓
更新技能索引
    ↓
后续任务中自动匹配使用

4.3 代码实现

class SkillGenerator:
    """自动技能生成器"""
    
    def __init__(self, llm_client, skill_store):
        self.llm = llm_client
        self.skills = skill_store
    
    def maybe_generate_skill(self, execution_trace: list, task_description: str) -> bool:
        """判断是否需要生成技能,并生成"""
        
        # 1. 检查复杂度
        tool_calls = [t for t in execution_trace if t.get("tool")]
        if len(tool_calls) < 5:
            return False
        
        # 2. 检查是否有失败
        failures = [t for t in execution_trace if not t.get("success", True)]
        if failures:
            return False
        
        # 3. 让 LLM 分析是否值得沉淀
        analysis = self._analyze_for_skill(execution_trace, task_description)
        
        if not analysis.get("should_create"):
            return False
        
        # 4. 生成技能文档
        skill_doc = self._generate_skill_document(
            execution_trace, 
            task_description, 
            analysis
        )
        
        # 5. 保存技能
        self.skills.save(analysis["name"], skill_doc)
        return True
    
    def _analyze_for_skill(self, trace: list, task: str) -> dict:
        """分析执行轨迹,判断是否适合生成技能"""
        
        prompt = f"""
        分析以下任务执行过程,判断是否值得提取为可复用技能:

        任务描述:{task}

        执行轨迹:
        {json.dumps(trace, ensure_ascii=False, indent=2)}

        请判断:
        1. 这个任务是否有可复用价值?(是否可能再次遇到类似任务)
        2. 执行过程是否有规律可循?
        3. 是否适合自动化?

        输出 JSON 格式:
        {{
            "should_create": true/false,
            "name": "技能名称(简短、英文、下划线分隔)",
            "trigger": "触发关键词",
            "description": "适用场景描述",
            "tools_required": ["需要的工具列表"],
            "reasoning": "判断理由"
        }}
        """
        
        response = self.llm.chat(prompt)
        return json.loads(response)
    
    def _generate_skill_document(self, trace: list, task: str, analysis: dict) -> str:
        """生成完整的技能文档"""
        
        prompt = f"""
        基于以下信息生成一个技能文档(Markdown 格式):

        任务:{task}
        执行轨迹:{json.dumps(trace, ensure_ascii=False, indent=2)}
        分析结果:{json.dumps(analysis, ensure_ascii=False, indent=2)}

        输出格式要求:
        ---
        name: <技能名>
        version: 1
        trigger: "<触发词>"
        tools_required: [<工具列表>]
        ---
        
        # <技能标题>
        
        ## 适用场景
        <描述什么情况下应该使用此技能>
        
        ## 执行步骤
        <详细的步骤列表>
        
        ## 注意事项
        <可能遇到的问题和解决方案>
        
        ## 成功案例
        <本次执行的简要描述>
        """
        
        return self.llm.chat(prompt)

4.4 技能的自我进化

技能不是静态的,会随着使用不断优化:

class SkillEvolver:
    """技能进化器"""
    
    def __init__(self, llm_client, skill_store):
        self.llm = llm_client
        self.skills = skill_store
    
    def evolve(self, skill_name: str, new_experience: dict):
        """基于新经验更新技能"""
        
        # 加载现有技能
        current_skill = self.skills.load_skill_full(skill_name)
        
        # 分析是否需要更新
        evolution = self._analyze_evolution(current_skill, new_experience)
        
        if evolution.get("should_update"):
            # 生成新版本
            new_version = current_skill["metadata"].get("version", 1) + 1
            updated_doc = self._update_skill_document(
                current_skill, 
                new_experience, 
                evolution,
                new_version
            )
            
            self.skills.save(skill_name, updated_doc)
            return True
        
        return False
    
    def _analyze_evolution(self, skill: dict, experience: dict) -> dict:
        """分析是否需要更新技能"""
        
        prompt = f"""
        当前技能:
        {skill['content']}

        新的执行经验:
        {json.dumps(experience, ensure_ascii=False, indent=2)}

        请判断:
        1. 新经验是否提供了更好的方法?
        2. 是否发现了之前没有考虑到的情况?
        3. 是否需要添加新的注意事项?

        输出 JSON:
        {{
            "should_update": true/false,
            "improvements": ["改进点列表"],
            "new_steps": ["需要添加的步骤"],
            "new_notes": ["需要添加的注意事项"]
        }}
        """
        
        response = self.llm.chat(prompt)
        return json.loads(response)

4.5 效果数据

指标数值说明
Skill 触发条件5+ 工具调用简单任务不会生成 Skill
自动评估周期约 15 个任务周期性评估表现并写入新 Skill
研究任务提速~40%使用自生成 Skill 后的速度提升
技能平均质量0.91 成功率基于后续使用的成功/失败统计

五、核心机制四:全平台消息网关

5.1 架构设计

Hermes Agent 的消息网关采用统一入口设计:

                    ┌─────────────────┐
                    │   Hermes Core   │
                    │   (Agent 逻辑)   │
                    └────────┬────────┘
                             │
                    ┌────────┴────────┐
                    │  Gateway Layer  │
                    │   (统一网关)     │
                    └────────┬────────┘
                             │
        ┌────────┬───────────┼───────────┬────────┐
        │        │           │           │        │
   ┌────┴───┐ ┌──┴───┐ ┌────┴────┐ ┌────┴───┐ ┌──┴───┐
   │Telegram│ │Discord│ │ Slack  │ │ 飞书  │ │ 企业微信│
   └────────┘ └──────┘ └────────┘ └────────┘ └──────┘

5.2 支持的平台

平台支持状态特色功能
Telegram✅ 稳定语音转录、文件传输
Discord✅ 稳定多服务器、线程支持
Slack✅ 稳定企业级集成
飞书✅ 稳定国内团队友好
企业微信✅ 稳定企业场景
WhatsApp✅ Beta个人助手场景
Signal✅ Beta隐私优先

5.3 跨平台上下文保持

一个关键特性:跨平台上下文不丢。你在 Telegram 聊到一半,切到终端继续,它记着呢。

class CrossPlatformContext:
    """跨平台上下文管理"""
    
    def __init__(self, db_path: str = "~/.hermes/context.db"):
        self.db_path = os.path.expanduser(db_path)
        self._init_db()
    
    def save_context(self, user_id: str, platform: str, context: dict):
        """保存当前上下文"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        # 使用 REPLACE 确保每个用户只有一份上下文
        cursor.execute("""
            REPLACE INTO user_context (user_id, platform, context, updated_at)
            VALUES (?, ?, ?, ?)
        """, (user_id, platform, json.dumps(context), datetime.now()))
        
        conn.commit()
        conn.close()
    
    def load_context(self, user_id: str) -> dict:
        """加载用户的上下文(无论从哪个平台)"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        cursor.execute("""
            SELECT context, platform FROM user_context WHERE user_id = ?
        """, (user_id,))
        
        row = cursor.fetchone()
        conn.close()
        
        if row:
            return {
                "context": json.loads(row[0]),
                "last_platform": row[1]
            }
        return None

六、安全设计:五层防线

Hermes Agent 在安全方面做得比较认真,设计了五层防线:

class SecurityPipeline:
    """五层安全架构"""
    
    def execute(self, command: str, context: dict) -> dict:
        
        # Layer 1: 用户授权检查
        if not self.check_user_authorization(context):
            return {"success": False, "error": "用户未授权"}
        
        # Layer 2: 危险命令审批
        if self.is_dangerous(command):
            approval = self.request_approval(command, context)
            if not approval:
                return {"success": False, "error": "命令被拒绝"}
        
        # Layer 3: 容器隔离执行
        result = self.run_in_container(command)
        
        # Layer 4: MCP 凭证过滤(防止凭证泄露到日志)
        result = self.filter_mcp_credentials(result)
        
        # Layer 5: 上下文注入扫描(Tirith)
        if self.detect_injection(result):
            return {"success": False, "error": "检测到注入攻击"}
        
        return result
    
    def is_dangerous(self, command: str) -> bool:
        """判断命令是否危险"""
        dangerous_patterns = [
            r"rm\s+-rf",           # 强制删除
            r"sudo\s+",            # 提权
            r">\s*/dev/",          # 设备写入
            r"curl.*\|\s*bash",   # 远程执行
            r"wget.*\|\s*sh",     # 远程执行
            r"eval\s+",           # 动态执行
            r"exec\s+",           # 动态执行
        ]
        
        for pattern in dangerous_patterns:
            if re.search(pattern, command):
                return True
        return False
    
    def run_in_container(self, command: str) -> dict:
        """在容器中隔离执行"""
        # Docker 配置
        container_config = {
            "image": "hermes-sandbox:latest",
            "read_only": True,           # 只读根目录
            "network_disabled": False,   # 允许网络(可配置)
            "pids_limit": 100,           # 进程数限制
            "mem_limit": "512m",         # 内存限制
            "cpu_quota": 50000,          # CPU 限制(50%)
            "security_opt": ["no-new-privileges"],  # 禁止提权
            "cap_drop": ["ALL"],         # 移除所有能力
        }
        
        # 执行命令...
        return self.docker_client.run(container_config, command)

6.1 生产环境安全建议

配置项推荐值说明
backenddocker使用容器隔离
approvals.modemanual危险操作需人工确认
GATEWAY_ALLOW_ALL_USERSfalse只允许白名单用户
sandbox.networkdisabled禁止网络访问(可选)

七、实战:搭建自己的 Hermes Agent

7.1 安装(3 分钟)

# 一行命令安装(Linux/macOS/WSL2)
curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash

# 验证安装
hermes version
hermes doctor  # 环境检查

# 交互式配置
hermes setup

# 选择模型
hermes model
# 支持:Nous Portal (OAuth)、OpenRouter (200+ 模型)、自定义 API 端点

7.2 模型选择建议

使用场景推荐方案原因
隐私优先/离线Ollama + Llama 3.3数据不出机器,免费
日常使用OpenRouter200+ 模型可选,按量付费
复杂任务GPT-4 / Claude效果最好,贵是真的贵
研究/训练vLLM 本地部署完全可控,支持 RL 训练

7.3 接入 Telegram 示例

# 1. 在 Telegram 找 @BotFather,创建 Bot,获取 Token

# 2. 配置网关
hermes gateway setup
# 选择 Telegram → 粘贴 Token

# 3. 启动
hermes gateway

# 4. 服务化(7x24 运行)
hermes gateway install
systemctl status hermes-gateway

7.4 从 OpenClaw 迁移

如果你已经在用 OpenClaw,Hermes 提供了一键迁移:

hermes import --from openclaw --path ~/.openclaw

会自动导入:

  • 记忆文件(MEMORY.md, USER.md)
  • 技能文件(skills/)
  • 配置文件(config.json)

八、最佳实践与踩坑记录

8.1 让 Agent 学得更快

  1. 给它干复杂任务:简单任务不会触发技能沉淀,要让 Agent 处理 5 个以上工具调用的任务。

  2. 及时反馈:任务完成后,明确告诉 Agent 「做得好」或「这里有改进空间」。这些反馈会被纳入 KEPA 的分析。

  3. 定期检查记忆:用 hermes memory 命令查看 Agent 记住了什么,清理不准确的信息。

  4. 给任务打标签:在任务描述中使用一致的词汇,帮助 Agent 建立模式识别。

8.2 常见坑点

坑点描述解决方案
Windows 装不上原生 Windows 暂不支持用 WSL2
频繁弹审批默认审批模式太严格Docker 环境下可适当调松 approvals.mode
消息平台没反应未配置 allowlist检查白名单或完成 DM pairing
记忆「串了」长期使用后偶尔出现记忆混淆定期用 hermes memory 检查和清理
技能质量差自动生成的技能不够好手动编辑 ~/.hermes/skills/ 下的文件

8.3 生产环境部署建议

# ~/.hermes/config.yaml

# 后端选择
backend: docker

# 安全配置
approvals:
  mode: manual  # 危险操作需人工确认
  
sandbox:
  network: disabled  # 禁止网络访问(如果不需要)
  
# 模型配置
model:
  provider: openrouter
  name: claude-sonnet-4-6
  temperature: 0.2

# 记忆配置
memory:
  max_tokens: 4000
  consolidation_interval: 3600  # 每小时整合一次记忆
  
# 技能配置
skills:
  auto_generate: true
  min_complexity: 5  # 最少 5 个工具调用才生成技能
  max_skills: 100    # 最多保留 100 个技能

九、源码级分析:关键模块解读

9.1 项目结构

hermes-agent/
├── hermes/
│   ├── agent/           # Agent 核心逻辑
│   │   ├── core.py      # 主循环
│   │   ├── planner.py   # 任务规划
│   │   └── executor.py  # 任务执行
│   ├── memory/          # 记忆系统
│   │   ├── session.py   # 会话记忆
│   │   ├── persistent.py# 持久记忆
│   │   ├── skills.py    # 技能记忆
│   │   └── meta.py      # 元记忆
│   ├── kepa/            # KEPA 系统
│   │   ├── reflector.py # 反思模块
│   │   ├── analyzer.py  # 分析模块
│   │   └── updater.py   # 更新模块
│   ├── gateway/         # 消息网关
│   │   ├── telegram.py
│   │   ├── discord.py
│   │   ├── slack.py
│   │   └── ...
│   ├── security/        # 安全模块
│   │   ├── sandbox.py   # 容器隔离
│   │   ├── approval.py  # 审批流程
│   │   └── scanner.py   # 注入扫描
│   └── tools/           # 工具集
│       ├── web.py       # 网页操作
│       ├── file.py      # 文件操作
│       └── ...
├── skills/              # 默认技能库
├── scripts/             # 安装脚本
└── docs/                # 文档

9.2 核心主循环

# hermes/agent/core.py (简化版)

class HermesAgent:
    """Hermes Agent 主循环"""
    
    def __init__(self):
        self.memory = MemorySystem()
        self.kepa = KEPASystem()
        self.tools = ToolRegistry()
        self.llm = LLMClient()
        
    async def process_message(self, user_id: str, message: str) -> str:
        """处理用户消息"""
        
        # 1. 构建上下文
        context = self.memory.retrieve_for_context(message)
        
        # 2. 检查是否匹配已有技能
        matched_skills = self.memory.skills.match(message)
        
        # 3. 规划任务
        plan = await self.plan_task(message, context, matched_skills)
        
        # 4. 执行任务
        execution_trace = []
        for step in plan.steps:
            result = await self.execute_step(step)
            execution_trace.append(result)
            
            if not result.success:
                # 失败时尝试恢复
                recovery = await self.recover(step, result)
                if recovery:
                    execution_trace.append(recovery)
        
        # 5. 记录执行轨迹
        self.kepa.record_execution(execution_trace)
        
        # 6. 尝试生成/更新技能
        self.kepa.maybe_generate_skill(execution_trace, message)
        
        # 7. 返回结果
        return self.format_response(execution_trace)
    
    async def plan_task(self, message: str, context: str, skills: list) -> Plan:
        """规划任务"""
        
        system_prompt = f"""
        你是一个 AI Agent,拥有以下能力:
        
        1. 已加载的技能:{json.dumps(skills, ensure_ascii=False)}
        2. 用户偏好和历史:{context}
        3. 可用工具:{self.tools.list()}
        
        请分析用户请求,制定执行计划。
        
        输出 JSON 格式:
        {{
            "understanding": "对用户请求的理解",
            "steps": [
                {{"tool": "工具名", "params": {{...}}, "purpose": "步骤目的"}}
            ],
            "expected_outcome": "预期结果"
        }}
        """
        
        response = await self.llm.chat(system_prompt, message)
        return Plan.from_json(response)

9.3 KEPA 反思循环

# hermes/kepa/reflector.py (简化版)

class KepaReflector:
    """KEPA 反思模块"""
    
    REFLECTION_INTERVAL = 15  # 每 15 次工具调用反思一次
    
    def __init__(self, llm_client, memory_system):
        self.llm = llm_client
        self.memory = memory_system
        self.trace_buffer = []
        self.call_count = 0
    
    def record(self, execution: dict):
        """记录执行轨迹"""
        self.trace_buffer.append(execution)
        self.call_count += 1
        
        if self.call_count >= self.REFLECTION_INTERVAL:
            self.reflect()
            self.trace_buffer = []
            self.call_count = 0
    
    async def reflect(self):
        """执行反思"""
        
        # 分析执行轨迹
        analysis = await self.analyze_trace(self.trace_buffer)
        
        # 提取学习点
        learnings = analysis.get("learnings", [])
        for learning in learnings:
            await self.memory.persistent.store(
                content=learning["content"],
                memory_type=learning["type"],
                importance=learning["importance"]
            )
        
        # 检查是否需要更新技能
        skill_updates = analysis.get("skill_updates", [])
        for update in skill_updates:
            await self.update_skill(update)
    
    async def analyze_trace(self, trace: list) -> dict:
        """分析执行轨迹"""
        
        prompt = f"""
        分析以下 Agent 执行轨迹,提取学习点和改进建议:

        {json.dumps(trace, ensure_ascii=False, indent=2)}

        请分析:
        1. 执行过程中的失败点和原因
        2. 用户偏好和习惯
        3. 可复用的模式
        4. 现有技能的改进建议

        输出 JSON:
        {{
            "learnings": [
                {{
                    "content": "学习内容",
                    "type": "preference|fact|pattern",
                    "importance": 0.0-1.0
                }}
            ],
            "skill_updates": [
                {{
                    "skill_name": "技能名",
                    "update_type": "add|modify|deprecate",
                    "changes": "具体修改"
                }}
            ],
            "overall_assessment": "整体评估"
        }}
        """
        
        response = await self.llm.chat(prompt)
        return json.loads(response)

十、与其他 Agent 框架的对比

10.1 对比表格

维度Hermes AgentOpenClawAutoGPTCrewAI
自学习能力✅ 自动生成技能❌ 人工编写⚠️ 有限❌ 无
记忆持久化✅ 四层架构⚠️ 外部存储❌ 无❌ 无
多平台支持✅ 7+ 平台✅ 10+ 平台❌ CLI only❌ CLI only
安全隔离✅ 五层防线⚠️ 基础❌ 无❌ 无
部署难度⭐⭐⭐⭐⭐⭐⭐
开源协议MITMITMITMIT
活跃度非常高

10.2 适用场景推荐

场景推荐框架原因
个人长期 AI 助手Hermes Agent核心优势,越用越懂你
企业级部署OpenClaw生态成熟,渠道多
快速原型CrewAI多 Agent 协作简单
自主任务执行AutoGPT经典方案,社区大

十一、总结与展望

11.1 核心结论

Hermes Agent 的核心价值不在于它能接多少平台、调多少工具——这些能力别的 Agent 也有。它真正拉开差距的地方在于闭环学习机制

  1. Agent 自己写 Skill:从成功经验中自动提取可复用模式
  2. 四层记忆架构:真正解决持久记忆问题
  3. KEPA 反向传播:把 prompt engineering 变成自动化优化过程

从工程角度看,这代表 Agent 从「模型能不能调工具」到「系统能不能长期跑」的跨越。

11.2 技术启示

Hermes Agent 的成功给我们几个重要启示:

  1. 不要什么都靠微调:应用层的学习机制(如 KEPA)成本更低、迭代更快

  2. 记忆是 Agent 的核心:没有持久记忆的 Agent 只是聊天机器人

  3. 安全不能事后补:五层防线的设计理念值得借鉴

  4. 开放标准很重要:agentskills.io 这样的开放标准能促进生态发展

11.3 未来展望

Hermes Agent 目前还有一些局限性:

  • Windows 原生支持:目前还在 experimental 阶段
  • 技能质量参差:自动生成的技能有时不够精确
  • 记忆「污染」风险:错误信息可能被长期记住

但这些问题都在积极迭代中。从 v0.1 到 v0.8 的演进速度来看,团队对产品方向有清晰的认识,执行效率也很高。


附录:快速参考

A. 常用命令

# 安装
curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash

# 配置
hermes setup              # 交互式配置
hermes model              # 选择模型
hermes doctor             # 环境检查

# 网关
hermes gateway setup      # 配置消息平台
hermes gateway            # 启动网关
hermes gateway install    # 安装为系统服务

# 记忆管理
hermes memory list        # 查看记忆
hermes memory clear       # 清空记忆
hermes memory export      # 导出记忆

# 技能管理
hermes skills list        # 查看技能
hermes skills show <name> # 查看技能详情
hermes skills edit <name> # 编辑技能

B. 配置文件位置

文件路径说明
主配置~/.hermes/config.yaml全局配置
记忆库~/.hermes/memories/持久记忆存储
技能库~/.hermes/skills/技能文件存储
日志~/.hermes/logs/运行日志

C. 参考资源


字数统计:约 8500 字


写在最后

AI Agent 的竞争终局不是谁接的渠道多、调的工具全,而是谁更懂你。从这个角度看,Hermes Agent 走的路子可能更接近答案。

它不是要替代 ChatGPT 或 Claude,而是要成为你的「第二大脑」——一个会随着使用不断成长的长期伙伴。

如果你正在寻找一个能记住你、懂你、越来越聪明的 AI 助手,Hermes Agent 值得一试。

本文基于 Hermes Agent v0.8.0 版本分析,项目仍在快速迭代中,部分内容可能随版本更新而变化。

复制全文 生成海报 AI Agent Hermes 开源 自学习 记忆系统 KEPA

推荐文章

pin.gl是基于WebRTC的屏幕共享工具
2024-11-19 06:38:05 +0800 CST
pycm:一个强大的混淆矩阵库
2024-11-18 16:17:54 +0800 CST
为什么大厂也无法避免写出Bug?
2024-11-19 10:03:23 +0800 CST
JavaScript 异步编程入门
2024-11-19 07:07:43 +0800 CST
使用Vue 3和Axios进行API数据交互
2024-11-18 22:31:21 +0800 CST
使用 node-ssh 实现自动化部署
2024-11-18 20:06:21 +0800 CST
CSS 特效与资源推荐
2024-11-19 00:43:31 +0800 CST
php客服服务管理系统
2024-11-19 06:48:35 +0800 CST
PHP 如何输出带微秒的时间
2024-11-18 01:58:41 +0800 CST
平面设计常用尺寸
2024-11-19 02:20:22 +0800 CST
JavaScript设计模式:桥接模式
2024-11-18 19:03:40 +0800 CST
markdowns滚动事件
2024-11-19 10:07:32 +0800 CST
Manticore Search:高性能的搜索引擎
2024-11-19 03:43:32 +0800 CST
赚点点任务系统
2024-11-19 02:17:29 +0800 CST
介绍25个常用的正则表达式
2024-11-18 12:43:00 +0800 CST
程序员茄子在线接单