拆开看看:Hermes Agent 的整体架构
会成长的AI:Hermes Agent 底层精讲 · 第二篇
上一篇讲完了 Hermes Agent 是什么、和 OpenClaw 有什么不同、“grows with you”背后的三套机制。读完那篇,我收到的反馈里有一句话很典型:“听起来挺复杂的,它到底是怎么把这些东西组织在一起的?”
这篇就来回答这个问题。
我研究一个新项目时,有个习惯:先不急着读代码,而是先搞清楚它的整体架构——谁负责什么、各个模块之间是怎么协作的、数据流经哪些地方。这就像拿到一套新房子之前,先看平面图,知道每个房间在哪里,再进去看细节才不会晕头转向。
Hermes 的代码量相当大,光 run_agent.py 一个文件就超过 1.5 万行。如果一上来就扎进代码细节,很容易失去方向感。所以这篇文章的任务只有一件事:把架构的全局地图画出来,让你知道这座“建筑”的平面图是什么样的,每个区域负责什么,房间和房间之间是怎么连通的。
用“城市”来理解架构
我喜欢用城市来类比 Hermes 的架构,因为它的各模块分工非常清晰:
市政中心(run_agent.py)——整个城市的运转核心。所有重要决策都在这里发生,是代码量最大、逻辑最集中的地方。无论消息从哪个渠道进来,最终都要经过这里处理。
城市入口(CLI / Gateway / ACP)——人和信息进入这座城市的三扇大门。命令行用户从 CLI 进来,手机用户从 Gateway 进来,在编辑器里工作的用户从 ACP 进来。三扇门,样式不同,走进来之后都到同一个地方。
工具仓库(tools/)——城市里所有“能干活”的设备都存在这里。执行代码、操作文件、搜索网页、控制浏览器,70 多个工具分门别类放在这个目录里。
记忆档案馆(hermes_state.py + agent/memory_manager.py)——城市的历史档案室。所有跨会话的对话记录,存在本地 SQLite 数据库里;你的个人偏好和工作背景,以记忆文件的形式保存在 ~/.hermes/memories/ 下。
技能培训学院(skills/)——AI 学会的那些“怎么做事”的方法,以 Markdown 文档的形式存放在这里。每次它自动创建一份新技能,就是在这里新增了一个文件。
通讯枢纽(gateway/)——连接外部 20 多个平台的核心模块。Telegram、Discord、微信、钉钉……每个平台的消息格式都不一样,Gateway 负责把它们全部翻译成 Hermes 内部统一的格式,处理完之后再翻译回去发出去。
工程图纸室(agent/prompt_builder.py)——每次 AI 开口之前,都要先在这里准备一份“任务说明书”(System Prompt),把记忆快照、技能目录、工具列表、身份设定等信息按照既定顺序拼装好,再送给模型。
把这几个区域的关系画出来,大致是这样:
外部入口层
┌────────────┬──────────────┬────────────┐
│命令行CLI│消息网关│编辑器ACP│
└─────┬──────┴──────┬───────┴─────┬─────┘
│││
└─────────────┼─────────────┘
▼
┌───────────────────────────────────────┐
│AIAgent(核心大脑)│
│┌─────────┐┌──────────┐┌──────┐│
││Prompt││ 模型调用││ 工具 ││
││组装器││ 与供应商││ 调度 ││
│└─────────┘└──────────┘└──────┘│
└────────────┬──────────────────┬───────┘
││
┌─────────┴──────┐┌────────┴────────┐
│会话数据库││工具后端层│
│SQLite + FTS5││ 终端/浏览器/网络 │
└────────────────┘└─────────────────┘
这张图里最重要的是中间那个框:AIAgent。它是整个系统的大脑,所有从外部进来的请求,无论走哪个入口,最终都汇聚到这里来处理。
三扇大门,一个大脑
Hermes 对外有三个入口,背后对应三种不同的使用场景。
命令行 CLI 是最直接的一扇门。你在终端里打字对话,cli.py 负责接收输入、显示输出、处理进度动画和交互反馈,然后把你的消息送进 AIAgent。这是技术用户和重度用户最常用的方式,也是权限最完整的入口——所有工具默认都可以用。
消息网关 Gateway 是让 Hermes “住进手机”的关键机制。它作为后台服务持续运行,同时连接你配置的多个平台。当你在 Telegram 发来一条消息,当你在微信里发来一条消息,Gateway 分别接收到、解析、验证权限,然后为这条消息创建一个 AIAgent 实例来处理,最后把回复通过原来的平台发回给你。整个过程对你来说是透明的——你感受到的只是“和 AI 在聊天”。
ACP 适配器是给代码编辑器准备的接口。它让 Hermes 可以作为编辑器里的原生 AI 助手运行,支持 VS Code、Zed 和 JetBrains 系列。对于习惯在 IDE 里长时间工作的开发者,这个入口的体验更自然,不需要切换到终端窗口。
三扇门,接口不同,进来之后走的是同一套逻辑。这个设计有一个很实用的好处:不同入口可以套用不同的工具集权限。CLI 入口默认打开所有工具,包括执行任意终端命令;Gateway 入口可以按平台配置更保守的权限,防止有人通过 Telegram 误触高风险操作。智能是统一的,安全边界是可以按场景配置的。
AIAgent 内部的三个工作站
AIAgent 是整个项目里最复杂的部分,内部有三个分工清晰的工作站,每次会话都要经过这三个地方的协作。
Prompt 组装器(agent/prompt_builder.py)——AI 开口之前的准备工作。它负责把你的身份偏好、历史记忆、可用技能列表、当前平台信息、时间戳等内容,按照一定顺序拼成一份完整的 System Prompt,送给模型。这份说明书不是固定的文本,每次对话都是动态拼装出来的,里面塞了多少内容,直接决定了 AI 这次“知道多少背景”。第 7 篇会专门拆解这个拼装过程。
模型调用与供应商选择(hermes_cli/runtime_provider.py)——把消息发给谁、怎么发的问题。Hermes 同时支持 Anthropic、OpenAI、OpenRouter 等十几个模型供应商,这个模块根据你的配置决定本次调用用哪个接口、用什么格式发送、如果某个供应商出错了怎么自动切换到备用的。底层支持三种 API 格式:OpenAI 兼容格式、Anthropic 原生格式,以及 OpenAI Responses API 格式,这三种格式最终在内部统一成同一套消息结构再处理。
工具调度(model_tools.py)——当模型决定要“动手”时的执行层。模型回复里如果带有工具调用请求(比如“请搜索一下这个关键词”),工具调度模块就找到对应的工具处理器、执行它、把结果附回给模型,然后继续这一轮对话。Hermes 有 70 多个工具,它们的注册、发现、调用逻辑都集中在这里管理。多个工具可以并发执行,用线程池最多同时跑 8 个,结果按原始请求顺序拼回去。
三个工作站分工一句话总结:Prompt 组装器负责“想好要说什么”,模型调用负责“把话说出去”,工具调度负责“把手伸出去做事”。
三条数据通路
理解了入口和大脑,再来看数据是怎么在这座城市里流动的。Hermes 有三条主干道,对应三种不同的触发方式。
第一条:CLI 对话流
这是最简单的一条路,从你打字到 AI 回复的完整路径:你输入一条消息 → HermesCLI 接收 → 送进 AIAgent.run_conversation() → Prompt 组装器准备 System Prompt → 检查上下文是否需要压缩 → 调用模型 API → 模型要用工具吗?要的话执行工具、带着结果重新调用模型,循环直到不再需要工具 → 输出最终回复,同时把这轮对话写进数据库。
第二条:Gateway 消息流
这条路多了几个环节。平台推来一条消息 → 对应的平台适配器把它标准化成内部的 MessageEvent → GatewayRunner 接收后先做两件事:一是验证发消息的用户有没有权限;二是解析出这条消息属于哪个会话(用格式为 agent:main:{平台}:{聊天类型}:{聊天ID} 的 Session Key 来标识)→ 从数据库加载这个会话的历史记录 → 连同新消息一起送进 AIAgent 运行 → 生成回复后通过适配器原路发回。
这里有一个有意思的细节:如果你正在和 AI 对话,这时候你在同一个平台又发来了一条新消息,系统有两层保护机制确保处理不乱——平台适配器层先把新消息排进队列,Gateway 运行层再判断是打断当前对话还是继续排队等待。这避免了两条消息同时处理相互干扰的问题。
第三条:定时任务流
这条路完全自动触发,不需要你手动发消息。调度器按计划检查任务队列 → 找到该运行的任务 → 新建一个空白 AIAgent(没有任何对话历史,从零开始)→ 把任务绑定的技能文档注入进去作为上下文 → 执行任务 → 把结果发送到你指定的平台 → 更新任务状态和下次运行时间。
定时任务用的是全新 AIAgent 实例、不带任何会话历史,这是刻意设计的:让定时任务保持纯粹,不被其他正在进行的对话干扰,每次从一张干净的白纸开始执行。
数据住在哪里
讲完数据怎么流动,再说数据存在哪里。
对话历史存在 ~/.hermes/state.db,一个 SQLite 数据库。这个数据库的设计比想象的要精细:它同时建了两张全文检索(FTS5)虚拟表,一张用标准分词器,另一张专门加了 trigram 分词器,用来支持中文和其他 CJK 语言的子串搜索。也就是说,你以后在历史会话里搜索一个关键词,它不是在做字符串匹配,而是走了专门的全文检索引擎,搜索速度和精度都要强得多。
数据库还开启了 WAL 模式(Write-Ahead Logging)——这是一个专门为“一个写入者、多个读取者”场景优化的设置。Gateway 同时连着多个平台,可能同时有多条消息在处理,WAL 模式确保并发读写不会相互阻塞。
除了数据库,你的记忆文件、技能文档、配置文件、AI 人格定义,都存在 ~/.hermes/ 这个目录下:
~/.hermes/
├── config.yaml# 主配置
├── SOUL.md# AI 的“人格”定义
├── memories/# 持久化记忆条目
├── skills/# 技能文档
└── state.db# 所有对话历史
SOUL.md 值得单独提一下。它是一个普通的 Markdown 文件,但它的内容会在每次会话开始时注入到 System Prompt 的最顶层。你在里面写什么,AI 就用什么“性格”跟你说话。官方建议这个文件控制在 1KB 以内,因为它是每条消息都要带着的——太大了每次都多付 Token 的钱。
读懂这张地图,后面的文章就有了参照
我知道这篇文章的信息密度偏高,没有什么故事性,更像是在看说明书。但我的判断是,这张全局地图是整个系列里最值得认真读的一篇,因为它是后面所有文章的索引。
后面每一篇,讲的都是这张地图上的某个具体区域:第 3 篇进入 AIAgent 内部看循环逻辑,第 7 篇打开 Prompt 组装器看拼装过程,第 10 篇走进 Gateway 看平台适配的细节……你现在知道了这些模块在整体里的位置,读那些文章时就不会感觉在看孤立的技术细节,而是知道“哦,这是那个区域”。
读架构就是这样:刚读完的时候可能感觉只是记了一些名词,但等读到后面几篇的时候,你会突然发现这些名词变成了实实在在的理解。
下一篇,我们真正进入 AIAgent 的内部,把它每次“思考”时的核心循环拆开来看。
夜雨聆风