Hermes Agent 和 OpenClaw 很容易被放在同一个篮子里讲:都能聊天、都能调工具、都能接入消息平台、都支持长期运行。但源码读下来,它们的重心其实不一样。

OpenClaw 更像一套“平台控制面”:Gateway、Channel、Node、Plugin、Agent Harness 都围绕统一控制面展开。Hermes Agent 更像一套“自我学习型执行内核”:核心是一个厚实的 Python Agent Loop,再把记忆、技能、工具、Gateway、Cron、执行环境和研究训练路径都接到这个 Loop 周围。

这篇基于 NousResearch/hermes-agent 源码分析,基线提交为 a7cdd413,提交时间是 2026-04-27T20:41:36-07:00。对照部分结合 OpenClaw 本地源码快照 4792a50 的 Agent Harness 设计。

01 总览:Hermes 的中心不是 Gateway,而是 Agent Loop

Hermes Agent 整体架构

图 1:Hermes Agent 的整体结构。CLI、Gateway、Cron、批处理和 RL 环境最终都会把任务送进同一个 Python Agent Loop。

从目录结构看,Hermes 的模块分层非常直接:

模块主要职责关键源码
CLI / TUI命令入口、模型选择、配置、登录、更新、交互界面启动hermes_cli/main.pycli.py
Agent Core会话循环、模型调用、工具调度、上下文压缩、费用统计、失败恢复run_agent.py
Tool Registry工具发现、工具 schema 过滤、工具执行、MCP/插件工具接入model_tools.pytools/registry.py
Memory / Skills文件记忆、外部记忆插件、会话搜索、技能加载与技能自改进agent/memory_manager.pytools/memory_tool.pyagent/skill_commands.py
GatewayTelegram、Discord、Slack、WhatsApp、Signal、Email 等消息入口gateway/run.pygateway/session.py
Execution Backendslocal、Docker、SSH、Modal、Daytona、Singularity 等终端环境tools/terminal_tool.pytools/environments/
Research / RL批量轨迹生成、Atropos 环境、工具调用 parser、训练数据压缩environments/batch_runner.py

Hermes 的核心判断可以概括成一句话:

Hermes Agent 是一个以 AIAgent 为中心的长期运行 Agent 系统,Gateway 和 TUI 是入口,memory/skills/session_search/context compressor 是学习闭环,tools/environments 是行动层。

这和 OpenClaw 有明显差异。OpenClaw 的文章里我已经讲过,OpenClaw 的重心在 Gateway 控制面和嵌入式 Runtime 编排。Hermes 则把复杂度堆在 run_agent.py 这个厚执行核里,再用 Python 模块把工具、记忆和平台接进来。

02 启动路径:CLI 很厚,但真正运行会落到 AIAgent

Hermes 的用户入口看起来很多:

  • hermes:启动终端 TUI。
  • hermes model:选择 provider 和 model。
  • hermes gateway:启动消息平台网关。
  • hermes setup:跑配置向导。
  • hermes claw migrate:从 OpenClaw 迁移。
  • batch_runner.py / environments/:研究和训练场景。

但这些入口最后基本都绕不开 AIAgent

hermes_cli/main.py 是一个非常大的命令分发文件,负责模型配置、认证、TUI 构建、Gateway 启动、更新、日志、备份、profile、completion 等命令。它更像“产品壳层”,不是推理内核。

真正的 Agent 执行在 run_agent.pyAIAgent 类里。这个类的构造参数非常长,原因不是设计失控,而是它要同时服务 CLI、Gateway、Cron、subagent、ACP、batch eval 等多种场景:

  • provider / api_mode / model 决定模型传输层。
  • enabled_toolsets / disabled_toolsets 决定工具面。
  • platform / user_id / chat_id 决定消息平台上下文。
  • session_id / session_db 决定会话持久化。
  • skip_memory / skip_context_files 决定是否加载长期上下文。
  • iteration_budget / parent_session_id 决定多 Agent 协作边界。
  • 各种 callback 把 streaming、tool progress、clarify、status 回传给 CLI 或 Gateway。

这说明 Hermes 没有把“交互界面”和“Agent 内核”分成两个完全独立产品,而是用一个 AIAgent 承载所有入口的实际执行。

03 Agent Loop:它不是一次请求,而是带预算和恢复逻辑的执行机器

Hermes Agent Loop

图 2:Hermes 的一轮 Agent Loop。每一轮都会经过 prompt 构建、模型调用、工具解析、工具执行、上下文预算和持久化。

