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 Stars | 47,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 领域,记忆问题分为两类:
访问型记忆(Retrieval Memory):从外部知识库检索信息。这个相对简单,RAG 技术已经比较成熟。
内化型记忆(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 而不是向量数据库?
这是一个很实际的设计决策:
- 零依赖:不需要额外安装 Milvus、Pinecone 等服务
- 本地优先:所有数据在本地,不依赖网络
- 全文检索够用:对于短文本(偏好、事实),FTS5 的效果不比向量差
- 维护简单:一个文件,容易备份和迁移
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 Agent | OpenClaw |
|---|---|---|
| 记忆持续性 | ✅ 完全支持 | ⚠️ 依赖外部存储 |
| 记忆整合 | ✅ 四层架构 | ❌ 单一结构 |
| 动态更新 | ✅ 自适应机制 | ❌ 静态存储 |
| 技能来源 | ✅ 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 | ✅ 稳定 | 企业级集成 |
| 飞书 | ✅ 稳定 | 国内团队友好 |
| 企业微信 | ✅ 稳定 | 企业场景 |
| ✅ 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 生产环境安全建议
| 配置项 | 推荐值 | 说明 |
|---|---|---|
backend | docker | 使用容器隔离 |
approvals.mode | manual | 危险操作需人工确认 |
GATEWAY_ALLOW_ALL_USERS | false | 只允许白名单用户 |
sandbox.network | disabled | 禁止网络访问(可选) |
七、实战:搭建自己的 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 | 数据不出机器,免费 |
| 日常使用 | OpenRouter | 200+ 模型可选,按量付费 |
| 复杂任务 | 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 学得更快
给它干复杂任务:简单任务不会触发技能沉淀,要让 Agent 处理 5 个以上工具调用的任务。
及时反馈:任务完成后,明确告诉 Agent 「做得好」或「这里有改进空间」。这些反馈会被纳入 KEPA 的分析。
定期检查记忆:用
hermes memory命令查看 Agent 记住了什么,清理不准确的信息。给任务打标签:在任务描述中使用一致的词汇,帮助 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 Agent | OpenClaw | AutoGPT | CrewAI |
|---|---|---|---|---|
| 自学习能力 | ✅ 自动生成技能 | ❌ 人工编写 | ⚠️ 有限 | ❌ 无 |
| 记忆持久化 | ✅ 四层架构 | ⚠️ 外部存储 | ❌ 无 | ❌ 无 |
| 多平台支持 | ✅ 7+ 平台 | ✅ 10+ 平台 | ❌ CLI only | ❌ CLI only |
| 安全隔离 | ✅ 五层防线 | ⚠️ 基础 | ❌ 无 | ❌ 无 |
| 部署难度 | ⭐⭐⭐ | ⭐⭐ | ⭐ | ⭐⭐ |
| 开源协议 | MIT | MIT | MIT | MIT |
| 活跃度 | 高 | 非常高 | 中 | 高 |
10.2 适用场景推荐
| 场景 | 推荐框架 | 原因 |
|---|---|---|
| 个人长期 AI 助手 | Hermes Agent | 核心优势,越用越懂你 |
| 企业级部署 | OpenClaw | 生态成熟,渠道多 |
| 快速原型 | CrewAI | 多 Agent 协作简单 |
| 自主任务执行 | AutoGPT | 经典方案,社区大 |
十一、总结与展望
11.1 核心结论
Hermes Agent 的核心价值不在于它能接多少平台、调多少工具——这些能力别的 Agent 也有。它真正拉开差距的地方在于闭环学习机制:
- Agent 自己写 Skill:从成功经验中自动提取可复用模式
- 四层记忆架构:真正解决持久记忆问题
- KEPA 反向传播:把 prompt engineering 变成自动化优化过程
从工程角度看,这代表 Agent 从「模型能不能调工具」到「系统能不能长期跑」的跨越。
11.2 技术启示
Hermes Agent 的成功给我们几个重要启示:
不要什么都靠微调:应用层的学习机制(如 KEPA)成本更低、迭代更快
记忆是 Agent 的核心:没有持久记忆的 Agent 只是聊天机器人
安全不能事后补:五层防线的设计理念值得借鉴
开放标准很重要: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 版本分析,项目仍在快速迭代中,部分内容可能随版本更新而变化。