Hermes Agent 核心架构分析(官网 Directory Structure + 架构图 + 源码心得)

Hermes Agent 核心架构分析

官网文档:https://hermes-agent.nousresearch.com/docs/developer-guide/architecture
源码路径:~/.hermes/hermes-agent/
分析版本:v0.13.0 (May 2026) + 官网架构文档 v0.13.0


一、整体架构

┌─────────────────────────────────────────────────────────────────────────┐
│                          入口层(Entry Points)                          │
│                                                                          │
│   CLI (cli.py)     Gateway (gateway/run.py)    ACP (acp_adapter/)       │
│   Batch Runner      API Server                  Python Library           │
└──────────┬─────────────────┬──────────────────────┬────────────────────┘
           │                 │                      │
           ▼                 ▼                      ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                    AIAgent (run_agent.py)                                │
│                    核心对话循环 ~15,700 LOC                              │
│                                                                          │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────────────┐ │
│  │ Prompt Builder  │  │ Provider 解析    │  │ Tool Dispatch           │ │
│  │ (agent/prompt_  │  │ (hermes_cli/    │  │ (model_tools.py)        │ │
│  │  builder.py)    │  │  runtime_       │  │                         │ │
│  │                 │  │  provider.py)   │  │                         │ │
│  └────────┬────────┘  └────────┬────────┘  └────────────┬────────────┘ │
│           │                    │                        │              │
│  ┌────────▼────────┐  ┌────────▼────────┐  ┌───────────▼────────────┐ │
│  │ 压缩 & 缓存     │  │ 3 种 API 模式   │  │ Tool Registry (registry)│ │
│  │ ContextEngine  │  │ chat_complet.   │  │ 70+ 工具               │ │
│  │ (ABC 可插拔)   │  │ codex_resp.     │  │ 28 toolsets            │ │
│  │                │  │ anthropic_      │  │                         │ │
│  └────────────────┘  │  messages       │  └─────────────────────────┘ │
│                      └─────────────────┘                                  │
└─────────────────────────────────────────────────────────────────────────┘
           │                                    │
           ▼                                    ▼
┌──────────────────────┐       ┌──────────────────────────────────────┐
| Session Storage      │       │ Tool Backends                         │
| (SQLite + FTS5)      │       │ Terminal (7 backends)                │
| hermes_state.py      │       │ Browser (5 backends)                 │
| gateway/session.py    │       │ Web (4 backends)                      │
└──────────────────────┘       │ MCP (动态发现)                         │
                               │ File, Vision, etc.                     │
                               └──────────────────────────────────────┘

官方原文架构图说明:
AIAgent 是核心编排引擎,负责:系统提示词组装、Provider/API 模式选择、可中断的模型调用、工具执行、对话历史维护、压缩/重试/降级、迭代预算跟踪、上下文丢失前的记忆持久化。


二、Directory Structure(源码文件树)

来源:官网 Directory Structure
说明:仅列出有注释说明的文件,__init__.py 及无描述的空文件已省略。