Hermes 的 Agent Loop 主要在 run_agent.py 中展开。代码量很大,但核心结构是稳定的:

  1. 初始化系统提示词、memory snapshot、context files、skills、platform hints。
  2. 组装当前 messages。
  3. 调模型接口。
  4. 解析模型返回的 tool_calls 或 raw <tool_call>
  5. 执行工具。
  6. 把工具结果写回 messages。
  7. 更新 token、费用、上下文压缩状态和 session DB。
  8. 如果模型还要继续调工具,进入下一轮。
  9. 如果模型返回最终文本,持久化并退出。

这个循环里最值得注意的不是“会调工具”,而是周边的防御逻辑非常多:

  • IterationBudget 限制最大迭代次数,父 Agent 和子 Agent 可以共享或独立预算。
  • _should_parallelize_tool_batch() 判断哪些工具可以并发执行。
  • _repair_tool_call_arguments() 尝试修复模型生成的损坏 JSON 参数。
  • length 截断有 continuation retry。
  • 对“思考耗尽输出 token”有专门提示。
  • ContextCompressor 在接近上下文窗口时压缩中间消息。
  • StreamingContextScrubber 防止 memory context 片段通过 streaming 泄漏到用户侧。
  • session token 和费用会写入 DB,供 /usage/insights 查询。

Hermes 的执行循环更像一个“容错执行器”,不是简单的 while loop。它的目标不是跑通 demo,而是长期会话里尽可能不因为模型输出异常、工具输出过长、网络失败、上下文爆炸、pipe 断开或平台中断而崩掉。

04 模型层:Hermes 把 provider 差异吸收到 transport 和 adapter

Hermes 支持的模型入口非常多:OpenAI、OpenRouter、Nous Portal、Anthropic、Bedrock、Gemini、Copilot ACP、Kimi、Moonshot、xAI、custom endpoint 等。

源码里没有把所有 provider 分支都写成一堆散落的 if,而是逐步抽象出 transport:

AIAgent.__init__() 会根据 provider、base_url、model、api_mode 自动判断使用哪条 API 路径:

  • chat_completions
  • codex_responses
  • anthropic_messages
  • bedrock_converse

这层判断非常工程化。例如 GPT-5/Codex 风格模型通常走 Responses API,但 Azure OpenAI 又是例外;Anthropic 原生和第三方兼容 Anthropic endpoint 又要走不同 adapter;Bedrock 则绕过 OpenAI client,直接走 AWS Converse API。

这套设计的核心不是“支持很多模型”,而是:把模型 API 差异压进 transport 层,让 Agent Loop 继续围绕统一的 message/tool/result 语义工作。

05 工具系统:registry 是核心,toolset 是可治理边界

Hermes Tool Registry

图 3:Hermes 的工具注册和过滤链路。工具模块自注册,model_tools 负责发现、过滤、schema 动态改写和执行分发。

Hermes 的工具系统由两个文件托底:

