Hermes Agent 深度拆解:110K Star 开源自进化 AI Agent 架构设计完整指南(2026)
引言:当 Agent 不再「每次重新开始」
大多数 AI 助手都有一个致命缺陷:每次对话都是从零开始。你昨天教它的偏好、上个月积累的项目背景、半年前沉淀的领域知识,下一次对话时全部归零。它能回答今天的问题,却记不住昨天的约定。
2026 年 2 月,Nous Research 发布了一个叫 Hermes Agent 的开源项目,试图从根本上解决这个问题。两个多月后,GitHub Star 数突破 110K,贡献者超过 240 人,Commit 数超过 4,800 次,成为当年最受关注的现象级开源 AI Agent 项目。
但 Star 涨得快不代表技术一定强。翻了 Hermes Agent 的代码库和官方文档后,我的判断是:这个项目在架构设计上确实有东西——尤其是它把「闭环学习」(Closed Learning Loop)做成了原生能力,不是事后打补丁,而是从 Day 1 就融入了核心架构。
本文从源码出发,把 Hermes Agent 的架构拆开来看,重点不是介绍它有什么功能(README 写得够详细了),而是分析它为什么这样设计,以及这些设计决策背后的取舍。
一、项目定位:解决什么问题?
1.1 传统 Agent 框架的思路
大多数 Agent 框架解决的核心问题是:怎么让 LLM 更好地调用工具。
这个思路下的典型产品包括 LangChain Agents、AutoGPT、AgentGPT 等。它们的核心能力是「工具调用编排」——给 Agent 一个任务,让它自主决定调用哪些工具、如何组合、怎么处理异常。工具调用完毕,任务完成,Agent 回到初始状态。
这个模式的问题在于:没有积累。每次任务都是独立事件,Agent 无法从历史经验中学习。同样的坑可能踩无数遍。
1.2 Hermes Agent 的思路
Hermes Agent 解决的核心问题是:怎么让 Agent 越用越聪明。
它不只是一个任务执行工具,而是一个具有「记忆」和「自进化」能力的数字员工。它的核心设计哲学是:
今天的经验,明天直接用。
体现在具体机制上,它的闭环学习包含五个环节:
- 策划记忆:任务完成后,Agent 自主判断什么值得记住
- 创建 Skill:识别重复模式,自动生成 Markdown 格式的 Skill 文件
- Skill 自改进:现有 Skill 失败时自动优化
- FTS5 召回:按需检索历史对话(SQLite 全文索引)
- 用户建模:从行为推断偏好(Honcho 方言式建模)
这个循环对应了认知科学的三种记忆类型:
| 认知科学记忆类型 | Hermes Agent 对应机制 |
|---|---|
| 情景记忆(Episodic) | 会话历史归档 + SQLite 持久化 |
| 语义记忆(Semantic) | MEMORY.md 持久事实层 |
| 程序性记忆(Procedural) | Skill 文件自动生成与优化 |
二、核心架构概览
2.1 技术栈与协议
Hermes Agent 采用 MIT 协议开源,技术栈以 Python 3.11+ 为主。核心依赖:
- LLM 接入:OpenAI、Anthropic、Google Bedrock、OpenRouter 等(200+ 模型)
- 数据库:SQLite + FTS5(全文搜索)
- 消息网关:支持 Telegram、Discord、Slack、微信等 12+ 平台
- 部署后端:local、Docker、SSH、Modal、Daytona、Singularity
- 包管理:honcho(记忆协议)、hermes(主包)
2.2 目录结构与职责划分
先看目录结构,能快速理解系统的职责划分:
run_agent.py # AIAgent 主类,Agent 循环核心
tools/ # 40+ 工具实现(终端、浏览器、文件、搜索、MCP)
toolsets.py # Toolset 定义和组合系统
agent/
prompt_builder.py # System Prompt 组装器
memory_manager.py # 记忆管理(双 Provider 架构)
context_engine.py # 上下文引擎(可插拔)
context_compressor.py # 轨迹压缩器
conversation_loop.py # 对话主循环
skill_bundles.py # 技能自动生成逻辑
curator.py # Curator 后台维护员
dialectic.py # 方言式用户建模
hermes_state.py # SQLite 状态存储(FTS5 全文搜索)
gateway/
run.py # 多平台消息网关
skills/ # 内置 Skill 库(24 个分类)
plugins/ # 插件系统(8 个插件)
hermes_cli/ # CLI 接口(51 个模块)
environments/ # 执行环境后端
2.3 关键设计决策
架构上有几个关键决策值得重点分析:
决策一:Agent 循环和工具执行在同一进程
通过 run_agent.py 中的 AIAgent 类管理整个生命周期,没有用微服务那套东西。这意味着:
- 启动快:一个 Python 进程拉起
- 调试简单:没有跨进程通信的复杂性
- 资源轻:不跑本地 LLM 的情况下,Agent 进程本身占用不到 500MB
官方宣称可以在 $5/月的 VPS 上运行,这个数据从架构上看是合理的。
决策二:工具自注册模式
每个工具文件在模块级别调用 registry.register() 声明自己,不需要中心化的注册表。这种设计的优势是:
- 新增工具只需创建新文件,无需修改中心注册表
- 工具定义和实现天然绑定
- 线程安全(使用
threading.RLock())
决策三:上下文压缩可插拔
ContextEngine 是抽象基类,默认实现是 ContextCompressor,但可以替换为其他压缩策略。这意味着:
- 未来可以接入更复杂的压缩算法(如 RAPTOR)
- 企业可以定制自己的上下文策略
- 适合不同模型的上下文长度限制
决策四:Profile 多实例系统
v0.6.0 引入了多实例 Profile,每个 Profile 拥有独立的配置、记忆库、会话历史、Skill 集合和工具权限。这意味着:
- 同一台机器可以跑多个独立的 Agent 实例,互不干扰
- 工作项目和私人项目完全隔离
- 每个 Profile 可以配置不同的模型、工具集和人格
三、Agent 循环深度拆解
3.1 主循环流程
run_agent.py 中的 AIAgent 类是整个系统的心脏。Agent 循环的基本流程是:
接收用户消息
↓
构建请求(含 system prompt + 记忆 + 上下文)
↓
调用 LLM
↓
解析响应
↓
包含工具调用? → 执行工具 → 把结果加入上下文 → 再次调用 LLM
↓(无工具调用)
返回最终响应
这个循环有几个关键的控制机制,下面逐一展开。
3.2 迭代预算控制:防止死循环
Agent 循环不是无限运行的。IterationBudget 类实现了一个线程安全的迭代计数器:
class IterationBudget:
"""线程安全的迭代预算控制"""
def __init__(self, max_iterations: int, is_subagent: bool = False):
self._budget = max_iterations if not is_subagent else 50
self._lock = threading.Lock()
@property
def remaining(self) -> int:
with self._lock:
return self._budget
def use(self) -> bool:
"""消耗一次迭代,返回是否还有剩余预算"""
with self._lock:
if self._budget <= 0:
return False
self._budget -= 1
return True
- 父 Agent 默认 90 次迭代
- 子 Agent 默认 50 次迭代
这个设计解决的是一个很实际的问题:Agent 有时候会陷入死循环,反复调用同一个工具。迭代预算到了就强制停止,防止 token 烧穿你的 API 额度。
3.3 并行工具执行:读操作不排队
Agent 循环中有一个关键判断逻辑在 _should_parallelize_tool_batch() 方法中。它把工具分成三类:
_NEVER_PARALLEL_TOOLS = {"clarify"} # 需要用户交互,不能并行
_PARALLEL_SAFE_TOOLS = {"web_search", "read_file", "git_status"} # 纯读操作
_PATH_SCOPED_TOOLS = {"write_file", "patch", "exec"} # 路径隔离后才能并行
| 分类 | 策略 | 典型工具 |
|---|---|---|
_NEVER_PARALLEL | 永远不并行 | clarify(需要用户交互) |
_PARALLEL_SAFE | 只读安全,并行执行 | web_search, read_file |
_PATH_SCOPED | 路径隔离,条件并行 | write_file, patch |
最大并发工作线程数硬编码为 8(_MAX_TOOL_WORKERS)。
这个设计的精妙之处在于:读操作(搜索、读取文件)天然可以并行,写操作需要检查路径是否冲突。比如同时写两个不同文件是可以的,但同时写同一个文件就有风险。
3.4 中断与转向机制:务实的交互设计
Agent 在执行过程中可能会收到用户的新指令。Hermes Agent 的处理方式是 _interrupt_requested + _pending_steer 双标志位设计:
# 伪代码实现
def _process_interrupts(self):
if self._interrupt_requested:
# 不打断当前正在执行的工具批次
# 等工具批次完成后再处理
pass
if self._pending_steer:
# 把用户的新需求注入下一轮对话
self.messages.append(self._build_steer_message())
self._pending_steer = None
这个选择很务实:如果强行中断正在执行的 write_file,可能导致文件写了一半。等工具批次完成再转向,保证了操作的原子性。
3.5 多 API 模式:无缝切换底层模型
AIAgent 支持四种 API 模式:
| API 模式 | 支持的模型 |
|---|---|
chat_completions | OpenAI、DeepSeek、Qwen 等 |
codex_responses | OpenAI Codex 系列 |
anthropic_messages | Anthropic Claude 系列 |
bedrock_converse | AWS Bedrock 系列 |
模型提供商路由是自动检测的,支持 OpenRouter(200+ 模型)、NVIDIA NIM、Hugging Face 等。切换模型只需一条命令:
hermes model set openai gpt-5.6
不需要改代码,不需要重启进程。
四、记忆系统:三层架构与冻结快照
记忆系统是 Hermes Agent 区别于其他 Agent 框架的核心创新。大多数 Agent 框架把记忆当作文本注入的补丁,Hermes Agent 把记忆做成了一套完整的工程方案。
4.1 三层架构
Hermes 的记忆不是一个东西,是三层堆叠的:
┌─────────────────────────────────────────────────────────────┐
│ Layer 1: Built-in Memory(始终激活,会话启动时注入) │
│ - MEMORY.md: Agent 个人笔记,2200 字符上限 │
│ - USER.md: 用户画像,1375 字符上限 │
├─────────────────────────────────────────────────────────────┤
│ Layer 2: External Memory Providers(按需激活,语义记忆) │
│ - SQLite FTS5: 无限容量会话归档 + 全文检索 │
│ - 支持 8 种可插拔 Provider │
├─────────────────────────────────────────────────────────────┤
│ Layer 3: Skills(程序性记忆,按需加载) │
│ - 自动生成的 Markdown 技能文件 │
│ - 按任务模式匹配加载 │
└─────────────────────────────────────────────────────────────┘
Layer 1 是始终激活的。两个 Markdown 文件在会话启动时注入系统提示,确保 Agent 永远知道「你是谁」「环境是什么」。
Layer 2 是外部记忆提供者,按需激活。memory_manager.py 定义了 ExternalMemoryProvider 抽象接口,当前内置实现包括 SQLite FTS5(基于全文索引的语义搜索)、向量数据库等。
Layer 3 是 Skills,自动生成、可复用、按需加载,是最高级的记忆形式。
4.2 冻结快照与上下文围栏
这里有一个非常巧妙的设计:冻结快照模式。
当 Layer 1 的两个文件准备好之后,记忆系统会生成一个「冻结快照」——一个包含所有记忆内容的只读前缀块。这个快照在同一个会话的所有 API 调用中保持不变,LLM 的前缀缓存可以命中它。
会话开始
↓
构建 Layer 1 记忆内容
↓
生成冻结快照(只读,缓存友好)
↓
同一会话中所有 LLM 调用共享这个前缀
这解决了什么问题?传统做法中,每次 LLM 调用都要重新注入记忆内容,导致:
- 记忆内容重复发送给 API,产生额外 token 费用
- 每次都重新构建上下文,增加延迟
冻结快照让第一次调用的成本 = 后续调用的成本,不会因为记忆增长而额外付费。
此外还有一个「上下文围栏」机制(Context Fencing):
# 伪代码
def format_for_system_prompt(self, layer: str) -> str:
# 给模型明确的指令:记忆内容是"事实",不是"命令"
if layer == "memory":
return "【客观事实】以下是关于 Agent 环境的已知事实:\n" + content
elif layer == "user":
return "【用户偏好】以下是从用户行为中推断出的偏好:\n" + content
这个设计解决了一个常见问题:Agent 把记忆里的「偏好」当成「指令」,导致行为僵化。围栏告诉模型:这些是事实描述,不是命令。
4.3 容量控制:防止记忆无限膨胀
两个核心文件都有严格的字符上限:
| 文件 | 容量上限 | 记录内容 |
|---|---|---|
MEMORY.md | ~2200 字符 | Agent 个人笔记:环境配置、使用约定、技术发现 |
USER.md | ~1375 字符 | 用户偏好:编码风格、时区、语言习惯 |
容量超限时,Curator 后台维护员自动介入,执行记忆压缩:
- 识别低价值内容(长期未引用的条目)
- 合并相似条目
- 删除过时信息
- 重写文件,保持字符数在限制内
这个设计的哲学是:记忆不在多,在于精。Agent 不需要记住一切,只需要记住真正重要的。
4.4 FTS5 召回:全文索引驱动的记忆检索
会话历史的检索基于 SQLite 的 FTS5(Full-Text Search 5)扩展:
# heremes_state.py 中的检索逻辑
def search_history(self, query: str, limit: int = 10):
"""基于 SQLite FTS5 的全文检索"""
cursor.execute("""
SELECT snippet(conversation_fts, 0, '【', '】', '...', 32) as snippet,
rank
FROM conversation_fts
WHERE conversation_fts MATCH ?
ORDER BY rank
LIMIT ?
""", (query, limit))
return cursor.fetchall()
FTS5 使用倒排索引,支持:
- 布尔查询:
LLM AND memory找同时包含两个词的结果 - 短语搜索:
"closed learning loop"精确匹配 - 权重排序:近期对话权重更高
与向量检索相比,FTS5 的优势是精确可控——你可以搜索确切的技术术语,不依赖语义相似度的模糊匹配。
五、Skills 系统:程序性记忆的自动生成
5.1 什么是 Skill?
Skill 是 Hermes Agent 的「程序性记忆」单元。它以 Markdown 格式存储,描述了一个完整的任务流程:
---
name: deploy-docker
description: 部署 Docker 应用的标准流程
agent: default
version: 1.2.0
triggers:
- "部署应用"
- "docker deploy"
- "发布到服务器"
steps:
- build: 构建 Docker 镜像
- push: 推送到镜像仓库
- pull: 服务器拉取镜像
- restart: 重启容器
---
这个结构让 Skill 文件既人类可读(可以手动编辑),又机器可执行(结构化数据供 Agent 解析)。
5.2 自动生成流程
Skill 的生成发生在 agent/skill_bundles.py 中,由 Curator 驱动:
任务完成
↓
Curator 分析对话轨迹(Conversation Traces)
↓
识别重复模式(Pattern Recognition)
↓
生成 Skill 文件草稿
↓
Agent 审查并确认
↓
Skill 持久化到 skills/ 目录
Curator 的分析维度:
- 频率:同一个任务被执行过几次?
- 复杂度:任务包含多少步骤?
- 稳定性:步骤顺序是否固定?
只有同时满足「频率高 + 复杂度适中 + 步骤固定」的流程才会被自动生成 Skill,避免无意义的碎片化。
5.3 Skill 自改进机制
当一个现有 Skill 在执行时失败:
# 伪代码:Skill 执行失败时的自改进流程
def on_skill_failure(skill: Skill, error: ExecutionError):
# 1. 记录失败上下文
failure_context = {
"skill": skill.name,
"error": str(error),
"trace": get_recent_conversation()
}
# 2. 诊断失败原因
diagnosis = llm.diagnose(failure_context)
# 3. 生成改进建议
improvement = llm.suggest_fix(skill.content, diagnosis)
# 4. 更新 Skill 文件
skill.update(improvement)
这个机制让 Agent 具备了「犯错后自我修正」的能力,是闭环学习的最后一环。
5.4 Skill 索引与缓存
当 Skill 数量很多时,每次会话启动都加载所有 Skill 会很慢。PromptBuilder 实现了两级缓存机制:
class PromptBuilder:
def __init__(self):
# L1: 内存 LRU 缓存
self._skill_index_cache = LRU(maxsize=128)
# L2: 磁盘快照
self._snapshot_file = Path("~/.hermes/skills/.index_snapshot")
def get_skill_index(self) -> SkillIndex:
cache_key = self._compute_cache_key()
# 先查 L1
if cache_key in self._skill_index_cache:
return self._skill_index_cache[cache_key]
# 再查 L2 磁盘快照
if self._snapshot_file.exists():
snapshot = self._load_snapshot()
self._skill_index_cache[cache_key] = snapshot
return snapshot
# 都没有,生成并缓存
index = self._build_skill_index()
self._save_snapshot(index)
self._skill_index_cache[cache_key] = index
return index
六、工具系统:自注册与 Toolset 组合
6.1 ToolRegistry 自注册模式
工具系统的核心在 tools/registry.py。每个工具文件在模块级别声明自己:
# tools/web_search.py
# 模块级别的自注册
def __init_module__():
registry.register(
name="web_search",
description="Search the web for current information",
schema={
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search query"},
"count": {"type": "integer", "default": 10}
},
"required": ["query"]
},
handler=web_search_handler,
toolset="information",
parallel_safe=True # 标记为可并行
)
这种方式的优势:
- 零配置新增:新增工具只需创建文件,无需修改任何注册表
- 自包含:工具定义和实现天然在一起
- 声明式:工具元数据(schema、描述、所属 Toolset)在同一处
6.2 Toolset 组合系统
toolsets.py 定义了工具的组合逻辑:
class Toolset:
"""工具集合定义"""
DEFAULT_TOOLSETS = {
"code": ["read_file", "write_file", "patch", "exec", "git_*", "lsp_*"],
"information": ["web_search", "read_url", "memory_search"],
"communication": ["send_message", "read_messages"],
"system": ["bash", "env_check", "process_list"],
}
用户可以按场景组合工具集:
# 只启用代码工具
hermes run --toolset code
# 启用所有工具
hermes run --toolset all
# 自定义组合
hermes run --toolset code,information
6.3 MCP 双向支持
Hermes Agent 实现了 MCP(Model Context Protocol)的双向支持:
- 作为 MCP 客户端:可以连接外部 MCP 服务器(如 Filesystem MCP、Git MCP)
- 作为 MCP 服务端:可以被 Cursor、VS Code 等 IDE 接入
# 作为客户端连接外部 MCP 服务器
hermes config add-mcp-server filesystem \
--command "npx" \
--args "mcp-server-filesystem /path/to/project"
# 查看已连接的 MCP 服务器
hermes mcp list
七、部署实战:从零到生产级
7.1 快速安装
官方提供一键安装脚本:
# Linux / macOS
curl -fsSL https://hermesagent.ai/install.sh | bash
# Windows (PowerShell)
irm https://hermesagent.ai/install.ps1 | iex
# 验证安装
hermes --version
安装后会创建以下目录结构:
~/.hermes/
├── config.yaml # 主配置文件
├── .env # API Key 和密钥
├── SOUL.md # Agent 人格定义
├── memories/ # 持久记忆
├── skills/ # 技能库
├── cron/ # 定时任务
├── sessions/ # 会话记录
└── logs/ # 日志
7.2 配置文件说明
# config.yaml
model:
provider: openrouter
model: openai/gpt-5.6
environment:
backend: local # local / docker / ssh / modal
shell: zsh
tools:
enabled: true
toolsets:
- code
- information
- system
memory:
built_in_limit: 2200 # MEMORY.md 字符上限
user_profile_limit: 1375 # USER.md 字符上限
curator_enabled: true # 启用自动清理
profile:
current: default # 当前 Profile
available:
- name: default
description: 默认配置
- name: work
description: 工作项目
- name: personal
description: 个人项目
7.3 连接多平台
# 配置 Telegram Bot
hermes config add-platform telegram \
--bot-token "YOUR_BOT_TOKEN"
# 配置 Discord Webhook
hermes config add-platform discord \
--webhook-url "YOUR_WEBHOOK_URL"
# 配置 Slack
hermes config add-platform slack \
--bot-token "xoxb-..." \
--signing-secret "..."
# 启动网关
hermes gateway start
7.4 Docker 部署
FROM python:3.11-slim
WORKDIR /app
RUN pip install hermesagent
COPY config.yaml .env SOUL.md ./
RUN hermes setup --non-interactive
CMD ["hermes", "run"]
# docker-compose.yml
version: '3.8'
services:
hermes:
build: .
volumes:
- ./data:/root/.hermes
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}
restart: unless-stopped
ports:
- "8080:8080" # Gateway 端口
八、性能优化与生产调优
8.1 上下文压缩策略
当对话历史超过模型上下文窗口时,ContextCompressor 自动触发压缩:
class ContextCompressor:
"""可插拔的上下文压缩策略"""
def compress(self, messages: list[Message]) -> list[Message]:
# 策略1: 保留首尾消息(对话窗口效应)
# 策略2: 摘要中间消息
# 策略3: 删除工具调用的冗余结果
...
8.2 Token 成本控制
冻结快照的一个直接收益是Token 成本可预测:
基础 Token 消耗 = 冻结快照大小(固定)
可变 Token 消耗 = 当前轮次的新内容
总 Token = 基础 + 可变
没有冻结快照时,记忆内容会在每次 API 调用中重复发送,成本随对话长度线性增长。冻结快照把记忆从「每次消耗」变成「固定成本」。
8.3 本地模型接入
使用 Ollama 接入本地模型:
# 安装 Ollama
brew install ollama
# 拉取模型
ollama pull qwen3-8b
# 配置 Hermes 使用 Ollama
hermes model set ollama qwen3-8b
# 验证
hermes model current
# → ollama/qwen3-8b
本地模型的优势:
- 零 API 成本:不消耗外部 API 额度
- 隐私可控:数据不出本机
- 离线可用:不需要网络连接
九、与其他框架的对比
9.1 Hermes Agent vs OpenClaw
| 维度 | Hermes Agent | OpenClaw |
|---|---|---|
| 核心架构 | Agent-first | Gateway-first |
| 记忆系统 | 三层架构(Built-in + External + Skills) | 静态文本(MEMORY.md) |
| 自进化 | 原生闭环学习 + Curator | 依赖 Skill 手动编写 |
| 记忆检索 | SQLite FTS5 全文索引 | 关键词搜索 |
| 部署 | 轻量(500MB 内存) | 较重(需要额外进程) |
| 模型支持 | 200+(OpenRouter 聚合) | 较多 |
| 工具生态 | 40+ 内置工具 + MCP | Skills 模块化 |
两者定位不同:Hermes Agent 更侧重「自主进化」,OpenClaw 更侧重「多渠道连接」。
9.2 Hermes Agent vs LangChain Agents
LangChain 的 Agent 是「工具编排引擎」,没有内置的记忆和自进化机制。Hermes Agent 把 LangChain 当作一个可选的工具后端(通过 LangChain MCP)。
十、总结与展望
10.1 核心价值
Hermes Agent 的核心价值不在于「有多少 Star」,而在于它提出并实现了一个清晰的愿景:让 Agent 具有真正的学习能力。
它的三个关键创新:
- 闭环学习:不是给 Agent 加记忆功能,而是让 Agent 自己决定记什么、怎么用、什么时候改进
- 三层记忆架构:对应认知科学的三种记忆类型,从工程上找到了语义记忆和程序性记忆的落地方案
- 冻结快照:解决了记忆内容的「重复发送」问题,让成本可控
10.2 局限性
- 记忆容量硬限制:两个 Markdown 文件的字符上限意味着 Agent 不可能「记住一切」
- Curator 的主动性:自动清理依赖 Curator 的质量,误删重要记忆有风险
- Profile 隔离的粒度:当前 Profile 隔离是全有全无的,不支持「部分共享」
- 自生成 Skill 的可验证性:Curator 自动生成的 Skill 质量参差不齐,需要人工审核
10.3 未来方向
从 v0.14.0 的 roadmap 看,Hermes Agent 的下一阶段重点:
- 向量记忆层:将 FTS5 替换为语义向量检索,提升记忆召回的准确性
- 多 Agent 协作:支持多个 Hermes Agent 实例之间的任务分发
- 持久化 Skill 版本控制:Skill 文件的 Git 管理与回滚
- 企业级 SSO:LDAP/OIDC 接入支持
参考资源
- GitHub: https://github.com/NousResearch/hermes-agent
- 官方文档: https://hermesagent.ai/docs
- Nous Research: https://nousresearch.com
- Honcho 协议: https://github.com/NousResearch/honcho