hermes-agent/                        # Python 包根目录
│
├── run_agent.py                    # AIAgent 核心对话循环(大文件)
├── cli.py                          # HermesCLI 交互式终端(大文件)
├── model_tools.py                  # 工具编排层
├── toolsets.py                     # 工具分组与别名
├── hermes_state.py                 # SQLite + FTS5 会话存储 ★
├── hermes_constants.py             # HERMES_HOME、profile 路径常量
├── hermes_bootstrap.py             # Windows UTF-8 stdio 修复(必须在最早期 import)
├── hermes_logging.py               # 日志基础设施
├── hermes_time.py                  # 时间工具
├── utils.py                        # 通用工具函数
│
├── agent/                          # Agent 内部模块 ★
│   ├── prompt_builder.py           # 系统提示词组装(8 层缓存)
│   ├── context_engine.py           # ContextEngine ABC(可插拔)
│   ├── context_compressor.py        # 默认有损摘要压缩引擎
│   ├── context_references.py        # 上下文引用
│   ├── prompt_caching.py            # Anthropic prompt caching
│   ├── anthropic_adapter.py         # Anthropic Messages API 格式转换
│   ├── bedrock_adapter.py           # AWS Bedrock 适配器
│   ├── codex_responses_adapter.py   # OpenAI Codex/Responses API 适配器
│   ├── auxiliary_client.py          # 辅助 LLM(视觉、摘要等)
│   ├── memory_manager.py            # 记忆管理编排
│   ├── memory_provider.py           # Memory Provider ABC
│   ├── display.py                   # KawaiiSpinner、工具预览格式化
│   ├── error_classifier.py          # 错误分类
│   ├── file_safety.py               # 文件安全检查
│   ├── model_metadata.py            # 模型上下文长度、token 估算
│   ├── models_dev.py               # models.dev 集成
│   ├── skill_commands.py            # Skill slash 命令扫描和注入
│   ├── skill_preprocessing.py       # Skill 预处理
│   ├── skill_utils.py               # Skill 工具函数
│   ├── title_generator.py            # 会话标题生成
│   ├── trajectory.py                # 轨迹保存助手
│   ├── tool_guardrails.py           # 工具护栏
│   ├── usage_pricing.py             # 用量计费
│   ├── account_usage.py             # 账户用量跟踪
│   ├── rate_limit_tracker.py        # 速率限制跟踪
│   ├── redact.py                    # 内容脱敏
│   ├── retry_utils.py               # 重试工具
│   ├── think_scrubber.py            # 去除 think 标签
│   ├── image_gen_provider.py        # 图像生成 Provider
│   ├── image_gen_registry.py        # 图像生成注册表
│   ├── image_routing.py             # 图像路由
│   ├── i18n.py                      # 国际化
│   ├── curator.py                   # Curator 相关
│   ├── copilot_acp_client.py        # GitHub Copilot ACP 客户端
│   ├── credential_pool.py           # 凭据池
│   ├── credential_sources.py        # 凭据来源
│   └── transports/                  # 传输层(3 种 API 模式的 HTTP 客户端)
│       ├── base.py                  # BaseTransport ABC
│       ├── chat_completions.py      # OpenAI chat.completions 传输
│       ├── anthropic.py             # Anthropic 传输
│       ├── codex.py                 # Codex 传输
│       ├── bedrock.py               # Bedrock 传输
│       └── types.py                 # 传输层类型定义
│
├── hermes_cli/                     # CLI 子命令和设置
│   ├── main.py                     # 所有 `hermes` 子命令入口(大文件)
│   ├── commands.py                 # 单一 COMMAND_REGISTRY(所有 slash 命令)
│   ├── config.py                   # DEFAULT_CONFIG、OPTIONAL_ENV_VARS、迁移
│   ├── auth.py                     # PROVIDER_REGISTRY、凭据解析
│   ├── models.py                   # 模型目录、provider 模型列表
│   ├── model_switch.py             # /model 命令逻辑(CLI + gateway 共享)
│   ├── setup.py                    # 交互式设置向导(大文件)
│   ├── skin_engine.py              # CLI 皮肤引擎
│   ├── skills_config.py            # hermes skills — 每个平台启用/禁用
│   ├── skills_hub.py               # /skills slash 命令
│   ├── tools_config.py             # hermes tools — 每个平台启用/禁用
│   ├── plugins.py                  # PluginManager — 发现、加载、钩子
│   ├── callbacks.py                # 终端回调(clarify、sudo、approval)
│   ├── gateway.py                  # hermes gateway 启动/停止
│   ├── cron.py                     # /cron 子命令
│   ├── kanban.py                   # Kanban 看板命令
│   ├── banner.py                   # Banner 显示
│   ├── checkpoints.py             # 检查点
│   ├── claw.py                     # Claw 命令
│   ├── cli_output.py               # CLI 输出
│   ├── clipboard.py               # 剪贴板
│   ├── colors.py                   # 颜色工具
│   ├── completion.py              # 自动补全
│   ├── curses_ui.py                # Curses UI
│   ├── debug.py                    # 调试命令
│   ├── doctor.py                   # 健康检查
│   ├── logs.py                     # 日志命令
│   ├── mcp_config.py               # MCP 配置
│   ├── memory_setup.py             # 记忆设置
│   ├── platforms.py                # 平台支持
│   ├── voice.py                    # 语音命令
│   └── webhook.py                  # Webhook 命令
│
├── tools/                          # 工具实现(每个工具一个文件)
│   ├── registry.py                 # 中心工具注册表
│   ├── approval.py                 # 危险命令检测
│   ├── terminal_tool.py            # 终端编排
│   ├── process_registry.py         # 后台进程管理
│   ├── file_tools.py               # read_file, write_file, patch, search_files
│   ├── web_tools.py                # web_search, web_extract
│   ├── browser_tool.py             # 10 个浏览器自动化工具
│   ├── code_execution_tool.py      # execute_code 沙箱
│   ├── delegate_tool.py            # 子 agent 委托
│   ├── mcp_tool.py                 # MCP 客户端(大文件)
│   └── environments/               # 终端后端
│       ├── local.py                # 本地 shell 执行
│       └── docker.py               # Docker 容器执行
│
├── gateway/                        # 消息平台网关
│   ├── run.py                      # GatewayRunner — 消息分发(大文件)
│   ├── session.py                  # SessionStore — 对话持久化
│   ├── delivery.py                 # 出站消息投递
│   ├── pairing.py                  # DM 配对授权
│   ├── hooks.py                    # 钩子发现和生命周期事件
│   ├── mirror.py                   # 跨会话消息镜像
│   └── status.py                   # Token 锁、profile 范围进程跟踪
│
├── acp_adapter/                     # ACP 服务端(VS Code / Zed / JetBrains)
├── cron/                           # 调度器(jobs.py, scheduler.py)
├── plugins/memory/                 # 记忆提供方插件
├── plugins/context_engine/          # 上下文引擎插件
├── skills/                         # 内置技能(始终可用)
├── optional-skills/                # 官方可选技能(需显式安装)
├── website/                        # Docusaurus 文档站
└── tests/                         # Pytest 测试套件(~3,000+ 测试)

