Hermes Agent 实战笔记:从跑通到跑好的几个关键决策
Hermes Agent 不需要更多”安装教程”了——腾讯云上有 Docker 部署教程 [1],CSDN 上

Hermes Agent 不需要更多”安装教程”了——腾讯云上有 Docker 部署教程 [1],CSDN 上有架构全景图 [2],博客园上有踩坑日记 [3],甚至有人把 117 篇官方文档浓缩成中文使用手册 [4b]。
这篇文章想聊点别的:跑起来之后的事。
Hermes 的文档和社区文章已经很多,但大多停留在”怎么装、怎么配、怎么跑通”。真正落地时会碰到的那些问题——记忆漂移怎么办、查询 30 分钟怎么排查、自进化能力该放在架构的哪个位置——几乎没人系统聊过。
这篇文章不敢叫”落地指南”,Hermes 的生态太大,一篇文章覆盖不了全貌。这里只是记录了实际落地过程中碰到的几个关键决策和踩坑记录,希望能给同样在做 Hermes 落地的人一些参考。
一、安装篇:三条路,三种取舍
落地第一步,先把 Hermes 跑起来。但”跑起来”本身就有三种完全不同的路径,尤其对于 Windows 用户,每条路的坑都不一样。
1.1 三条路对比
维度
路 1:Docker Desktop
路 2:WSL2 + 源码
路 3:代码复用
本质
拉镜像,跑容器
WSL2 里 clone + uv
不跑 Hermes 本体,引入核心模块
适合谁
快速体验、不想碰环境
深度定制、调试源码
有自己的智能体系统
Windows 权限
容器 uid 与 NTFS 不兼容,挂载写不了文件
WSL2 跨 /mnt/c 读写性能差
无此问题,跑在原生 Python
核心坑
路径设计 + 权限映射
Python 版本 + subprocess 兼容性
模块解耦,隐式依赖
Skill 挂载
需要挂载到 /opt/data/skills/ 子目录
直接放 ~/.hermes/skills/
自己控制加载逻辑
路 3 适合的场景:有自己的智能体系统,只需要 Hermes 的自进化、记忆管理、Skill 管理等核心能力。最大的挑战是模块解耦——Hermes 的代码不是设计成独立库,模块之间有隐式依赖(比如 skill_manager_tool.py 依赖 model_tools.py 的工具发现机制)。
1.2 Docker 的挂载坑
容器内部三个关键路径,搞混就出事:
路径
作用
坑/opt/data
HERMES_HOME(配置+记忆+会话)
与容器内默认 HOME 冲突/workspace
Agent 工作目录
子路径挂载被误判为已挂载 #13900{HERMES_HOME}/home/
subprocess 的 HOME~
展开目标与 Python 进程不同 #12260
Windows 上的额外权限坑:Docker Desktop 在 Windows 上跑 Linux 容器,文件权限是映射的。chown -R 10000:10000 在 Windows 宿主上无效(NTFS 不认 Linux uid),但 volume mount 指向 WSL2 文件系统时,容器内可能写不了文件。比路径冲突更隐蔽。
推荐挂载设计:
1 | `volumes: |
1.3 源码安装的 subprocess 坑
select.select()
在 Windows 不支持 pipe PR #12795preexec_fn=os.setsid
有线程安全问题 PR #12559- 官方态度:Native Windows is not supported,WSL2 是唯一正解 #16201
用 uv 管理版本:uv venv venv --python 3.11
1.4 Skill 挂载:目录扫描,不需要注册
Skill 的发现机制是扫描 ~/.hermes/skills/ 下所有 SKILL.md 文件。不需要注册,不需要 import。 放对目录就能被发现。
每个 Skill 的最小结构:
1 | `~/.hermes/skills/trading/ |
Docker 场景下,把自定义 Skill 挂载到 /opt/data/skills/ 的子目录即可。也可用 external_dirs 配置外部目录,但外部目录是只读的——Agent 创建新 Skill 只会写到主目录。
二、能力篇:三层架构与实体关系
跑起来之后,第一个问题不是”它能做什么”,而是”它的能力体系怎么划分”。
官方架构文档画了一个洋葱模型,社区文章有人拆成五层六层(触达层、核心层、工具层、执行层、持久层……)。理解全貌时这些拆法有价值,但落地时你会发现——Skill 下面有 Level 0/1/2 渐进式披露,Tool 里有 Toolset 分组,Agent 上面有 Profile 隔离和 Gateway 多端适配,这些都不影响你做架构决策。你真正需要回答的就三个问题:调度逻辑(Agent)?可进化的经验(Skill)?确定性的代码实现(Tool)?三个问题答完,分层就做完了。
2.1 Agent - Skill - Tool 三层模型
层级
物质形态
可自进化
发现机制
AgentAIAgent
实例(run_agent.py,约 1 万行)
通过 Skill 间接
单例,所有入口汇聚
SkillSKILL.md
文本(prompt + 流程)
✅ 核心
目录扫描,~/.hermes/skills/
Tool
Python 模块(registry.register())
❌
import 时 AST 扫描自动注册
怎么判断一个能力该做成 Skill 还是 Tool? 简单说:如果只需要给 Agent 一段”说明书”(流程指引、注意事项),让它用现有工具就能完成 → Skill。如果需要写真正的 Python 代码来处理 API 认证、二进制数据、流式响应 → Tool。
2.2 实体关系:Agent 1:N Skill,Profile 隔离,Delegation 并行
三层之间的关系不是扁平的。落地时必须搞清楚谁拥有谁、谁共享谁:
Agent 与 Skill(1:N):一个 Agent 实例可以加载任意数量的 Skill。Skill 存储在 ~/.hermes/skills/ 下,按 category 分子目录。Agent 通过目录扫描发现 Skill,不需要注册。100+ 内置 Skill + 自定义 Skill 共存,用 top-k 检索控制加载量。
Agent 与 Profile(1:1):Hermes 的 Profile 机制(hermes -p <name>)让每个 Agent 实例有独立的 HERMES_HOME、独立的 config、独立的记忆、独立的 Skill 集合。同一台机器上可以跑多个 Profile,逻辑隔离,互不干扰。这意味着:不同业务线的 Agent 可以有不同的 Skill 组合和记忆空间。
Agent 与 Delegation(1:N 临时):主 Agent 通过 Delegation Tool 创建临时子智能体。子智能体有独立的上下文和 terminal,但不共享主 Agent 的记忆和 Skill 加载状态。传给子智能体的信息只有 goal + context 参数——必须把关键上下文显式传进去,否则子智能体就是一张白纸。
三层协作的全景图:
1 | `Profile-A (HERMES_HOME=~/.hermes/profiles/trading) |
2.3 Delegation:落地约束
约束
具体值
影响
上下文隔离
子智能体看不到主 Agent 的对话历史
关键上下文必须显式传入
记忆不共享
子智能体不读写主 Agent 的 MEMORY.md
子智能体的经验不会自动沉淀
并发上限
默认 3(max_concurrent_children = 3)
可配置,但 LLM API 调用会排队
嵌套深度
默认 flat(max_spawn_depth = 1)
子智能体不能再委派,除非手动调大
文件竞争
多个子智能体可能写同一个文件
有 FileStateRegistry 做协调 PR #13718,复杂场景需人工隔离
MVP 阶段不需要改动默认配置。串行处理成为瓶颈时再启用 Delegation。
三、记忆篇:落地时必须做对的三个决策
三层架构里,Agent 负责调度,Skill 负责流程,Tool 负责执行——但”经验”存在哪里?答案是记忆系统。记忆系统是 Hermes 最容易被忽视的部分。大多数人的注意力被自进化吸引,却忽略了——没有好的记忆设计,自进化就是空中楼阁。 Agent 每次从零开始,什么都”进化”不了。
3.1 决策一:MEMORY.md 的治理边界
MEMORY.md 是 Agent 的持久笔记,有字符上限。满了之后 Agent 会合并或替换条目。核心问题是:谁来决定什么值得记?
Hermes 的答案是 Agent 自己决定。但这不意味着你什么都不用管。落地时需要关注的坑:
- 记忆漂移
:Agent 长期运行后,MEMORY.md可能被不重要的信息占满,关键信息被挤出。定期用/insights检查面板,发现漂移就手动干预 - Docker 场景下的持久化
:MEMORY.md存在~/.hermes/下,必须挂载到持久卷。否则容器重建后记忆清零,Agent 退化回白纸 - 多 Profile 的记忆隔离
:不同业务线的 Profile 有独立的MEMORY.md,不要期望跨 Profile 共享记忆
3.2 决策二:会话归档的存储膨胀
SQLite + FTS5 做会话归档,支持全文检索。Agent 通过 session_search 查询历史对话。这是好东西,但存储会膨胀。
- 长期运行的 Agent,sessions 数据库可能增长到数 GB
- FTS5 的索引膨胀需要定期用
hermes doctor检查 - 如果业务量上来,考虑换 Memory Provider 插件(Hermes 支持 PostgreSQL 等外部存储)
- Docker 场景下,
hermes_state.py对应的数据库文件同样需要在持久卷上
3.3 决策三:记忆与 Skill 的配合
记忆是”知道什么”(declarative),Skill 是”知道怎么做”(procedural)。Agent 完成复杂任务后,会同时更新两者。落地时不要把所有信息都塞进记忆——该流程化的写 Skill,该记事实的写记忆。
一个实用的判断标准:
- “API 的认证 token 每天凌晨过期”→ 写记忆(事实)
- “每天凌晨重新获取 token 的完整流程”→ 写 Skill(流程)
- 两者配合,Agent 遇到 token 过期时,记忆告诉它”会过期”,Skill 告诉它”怎么刷新”
Nudge 机制会让 Agent 主动把重要经验写入长期记忆,不需要手动触发。但主动不等于准确——你需要定期审查,确保 Agent 记住的是对的。
四、可选能力:工具集、路由与消息对接
记忆搞定了,接下来是三个绕不开的基础设施问题:工具集怎么按平台裁剪、LLM API 挂了怎么容灾、用户从哪个平台接入。MVP 阶段可以先用默认配置,但到了 Growth 阶段这三个都要自己决策。
4.1 Toolset 体系
61 个工具按 toolset 分组,可按平台独立配置:
Toolset
核心工具
说明web``web_search
, web_extract
网络搜索和页面提取terminal``terminal
, process
终端执行和后台进程file``read_file
, write_file, patch
文件操作browser
10 个浏览器自动化工具
Playwright 驱动delegate``delegate_task
子代理委派skill_manager``create_skill
, improve_skill
技能管理memory``memory
记忆管理
CLI 下全开,Telegram 下只开 web + terminal + file,禁掉 browser。用 hermes tools 管理。
4.2 Provider 路由
工具集按平台裁剪解决了”能力边界”的问题,但还有一个基础设施层面的问题:LLM API 挂了怎么办?
runtime_provider.py 是共享的 Provider 解析器,提供三个关键能力:凭据池(多 API Key 轮换)、Fallback(主模型出错自动切备选)、热切换(/model 命令切换,无需重启)。支持数十种 Provider(OpenAI、Anthropic、DeepSeek、OpenRouter、本地 Ollama/vLLM 等)。Provider 路由不是炫技,是生产刚需——LLM API 挂了,Hermes 自动切到备选,Agent 不中断。
4.3 消息平台对接
Provider 路由解决了”模型挂了怎么办”,最后一个问题:用户从哪里接入?
20 个平台适配器:Telegram、Discord、Slack、WhatsApp、Signal、Matrix、飞书、钉钉、企业微信、QQ 等。所有平台共享同一套记忆和技能。
企业微信的坑:接入有两条路,别走错。
方式
适配器
配置位置
推荐度
自建应用wecom
应用管理 → 自建应用
❌ 需要公网回调服务器,复杂
长连接机器人wecom_callback
管理工具 → 机器人
✅ 长连接,无需公网,简单
不是应用管理里的自定义应用,是管理工具里的长连接微信机器人。wecom_callback 才是正确的路。
ACP 协议(接入 VS Code/Zed/JetBrains)——除非需要 IDE 里的 AI 助手共享 Hermes 的长期记忆,否则没必要引入这层抽象。
五、性能篇:从 30 分钟到 3 秒的排查实录
能力设计好了,记忆管好了,消息也接上了——然后你会发现一个令人崩溃的现实:Agent 回复一条消息要 30 分钟。性能问题不是理论推演,是实打实的使用事故。
5.1 第一个性能事故:企业微信简单查询,5 分钟起步
场景很朴素:通过企业微信发一条消息,让 Agent 做一个简单的数据查询。结果呢?5 分钟起步,慢的时候 30 分钟才出结果。
对于一个面向用户的交互场景,30 秒已经是忍耐极限。30 分钟?用户早就走了。
排查过程:
- 检查 Skill 加载策略
:Hermes 有渐进式披露(Progressive Disclosure)——Level 0 只加载名称和描述(~3k tokens),Level 1 才加载完整内容,Level 2 加载引用文件。默认 Level 0 的开销不大,所以 Skill 索引本身不是主要瓶颈。但在mode: all下,100+ 个 Skill 的 Level 0 描述累积到 system prompt 里仍然可观。切到top-k检索后有所改善 - 加
/command加速:给高频查询场景配了专属的/command,跳过 Skill 的模糊匹配,走精确的 procedure 路径。效果明显,但还是慢 - 加调用链打点
:在 Skill 的 procedure 里加了切面埋点,逐段计时。最终定位到——瓶颈就是 LLM 推理本身。Agent 每一步都在调 LLM 做决策(”下一步该调哪个工具””参数怎么填”),每一步都是一次 API 调用,每次 API 调用都要等推理完成。步骤一多,延迟线性累加
结论:要效率,必须固化代码,没有别的路数。
排查过程中还发现一个隐藏瓶颈:Hermes 没有独立的知识库概念,只有记忆库(MEMORY.md + 会话归档)。当 Agent 需要从大量业务文档中检索信息时,只能把内容塞进记忆或者让 LLM 每次重新分析原始数据。没有 RAG / 向量检索能力,意味着大量信息要走 LLM 长上下文处理,极其昂贵。解法是通过 MCP 接外部向量数据库,或者自己写一个检索 Tool。
LLM 推理是”慢决策”,代码执行是”快执行”。能用代码解决的事情,不要让 LLM 推理。具体做法:
- 高频操作写死 Tool
:查询逻辑、参数校验、数据格式化,全部写成 Python Tool,Agent 直接调用,不经过 LLM 推理 - Skill 的 procedure 尽量短
:把多步推理的 Skill 拆成”判断用哪个 Tool → 调 Tool → 返回”,中间不要让 LLM 做多余的分析 - 用
/command绕过 Skill 匹配:对确定性高的操作,直接用/command触发,省掉 Skill 索引和匹配的开销
5.2 连接池:1000+ 规则校验场景的血泪教训
如果你的智能体需要对外部数据库做大量走查——比如 1000+ 条规则逐条校验,每条都可能查询 MongoDB——连接池设计就是生死线。
每个 Python 子进程(Delegation 的子智能体、terminal 里执行的脚本)如果都新建一个数据库 client,1000 条规则就是 1000 个连接。瞬间打满连接上限,后面的请求全部超时。而且每个连接都要做 TCP 三次握手 + 认证,延迟累加到分钟级。
解法:统一连接池代理。不在每个 Python 进程里新建 client,而是部署一个连接池代理服务(如 mongos、pgbouncer 或自建的轻量 proxy),所有子进程通过代理复用连接。
1 | `Agent (主循环) |
落地要点:连接池大小 = CPU 核心数 × 2 + 有效磁盘数;子智能体生命周期短,连接必须由代理回收;SQLite 场景同理,hermes doctor 检查 FTS5 索引膨胀,Memory Provider 可插拔换 PostgreSQL。
5.3 缓存层:所有查询都该有缓存,但由 Skill 自己决定
连接池解决的是”连接复用”,缓存解决的是”查询复用”。如果你的智能体频繁查询相同的数据(比如同一组规则的校验结果、同一份配置的解析结果),没有缓存就意味着每次都重新走一遍完整链路——LLM 推理 + Tool 调用 + 数据库查询,全来一遍。
设计原则:显式缓存,不要隐式缓存。
隐式缓存(比如在 Tool 层面做透明缓存)看似省事,但会导致一个致命问题:Skill 不知道自己的查询结果可能是过期的。对于实时性要求高的场景(比如交易策略校验),过期数据比没有数据更危险。
正确的做法是让 Skill 自己决定是否使用缓存:
- Skill 的 procedure 里显式声明”这一步需要实时数据”或”这一步可以接受 5 分钟内的缓存”
- 缓存的 key 由 Skill 的参数决定,缓存的 TTL 由 Skill 的业务逻辑决定
- Skill 可以主动失效缓存(比如在写入操作后清除相关缓存)
实现方案:SQLite 足够。 一张表,四个字段:key、value、created_at、ttl。读写都是微秒级,不需要 Redis 这类外部依赖。对于 MVP 阶段,SQLite 文件放在 ~/.hermes/ 下,跟其他数据一起持久化。
1 | `def cached_query(key: str, skill_ttl: int, fetch_fn): |
关键在于 skill_ttl 这个参数——它由 Skill 传入,不是缓存层的全局配置。不同 Skill 对数据新鲜度的要求不同,这个控制权必须留在 Skill 手里。
5.4 最后的手段:LLM 参数收紧
代码路径优化完了,缓存加了,连接池管好了,如果还是慢——那就只能收 LLM 的参数了:
- max_tokens 384-512
:防止长文本截断触发重试 - Temperature 0.25-0.3
:Agent 场景确定性比创造性重要 /compress
:10 轮后手动压缩上下文- 上下文窗口锁定 8192 Token
:hermes config set context.max_context_tokens 8192
这些是最后的手段,不是第一步。先优化代码路径和基础设施,再动 LLM 参数。
六、架构篇:从 MVP 到生产的 Roadmap
安装跑通了,能力搞清了,记忆管好了,性能也优化了——最后一步,把这些串成一个可以持续演进的架构。
6.1 进化能力的架构位置
Hermes 的自进化引擎叫 GEPA(Generic Evolution of Prompt Architectures)。名字听起来很学术,但落地时只需要回答一个问题:进化能力放在架构的哪个位置?
GEPA 不限于 Skill——只要满足”可序列化、可评估、可变异”的接口,什么都可以进化。Hermes 原生覆盖 Skill、Prompt、知识/记忆三个层级。对于更复杂的业务对象(策略参数、决策规则),需要外部进化框架扩展。
落地时的架构选择:进化能力放在哪里?有两种模式:
- 模式 A:内嵌式
——进化能力作为每个 Skill 的内置行为。Skill 在使用过程中自动优化自己的 prompt 和流程。Hermes 原生的improve_skill就是这个思路 - 模式 B:独立 Skill
——进化能力作为一个完整的独立 Skill,专门负责评估和优化其他 Skill、策略参数、决策规则。其他 Skill 可以被它进化,但不自带进化逻辑
模式 B 更适合生产场景。 把进化做成一个独立 Skill,好处是:进化逻辑集中管理、评估标准统一、不会跟业务 Skill 的 prompt 耦合。而且独立的进化 Skill 本身也可以被进化——“进化如何进化”这个元能力,在模式 A 里很难实现,在模式 B 里天然闭环。
Hermes 的 MIT 协议设计本身就暗示了这条路——它不绑定进化对象,进化器与进化对象解耦。不需要重新发明进化器,只需要实现进化对象的接口。
6.2 配置隔离
三种配置来源,容易冲突:
- config.yaml
:Hermes 主配置 - 环境变量
:HERMES_HOME、API Key(Docker 场景最容易冲突) - PR #10570 修复了 HERMES_HOME 隔离泄漏
- PR #11892 修复了
${ENV_VAR}被展开为明文的问题 - SDK 配置
:外部 SDK 的认证文件,不应污染主配置
MVP 原则:.env 统一管密钥,config.yaml 用 ${ENV_VAR} 引用,SDK 认证放各自插件目录。不要引入配置中心——文件就够了。
6.3 路径管理:SKILL.md 里写协议,Tool 里写实现
配置隔离里有一个特别容易踩的坑:路径变量在 SKILL.md 里不好使。
场景很常见:SKILL.md 里写了 data/rules/strategy_a.json 这样的相对路径。但同一个 SKILL.md 可能被多个系统消费——Hermes Agent 从 ~/.hermes/skills/ 加载它,Trae IDE 通过硬链接从 .trae/ 读它,Python 脚本从 e:\project\ 执行它。三个上下文,同一个相对路径,指向三个不同的地方。
Hermes 有 Skill Config 机制,可以在 SKILL.md 的 frontmatter 里声明路径配置:
1 | `metadata: |
加载时 Hermes 会把解析后的值注入到 Agent 上下文里。但这里有个限制——它只告诉 Agent 路径是什么,不做正文的字符串替换。LLM 需要自己从上下文中找到 config 值,理解应该怎么拼路径。LLM 做不好这件事。
最终方案:SKILL.md 只写”做什么”,不写”在哪做”。 路径是部署细节,收进 Tool 的 Python 代码里:
1 | `<!-- SKILL.md:只描述流程,不出现任何路径 --> |
1 | `# tools/run_strategy.py:路径全部走环境变量 |
这样不管谁读 SKILL.md——Hermes、Trae IDE、人——看到的都是干净的流程描述。切换环境只改 .env,不动 SKILL.md。
6.4 演进路线
阶段
配置
Agent 模式
触发信号
MVP
单机 config.yaml + .env
单 Agent + Delegation
—
Growth
多 Profile
多 Docker,每个 1 Agent
业务线需要隔离
Production
配置中心 + 密钥服务
K8s + Modal/Daytona serverless
需要 7×24 + 自动扩缩
七、参考
关键 Issue / PR
- #13900 — docker_volumes 子路径误判
- #12260 —
~展开 HOME 不一致 - #1445 — 当前目录不自动映射
- #6607 — checkpoint cwd 不存在
- #16201 — Windows 多种问题
- PR #12795 — Windows select.select() 修复
- PR #12559 — preexec_fn → start_new_session
- PR #10570 — HERMES_HOME 隔离泄漏
- PR #11892 — ENV_VAR 占位符保留
- PR #13718 — 跨子 Agent 文件状态协调
- #337 — 进化式自改进 Feature Request
社区参考
[1] 腾讯云:Hermes Agent Docker 完整部署教程 — https://developer.cloud.tencent.com/article/2663042
[2] CSDN:Hermes Agent 整体技术架构解析 — https://blog.csdn.net/m0_59163425/article/details/160156080
[3] 博客园:部署全过程踩坑记 — https://www.cnblogs.com/like/p/19897200
[4b] Hermes Agent 中文完全指南(117篇文档浓缩) — https://xiejiayun.github.io/post/hermes-agent-complete-guide/
扩展阅读
- CSDN:自定义工具开发全攻略 — https://blog.csdn.net/liuzhupeng/article/details/160628384
- 博客园:完整排错指南 2026 — https://www.cnblogs.com/qiniushanghai/p/19897024
- Inside Hermes Agent: What ‘Self-Improving’ Actually Means — https://saulius.io/blog/hermes-agent-self-improving-ai-architecture
- 官方架构文档 — https://hermes-agent.nousresearch.com/docs/developer-guide/architecture/
- 官方 Skills System 文档 — https://hermes-agent.nousresearch.com/docs/user-guide/features/skills/
- 官方 Memory 文档 — https://hermes-agent.nousresearch.com/docs/user-guide/features/memory/
- Hermes Agent 中文站(GEPA 介绍) — https://hermesagentai.cn/
💬 本文评论区已开启,但暂无读者留言。
本文转载自微信公众号,如有侵权请联系删除。
- 标题: Hermes Agent 实战笔记:从跑通到跑好的几个关键决策
- 作者: lxiol
- 创建于 : 2026-05-06 19:56:30
- 更新于 : 2026-05-12 16:07:03
- 链接: https://blog.lxiol.cn/2026/05/06/Hermes-Agent-实战笔记从跑通到跑好的几个关键决策/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。