Hermes Agent 深度拆解:110K Star 背后的「自进化」架构哲学——当一个 AI Agent 决定「越用越聪明」后,闭环学习、三层记忆与 400+ 技能的工程实战
2026 年 2 月,Nous Research 发布了 Hermes Agent。三个月后,GitHub Star 数冲破 110K,贡献者超过 240 人。和市面上绝大多数 Agent 框架不同,它的核心卖点不是「更好地调用工具」,而是「越用越聪明」。这篇文章从源码出发,拆解这个「自进化」Agent 的架构设计、闭环学习机制、三层记忆系统与 400+ 技能生态,附完整代码示例与生产部署指南。
一、为什么你需要关注 Hermes Agent?
1.1 Agent 赛道的现状与痛点
2026 年的 AI Agent 赛道已经非常拥挤。AutoGPT、MetaGPT、CrewAI、LangGraph、OpenClaw……每隔几周就有一个新框架冒出来。但如果你真正用过这些框架,会发现一个共同的痛点:
Agent 永远是「无状态」的。
每次对话从零开始,或者依赖简单的上下文窗口来维持「记忆」。你花了一周教它你的项目结构、编码规范、工作流程,结果换个会话就全忘了。这不是 Agent,这是一个每次都失忆的实习生。
Hermes Agent 解决的就是这个问题。它的核心理念可以用一句话概括:
The self-improving AI agent — 一个能从经验中学习、在使用中进化、越用越聪明的智能体。
1.2 核心数据一览
| 属性 | 详情 |
|---|---|
| 开发者 | Nous Research |
| 许可证 | MIT(完全自由) |
| 主语言 | Python(909+ 文件) |
| 辅助语言 | TypeScript/TSX(Web UI) |
| Python 版本 | ≥ 3.11 |
| 总文件数 | ~1717 |
| 测试用例 | ~3000 |
| 工具数量 | 40+ 内置工具 |
| 技能数量 | 288 内置 + 116 可选 |
| 支持平台 | 17+ 消息平台 |
| GitHub Star | 110K+ |
和 OpenClaw 的 14000+ TypeScript 文件相比,Hermes Agent 的 ~1700 个 Python 文件更易理解和贡献。这不是一个「大而全」的框架,而是一个「中等规模但设计精巧」的项目。
二、架构全景:从目录结构看设计哲学
2.1 目录结构速览
hermes-agent/
├── run_agent.py # ★ 核心:AIAgent 类与对话循环
├── model_tools.py # 工具编排与函数调用分发
├── toolsets.py # 工具集定义(40+ 工具列表)
├── cli.py # 交互式 CLI 编排器
├── hermes_state.py # SessionDB — SQLite 会话存储
│
├── agent/ # Agent 内部模块(33 文件)
│ ├── prompt_builder.py # 系统提示词组装
│ ├── context_compressor.py # 自动上下文压缩
│ ├── memory_manager.py # 记忆上下文构建
│ └── error_classifier.py # API 错误分类与故障转移
│
├── tools/ # 工具实现(71 文件)
│ ├── registry.py # ★ 中央工具注册表
│ ├── terminal_tool.py # 终端编排
│ ├── file_tools.py # 文件操作
│ ├── browser_tool.py # 浏览器自动化
│ └── environments/ # 6 种终端后端实现
│ ├── local.py # 本地终端
│ ├── docker.py # Docker 容器
│ ├── ssh.py # SSH 远程
│ └── ...
│
├── hermes_cli/ # CLI 子命令(48 文件)
│ ├── main.py # 所有 hermes 子命令入口
│ ├── skin_engine.py # ★ 皮肤/主题引擎
│ └── skills_hub.py # 技能市场
│
├── gateway/ # 消息平台网关(42 文件)
│ └── platforms/ # Telegram/Discord/Slack/WhatsApp/QQ...
│
├── acp_adapter/ # VS Code / Zed / JetBrains 集成
├── skills/ # 288 个内置技能(Markdown)
├── optional-skills/ # 116 个可选技能
├── tests/ # ~3000 个测试
└── environments/ # RL 训练环境(Atropos)
2.2 五个关键架构决策
决策一:同步 Agent 循环
run_conversation() 是一个完全同步的 while 循环,没有使用 async/await。这种设计看似「保守」,实则大大降低了理解和调试的复杂度:
while api_call_count < self.max_iterations and self.iteration_budget.remaining > 0:
response = client.chat.completions.create(
model=model,
messages=messages,
tools=tool_schemas
)
if response.tool_calls:
for tool_call in response.tool_calls:
result = handle_function_call(tool_call.name, tool_call.args, task_id)
messages.append(tool_result_message(result))
api_call_count += 1
else:
return response.content
对比 OpenClaw 的复杂异步架构,Hermes Agent 的同步设计对于快速迭代的初创团队更友好。调试时你只需要在一个线程里追踪整个执行流程,不需要处理 async/await 的状态交错。
决策二:中心化工具注册
所有工具通过 tools/registry.py 统一注册和分发。添加新工具只需两步:
# tools/your_tool.py
from tools.registry import registry
async def handle_your_tool(args, task_id):
"""处理你的工具逻辑"""
result = do_something(args)
return {"output": result}
# 注册工具
registry.register(
name="your_tool",
toolset="hermes-core",
handler=handle_your_tool,
schema={
"type": "function",
"function": {
"name": "your_tool",
"description": "你的自定义工具",
"parameters": {
"type": "object",
"properties": {
"input": {"type": "string", "description": "输入参数"}
},
"required": ["input"]
}
}
}
)
这种自注册模式的优势在于:新接入一个平台时,只需要定义该平台特有的工具,然后引用核心工具集就行。工具的发现机制通过 AST 分析检测哪些 .py 文件包含 registry.register() 调用,不需要手动维护工具列表。
决策三:Profile 多实例隔离
通过 HERMES_HOME 环境变量实现完全隔离的多实例支持,代码中 119+ 处引用 get_hermes_home() 确保路径隔离。这意味着你可以在同一台机器上跑多个独立的 Agent 实例,互不干扰——比如一个用于工作项目,一个用于个人自动化。
# 创建独立的 Profile
hermes profile create work-assistant --clone
hermes profile create personal-bot --clone
# 使用不同 Profile 启动
hermes -p work-assistant
hermes -p personal-bot
每个 Profile 拥有独立的配置、记忆库、会话历史、Skill 集合和工具权限。数据全部存储在本地 ~/.hermes/ 目录,搬家的时候拷贝目录就行。
决策四:可插拔上下文引擎
agent/context_engine.py 定义了抽象基类 ContextEngine,agent/context_compressor.py 提供了默认实现。可插拔设计意味着你可以实现自己的上下文管理策略,比如基于 RAG 的检索增强、基于重要性评分的选择性保留等。
from abc import ABC, abstractmethod
class ContextEngine(ABC):
@abstractmethod
async def compress(self, messages, token_budget):
"""压缩对话历史,返回压缩后的消息列表"""
pass
class ContextCompressor(ContextEngine):
def __init__(self, threshold_percent=0.75, protect_first_n=3, protect_last_n=6):
self.threshold_percent = threshold_percent
self.protect_first_n = protect_first_n
self.protect_last_n = protect_last_n
async def compress(self, messages, token_budget):
usage_percent = self._calculate_usage(messages, token_budget)
if usage_percent < self.threshold_percent:
return messages
# 保护头部和尾部
head = messages[:self.protect_first_n]
tail = messages[-self.protect_last_n:]
middle = messages[self.protect_first_n:-self.protect_last_n]
# 中间部分用辅助模型总结
summary = await self._summarize_with_auxiliary_model(middle)
return head + [summary] + tail
决策五:研究导向的模块设计
RL 训练环境、轨迹压缩、批量运行器这些模块不是「后来加的」,而是从一开始就融入架构设计的核心组件。如果你在做 Agent 相关的学术研究或模型训练,Hermes Agent 可能是目前最开箱即用的研究平台。
三、闭环学习系统:Agent 如何「自我进化」
这是 Hermes Agent 和其他 Agent 框架拉开差距的地方。
3.1 闭环学习的五个环节
完成任务 → 策划记忆 → 创建 Skill → Skill 自改进 → FTS5 召回 → 用户建模 → (循环)
这套机制对应认知科学的三种记忆类型:
- 情景记忆(Episodic Memory):会话历史,通过 SQLite FTS5 全文搜索检索
- 语义记忆(Semantic Memory):MEMORY.md 持久事实,记录环境信息、项目约定
- 程序性记忆(Procedural Memory):Skill 文件,记录可复用的操作步骤
3.2 Skill 自动创建与改进
Skill 是 Hermes Agent 最核心的抽象。它不是简单的 prompt 模板,而是一个完整的「操作手册」,包含触发条件、执行步骤、注意事项和代码示例。
# deploy-to-production.md
## 触发条件
当用户说「部署到生产」「上线」「push to prod」时触发
## 前置检查
1. 确认当前分支是 main
2. 运行 `git status` 确认无未提交更改
3. 运行 `npm test` 确认测试全部通过
## 部署步骤
1. `git pull origin main`
2. `npm run build`
3. `docker build -t myapp:latest .`
4. `docker push myapp:latest`
5. `kubectl set image deployment/myapp myapp=myapp:latest`
## 回滚方案
如果部署后出现异常:
1. `kubectl rollout undo deployment/myapp`
2. 检查日志:`kubectl logs -l app=myapp --tail=100`
## 注意事项
- 部署前必须确认数据库迁移已执行
- 高峰期(14:00-18:00)避免部署
- 生产环境禁止使用 `--force` 参数
Agent 完成一个复杂任务后,会自主判断是否包含可复用的模式。如果有,就自动生成 Markdown 格式的 Skill 文件。使用 Skill 时如果发现问题(过时、报错),立即 patch 更新。
3.3 记忆策展机制
Hermes Agent 的记忆不是简单地「把所有对话都存下来」,而是有选择性地策展:
# agent/memory_manager.py 中的记忆策展逻辑(简化)
class MemoryManager:
def curate_memory(self, conversation_history):
"""Agent 自主判断什么值得记住"""
# 1. 识别关键事实(项目约定、用户偏好、环境信息)
key_facts = self._extract_key_facts(conversation_history)
# 2. 识别可复用模式(重复出现的操作步骤)
patterns = self._identify_reusable_patterns(conversation_history)
# 3. 生成 Skill 文件
if patterns:
self._create_skill_from_pattern(patterns)
# 4. 更新 MEMORY.md
self._update_persistent_memory(key_facts)
记忆条目之间用 §(section sign)分隔——这个选择挺有意思,用一个不太常见的字符做分隔符,降低了和正文内容冲突的概率。
3.4 冻结快照模式
这个设计解决了一个很实际的问题:系统提示的稳定性。
会话开始时,MemoryManager 把当前的记忆内容作为快照注入系统提示。之后整个会话期间,系统提示保持不变——中途写入的记忆只更新磁盘文件,不刷新系统提示。
# 冻结快照模式的核心逻辑
class MemoryManager:
def start_session(self):
"""会话开始时创建冻结快照"""
# 读取当前记忆
memory_content = self._read_memory_files()
# 创建快照(不可变)
self._frozen_snapshot = memory_content
# 注入系统提示(整个会话期间不变)
return self._build_system_prompt_with_snapshot(self._frozen_snapshot)
def update_memory(self, new_entries):
"""中途更新记忆(只写磁盘,不刷新系统提示)"""
self._append_to_memory_file(new_entries)
# 注意:self._frozen_snapshot 不变!
这样做的好处是保持前缀缓存(prefix cache)有效。如果每次记忆更新都刷新系统提示,KV cache 就会失效,每次请求都要重新计算前面所有 token 的 KV 对。冻结快照让前缀缓存命中率大大提高。
代价是 Agent 在一个会话内对记忆的修改,需要等到下一个会话才能被读取。对于大多数使用场景来说,这个延迟是可以接受的。
四、三层记忆架构:从短期到长期的知识管理
4.1 双 Provider 记忆架构
agent/memory_manager.py 中的 MemoryManager 采用双 Provider 架构:
class MemoryManager:
def __init__(self):
# 内置 Provider:管理 MEMORY.md 和 USER.md
self.builtin_provider = BuiltinMemoryProvider()
# 外部 Provider(可选):如 Honcho 用户建模
self.external_provider = None # 可注入 Honcho 等
def get_memory_context(self):
"""获取记忆上下文"""
contexts = []
# 1. 从内置 Provider 获取
contexts.append(self.builtin_provider.get_memory())
# 2. 从外部 Provider 获取(如果有)
if self.external_provider:
contexts.append(self.external_provider.get_user_model())
# 3. 用 <memory-context> 标签做上下文围栏
return self._wrap_with_fence("\n".join(contexts))
两个记忆文件的分工很明确:
- MEMORY.md:Agent 的个人笔记。记录环境事实、项目约定、工具的使用技巧
- USER.md:Agent 对用户的认知。记录偏好、沟通风格、期望
记忆注入时使用 <memory-context> 标签做上下文围栏,防止模型把记忆上下文误认为新的用户输入。
4.2 FTS5 全文搜索召回
hermes_state.py 中的 SessionDB 基于 SQLite FTS5 实现跨所有会话消息的全文搜索:
import sqlite3
class SessionDB:
def __init__(self, db_path):
self.conn = sqlite3.connect(db_path)
self._init_fts5()
def _init_fts5(self):
"""初始化 FTS5 全文搜索索引"""
self.conn.execute("""
CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts
USING fts5(content, session_id, timestamp)
""")
def search(self, query, limit=10):
"""全文搜索历史消息"""
cursor = self.conn.execute("""
SELECT content, session_id, timestamp
FROM messages_fts
WHERE messages_fts MATCH ?
ORDER BY rank
LIMIT ?
""", (query, limit))
return cursor.fetchall()
搜索流程是:FTS5 召回相关片段 → LLM 总结 → 注入当前上下文。这是一个多级检索的设计,不同类型的记忆走不同的通道。
4.3 Honcho 用户建模
Hermes Agent 集成了 Honcho 辩证用户建模系统,通过对话式交互构建用户画像:
# Honcho 用户建模的核心逻辑(简化)
class HonchoUserModel:
def __init__(self):
self.user_profile = {}
def observe_interaction(self, user_message, agent_response, context):
"""从交互中提取用户偏好"""
# 分析用户的沟通风格
style = self._analyze_communication_style(user_message)
# 提取技术偏好
tech_prefs = self._extract_tech_preferences(context)
# 更新用户画像
self.user_profile.update({
"communication_style": style,
"technical_preferences": tech_prefs,
"last_updated": datetime.now()
})
def get_user_model(self):
"""返回用户建模结果"""
return json.dumps(self.user_profile, ensure_ascii=False)
Honcho 的核心理念是「方言式建模」——不是简单地给用户打标签,而是通过观察用户的实际行为来理解他们的「方言」(即独特的沟通和工作方式)。
五、工具系统:自注册 + Toolset 组合
5.1 ToolRegistry 自注册模式
工具系统的核心在 tools/registry.py:
import threading
class ToolEntry:
def __init__(self, name, toolset, schema, handler, check_fn=None,
requires_env=False, is_async=False, description="", emoji=""):
self.name = name
self.toolset = toolset
self.schema = schema
self.handler = handler
self.check_fn = check_fn
self.requires_env = requires_env
self.is_async = is_async
self.description = description
self.emoji = emoji
class ToolRegistry:
def __init__(self):
self._tools = {}
self._lock = threading.RLock()
def register(self, name, toolset, schema, handler, **kwargs):
"""注册工具(线程安全)"""
with self._lock:
entry = ToolEntry(
name=name,
toolset=toolset,
schema=schema,
handler=handler,
**kwargs
)
self._tools[name] = entry
def get_tool(self, name):
"""获取工具(快照读取)"""
with self._lock:
return self._tools.get(name)
def discover_builtin_tools(self):
"""通过 AST 分析自动发现工具"""
import ast
import os
tools_dir = os.path.join(os.path.dirname(__file__), "tools")
for root, dirs, files in os.walk(tools_dir):
for f in files:
if f.endswith(".py"):
filepath = os.path.join(root, f)
with open(filepath) as fp:
tree = ast.parse(fp.read())
for node in ast.walk(tree):
if isinstance(node, ast.Call):
if hasattr(node.func, 'attr') and node.func.attr == 'register':
# 找到 registry.register() 调用
pass
发现机制通过 AST 分析检测哪些 .py 文件包含 registry.register() 调用,不需要手动维护工具列表。动态注册/注销场景主要用于 MCP 服务器刷新:MCP 工具上线时调用 register(),下线时调用 deregister()。
5.2 Toolset 组合系统
toolsets.py 实现了一个组合式工具集系统:
# 核心工具列表
_HERMES_CORE_TOOLS = [
# Web
"web_search", "web_extract",
# 终端
"terminal", "process",
# 文件
"read_file", "write_file", "patch", "search_files",
# 视觉
"vision_analyze", "image_generate",
# 技能
"skills_list", "skill_view", "skill_manage",
# 浏览器
"browser_navigate", "browser_click", "browser_type",
# 规划
"todo", "memory",
# 代码执行
"execute_code", "delegate_task",
# 定时任务
"cronjob",
# 其他
"send_message", "session_search", "clarify",
]
# 平台特定 toolset
_HERMES_TELEGRAM_TOOLS = _HERMES_CORE_TOOLS + [
"telegram_send_message",
"telegram_send_photo",
"telegram_edit_message",
]
_HERMES_DISCORD_TOOLS = _HERMES_CORE_TOOLS + [
"discord_send_message",
"discord_send_embed",
"discord_add_reaction",
]
# 所有平台的并集
_HERMES_GATEWAY_TOOLS = list(set(
_HERMES_TELEGRAM_TOOLS +
_HERMES_DISCORD_TOOLS +
_HERMES_SLACK_TOOLS +
# ... 更多平台
))
这种组合式设计的好处是:新接入一个平台时,只需要定义该平台特有的工具,然后 includes 核心工具集就行。比如新增一个飞书适配器,只需要定义飞书的消息发送、消息格式化等平台特有工具,然后引用 hermes-gateway 的基础工具集。
5.3 并行工具执行
Agent 循环中的一个关键判断逻辑在 _should_parallelize_tool_batch() 方法中:
# 工具并行分类
_NEVER_PARALLEL_TOOLS = {"clarify"} # 需要用户交互,永远不并行
_PARALLEL_SAFE_TOOLS = {"web_search", "read_file"} # 只读安全,可并行
_PATH_SCOPED_TOOLS = {"read_file", "write_file", "patch"} # 路径隔离,条件并行
_MAX_TOOL_WORKERS = 8 # 最大并发工作线程数
def _should_parallelize_tool_batch(self, tool_calls):
"""判断工具批次是否可以并行执行"""
for tc in tool_calls:
if tc.name in _NEVER_PARALLEL_TOOLS:
return False
# 检查路径冲突
write_ops = [tc for tc in tool_calls if tc.name in _PATH_SCOPED_TOOLS]
if len(write_ops) > 1:
paths = [tc.args.get("path") for tc in write_ops]
if len(set(paths)) < len(paths): # 有路径冲突
return False
return True
这个设计说明团队对 Agent 的实际使用场景做过深入思考。比如 web_search 和 read_file 都是纯读操作,并行执行完全安全。但 write_file 和 patch 操作同一文件时就有冲突风险,所以需要路径隔离检查。
六、子 Agent 委托:从单兵到团队
6.1 隔离设计
tools/delegate_tool.py 实现了子 Agent 委托机制:
# 子 Agent 关键配置
MAX_DEPTH = 1 # 默认扁平,最多可配到 3
MAX_CONCURRENT = 3 # 最多 3 个并行子 Agent
# 被禁止的工具(子 Agent 不能使用)
DELEGATE_BLOCKED_TOOLS = {
"delegate_task", # 防止递归委托
"clarify", # 子 Agent 不应该直接和用户对话
"memory_write", # 防止子 Agent 污染主 Agent 的记忆
"skill_manage", # 子 Agent 不应该修改技能
}
子 Agent 的隔离做得比较彻底:
- 无父历史:子 Agent 看不到父 Agent 的对话历史
- 独立终端会话:子 Agent 有自己的终端环境
- 工具限制:特定工具被禁止使用
class SubAgent:
def __init__(self, task, parent_context=None):
self.task = task
self.depth = 0
self.conversation_history = [] # 独立的对话历史
self.terminal = TerminalBackend() # 独立的终端
async def run(self):
"""执行子 Agent 任务"""
# 不继承父 Agent 的历史
messages = [
{"role": "system", "content": self._build_system_prompt()},
{"role": "user", "content": self.task}
]
# 限制可用工具
available_tools = [
t for t in ALL_TOOLS
if t.name not in DELEGATE_BLOCKED_TOOLS
]
return await self._agent_loop(messages, available_tools)
七、多平台网关:一个 Agent,所有平台
7.1 统一消息网关
gateway/run.py 实现了一个统一的消息网关,单一进程处理所有平台消息:
class Gateway:
def __init__(self):
self.platforms = {
"telegram": TelegramAdapter(),
"discord": DiscordAdapter(),
"slack": SlackAdapter(),
"whatsapp": WhatsAppAdapter(),
"signal": SignalAdapter(),
"email": EmailAdapter(),
"wechat": WeChatAdapter(),
"dingtalk": DingTalkAdapter(),
"feishu": FeishuAdapter(),
# ... 17+ 平台
}
self.agent_cache = LRUCache(maxsize=128)
self.agent_ttl = 3600 # 1 小时空闲淘汰
async def handle_message(self, platform, user_id, message):
"""统一消息处理入口"""
# 1. 查找或创建 Agent 实例
agent = self._get_or_create_agent(platform, user_id)
# 2. 转换消息格式
normalized = self.platforms[platform].normalize(message)
# 3. 交给 Agent 处理
response = await agent.process(normalized)
# 4. 转换回平台格式并发送
formatted = self.platforms[platform].format_response(response)
await self.platforms[platform].send(user_id, formatted)
这意味着同一个 Agent 可以同时服务多个平台——你可以在 Telegram 上开始一个对话,然后在 Discord 上继续。不同平台的消息格式差异在网关层统一处理,Agent 核心不需要关心这些细节。
7.2 Agent 缓存策略
网关用 LRU 缓存 + 空闲 TTL 淘汰来管理 Agent 实例:
class AgentCache:
def __init__(self, maxsize=128, ttl=3600):
self.cache = {}
self.access_times = {}
self.maxsize = maxsize
self.ttl = ttl
def get(self, key):
if key in self.cache:
self.access_times[key] = time.time()
return self.cache[key]
return None
def put(self, key, agent):
if len(self.cache) >= self.maxsize:
# 淘汰最久未访问的
oldest = min(self.access_times, key=self.access_times.get)
del self.cache[oldest]
del self.access_times[oldest]
self.cache[key] = agent
self.access_times[key] = time.time()
def cleanup_expired(self):
"""清理过期的 Agent 实例"""
now = time.time()
expired = [
k for k, t in self.access_times.items()
if now - t > self.ttl
]
for k in expired:
del self.cache[k]
del self.access_times[k]
八、状态持久化:SQLite + FTS5
8.1 技术选型
Hermes Agent 选择 SQLite 作为状态存储层,这个决策非常务实:
- SQLite + WAL 模式:支持多读者 + 单写者,适合网关多平台并发场景
- FTS5 全文搜索:跨所有会话消息的快速文本搜索
- Schema 版本控制:当前 v8,自动迁移
import sqlite3
class SessionDB:
def __init__(self, db_path):
self.conn = sqlite3.connect(db_path, timeout=30)
self.conn.execute("PRAGMA journal_mode=WAL")
self.conn.execute("PRAGMA busy_timeout=5000")
self._migrate()
def _migrate(self):
"""Schema 版本控制与自动迁移"""
current_version = self._get_version()
migrations = {
1: self._migrate_v1_to_v2,
2: self._migrate_v2_to_v3,
# ... 更多迁移
}
for v in range(current_version, max(migrations.keys()) + 1):
if v in migrations:
migrations[v]()
self._set_version(v + 1)
8.2 写竞争处理
SQLite 在高并发写入时容易出现锁竞争。SessionDB 的处理方式是随机抖动重试:
import random
import time
class SessionDB:
MAX_RETRIES = 15
BASE_DELAY_MS = 20
MAX_DELAY_MS = 150
def _execute_with_retry(self, query, params=None):
"""带随机抖动的重试机制"""
for attempt in range(self.MAX_RETRIES):
try:
if params:
return self.conn.execute(query, params)
else:
return self.conn.execute(query)
except sqlite3.OperationalError as e:
if "database is locked" in str(e):
# 随机抖动,避免护航效应
delay = random.randint(self.BASE_DELAY_MS, self.MAX_DELAY_MS) / 1000
time.sleep(delay)
else:
raise
raise Exception("数据库写入失败:重试次数已耗尽")
随机抖动可以避免多个写请求同时重试导致的护航效应(convoy effect)。从选型上看,SQLite 在 Agent 状态管理场景下是一个平衡得很好的方案——PostgreSQL 太重,纯文件存储又缺乏查询能力。
九、PromptBuilder 与安全扫描
9.1 系统提示组装
agent/prompt_builder.py 负责组装完整的 system prompt,包含多个层次:
class PromptBuilder:
def build_system_prompt(self, context_files, memory_snapshot, skills_index):
"""组装完整的系统提示"""
parts = []
# 1. 核心身份定义
parts.append(DEFAULT_AGENT_IDENTITY)
# 2. 平台特定提示
parts.append(self._get_platform_hint())
# 3. 技能索引
parts.append(SKILLS_GUIDANCE)
parts.append(self._format_skills_index(skills_index))
# 4. 上下文文件
for ctx_file in context_files:
parts.append(f"## Context: {ctx_file.name}\n{ctx_file.content}")
# 5. 记忆快照(冻结)
parts.append(f"<memory-context>\n{memory_snapshot}\n</memory-context>")
# 6. 工具使用指导
parts.append(TOOL_USE_ENFORCEMENT_GUIDANCE)
return "\n\n".join(parts)
PromptBuilder 还有一个两级缓存机制来加速 Skill 索引的读取:LRU 缓存(内存中)+ 磁盘快照(持久化)。这在 Skill 数量很多的时候能明显减少启动时间。
9.2 安全扫描
PromptBuilder 还有一个容易被忽略的功能:_scan_context_content() 检测注入攻击:
class PromptBuilder:
def _scan_context_content(self, content):
"""检测 prompt injection 攻击"""
suspicious_patterns = [
r"ignore\s+previous\s+instructions",
r"you\s+are\s+now\s+a\s+",
r"system\s*:\s*",
r"<\|im_start\|>",
r"Human:\s*",
]
for pattern in suspicious_patterns:
if re.search(pattern, content, re.IGNORECASE):
raise SecurityError(f"检测到可疑内容:{pattern}")
return content
上下文文件(.hermes.md、AGENTS.md、CLAUDE.md、.cursorrules)的优先级是 .hermes.md > AGENTS.md > CLAUDE.md > .cursorrules。安全扫描会检查这些文件中是否包含恶意指令。
十、生产部署实战
10.1 一键安装
# macOS / Linux
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
# Windows(需 WSL2)
wsl --install
# 在 WSL2 终端中执行:
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
安装脚本会自动完成:
- 检测并安装 Python 3.11
- 检测并安装 Node.js v22
- 检测并安装 ripgrep(高速文件搜索)
- 检测并安装 ffmpeg(音视频处理)
- 创建独立的 Python 虚拟环境
- 克隆代码仓库并安装依赖
- 将
hermes命令添加到 PATH
10.2 配置模型
# 交互式配置
hermes setup
# 或者直接指定模型
hermes model set openrouter/anthropic/claude-sonnet-4-20250514
# 支持的模型后端
hermes model list
# → OpenAI, Anthropic, Bedrock, OpenRouter, Ollama, Nous Portal...
10.3 启动网关
# 启动 Telegram 网关
hermes gateway start --platform telegram
# 启动多平台网关
hermes gateway start --platform all
# 后台运行
hermes gateway start --platform telegram --daemon
10.4 $5/月 VPS 部署
# 在 cheap VPS 上部署
# 1. 安装
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
# 2. 配置 OpenRouter(便宜的模型)
hermes model set openrouter/meta-llama/llama-3.1-8b-instruct
# 3. 启动 Telegram 网关
hermes gateway start --platform telegram --daemon
# 内存占用:不跑本地 LLM 的情况下 < 500MB
# 适合:个人使用、轻量自动化
十一、性能与限制
11.1 性能数据
| 指标 | 数值 |
|---|---|
| Agent 进程内存 | < 500MB(不含本地 LLM) |
| 冷启动时间 | ~2s(含 Skill 索引加载) |
| 单次 LLM 调用延迟 | 取决于模型后端 |
| 并行工具执行 | 最多 8 个工作线程 |
| 子 Agent 并发 | 最多 3 个 |
| Agent 缓存容量 | 128 个实例 |
| 空闲淘汰时间 | 1 小时 |
11.2 已知限制
- 子 Agent 并发上限 3 个:复杂并行场景受限,社区有人吐槽过
- Windows 原生不支持:必须通过 WSL2
- 迭代节奏快:不到 3 周发布了 4 个大版本,稳定性需要观察
- 内存占用:虽然 < 500MB 看起来不多,但在 $5 VPS 上已经是不小的开销
11.3 与其他框架对比
| 维度 | Hermes Agent | OpenClaw | AutoGPT | LangGraph |
|---|---|---|---|---|
| 核心定位 | 自进化 Agent | 个人 AI 助手 | 自主 Agent | 工作流编排 |
| 语言 | Python | TypeScript | Python | Python |
| 文件数 | ~1700 | ~14000 | ~3000 | ~2000 |
| 闭环学习 | ✅ 原生 | ✅ 支持 | ❌ | ❌ |
| 多平台 | 17+ | 5+ | 1 | 0 |
| 研究就绪 | ✅ | ❌ | ❌ | ❌ |
| 本地优先 | ✅ | ✅ | ❌ | ❌ |
十二、总结与展望
翻完 Hermes Agent 的代码库,几个架构层面的判断:
做得好的地方
- 闭环学习是原生能力,不是事后加的补丁。从 PromptBuilder 的 MEMORY_GUIDANCE 到 MemoryManager 的双文件架构,再到 SessionDB 的 FTS5 搜索,整套学习闭环在架构层面是贯通的
- 工具自注册 + Toolset 组合的设计很灵活,新接入平台只需定义差异部分
- 上下文压缩的可插拔架构给未来的优化留下了空间
- 迭代预算 + 中断机制体现了对 Agent 实际运行问题的深入理解
需要关注的局限
- 子 Agent 并发上限 3 个,复杂并行场景受限
- 项目迭代节奏很快,稳定性需要观察
- Windows 原生不支持,必须通过 WSL2
- 关于抄袭的争议(中国团队指控架构级抄袭)目前还没有最终结论
未来方向
Hermes Agent 最大的贡献是把 Mitchell Hashimoto 提出的 Harness Engineering 五大组件(指令层、约束层、反馈层、记忆层、编排层)做成了产品级的内建能力。这在 Agent 框架领域是比较少见的。
如果你在做 Agent 相关的架构设计,Hermes Agent 的闭环学习和上下文管理部分值得细看。开源生态里能做到这个完成度的 Agent 框架,目前确实不多。
随着 Nous Research 获得 7500 万美元融资(估值 15 亿美元),Hermes Agent 的发展速度只会更快。对于开发者来说,现在正是深入理解其架构的好时机——等到它成为行业标准时,再回头来看设计决策就晚了。
参考资源
- GitHub 仓库:https://github.com/NousResearch/hermes-agent
- 官方文档:https://hermes.nousresearch.com/docs
- Nous Research:https://nousresearch.com
- License:MIT