三、核心循环(run_agent.py,~15,700 LOC)

3.1 两个入口接口

# 简单接口 — 返回最终响应字符串
response = agent.chat("Fix the bug in main.py")

# 完整接口 — 返回 dict 含 final_response + messages + metadata + usage
result = agent.run_conversation(
    user_message="Fix the bug in main.py",
    system_message=None,         # 自动构建,可选
    conversation_history=None,    # 自动从 session 加载,可选
    task_id="task_abc123"
)

3.2 三种 API 执行模式

API 模式 用途 客户端
chat_completions OpenAI 兼容端点(OpenRouter/自定义/大多数 Provider) openai.OpenAI
codex_responses OpenAI Codex / Responses API openai.OpenAI(Responses 格式)
anthropic_messages 原生 Anthropic Messages API anthropic.Anthropic(经 adapter)

模式解析优先级:

  1. 构造函数显式 api_mode 参数(最高)
  2. Provider 特定检测(如 anthropic provider → anthropic_messages
  3. Base URL 启发式(如 api.anthropic.comanthropic_messages
  4. 默认:chat_completions

三种模式在 API 调用前后都收敛到同一个内部消息格式(OpenAI 风格的 role/content/tool_calls 字典)。

3.3 循环生命周期(Turn Lifecycle)

每轮迭代遵循以下序列:

run_conversation()
  1. 生成 task_id(若未提供)
  2. 将用户消息追加到对话历史
  3. 构建或复用缓存的系统提示词(prompt_builder.py)
  4. 检查是否需要预压缩(上下文 >50%)
  5. 从对话历史构建 API 消息
       chat_completions  → OpenAI 格式直接使用
       codex_responses   → 转换为 Responses API input items
       anthropic_messages → 经 anthropic_adapter.py 转换
  6. 注入临时提示词层(预算警告、上下文压力)
  7. 若在 Anthropic 上应用 prompt caching 标记
  8. 执行可中断 API 调用(_interruptible_api_call)
  9. 解析响应:
       若有 tool_calls → 执行,追加结果,循环回步骤 5
       若为文本响应 → 持久化 session,必要时刷新记忆,返回

3.4 消息格式

所有消息在内部使用 OpenAI 兼容格式:

{"role": "system", "content": "..."}
{"role": "user", "content": "..."}
{"role": "assistant", "content": "...", "tool_calls": [...]}
{"role": "tool", "tool_call_id": "...", "content": "..."}

reasoning 内容存在 assistant_msg["reasoning"] 中。


四、工具系统(Tool System)

4.1 工具注册中心(tools/registry.py,~563 LOC)

核心:ToolEntry 元数据结构(__slots__ 优化内存):

class ToolEntry:
    __slots__ = (
        "name",              # 唯一工具名(API schema 中使用)
        "toolset",           # 所属工具集
        "schema",            # OpenAI function-calling schema
        "handler",           # 工具被调用时执行的函数
        "check_fn",          # 可选:返回工具是否可用的布尔值
        "requires_env",      # 可选:所需环境变量(用于 UI 显示)
        "is_async",          # handler 是否为 async 协程
        "description",       # 人类可读描述
        "emoji",             # spinner/进度显示的 emoji
        "max_result_size_chars",    # 结果最大字符数
        "dynamic_schema_overrides", # 运行时动态 schema 覆盖
    )

4.2 自注册机制

每个工具文件在模块顶层调用 registry.register(...)

registry.register(
    name="terminal",
    toolset="terminal",
    schema={...},
    handler=handle_terminal,
    check_fn=check_terminal,
    requires_env=["TERM"],
    is_async=False,
    description="Run commands",
    emoji="",
)

4.3 AST 自动发现(discover_builtin_tools)

model_tools.py 导入时调用 discover_builtin_tools(),通过 AST 解析扫描所有 tools/*.py 文件,找出含顶层 registry.register() 调用的模块并 import:

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)

4.4 check_fn TTL 缓存(30s)

check_fn 检查外部状态(Docker daemon / Modal SDK / playwright 等),缓存 30s 避免频繁探测,同时确保环境变量切换后 1-2 轮内生效。

4.5 动态 Schema Override

dynamic_schema_overrides 是零参 callable,在每次 get_definitions() 时调用,用于运行时动态修改 schema——例如 delegate_task 的描述反映用户当前的 max_concurrent_children 配置。

4.6 终端执行环境(tools/environments/)

环境 说明
local.py 本地 shell 执行
docker.py Docker 容器执行
ssh.py 远程 SSH 执行
modal.py Modal 云端执行
daytona.py Daytona 云端沙箱
managed_modal.py Modal 托管环境
singularity.py Singularity 容器
vercel_sandbox.py Vercel 沙箱

五、提示词系统(Prompt System)

5.1 核心设计原则

Hermes 刻意分离两类状态:

  • 缓存的系统提示词(Cached system prompt)— 会话期间不变
  • 临时的 API 调用时添加(Ephemeral additions)— 每轮动态变化

5.2 缓存系统提示词层次(组装顺序)

Layer 1: Agent Identity
  └── SOUL.md(~/.hermes/SOUL.md),若无可用则用 DEFAULT_AGENT_IDENTITY

Layer 2: Tool-aware behavior guidance
  └── 工具使用指导(GPT/Codex 模型专用)

Layer 3: Honcho static block(若激活)

Layer 4: Optional system message(来自配置或 API)

Layer 5: Frozen MEMORY snapshot
  └── 持久记忆的快照(~/.hermes/memories/MEMORY.md)

Layer 6: Frozen USER profile snapshot
  └── 用户配置文件快照(~/.hermes/memories/USER.md)

Layer 7: Skills index

Layer 8: Context files
  └── AGENTS.md、.cursorrules、.cursor/rules/*.mdc

Layer 9: Timestamp / session ID / platform hint

5.3 Context Compression(双重压缩系统)

              ┌─────────────────────────┐
  消息流入    │ Gateway Session Hygiene │  → 85% 上下文阈值(预压缩,粗估计)
              └────────────┬────────────┘
                           ▼
              ┌─────────────────────────┐
              │ Agent ContextCompressor │  → 50% 上下文阈值(环内,真实 token)
              └─────────────────────────┘

六、会话存储(hermes_state.py,~2,966 LOC)

6.1 数据库架构

~/.hermes/state.db (SQLite, WAL 模式)
├── sessions          — Session 元数据、token 计数、计费
├── messages          — 每个 session 的完整消息历史
├── messages_fts      — FTS5 虚拟表(content + tool_name + tool_calls)
├── messages_fts_trigram — FTS5 trigram 分词器(CJK/子串搜索)
├── state_meta        — 键/值元数据表
└── schema_version    — 单行表,跟踪迁移状态

6.2 WAL 降级策略

WAL 模式在网络文件系统(NFS / SMB / CIFS / WSL1)上不兼容,遇到 SQLITE_PROTOCOL 错误时自动降级到 journal_mode=DELETE,牺牲并发换可靠性。


七、消息网关(Gateway Internals)

7.1 支持平台(20 个 Adapter)

telegram / discord / slack / whatsapp / signal / matrix / mattermost / email / sms / dingtalk / feishu / wecom / wecom_callback / weixin / bluebubbles / qqbot / homeassistant / webhook / api_server / yuanbao

7.2 Session Key 格式

agent:main:{platform}:{chat_type}:{chat_id}

八、设计原则(Design Principles)

原则 实践含义
Prompt stability 系统提示词在会话期间不改变。除非用户显式操作(如 /model),否则没有缓存破坏性变更。
Observable execution 每个工具调用都通过回调对用户可见。CLI 有 spinner 进度更新,gateway 有聊天消息进度。
Interruptible API 调用和工具执行可被用户输入或信号中途取消。
Platform-agnostic core 一个 AIAgent 类服务 CLI、gateway、ACP、batch 和 API server。平台差异在入口点,而非 agent 本身。
Loose coupling 可选子系统(MCP、插件、memory providers、RL 环境)使用注册表模式和 check_fn 门控,无硬依赖。
Profile isolation 每个 profile(hermes -p <name>)有自己的 HERMES_HOME、config、memory、sessions 和 gateway PID,多个 profile 可并发运行。

九、源码阅读心得

9.1 零循环依赖的自注册架构

tools/registry.py 处于依赖链的最底层——它不从任何其他模块导入。而每个工具文件(tools/*.py)只在模块顶层调用一次 registry.register(),然后由 model_tools.py 通过 AST 扫描发现并 import。

这条单向依赖链保证了:

  • 新增工具只需在 tools/ 下创建新文件,无需修改任何注册表列表
  • registry.py 的测试不需要 mock 任何其他模块
  • 工具模块之间无隐式耦合

9.2 Lazy Import 优化启动时间

run_agent.py 顶部用 _OpenAIProxy 代理类延迟了 openai.OpenAI 的导入,注释解释这能节省约 240ms 的 import 时间。这在 fire 刚安装完首次运行时特别有意义——避免 import run_agent 卡顿。

class _OpenAIProxy:
    def __call__(self, *args, **kwargs):
        return _load_openai_cls()(*args, **kwargs)

9.3 __slots__ 广泛使用

ToolEntry 使用 __slots__ 而非 __dict__ 存储属性,大幅减少每个工具元对象的内存占用(70+ 工具实例累积下来很可观)。代码库中其他频繁实例化的类也采用了类似做法。

9.4 Profile 隔离

每个 profile(hermes -p <name>)有独立的 HERMES_HOME 目录树,包括 config、memory、sessions、gateway PID。这通过 hermes_constants.py 中的 get_hermes_home() 实现,profile 名作为 subdirectory 嵌入路径。设计意图类似 Linux 多用户隔离,但靠目录实现而非命名空间。

9.5 Profile 开关对环境的影响

Profile 隔离下,不同 profile 的 gateway 可以并发运行,各自服务不同的消息平台。这对需要同时接入 Telegram(个人用)和 Discord(工作群)的场景很有价值。但这也意味着 token 计数、计费、memory 等都是 profile 独立的,不能跨 profile 共享。

9.6 TUI 的前后端分离

TypeScript Ink React 掌控渲染,Python 掌控逻辑,通过 newline-delimited JSON-RPC over stdio 通信。好处是前端可以用 React 生态,后端保持 Python 的工具链。但 stdin/stdout 作为传输协议意味着 TUI 不能通过 SSH 远程运行(需要 PTY 绑定本地终端)。

9.7 传输层的三套适配器

agent/transports/ 目录下对三种 API 模式分别有独立的传输实现。这比把所有逻辑塞进 run_agent.py 更清晰,但也意味着如果新增一个 Provider 需要修改多个传输文件。

9.8 平台适配器的统一抽象

BasePlatform ABC 定义了所有 20 个平台适配器的共同接口。但实际看 platforms/ 目录,很多平台有自己独特的字段和逻辑(如微信的加密、企微的回调)。这说明"统一抽象"是有代价的——adapter 层本身复杂度不低。

9.9 测试覆盖策略

代码库有 ~3,000+ 测试,大量使用 monkeypatch 和 patch()test_tools/ 下的测试尤其多——每个工具一个或多个测试文件。这种广覆盖策略保证了工具系统的稳定性,但也意味着重构工具时需要同步更新大量测试。


十、关键文件速查

文件 LOC 职责
run_agent.py ~15,700 AIAgent 核心对话循环、三种 API 模式
cli.py ~13,540 HermesCLI 交互式终端
model_tools.py ~865 工具编排层、asyncio 循环复用
tools/registry.py ~563 工具注册中心(AST 发现)
hermes_state.py ~2,966 SQLite + FTS5 会话存储
agent/prompt_builder.py 系统提示词组装(8 层缓存)
agent/context_compressor.py 默认有损摘要压缩引擎
agent/transports/ 3 种 API 模式的 HTTP 客户端
hermes_cli/commands.py 单一 COMMAND_REGISTRY(所有 slash 命令)
gateway/run.py GatewayRunner — 消息网关主循环
gateway/platforms/ ~20 个平台适配器
tools/environments/ 8 种终端执行环境
posted @ 2026-05-13 17:12  getmoon  阅读(153)  评论(0)    收藏  举报