Hermes Agent 核心架构分析
源码路径:
/home/xc/.hermes/hermes-agent/
分析版本:v0.13.0 (May 2026)
一、整体架构
┌─────────────────────────────────────────────────────────────────────┐
│ Hermes Agent │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ cli.py (~13,540 LOC) / ui-tui/ (Ink React) │ │
│ │ HermesCLI — 交互式终端,prompt_toolkit / Ink 双前端 │ │
│ └────────────────────────────┬───────────────────────────────────┘ │
│ │ │
│ ┌────────────────────────────▼───────────────────────────────────┐ │
│ │ run_agent.py (~15,700 LOC) │ │
│ │ AIAgent.run_conversation() — 核心对话循环 │ │
│ │ while not done: │ │
│ │ resp = client.chat.completions.create(messages, tools) │ │
│ │ for tool_call in resp.tool_calls: │ │
│ │ result = handle_function_call(tool_call.name, args) │ │
│ │ messages.append(tool_result_message(result)) │ │
│ └────────────────────────────┬───────────────────────────────────┘ │
│ │ │
│ ┌────────────────────────────▼───────────────────────────────────┐ │
│ │ model_tools.py (~865 LOC) — 工具编排层 │ │
│ │ get_tool_definitions() / handle_function_call() │ │
│ │ 持久化 asyncio 事件循环(防 Event loop is closed 错误) │ │
│ └────────────────────────────┬───────────────────────────────────┘ │
│ │ │
│ ┌────────────────────────────▼───────────────────────────────────┐ │
│ │ tools/registry.py (~563 LOC) — 工具注册中心 │ │
│ │ discover_builtin_tools() — AST 扫描自动发现 │ │
│ │ registry.register() — 工具自注册 │ │
│ └────────────────────────────┬───────────────────────────────────┘ │
│ │ │
│ ┌────────────────────────────▼───────────────────────────────────┐ │
│ │ toolsets.py (~855 LOC) — 工具分组与别名 │ │
│ │ _HERMES_CORE_TOOLS — 核心工具列表 │ │
│ │ TOOLSETS["web"] / TOOLSETS["terminal"] / ... │ │
│ └────────────────────────────┬───────────────────────────────────┘ │
│ │ │
│ ┌────────────────────────────▼───────────────────────────────────┐ │
│ │ tools/*.py — ~70 个工具实现(自注册) │ │
│ │ terminal_tool / file_tools / web_tools / delegate_tool / ... │ │
│ │ environments/ — local / ssh / docker / modal / daytona / ... │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ agent/ — Agent 内部模块 │ │
│ │ prompt_builder / context_compressor / memory_manager │ │
│ │ anthropic_adapter / bedrock_adapter / gemini_native_adapter │ │
│ │ skill_commands / skill_utils / skill_preprocessing │ │
│ │ token_cost / rate_limit_tracker / retry_utils │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ hermes_state.py (~2,966 LOC) — SQLite + FTS5 会话存储 │ │
│ │ SessionDB — WAL 模式 / FTS5 全文搜索 / 压缩分割 │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ gateway/ — 消息网关(多平台适配) │ │
│ │ run.py / session.py / platforms/ — telegram/discord/slack/... │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ plugins/ — 插件系统 │ │
│ │ kanban / memory / model-providers / observability / ... │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ skills/ — 内置技能(~30 个领域技能) │ │
│ │ github / cnblogs / jupyter-live-kernel / dogfood / ... │ │
│ └──────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
二、核心模块详解
2.1 AIAgent 核心循环(run_agent.py)
文件:~15,700 LOC,核心类 AIAgent
两个入口接口:
def chat(self, message: str) -> str:"""简单接口 — 返回最终响应字符串"""def run_conversation(self, user_message: str, system_message: str = None,conversation_history: list = None, task_id: str = None) -> dict:"""完整接口 — 返回 dict 含 final_response + messages"""
核心循环逻辑:
while (api_call_count < self.max_iterations and self.iteration_budget.remaining > 0) \or self._budget_grace_call:if self._interrupt_requested: breakresponse = 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 += 1else:return response.content
关键设计点:
- 完全同步的循环,含 interrupt 检查 + budget 跟踪
- OpenAI 格式消息:
{"role": "system/user/assistant/tool", ...} - reasoning 内容存在
assistant_msg["reasoning"] max_iterations=90(默认工具调用上限)- OpenAI SDK 延迟导入(避免 ~240ms 的 import 开销)
AIAgent.init 参数:
约 60 个参数,包含 base_url / api_key / provider / model / max_iterations / enabled_toolsets / disabled_toolsets / platform / session_id / credential_pool / iteration_budget / fallback_model 等。
2.2 工具编排层(model_tools.py)
文件:~865 LOC
公共 API:
get_tool_definitions(enabled_toolsets, disabled_toolsets, quiet_mode) -> list
handle_function_call(function_name, function_args, task_id, user_task) -> str
TOOL_TO_TOOLSET_MAP: dict # 批量运行时用
get_available_toolsets() -> dict
asyncio 事件循环复用设计:
# 问题:asyncio.run() 每次创建并关闭循环
# -> cached httpx/AsyncOpenAI 客户端在 GC 时报 "Event loop is closed"# 解决:持久化循环,主线程 + 每个 worker 线程各有一个
_tool_loop = None # 主 CLI 线程
_worker_thread_local.loop # delegate_task 线程池各用各的循环
这解决了长期运行的 CLI 或 gateway 进程中异步客户端的生命周期问题。
2.3 工具注册中心(tools/registry.py)
文件:~563 LOC,核心 ToolEntry 类
工具自注册机制:
每个工具文件在模块顶层调用 registry.register(),registry 通过 AST 扫描发现所有工具:
tools/registry.py (无任何导入依赖)^
tools/*.py (模块顶层调用 registry.register())^
model_tools.py (导入 registry + 所有工具模块)^
run_agent.py / cli.py / batch_runner.py / environments/
AST 自动发现:
def _module_registers_tools(module_path: Path) -> bool:tree = ast.parse(source)# 只检查模块顶层语句,函数内的 helper 调用不误判return any(is_registry_register_call(stmt) for stmt in tree.body)
ToolEntry 元数据结构:
class ToolEntry:__slots__ = ("name", "toolset", "schema", "handler", "check_fn","requires_env", "is_async", "description", "emoji","max_result_size_chars", "dynamic_schema_overrides",)
check_fn TTL 缓存(30s):
check_fn 检查外部状态(Docker daemon / Modal SDK / playwright 等),缓存 30s 避免频繁探测,同时确保环境变量切换后 1-2 轮内生效。
动态 schema override:
dynamic_schema_overrides 字段是零参 callable,在每次 get_definitions() 时调用,用于运行时动态修改 schema(如 delegate_task 的描述反映用户当前的 max_concurrent_children 配置)。
2.4 工具分组与别名(toolsets.py)
文件:~855 LOC
核心工具列表 _HERMES_CORE_TOOLS(所有平台共享):
_HERMES_CORE_TOOLS = [# Web"web_search", "web_extract",# Terminal + process management"terminal", "process",# File manipulation"read_file", "write_file", "patch", "search_files",# Vision + image generation"vision_analyze", "image_generate",# Skills"skills_list", "skill_view", "skill_manage",# Browser automation"browser_navigate", "browser_snapshot", "browser_click", ...# Delegation"execute_code", "delegate_task",# Kanban"kanban_show", "kanban_list", "kanban_complete", ...# Computer use (macOS)"computer_use",
]
工具集定义示例:
TOOLSETS = {"web": {...},"terminal": {...},"file": {...},"vision": {...},"skills": {...},"browser": {...},"full": union of all above,"minimal": web + terminal + file only,
}
2.5 会话存储(hermes_state.py)
文件:~2,966 LOC,SessionDB 类
核心设计:
- SQLite + WAL 模式(WAL = Write-Ahead Logging,并发读 + 单写)
- FTS5 虚拟表:全文本搜索跨所有会话消息
- 压缩触发会话分割:通过
parent_session_id链管理 - 会话来源标签:
'cli'/'telegram'/'discord'等
WAL 降级策略:
WAL 模式在网络文件系统(NFS / SMB / CIFS / WSL1)上不兼容,遇到 SQLITE_PROTOCOL 错误时自动降级到 journal_mode=DELETE,牺牲并发换可靠性。
Schema 版本: SCHEMA_VERSION = 11
2.6 CLI(cli.py)
文件:~13,540 LOC,HermesCLI 类
依赖:
- Rich — banner / panels 渲染
- prompt_toolkit — 带自动补全的交互式输入
核心机制:
KawaiiSpinner(agent/display.py)— API 调用时的动画表情 + 活动日志- Skin engine(
hermes_cli/skin_engine.py)— 数据驱动的 CLI 主题定制 - Slash 命令注册表(
hermes_cli/commands.py)— 单一COMMAND_REGISTRY,CLI / Gateway / Telegram / Slack / autocomplete 自动同步
Slash 命令注入方式:
agent/skill_commands.py 扫描 ~/.hermes/skills/,注入为 user message(而非 system prompt),保留 prompt 缓存效益。
2.7 网关(gateway/)
进程模型:
gateway/run.py — 网关主进程
gateway/session.py — 会话上下文
gateway/platforms/ — telegram / discord / slack / whatsapp / signal / matrix / ...
gateway/builtin_hooks/ — 扩展钩子
多平台适配器架构:
每个平台(telegram / discord 等)是一个 adapter,平台无关的逻辑在 run.py / session.py 中统一处理。
2.8 Agent 内部模块(agent/)
约 50+ 个文件,核心子模块:
| 模块 | 职责 |
|---|---|
anthropic_adapter.py / bedrock_adapter.py / gemini_native_adapter.py |
多模型提供方适配 |
prompt_builder.py |
系统提示词构建 |
context_compressor.py |
上下文压缩(处理超长会话) |
memory_manager.py |
记忆管理 |
skill_commands.py |
Skill 命令扫描和注入 |
skill_utils.py / skill_preprocessing.py |
Skill 工具函数 |
token_cost.py / usage_pricing.py |
Token 成本计算 |
rate_limit_tracker.py |
速率限制跟踪 |
retry_utils.py |
重试逻辑 |
trajectory.py |
轨迹记录 |
checkpoint_manager.py |
检查点管理 |
credential_pool.py |
凭据池管理 |
2.9 插件系统(plugins/)
| 插件 | 职责 |
|---|---|
kanban/ |
多 Agent 看板协调 |
memory/ |
记忆提供方插件(mem0 / supermemory / ...) |
model-providers/ |
推理后端插件(openrouter / anthropic / gmi / ...) |
observability/ |
指标 / 追踪 / 日志 |
image_gen/ |
图像生成提供方 |
spotify/ |
Spotify 集成 |
teams_pipeline/ |
Teams 会议摘要流水线 |
hermes-achievements/ |
游戏化成就追踪 |
disk-cleanup/ |
磁盘清理 |
2.10 技能系统(skills/)
Skills 是 Hermes Agent 的知识模块系统:
- 每个 Skill 有一个
SKILL.md定义接口和行为 - Skill 文件存储在
~/.hermes/skills/ - Skill 可以在 cronjob 中加载,跨会话持久运行
- 内置约 30 个技能,涵盖 github / cnblogs / jupyter / dogfood / autonomous-ai-agents 等
三、工具执行环境(tools/environments/)
| 环境 | 说明 |
|---|---|
local.py |
本地 shell 执行 |
ssh.py |
远程 SSH 执行 |
docker.py |
Docker 容器执行 |
modal.py |
Modal 云端执行 |
daytona.py |
Daytona 云端沙箱 |
managed_modal.py |
Modal 托管环境 |
singularity.py |
Singularity 容器 |
vercel_sandbox.py |
Vercel 沙箱 |
四、TUI 架构(ui-tui/ + tui_gateway/)
hermes --tui└─ Node (Ink React) ──stdio JSON-RPC── Python (tui_gateway)│ └─ AIAgent + tools + sessions└─ 渲染 transcript / composer / prompts / activity
TypeScript 掌控屏幕渲染,Python 掌控会话、工具和模型调用。
传输协议:newline-delimited JSON-RPC over stdio。
五、关键设计哲学
1. 自注册工具模式
工具不需要在中心配置文件声明——每个工具文件在模块顶层调用 registry.register(),registry 通过 AST 扫描自动发现。新增工具只需创建新文件,无需修改任何中心文件。
2. 零循环导入设计
tools/registry.py → 无从任何模块导入
tools/*.py → 只从 registry.py 导入
model_tools.py → 从 registry + toolsets 导入
run_agent.py → 从 model_tools 导入
禁止反向依赖,保证工具系统完全解耦。
3. 事件循环复用
asyncio 循环不在每次调用时创建和销毁,而是在主线程和每个 worker 线程中持久化,避免异步客户端在循环关闭后报错。
4. 单一命令注册表
所有 slash 命令在一个 COMMAND_REGISTRY 中定义,CLI / Gateway / Telegram / Slack / autocomplete 自动从同一数据源派生,无需多处修改。
5. Skill 作为知识模块
Skill 不是硬编码逻辑,而是声明式的 SKILL.md,可被 cronjob 加载、跨会话持久化,支持版本管理和动态更新。
六、关键文件速查
| 文件 | LOC | 职责 |
|---|---|---|
run_agent.py |
~15,700 | AIAgent 核心对话循环 |
cli.py |
~13,540 | HermesCLI 交互式终端 |
model_tools.py |
~865 | 工具编排层 |
tools/registry.py |
~563 | 工具注册中心(AST 发现) |
toolsets.py |
~855 | 工具分组与别名 |
hermes_state.py |
~2,966 | SQLite + FTS5 会话存储 |
hermes_constants.py |
— | get_hermes_home() 路径管理 |
gateway/run.py |
— | 消息网关主进程 |
gateway/session.py |
— | 会话上下文 |
gateway/platforms/ |
— | ~20+ 平台适配器 |
agent/ |
~50 文件 | Agent 内部模块 |
plugins/ |
— | 插件系统 |
tools/ |
~70 文件 | ~70 个工具实现 |
tools/environments/ |
— | 8 种终端执行环境 |
hermes_cli/ |
— | CLI 子命令、皮肤引擎、命令注册表 |
ui-tui/ |
— | Ink React TUI 前端 |
tui_gateway/ |
— | TUI JSON-RPC 后端 |
AGENTS.md |
— | 开发者指南 |