工具不是集中写在一个大列表里,而是每个 tools/*.py 模块在 import 时调用 registry.register() 自注册。discover_builtin_tools() 会扫描工具文件 AST,只导入顶层存在 registry.register(...) 的模块,避免把无关 helper 全部拉进来。

get_tool_definitions() 做的事情很多:

  • 根据 enabled_toolsets / disabled_toolsets 解析有效工具。
  • 运行工具可用性检查,例如依赖、环境变量、平台状态。
  • 动态重写 execute_code schema,只暴露当前真实可用的 sandbox tools。
  • 动态重写 Discord 工具 schema,隐藏 bot 权限不支持的动作。
  • web_search / web_extract 不可用时,去掉 browser tool 描述里的交叉引用,降低模型幻觉调用不存在工具的概率。
  • 通过 schema_sanitizer 清理不同后端不兼容的 JSON schema 形状。

这说明 Hermes 的工具系统不只是“给模型一组 function schema”。它在做一件更重要的事:让模型看到的工具说明尽量贴近当前 session 的真实能力。

工具执行时,model_tools.handle_function_call() 最终会走 registry dispatch。同步/异步桥接也做了专门处理:主线程有持久 event loop,worker 线程有 thread-local loop,避免 asyncio.run() 反复创建和关闭 event loop 导致缓存客户端出错。

这类细节看起来不醒目,但这是长期运行 Agent 的真实工程成本。

06 记忆系统:Hermes 的“自我学习循环”由四部分组成

Hermes Memory Loop

图 4:Hermes 的记忆闭环。短期 context、文件记忆、会话搜索、外部 memory provider 和技能系统共同构成学习循环。

Hermes README 里强调它有 built-in learning loop。源码里这个 loop 不是一个单点功能,而是由四类机制拼出来的。

第一类是文件记忆。tools/memory_tool.py 管理两个文件:

  • MEMORY.md:环境事实、项目约定、工具经验、长期可复用观察。
  • USER.md:用户偏好、沟通风格、稳定习惯。

它的设计很克制:使用 § 作为 entry delimiter,有字符上限,写入前扫描 prompt injection 和 exfiltration 模式,读写时加文件锁。最关键的是 frozen snapshot:session 开始时把记忆注入系统提示词,session 中途写入会落盘,但不会立刻改变当前系统提示词。这样可以稳定 prompt cache,也避免当前轮被刚写入的记忆反复扰动。

第二类是 memory provider。agent/memory_manager.py 把内置记忆和外部 provider 统一成 MemoryProvider 接口。内置 provider 永远存在,外部 provider 同时只允许一个,避免工具 schema 膨胀和后端冲突。

外部 provider 位于 plugins/memory/,包括 Honcho、Hindsight、Mem0、ByteRover、OpenViking、Supermemory、RetainDB、Holographic 等。每个 provider 可以实现:

  • prefetch():每轮前召回相关上下文。
  • sync_turn():每轮后同步对话。
  • get_tool_schemas():向模型暴露专属 memory 工具。
  • on_pre_compress():上下文压缩前抽取重要信息。
  • on_delegation():观察子 Agent 的结果。

第三类是 session search。tools/session_search_tool.py 不直接把历史聊天全塞给模型,而是先用 SQLite FTS5 搜索历史消息,再按 session 聚合,截取匹配附近的上下文,最后用辅助模型做摘要。这是长期记忆里很实用的一层:文件记忆存“稳定事实”,session search 找“过去发生过什么”。

第四类是技能系统。Hermes 的技能不是记忆文件,而是可复用工作流。agent/prompt_builder.py 里的 SKILLS_GUIDANCE 会鼓励模型在复杂任务后保存技能;agent/skill_commands.py 负责把 SKILL.md 变成 slash command;agent/skill_preprocessing.py 支持 ${HERMES_SKILL_DIR}${HERMES_SESSION_ID} 模板变量和可选 inline shell 展开。

所以 Hermes 的“学习”不是神秘能力,而是几条明确的数据通路:

  • 稳定事实进 memory。
  • 历史过程进 session DB,再由 session_search 召回。
  • 可复用流程进 skill。
  • 长上下文过程由 compressor 保留摘要。
  • 外部 memory provider 可替换长期用户模型。

07 Context Engine:压缩不是删历史,而是做安全交接

Hermes Context Compression

图 5:Hermes 默认 ContextCompressor 的压缩策略。它保护头部和尾部,中间区域经过工具输出裁剪和辅助模型摘要。

agent/context_engine.py 定义了可插拔的 ContextEngine 抽象。默认实现是 agent/context_compressor.py

它的压缩流程大致是:

  1. 根据模型上下文长度和阈值判断是否需要压缩。
  2. 先裁剪旧工具结果,保留一行结构化摘要。
  3. 保护系统提示词和会话开头。
  4. 保护最近尾部消息,确保当前任务连续性。
  5. 对中间消息用辅助模型生成结构化摘要。
  6. 如果已经压缩过,再做 iterative summary update。
  7. 把摘要作为“参考信息”插入,而不是当成新的用户指令。

源码里 SUMMARY_PREFIX 的措辞很关键:它明确说明压缩摘要是旧上下文的 handoff,不是当前指令,也不要回答摘要里出现的问题。这解决了一个常见问题:压缩摘要如果写得像任务列表,模型会误以为那些旧任务仍然要执行。

Hermes 还在压缩前做了很多具体处理:

  • 多模态内容按图片 token 估算加入预算。
  • tool call arguments 用 JSON parse 后裁剪,避免把 JSON 字符串截坏。
  • 对 terminal、read_file、search_files、browser、web_search 等工具结果生成有信息量的一行摘要。
  • 对摘要失败设置 cooldown,避免每轮都重复失败。

这不是“上下文不够就总结一下”的简单实现,而是把压缩当成会话连续性工程来做。

08 Gateway:多平台入口,但不抢 Agent Core 的位置

Hermes Gateway

图 6:Hermes Gateway。各平台 adapter 把消息规范化为 session event,再交给 GatewayRunner 调用 AIAgent。

Hermes 也有 Gateway,但它和 OpenClaw 的 Gateway 气质不同。

gateway/run.pyGatewayRunner 负责平台 adapter、session、delivery、interrupt、slash command、media placeholder、cron ticker 等。gateway/session.py 负责 session key、sender/chat hash、session context prompt、session store、shared multi-user session 等。

Gateway 的核心价值是把多个消息平台变成统一 Agent 输入:

  • Telegram、Discord、Slack、WhatsApp、Signal、Email、WeCom、Feishu、Matrix、Mattermost 等平台各自有 adapter。
  • 平台消息会被转换成统一 session event。
  • 每个平台会注入不同 platform hints,例如 markdown 支持、媒体发送格式、群聊身份等。
  • /stop/new/reset/model/skills 等命令在 messaging 场景复用 CLI 语义。
  • gateway session 可以有自己的 platformuser_idchat_idthread_id,这些会传给 AIAgent

OpenClaw 的 Gateway 更像系统控制面;Hermes 的 Gateway 更像多平台适配层。它很重要,但它不拥有 Agent Runtime 的底层协议。底层执行仍然是 AIAgent

这也解释了两者架构差异:OpenClaw 把平台一致性放在 Gateway;Hermes 把执行一致性放在 Agent Loop。

09 执行环境:Hermes 把 terminal 当成可替换后端

Hermes 的 terminal tool 不只是 subprocess.run() 包一层。tools/terminal_tool.py 把执行后端抽象成多种环境:

  • local:直接在本机执行。
  • docker:容器隔离。
  • ssh:远程机器。
  • modal:云端 sandbox。
  • daytona:持久云开发环境。
  • singularity:HPC/集群常用容器。

这和 Hermes 的定位有关。它不是只在本地电脑上做代码助手,而是可以跑在 VPS、云环境、GPU 集群、serverless sandbox 上。terminal backend 的职责不仅是运行命令,还包括:

  • foreground/background 任务。
  • sudo 和危险命令审批。
  • workdir 安全校验。
  • interrupt 传播。
  • container/VM 生命周期。
  • persistent filesystem 与 idle cleanup。

这层能力和 Gateway 结合之后,Hermes 就变成了“你从 Telegram 发消息,它在云 VM 上跑任务”的长期 worker。

10 Subagent:Hermes 用 delegate_task 做上下文隔离和并行

tools/delegate_tool.py 是 Hermes 的子 Agent 实现。它的设计很清楚:

  • 子 Agent 是新的 AIAgent 实例。
  • 子 Agent 不继承父会话历史。
  • 每个子 Agent 有自己的 task_id 和 terminal session。
  • 子 Agent 默认不能再调用 delegate_task,防止递归失控。
  • 子 Agent 默认不能写 memory,避免污染共享长期记忆。
  • 子 Agent 默认不能 clarifysend_message,避免绕过父 Agent 与用户交互。
  • 父 Agent 只看到子 Agent 的最终摘要,不吃下子 Agent 的中间工具轨迹。

这其实是一种很务实的多 Agent 协作:不追求复杂自治社会,而是把子 Agent 当成隔离工作线程。它可以并行处理任务,但上下文成本和副作用被控制在边界内。

这点和 OpenClaw 的多 Agent/Swarm 或 Agent Harness 不是同一层概念。Hermes 的 subagent 是“同一执行内核下的新实例”;OpenClaw 的 harness 是“同一平台 runtime 下可替换底层执行器”。

11 结合 Agent Harness:Hermes 和 OpenClaw 的关键差异

Hermes vs OpenClaw Agent Harness

图 7:Hermes 与 OpenClaw Agent Harness 的对照。Hermes 把复杂度放在一个厚 Agent Loop;OpenClaw 把底层执行器抽象成可选择的 harness。

OpenClaw 的 docs/plugins/sdk-agent-harness.md 对 Agent Harness 的定义很明确:harness 是“一个 prepared OpenClaw agent turn 的底层 executor”,不是 provider、channel、tool registry。

源码上对应三个核心文件:

它的选择策略也很关键:

  1. 已有 session 记录的 harness id 优先,避免同一个 transcript 中途切换底层 runtime。
  2. OPENCLAW_AGENT_RUNTIME=<id> 可以强制选择某个 harness。
  3. auto 模式下注册 harness 自己判断是否支持 provider/model。
  4. 没有插件 harness 匹配时,默认 fallback 到 PI。
  5. 如果某个插件 harness 已经 claim 了本轮执行,失败后不会自动重放到 PI,避免重复副作用和语义变化。

这套设计适合 OpenClaw,因为 OpenClaw 要把 Codex app-server、PI、未来其他原生 agent runtime 都挂在同一个平台控制面下面。它需要“同一个 OpenClaw session 可以由不同底层执行器承载”的抽象。

Hermes 当前不是这个结构。Hermes 的 AIAgent 自己就是执行器,provider 差异由 transport/adapter 处理,执行环境差异由 tool backend 处理,消息平台差异由 Gateway adapter 处理。它没有把“底层 agent turn executor”抽象成可替换 harness。

两者取舍如下:

维度Hermes AgentOpenClaw Agent Harness
执行核心单个厚 AIAgent loop平台准备 turn,再选底层 harness
provider 差异transport/adapter 吸收provider 解析后由 harness 可选择性 claim
session 连续性Hermes session DB + messages + context compressorOpenClaw session pin harness id,防止 runtime 热切换
插件扩展点tools、memory provider、context engine、CLI/pluginprovider、tool、channel、agent harness、Codex extension
Codex 类原生 runtime走 provider/API adapter 语义可由 codex harness 接管 native thread/compaction/app-server
架构重心自我学习执行核平台控制面 + 可替换执行器

如果把 OpenClaw 的 Agent Harness 思路移植到 Hermes,合理的切入点不是替换 tool registry,也不是替换 Gateway,而是在 AIAgent.run_conversation() 外层定义一个类似 AgentTurnExecutor 的边界:

  • Hermes Core 继续负责 config、memory、skills、tools、platform hints、session DB。
  • 默认 executor 调用当前 AIAgent loop。
  • Codex/ACP/特殊 native agent 可以注册 executor。
  • executor claim 后负责底层 thread/resume/compact。
  • session 记录 executor id,避免中途切换。

但这会带来明显代价:Hermes 现在的优势正是一个 Python 执行核能看到所有工具、记忆、压缩和回调状态。拆成 harness 后,边界会更清晰,但集成成本和状态同步复杂度会上升。

12 研究训练路径:Hermes 不只是产品 Agent,也在服务数据生成

Hermes 还有一条很重要但容易被忽略的线:研究和训练。

environments/agent_loop.py 实现了可复用的 HermesAgentLoop,用于标准 OpenAI 工具调用格式。它服务于 Atropos/RL 环境,支持:

  • server 抽象调用 chat_completion()
  • tool schemas 和 valid tool names。
  • raw <tool_call> fallback parser。
  • 每轮 reasoning 抽取。
  • tool error 记录。
  • 大并发 eval 的 thread pool。

environments/tool_call_parsers/ 里有很多模型格式 parser,例如 Hermes、DeepSeek、GLM、Kimi、Llama、Mistral、Qwen 等。这说明 Hermes 不只是消费工具调用模型,也在为“训练能稳定调工具的模型”准备环境。

batch_runner.pymini_swe_runner.pyscripts/sample_and_compress.py 这些文件进一步说明它有数据生产和评测用途。产品 Agent 和训练环境共享一部分工具调用语义,这是 Hermes 与普通 CLI Agent 的另一个区别。

13 总结:Hermes 是一套长期运行的学习型 Agent 内核

读完 Hermes 源码后,我觉得它最值得关注的不是“支持很多模型”或“支持很多聊天平台”,而是它把长期运行 Agent 的几个难点放在同一个系统里解决:

  • 模型 API 差异:用 transport/adapter 吸收。
  • 工具能力膨胀:用 registry + toolset + dynamic schema 控制。
  • 长期记忆:用文件记忆、session search、memory provider 拆分职责。
  • 可复用经验:用 skills 从任务中沉淀流程。
  • 上下文爆炸:用 ContextEngine 和压缩摘要做安全交接。
  • 多入口:用 CLI/TUI/Gateway/Cron 共享同一个 Agent Core。
  • 多环境:用 terminal backend 支持本机、容器、远程和云 sandbox。
  • 多任务:用 delegate_task 隔离子 Agent。
  • 研究训练:用 environments 和 parser 把工具调用轨迹变成可评测数据。

和 OpenClaw 放在一起看,Hermes 的路线更像“厚内核 + 多入口”,OpenClaw 的路线更像“强控制面 + 可替换执行器”。Agent Harness 是 OpenClaw 的关键抽象,因为它要把 Codex、PI 或其他 native runtime 接进同一个平台;Hermes 暂时不需要同样的 harness 层,因为它的执行一致性已经集中在 AIAgent 里。

如果未来 Hermes 要进一步接入 Codex app-server、Claude Code、OpenClaw PI 这类带原生 session/compact/thread 语义的 runtime,Agent Harness 会是一个自然演进方向。但在当前源码里,Hermes 的核心竞争力仍然是:一个能长期记忆、能自我沉淀技能、能跨平台运行、能持续调工具的 Python Agent Loop。

参考源码