第四册:核心架构深度解析

本章你将学到

  • Hermes 的"五层架构"到底是哪五层,每一层负责什么,它们之间如何协作
  • 为什么即使你不是纯技术人员,了解架构也能帮你更好地使用 Hermes
  • CLI 入口、GatewayRunner、对话循环、预算机制、ToolRegistry、SQLite 持久化、平台适配器——这些核心模块的工作原理
  • Hermes 的"自学习闭环"是如何在架构层面实现的,为什么说它是 Hermes 的"灵魂"
  • 四层温度记忆模型是怎么工作的,热记忆、温记忆、冷记忆、外部记忆各有什么特点
  • Honcho 用户建模模块如何让 Agent 越来越懂你
  • Hermes 的安全架构如何保护你的数据和系统
  • Python 轻量架构的性能优势和扩展方向

架构听起来可能有点"硬核",但放心,我会用大量的类比和通俗语言,让你像逛超市一样轻松地理解 Hermes 的内部构造。


1. 架构总览:五层设计哲学

1.1 为什么要了解架构

在正式开始之前,我想先回答一个你可能会问的问题:"我只是想用 Hermes 来自动化一些日常工作,为什么要了解它的架构?"

这是一个非常好的问题。答案是:了解架构,能让你用得更明白、调得更顺手、出了问题更容易排查。

打个不太恰当的比方:你开车不需要懂发动机的工作原理,但如果你懂一点发动机的知识,当车子发出异响时,你就能大致判断是"小问题可以自己处理"还是"大问题需要送修"。同样,了解 Hermes 的架构,能让你:

  • 更合理地配置资源。 知道哪一层吃 CPU、哪一层吃内存、哪一层吃磁盘,你就能有针对性地优化。
  • 更快速地定位问题。 Agent 出问题时,如果你能判断问题大概出在哪个层次,排查效率会高十倍。
  • 更充分地利用功能。 很多高级功能之所以"高级",是因为它们涉及多个层次的协作。理解架构后,你会更清楚这些功能的边界和适用场景。
  • 更有信心做扩展。 如果你想开发自定义工具或接入新的平台,了解架构能让你知道应该从哪一层入手、需要遵循什么规范。

Tips

这一章我会用很多生活中的类比来解释技术概念。如果某个类比让你"哦,原来如此",那它就达到了目的;如果某个类比让你更困惑了,那就忘掉它,直接看技术描述。类比只是拐杖,不是真理本身。

1.2 五层架构概览

Hermes 的架构分为五个层次,从上到下依次是:

┌─────────────────────────────────────────┐
│  Layer 1: 入口与编排层                   │
│  HermesCLI + GatewayRunner              │
│  (像是餐厅的前台接待)                    │
├─────────────────────────────────────────┤
│  Layer 2: Agent 核心层                   │
│  同步对话循环 + 预算机制                   │
│  (像是餐厅的主厨和厨房管理)              │
├─────────────────────────────────────────┤
│  Layer 3: 工具与注册层                   │
│  ToolRegistry 单例 + 自注册机制           │
│  (像是餐厅的食材仓库和工具柜)            │
├─────────────────────────────────────────┤
│  Layer 4: 状态与持久化层                 │
│  SQLite + MEMORY.md + USER.md + Cron    │
│  (像是餐厅的档案室和日程表)              │
├─────────────────────────────────────────┤
│  Layer 5: 平台适配层                     │
│  15+ 平台适配器 + 6 种终端后端            │
│  (像是餐厅的外卖接口和配送系统)          │
└─────────────────────────────────────────┘

这个五层架构的设计,体现了一个核心思想:关注点分离(Separation of Concerns)。

每一层只负责一类事情,层与层之间通过清晰的接口通信。这种设计的优点是:

  • 某一层出了问题,不会连锁影响到其他层
  • 可以单独升级或替换某一层,而不需要重构整个系统
  • 新功能的开发可以集中在某一层,降低复杂度

1.3 每层一句话总结

在深入每一层之前,让我们先用一句话概括每一层的职责:

Layer 1(入口与编排层): 负责接收用户的输入(不管是从命令行、消息平台还是 API),把它包装成 Agent 能理解的格式,然后交给下一层处理。

Layer 2(Agent 核心层): 负责理解用户意图、规划执行步骤、调用工具、管理对话流程,是 Agent 的"大脑"和"中枢神经系统"。

Layer 3(工具与注册层): 负责管理所有可用的工具——内置的 47 个工具、第三方 MCP 工具、以及用户自定义的工具——让 Agent 知道"我能做什么"。

Layer 4(状态与持久化层): 负责把所有需要长期保存的信息存下来——记忆、用户画像、历史对话、定时任务——让 Agent"不会忘记"。

Layer 5(平台适配层): 负责把 Agent 的输出转换成各个平台能显示的格式,并处理平台特有的交互方式(如按钮、富文本、文件传输)。

1.4 与传统 Agent 架构的对比

为了让你更直观地理解 Hermes 架构的特点,我们把它和几种典型的 Agent 架构做一个对比。

类型一:单体脚本型(如早期 AutoGPT)

早期的 AutoGPT 基本上就是一个庞大的 Python 脚本,所有的逻辑——从接收输入、解析意图、调用工具、管理记忆——都杂糅在一个文件或少数几个文件里。

优点是简单直接,代码量少。缺点是:

  • 难以维护和扩展——改一个功能可能会影响十个地方
  • 难以测试——没有清晰的模块边界,单元测试几乎不可能
  • 难以复用——代码和具体业务逻辑高度耦合

Hermes 的五层架构,本质上是对这种"大泥球"式代码的反思和改进。

类型二:微服务型(如一些企业级 Agent 平台)

有些 Agent 系统采用了完全的微服务架构——每个功能都是一个独立的容器或服务,通过消息队列或 RPC 通信。

优点是弹性伸缩、故障隔离。缺点是:

  • 部署复杂——需要 Kubernetes、服务发现、负载均衡等基础设施
  • 调试困难——问题可能出在任何一个服务里,追踪调用链很麻烦
  • 资源开销大——每个服务都要独立的进程和内存

Hermes 的定位是"个人和小团队的 Agent",所以选择了轻量级的模块化设计(在一个进程内分层),而不是重型的微服务架构。

类型三:插件型(如一些 ChatGPT 插件系统)

这类架构有一个轻量级的核心,所有功能都通过插件扩展。优点是灵活性高,缺点是核心和插件之间的接口定义很关键,如果接口设计不好,插件生态就会混乱。

Hermes 的 ToolRegistry 和 Skill 系统借鉴了插件思想,但做了更严格的设计约束——所有工具必须遵循统一的注册接口,所有 Skill 必须遵循统一的格式规范。

常见问题

Q:Hermes 的架构适合企业级部署吗?

A:当前版本的 Hermes 主要面向个人开发者和中小型团队。对于大型企业部署,可能需要在 Layer 4(持久化层)替换 SQLite 为更强大的数据库(如 PostgreSQL),在 Layer 1(入口层)增加负载均衡和 API 网关。Nous Research 的中期规划中已经包含了企业级功能,未来会有更完善的企业部署方案。

Q:五层架构会不会让系统变慢?

A:分层确实会带来一些函数调用的开销,但对于 Hermes 这种以 LLM 调用为主要耗时的系统来说,这些开销几乎可以忽略不计。LLM 的一次 API 调用可能需要几秒钟,而层与层之间的数据传输只需要几毫秒。相比之下,清晰的架构带来的可维护性和可扩展性收益,远远大于这点性能损耗。


2. Layer 1: 入口与编排层(HermesCLI + GatewayRunner)

2.1 CLI 入口的设计理念

在深入 CLI 之前,先快速了解一下 Hermes 的安装方式。根据 Nous Research 的官方设计,Hermes 的安装极为简单——只需一条 curl 命令

# macOS / Linux 安装(官方推荐方式)
curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash

安装脚本会自动完成以下工作:

  • 下载 Hermes 二进制文件到 ~/.hermes/bin/
  • 安装 uv(Python 包管理器)
  • 安装 Python 3.11 运行时
  • 安装 Node.js v22(部分工具依赖)
  • 安装 ripgrep、ffmpeg 等辅助工具
  • ~/.hermes/bin/ 添加到你的 PATH
# 安装完成后,验证是否成功
hermes --version
 
# 查看二进制文件位置
which hermes
# 输出: /Users/yourname/.hermes/bin/hermes

Tips

~/.hermes/bin/ 是 Hermes 的"家目录"。除了二进制文件,这个目录下还会存放:

  • ~/.hermes/data/ —— SQLite 数据库和日志
  • ~/.hermes/skills/ —— 自动创建和下载的技能
  • ~/.hermes/custom_tools/ —— 你的自定义工具
  • ~/.hermes/MEMORY.md —— Agent 的工作笔记
  • ~/.hermes/USER.md —— 用户画像

建议定期备份整个 ~/.hermes/ 目录。

HermesCLI 是用户与 Hermes 交互的主要入口。它的设计理念可以用三个词概括:简洁、直观、渐进。

简洁 —— HermesCLI 的命令体系非常精简,核心命令只有十几个。你不需要记住一大堆复杂的参数和标志,常用的操作都能在 3 个单词以内的命令中完成。

# Hermes 的核心命令一览
hermes                    # 启动交互式对话
hermes -q "你的问题"       # 单次查询模式
hermes --continue         # 恢复上一次的会话
hermes setup              # 启动配置向导
hermes model              # 管理和切换大模型
hermes tools              # 查看和配置工具
hermes gateway setup      # 配置消息平台接入
hermes skills browse      # 浏览技能市场
hermes skills install     # 安装技能
hermes migrate openclaw   # 从 OpenClaw 迁移

直观 —— 命令的命名遵循"说人话"原则。hermes model 就是管模型的,hermes tools 就是管工具的,hermes gateway 就是管平台接入的。不需要查文档,凭直觉就能猜出命令的作用。

渐进 —— 命令的复杂度是渐进暴露的。初学者只需要知道 hermeshermes -q 就能开始使用;随着需求的增长,再逐步学习更高级的命令。不会一上来就给你一百个命令,让你不知道从何学起。

Tips

如果你记不住某个命令的具体用法,可以在命令后面加 --help。Hermes 的每个命令都有详细的中文帮助文档,还会给出示例。比如 hermes tools --help 会告诉你每个子命令是做什么的、有哪些参数、参数的含义是什么。

2.2 GatewayRunner 的作用

如果说 HermesCLI 是"人找系统"的入口(用户主动打开终端,输入命令),那么 GatewayRunner 就是"系统找人"的入口(Agent 主动通过消息平台推送消息给用户)。

GatewayRunner 是一个长期运行的服务进程,它负责:

  1. 监听多个平台的 incoming 消息。 无论是 Telegram 的消息、飞书的@提及、还是 Slack 的频道消息,GatewayRunner 都会实时接收。

  2. 消息格式统一化。 不同平台的消息格式千差万别——有的用 JSON,有的用 XML,有的用 Protobuf。GatewayRunner 把这些异构格式转换成 Hermes 内部的统一消息对象。

  3. 会话管理。 当同一个用户在不同平台发来消息时,GatewayRunner 要判断"这是不是同一个人",然后把消息路由到正确的会话中。

  4. 身份认证与安全校验。 对 Webhook 请求进行签名验证,防止伪造消息。

你可以把 GatewayRunner 想象成一个"多语言翻译官 + 前台接待"的组合体。它站在门口,同时和十几个平台"聊天",然后把所有平台的消息翻译成同一种"语言"(Hermes 内部格式),再转交给 Agent 处理。

2.3 命令解析流程

当你在终端输入一条 hermes 命令时,系统内部发生了什么?让我们跟踪一下完整的流程:

用户输入: hermes -q "帮我写一个 Python 爬虫"
    ↓
[Shell] 解析命令行参数
    ↓
[HermesCLI] 识别到这是 "单次查询" 模式 (-q 标志)
    ↓
[HermesCLI] 加载配置(从 ~/.config/hermes/ 读取)
    ↓
[HermesCLI] 初始化 Agent 实例(如果不存在)
    ↓
[HermesCLI] 把用户输入包装成 Message 对象
    ↓
[Agent 核心层] 接收 Message,开始处理...
    ↓
...(Agent 处理过程,详见 Layer 2)...
    ↓
[Agent 核心层] 返回处理结果
    ↓
[HermesCLI] 格式化输出(根据终端类型选择渲染方式)
    ↓
[HermesCLI] 显示结果给用户
    ↓
[持久化层] 保存对话历史到 SQLite

这个流程看似简单,但每个步骤背后都有不少工程细节。

比如"加载配置"这一步,Hermes 会按照以下优先级读取配置:

  1. 环境变量(最高优先级)—— 适合 CI/CD 和容器化部署
  2. 命令行参数 —— 适合临时覆盖某个配置
  3. 项目级配置文件(./.hermes/config.yaml)—— 适合项目特定的设置
  4. 用户级配置文件(~/.config/hermes/config.yaml)—— 适合个人偏好
  5. 系统级配置文件(/etc/hermes/config.yaml)—— 适合全局默认设置
  6. 内置默认值(最低优先级)—— 保证系统在没有配置时也能运行

这种分层配置的设计,让你可以非常灵活地管理不同场景下的配置需求。

# ~/.config/hermes/config.yaml 示例
# 这是用户级的配置文件
 
model:
  provider: openai # 默认使用的模型提供商
  model: gpt-4.1 # 默认使用的模型名称
  temperature: 0.7 # 创造力参数(0=保守,1=发散)
  max_tokens: 4096 # 单次响应的最大 Token 数
 
memory:
  max_memory_tokens: 2200 # MEMORY.md 的字符上限
  max_user_tokens: 1375 # USER.md 的字符上限
  enable_compression: true # 是否启用记忆压缩
 
budget:
  max_turns: 50 # 单次任务的最大对话轮数
  max_tool_calls: 100 # 单次任务的最大工具调用次数
  max_cost_usd: 5.0 # 单次任务的最大成本(美元)
 
terminal:
  backend: local # 终端后端:local / docker / ssh
  require_approval: true # 危险操作是否需要用户确认

2.4 多入口共存的设计选择

Hermes 的一个独特设计是:它同时支持三种入口方式,而且它们可以共存。

入口一:CLI(命令行)

适合场景:开发者日常操作、脚本自动化、快速测试 优点:直接、高效、不需要额外配置 缺点:需要打开终端,不适合移动端

入口二:Gateway(消息平台)

适合场景:团队协作、移动办公、7×24 小时值守 优点:随时随地可用、天然支持多人协作、消息历史自动保存 缺点:需要配置平台接入、受平台功能限制(如消息长度限制)

入口三:API(编程接口)

适合场景:集成到现有系统、批量任务处理、二次开发 优点:完全可控、易于自动化、可以嵌入任何应用 缺点:需要编程能力、需要自己处理错误和重试

这三种入口共享同一个 Agent 实例和同一套记忆数据。这意味着:你可以在 CLI 上和 Agent 聊了一半,然后在 Telegram 上继续聊,Agent 完全记得之前的上下文。

注意

多入口共存虽然很方便,但也带来了一个需要注意的问题:并发冲突。 如果 CLI 和 Telegram 同时给 Agent 发送任务,Agent 应该优先处理哪个?Hermes 目前的策略是"单线程处理"——一个任务完成后才开始下一个。这是为了避免 Agent 在多个任务之间"精神分裂"。未来版本可能会引入更精细的并发控制机制。


3. Layer 2: Agent 核心层(对话循环与预算机制)

3.1 同步对话循环的工作原理

Agent 核心层是整个 Hermes 系统中最复杂的部分。它的核心是一个同步对话循环(Synchronous Conversation Loop),这个循环驱动着 Agent 从接收用户输入到输出最终结果的完整流程。

让我们用一个生活化的类比来理解这个循环。

想象你是一家餐厅的主厨。你的工作是:顾客点了一道菜,你要决定需要什么食材、用什么厨具、按什么顺序加工,最后把成品端出去。

同步对话循环就像是主厨的"工作流程":

┌─────────────────────────────────────────────────────────────┐
│                     同步对话循环流程                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 接收订单(Receive)                                     │
│     ↓ 顾客说:"我要一份宫保鸡丁"                             │
│                                                             │
│  2. 理解需求(Comprehend)                                   │
│     ↓ 分析:宫保鸡丁 = 鸡肉 + 花生 + 干辣椒 + 葱姜蒜...       │
│                                                             │
│  3. 规划步骤(Plan)                                         │
│     ↓ 决定:先切鸡肉 → 腌制 → 炸花生 → 炒配料 → 合炒 → 出锅  │
│                                                             │
│  4. 执行步骤(Execute)—— 可能涉及多次工具调用                │
│     ↓ 调用工具:切菜(cut)、调味(season)、加热(heat)...   │
│     ↓ 每执行一步,观察结果,决定下一步                       │
│                                                             │
│  5. 检查结果(Evaluate)                                     │
│     ↓ 颜色对吗?味道对吗?顾客的特殊要求满足了吗?            │
│                                                             │
│  6. 输出结果(Respond)                                      │
│     ↓ 上菜!                                                │
│                                                             │
│  7. 学习总结(Learn)—— Hermes 特有                          │
│     ↓ 记录:这次宫保鸡丁做得不错,下次还可以这样做             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

在代码层面,这个循环大致是这样的结构(简化版):

# 这是简化版的对话循环伪代码,帮助理解核心逻辑
# 实际代码比这复杂得多,包含大量错误处理和状态管理
 
def conversation_loop(user_input: str, session: Session) -> str:
    """
    Agent 核心对话循环
 
    参数:
        user_input: 用户的输入消息
        session: 当前会话对象,包含上下文和历史
 
    返回:
        Agent 的最终回复
    """
 
    # 第 1 步:构建上下文
    context = build_context(session)
    # 上下文包括:系统提示、MEMORY.md 内容、USER.md 内容、
    # 当前会话的历史消息、可用的工具列表
 
    # 第 2 步:发送给 LLM,获取响应
    llm_response = call_llm(
        messages=context,
        tools=available_tools,  # 告诉 LLM 有哪些工具可用
    )
 
    # 第 3 步:解析 LLM 的响应
    # LLM 可能直接回复文字,也可能请求调用某个工具
    while llm_response.requires_tool_call:
        # LLM 要求调用工具
        tool_result = execute_tool(
            name=llm_response.tool_name,
            params=llm_response.tool_params,
        )
 
        # 把工具执行结果告诉 LLM
        context.add_tool_result(tool_result)
 
        # 再次调用 LLM,让它基于工具结果继续推理
        llm_response = call_llm(
            messages=context,
            tools=available_tools,
        )
 
        # 检查预算:是否超过了最大轮数或最大成本?
        if budget_exceeded(session):
            raise BudgetExceededError("任务预算已耗尽")
 
    # 第 4 步:LLM 给出了最终回复(不再要求调用工具)
    final_response = llm_response.content
 
    # 第 5 步:保存对话历史
    session.add_message(role="user", content=user_input)
    session.add_message(role="assistant", content=final_response)
 
    # 第 6 步:触发学习机制(如果满足条件)
    if should_learn(session):
        create_or_update_skill(session)
 
    return final_response

这个循环的精妙之处在于:它不是一次性完成的,而是可能涉及多轮 LLM 调用和工具调用的"迭代过程"。

举个例子:你说"帮我查一下明天北京的天气,如果下雨就提醒我带伞"。

Agent 的处理过程可能是这样的:

用户: 帮我查一下明天北京的天气,如果下雨就提醒我带伞
    ↓
LLM 思考:用户需要天气信息。我应该调用天气查询工具。
    ↓
调用工具: weather.query(location="北京", date="明天")
    ↓
工具返回: {"天气": "小雨", "温度": "15-22°C", "降水概率": "80%"}
    ↓
LLM 思考:天气是小雨,满足"下雨"的条件。我需要提醒用户带伞。
    ↓
LLM 回复: 明天北京有小雨,降水概率 80%,气温 15-22°C。记得带伞哦!

在这个过程中,LLM 被调用了两次:第一次决定调用天气工具,第二次在获得天气数据后生成最终回复。这就是对话循环的"迭代"特性。

Tips

你可以通过设置 budget.max_turns 来控制单次任务中 LLM 的最多调用轮数。默认值通常是 50,对于绝大多数任务来说足够了。如果你的任务特别复杂(比如需要查询多个数据源、进行多步分析),可以适当调高这个值。但要注意,每增加一轮 LLM 调用,都会增加 Token 消耗和响应时间。

3.2 预算机制:防止 Agent 失控的安全阀

预算机制(Budgeting)是 Hermes 安全架构中最重要的组件之一。它的作用是:给 Agent 的每一次任务设定资源上限,防止它陷入无限循环或过度消耗。

为什么需要预算机制?让我们看一个"恐怖故事"。

假设你让 Agent"帮我找一下关于量子计算的最新论文"。如果没有预算机制,Agent 可能会:

  1. 调用搜索工具,找到 100 篇论文
  2. 对每篇论文调用摘要提取工具——100 次工具调用
  3. 发现某些论文引用了更多论文,又去搜索引用论文——又 100 次
  4. 陷入递归循环,直到你的 API 账单爆表

这就像一个没有刹车的汽车,油门踩下去就不知道停。预算机制就是这辆车的"刹车系统"。

Hermes 的预算机制包含三个维度的限制:

维度一:对话轮数限制(max_turns)

限制单次任务中 LLM 的调用次数。每调用一次 LLM,就算一轮。

budget:
  max_turns: 50 # 最多 50 轮对话

超过这个限制后,Agent 会停止执行,并向用户报告:"任务太复杂了,我在预算范围内无法完成。你可以简化任务,或者调高预算限制。"

维度二:工具调用次数限制(max_tool_calls)

限制单次任务中调用工具的总次数。注意,这和对话轮数是不同的指标——一轮对话中可能调用多个工具。

budget:
  max_tool_calls: 100 # 最多调用 100 次工具

维度三:成本限制(max_cost_usd)

这是最"硬核"的限制——直接用美元计价。系统会根据每次 LLM 调用的 Token 数量和模型单价,实时计算累计成本。

budget:
  max_cost_usd: 5.0 # 单次任务最多花费 5 美元

当累计成本接近上限时,Agent 会收到警告;超过上限后,任务会被强制终止。

注意

成本限制依赖于准确的 Token 计数和模型定价表。如果模型提供商的 API 返回了错误的 Token 计数,或者定价表没有及时更新,成本估算可能会有偏差。建议把 max_cost_usd 设置得比你实际能承受的成本低 20%,留一些安全余量。

3.3 Token 计数与成本控制

要理解预算机制,就必须先理解 Token 这个概念。

Token 是大语言模型处理文本的基本单位。你可以把它理解为"词片段"——一个英文单词可能被拆成 1-2 个 Token,一个中文字符通常是 1-2 个 Token。

举例:
"Hello world" ≈ 3 Tokens(Hello + world + 空格/标点)
"你好世界" ≈ 4 Tokens(你 + 好 + 世 + 界)
"中华人民共和国" ≈ 6-8 Tokens(取决于分词方式)

为什么 Token 很重要?因为:

  1. Token 是计费的单位。 模型提供商按输入 Token 数和输出 Token 数收费。输入和输出的单价通常不同(输出更贵)。
  2. Token 是上下文窗口的单位。 每个模型都有最大上下文长度(如 GPT-4 是 128k Tokens),超过这个长度,最前面的内容会被截断或压缩。
  3. Token 是预算机制的计算基础。 max_cost_usd 的核算,依赖于准确的 Token 计数。

Hermes 在 Token 计数方面做了以下工作:

准确的 Token 估算。 在每次调用 LLM 之前,Hermes 会用对应模型的 Tokenizer 精确计算输入文本的 Token 数。不同模型使用不同的 Tokenizer(如 GPT 系列用 tiktoken,Claude 用不同的方案),Hermes 会自动选择正确的 Tokenizer。

实时的成本追踪。 每次 LLM 调用后,Hermes 会记录:

  • 输入 Token 数
  • 输出 Token 数
  • 模型单价
  • 本次调用的成本

这些数据被累加到会话的"成本账本"中,供预算机制检查。

Fallback 链的成本优化。 Hermes 支持 Fallback 链——当主模型失败或不可用时,自动切换到备选模型。这个机制不仅能提高可用性,还能用于成本优化。

# Fallback 链配置示例
models:
  primary:
    provider: openai
    model: gpt-4.1
    # GPT-4 效果好,但贵(约 $15 / 1M tokens)
 
  fallback:
    provider: deepseek
    model: deepseek-chat-v3
    # DeepSeek 便宜很多(约 $0.14 / 1M tokens)
    # 成本差异超过 100 倍!
 
  local:
    provider: ollama
    model: llama-3.3-70b
    # 本地模型,零成本,但需要自己的 GPU

Tips

一个实用的成本控制策略是:日常任务用便宜的模型(如 DeepSeek),复杂任务用能力强的模型(如 GPT-4)。Hermes 的模型切换非常简单:hermes model 就可以交互式地切换。你也可以在配置中设置自动降级规则——当任务类型匹配某些关键词时,自动选择更经济的模型。

3.4 上下文窗口管理策略

上下文窗口(Context Window)是 LLM 能"记住"的最大文本量。当前的主流模型,上下文窗口从 4k 到 200k+ Tokens 不等。

但上下文窗口有一个反直觉的特性:越大不等于越好。

研究表明,当上下文窗口中的内容过多时,模型的注意力会分散,对开头和结尾的内容记得更清楚,对中间的内容容易"遗忘"。这种现象被称为"中间丢失"(Lost in the Middle)。

Hermes 采用了多层策略来管理上下文窗口:

策略一:分层加载。

不是所有信息都塞进上下文,而是按优先级分层加载:

  1. 最高优先级: 系统提示 + 当前任务描述(必须包含)
  2. 高优先级: MEMORY.md + USER.md 的摘要(通常包含)
  3. 中优先级: 当前会话的最近 N 轮对话(尽量包含)
  4. 低优先级: 相关历史对话的检索结果(空间足够时包含)
  5. 最低优先级: 完整的工具描述列表(按需加载)

当上下文快满时,系统会优先丢弃低优先级的信息,保证高优先级信息的完整性。

策略二:智能摘要。

当会话历史很长时,系统不会把所有历史消息都塞进上下文,而是让 LLM 生成一个"会话摘要",用几百字概括之前的对话内容。这样既保留了关键信息,又大大节省了 Token。

原始会话历史(10 轮对话): 约 3000 Tokens
    ↓
智能摘要(1 段文字): 约 200 Tokens
    ↓
节省: 2800 Tokens(93% 的压缩率)

策略三:工具描述的渐进加载。

47 个内置工具的完整描述,如果全部塞进上下文,可能需要几千 Tokens。Hermes 采用了渐进式加载:

  • 第一轮:只告诉 LLM"有哪些工具类别"(如"文件系统类""Web 类""代码执行类")
  • 当 LLM 决定需要某类工具时:加载该类工具的详细描述
  • 当 LLM 决定调用某个具体工具时:加载该工具的完整参数说明

这种"按需加载"的方式,既让 LLM 知道"我有什么工具",又避免了上下文被大量工具描述撑爆。

3.5 错误恢复与重试机制

在 Agent 的运行过程中,各种错误是不可避免的:

  • LLM API 超时或返回错误
  • 工具执行失败(如网络不通、文件不存在)
  • 工具返回的数据格式不符合预期
  • Token 预算耗尽
  • 上下文窗口溢出

Hermes 设计了一套完善的错误恢复机制:

错误类型一:LLM API 错误。

# 当 LLM API 调用失败时的处理流程
try:
    response = call_llm(messages, tools)
except LLMTimeoutError:
    # 超时错误:等待几秒后重试
    time.sleep(2)
    response = call_llm(messages, tools)  # 重试一次
except LLMRateLimitError:
    # 速率限制:等待更长时间后重试
    time.sleep(10)
    response = call_llm(messages, tools)  # 重试
except LLMError as e:
    # 其他 LLM 错误:切换到 Fallback 模型
    response = call_llm_with_fallback(messages, tools)

错误类型二:工具执行错误。

# 当工具执行失败时的处理流程
try:
    result = execute_tool(tool_name, params)
except ToolNotFoundError:
    # 工具不存在:告诉 LLM 这个工具不可用,让它换别的
    context.add_system_message(f"工具 '{tool_name}' 不存在,请使用其他工具。")
except ToolExecutionError as e:
    # 工具执行失败:把错误信息告诉 LLM,让它决定怎么处理
    context.add_tool_error(f"工具 '{tool_name}' 执行失败: {e.message}")
    # LLM 可能会:重试、换其他工具、或者告诉用户出错了

错误类型三:预算耗尽。

if budget_exceeded(session):
    # 预算耗尽:终止当前任务,向用户报告
    return (
        "⚠️ 任务预算已耗尽。\n"
        "已使用: {used_turns} 轮对话, {used_tools} 次工具调用, ${used_cost:.2f}\n"
        "限额: {max_turns} 轮, {max_tools} 次, ${max_cost:.2f}\n\n"
        "建议:\n"
        "1. 简化你的任务描述\n"
        "2. 分步骤执行,每次只完成一部分\n"
        "3. 在配置中调高预算限制(hermes config set budget.max_cost_usd 10)"
    )

常见问题

Q:Agent 遇到错误时会自动重试吗?会不会无限重试?

A:Hermes 的重试机制有明确的上限。LLM API 错误最多重试 3 次(每次间隔递增),工具执行错误不重试(而是把错误信息告诉 LLM,由 LLM 决定下一步)。预算耗尽和上下文溢出这类"硬性限制"错误,不会重试,直接终止任务。这种设计避免了"死循环"式的无限重试。

Q:如果 Agent 在执行危险操作(如删除文件)时出错,会发生什么?

A:危险操作在执行前会经过"命令审批"流程(详见第 10 章安全架构)。只有当用户明确确认后,操作才会执行。如果执行过程中出错,系统会报告错误,但不会自动重试危险操作。这是安全设计的一部分。


4. Layer 3: 工具与注册层(ToolRegistry 与自注册)

4.1 ToolRegistry 单例模式详解

ToolRegistry 是 Hermes 工具系统的"中央枢纽"。你可以把它想象成一个工具柜台——每个工具都有自己的工位,Agent 需要用什么工具时,就到这里来"借"。

ToolRegistry 采用了**单例模式(Singleton Pattern)**设计。这意味着整个 Hermes 系统中,只有一个 ToolRegistry 实例存在。所有的工具注册、查询和调用,都通过这个唯一的实例完成。

为什么要用单例模式?

  1. 一致性。 所有模块看到的工具列表是完全一致的,不会出现"A 模块以为有这个工具、B 模块以为没有"的情况。
  2. 状态共享。 ToolRegistry 需要维护工具的注册状态、版本信息、调用统计等数据,单例模式确保这些数据全局可见。
  3. 资源节省。 不需要为每个会话创建独立的 ToolRegistry,降低了内存开销。
# ToolRegistry 单例模式的简化示意
class ToolRegistry:
    _instance = None  # 唯一的实例引用
 
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance._tools = {}  # 工具注册表
        return cls._instance
 
    def register(self, tool: Tool) -> None:
        """注册一个新工具"""
        self._tools[tool.name] = tool
 
    def get(self, name: str) -> Tool:
        """根据名称获取工具"""
        return self._tools.get(name)
 
    def list_all(self) -> list[Tool]:
        """列出所有已注册的工具"""
        return list(self._tools.values())
 
    def get_descriptions(self) -> str:
        """生成所有工具的描述文本(供 LLM 使用)"""
        descriptions = []
        for tool in self._tools.values():
            descriptions.append(f"- {tool.name}: {tool.description}")
        return "\n".join(descriptions)

Tips

单例模式虽然方便,但也有一个需要注意的地方:线程安全。 如果多个线程同时调用 register()get(),可能会产生竞争条件。Hermes 的 ToolRegistry 在初始化阶段(系统启动时)完成所有工具的注册,运行阶段主要是读取操作,所以实际使用中线程安全问题不大。但如果你要开发一个支持高并发的自定义扩展,这一点需要留意。

4.2 工具自注册机制

Hermes 最巧妙的机制之一,就是工具自注册(Self-Registration)

传统的工具系统,你需要在一个中心文件里手动列出所有可用的工具。每次新增或删除工具,都要修改这个中心文件。工具一多,这个文件就会膨胀到难以维护。

Hermes 的做法是:每个工具自己负责注册自己。

具体实现方式是:每个工具都是一个独立的 Python 模块,模块在加载时,会自动调用 ToolRegistry.register() 把自己注册进去。

# 一个工具模块的示例(简化版)
# 文件: hermes/tools/file_read.py
 
from hermes.core.registry import ToolRegistry
from hermes.core.tool import Tool, ToolParameter
 
# 定义工具
def file_read(file_path: str, encoding: str = "utf-8") -> str:
    """
    读取文件内容
 
    参数:
        file_path: 文件的完整路径
        encoding: 文件编码,默认 utf-8
 
    返回:
        文件的文本内容
    """
    with open(file_path, "r", encoding=encoding) as f:
        return f.read()
 
# 创建工具对象
file_read_tool = Tool(
    name="file_read",
    description="读取指定路径的文件内容,返回文本字符串",
    parameters=[
        ToolParameter(
            name="file_path",
            type="string",
            description="要读取的文件的完整路径",
            required=True,
        ),
        ToolParameter(
            name="encoding",
            type="string",
            description="文件的字符编码",
            required=False,
            default="utf-8",
        ),
    ],
    handler=file_read,
    category="filesystem",  # 工具类别
    requires_approval=False,  # 是否需要用户审批
)
 
# 自注册:模块加载时自动注册到 ToolRegistry
ToolRegistry().register(file_read_tool)

这种设计的好处是显而易见的:

  1. 新增工具零配置。 你把一个新的工具文件放到 tools/ 目录下,系统启动时自动加载并注册。不需要修改任何中心配置文件。
  2. 删除工具零残留。 删掉工具文件,注册自然消失。不会在配置文件中留下死引用。
  3. 工具高度自治。 每个工具自己管理自己的元数据(名称、描述、参数、类别、安全级别),不需要依赖外部配置。

注意

工具自注册依赖于 Python 的模块导入机制。系统启动时,会扫描 tools/ 目录下的所有 .py 文件,逐个导入。如果某个工具模块有语法错误或其他问题,导入会失败,但不会影响其他工具的注册。系统会在日志中记录哪些工具注册成功、哪些失败,方便排查问题。

4.3 47 个内置工具的分类架构

Hermes 内置了 47 个工具,覆盖了日常开发和工作中最常用的功能。这些工具不是随意堆砌的,而是按照功能类别进行了清晰的组织。

类别工具数量代表工具用途
文件系统6file_read, file_write, file_edit, file_search, directory_list, file_delete文件的读写、编辑、搜索和管理
代码执行4python_exec, shell_exec, code_lint, code_format运行 Python/Shell 代码,代码检查和格式化
Web 交互6web_search, web_extract, browser_navigate, browser_click, browser_screenshot, rss_fetch搜索网页、提取内容、浏览器自动化、RSS 订阅
终端命令2terminal_exec, terminal_approve执行系统终端命令(需审批)
记忆管理5memory_read, memory_write, memory_search, memory_delete, session_search读写 MEMORY.md、搜索历史会话
技能管理4skill_create, skill_read, skill_update, skill_delete创建和管理 Skill 文件
代理委托2delegate_task, check_status创建子 Agent 并行处理任务
数据库3db_query, db_insert, db_updateSQLite 数据库操作
通信4send_email, send_message, webhook_call, notification_push发送邮件、消息、调用 Webhook
媒体处理4image_analyze, audio_transcribe, video_extract, media_convert图像分析、语音转文字、视频处理
开发工具4git_commit, git_diff, git_branch, dependency_checkGit 操作、依赖检查
系统信息3system_info, env_read, process_list读取系统信息、环境变量、进程列表

Tips

不是所有工具默认都是启用的。有些工具(如 terminal_exec、file_delete)属于"危险工具",默认是禁用的。你需要运行 hermes tools 命令,交互式地启用你需要的工具。这种"白名单"机制是安全设计的一部分——默认最小权限,用户按需开启。

每个工具在注册时,都会带上以下元数据:

# 工具元数据结构(简化版)
{
    "name": "file_write",           # 工具的唯一标识
    "description": "写入文件内容",   # 给 LLM 看的描述
    "category": "filesystem",       # 所属类别
    "parameters": [                 # 参数列表
        {"name": "path", "type": "string", "required": True},
        {"name": "content", "type": "string", "required": True},
        {"name": "append", "type": "boolean", "required": False, "default": False}
    ],
    "requires_approval": False,     # 是否需要用户审批
    "dangerous": False,             # 是否属于危险操作
    "cost_estimate": "low",         # 执行成本估计
    "average_latency_ms": 50,       # 平均执行延迟
}

这些元数据不仅供 LLM 理解工具的用途,也供系统做安全判断、成本估算和性能优化。

4.4 工具调用的安全审批流程

对于可能产生副作用的工具(如删除文件、执行系统命令、发送邮件),Hermes 设计了一套安全审批流程

Agent 请求调用危险工具
    ↓
系统检查该工具是否标记为 requires_approval=True
    ↓
如果是,暂停执行,向用户显示审批请求
    ↓
用户界面显示:
  - 工具名称
  - 工具描述
  - 具体的参数值(如要删除的文件路径)
  - 风险评估(低/中/高)
  - 建议操作(确认 / 拒绝 / 修改参数)
    ↓
用户选择:
  - 确认 → 执行工具,记录审批日志
  - 拒绝 → 取消调用,告诉 Agent 用户拒绝了
  - 修改 → 让用户编辑参数后再次审批

在 CLI 模式下,审批界面是这样的:

⚠️  Agent 请求执行危险操作
 
工具: terminal_exec
描述: 执行系统终端命令
风险等级:
 
请求执行的命令:
  rm -rf /home/user/old_project/
 
 这个操作将删除目录 /home/user/old_project/ 及其所有内容。
   此操作不可撤销!
 
请选择:
  [Y] 确认执行
  [N] 拒绝
  [E] 编辑命令
  [A] 允许本次会话的所有同类操作
>

注意

"允许本次会话的所有同类操作"(选项 A)是一个方便但危险的功能。如果你选择了这个选项,当前会话中所有同类型的危险操作都会自动通过,不再提示。这在批量处理任务时很有用,但也意味着如果你没注意看 Agent 在做什么,可能会造成损失。建议只在完全信任当前任务、且已经审查过 Agent 的计划后,才使用这个选项。

4.5 自定义工具的扩展接口

Hermes 提供了非常友好的自定义工具接口,让你可以开发自己的工具,扩展 Agent 的能力。

方法一:Python 函数式工具(最简单)

如果你只需要一个简单的函数,可以直接用装饰器注册:

# 自定义工具示例:查询股票价格
# 文件: ~/.hermes/custom_tools/stock_query.py
 
from hermes.core.registry import ToolRegistry
from hermes.core.tool import tool  # 装饰器
 
@tool(
    name="stock_query",
    description="查询指定股票代码的当前价格和基本信息",
    parameters={
        "symbol": {"type": "string", "description": "股票代码,如 AAPL、TSLA、600519"},
        "market": {"type": "string", "description": "市场代码:us/hk/cn", "default": "us"},
    },
    category="finance",
)
def stock_query(symbol: str, market: str = "us") -> dict:
    """
    查询股票价格
 
    这个工具调用免费的股价 API 获取实时数据。
    注意:免费 API 有调用频率限制,适合个人使用。
    """
    import requests
 
    # 根据市场选择 API
    if market == "us":
        url = f"https://api.example.com/stock/us/{symbol}"
    elif market == "cn":
        url = f"https://api.example.com/stock/cn/{symbol}"
    else:
        return {"error": f"不支持的市场: {market}"}
 
    response = requests.get(url, timeout=10)
    data = response.json()
 
    return {
        "symbol": symbol,
        "price": data.get("price"),
        "change": data.get("change"),
        "change_percent": data.get("change_percent"),
        "market_cap": data.get("market_cap"),
    }
 
# 使用装饰器后,工具会自动注册,不需要手动调用 ToolRegistry.register()

方法二:完整的 Tool 类(更灵活)

如果你需要更复杂的逻辑(如初始化资源、异步执行、自定义审批逻辑),可以继承 Tool 基类:

# 自定义工具示例:操作公司内部的 REST API
from hermes.core.tool import Tool, ToolParameter
from hermes.core.registry import ToolRegistry
 
class InternalAPITool(Tool):
    def __init__(self):
        super().__init__(
            name="internal_api",
            description="调用公司内部 API",
            parameters=[
                ToolParameter(name="endpoint", type="string", required=True),
                ToolParameter(name="method", type="string", required=False, default="GET"),
                ToolParameter(name="payload", type="object", required=False),
            ],
            category="custom",
            requires_approval=True,  # 所有内部 API 调用都需要审批
        )
        # 初始化 API 客户端
        self.client = self._init_api_client()
 
    def _init_api_client(self):
        """初始化 API 客户端,加载认证信息"""
        import os
        token = os.environ.get("INTERNAL_API_TOKEN")
        if not token:
            raise ValueError("环境变量 INTERNAL_API_TOKEN 未设置")
        return APIClient(token=token)
 
    def execute(self, endpoint: str, method: str = "GET", payload: dict = None):
        """执行 API 调用"""
        return self.client.request(endpoint, method, payload)
 
# 注册工具
ToolRegistry().register(InternalAPITool())

Tips

自定义工具放在 ~/.hermes/custom_tools/ 目录下,系统启动时会自动扫描并加载。建议每个工具一个文件,文件名和工具名保持一致,方便管理。开发自定义工具时,一定要写好 description 参数——这是 LLM 理解你工具用途的唯一途径。描述要清晰、具体,最好包含使用示例。


5. Layer 4: 状态与持久化层(SQLite + MEMORY.md + Cron)

5.1 SQLite 数据库设计与 FTS5 全文索引

Layer 4 是 Hermes 的"记忆仓库"。它负责把所有需要长期保存的信息,以可靠、高效、可检索的方式存储起来。

Hermes 选择了 SQLite 作为默认的数据库。这个选择背后有很多考量:

为什么选择 SQLite?

  1. 零配置。 SQLite 是一个嵌入式数据库,不需要单独的服务器进程。数据库就是一个文件,开箱即用。
  2. 单文件存储。 整个数据库在一个 .db 文件中,备份和迁移非常简单——复制文件就行。
  3. 资源占用极低。 对于个人和小团队的场景,SQLite 的性能完全够用,内存和 CPU 开销几乎可以忽略。
  4. Python 原生支持。 Python 标准库内置 sqlite3 模块,不需要额外安装依赖。
  5. FTS5 全文索引。 SQLite 3.19+ 支持 FTS5(Full-Text Search 5),可以实现高效的全文检索。

常见问题

Q:SQLite 能支撑多少数据?会不会成为性能瓶颈?

A:SQLite 的官方文档说,它能处理 TB 级的数据。对于 Hermes 的使用场景(个人/小团队、主要是文本数据),SQLite 的性能完全够用。以每天 100 轮对话、每轮平均 1000 Token 计算,一年的数据量也只有几十 MB。即使数据量增长到 GB 级别,FTS5 索引的查询性能依然很好。如果确实有超大规模的需求,可以配置 Hermes 使用 PostgreSQL 等更强大的数据库(需要自行配置连接)。

数据库表结构:

Hermes 的 SQLite 数据库包含以下核心表:

-- 会话表:存储每个对话会话的元数据
CREATE TABLE sessions (
    id TEXT PRIMARY KEY,           -- 会话唯一 ID
    created_at TIMESTAMP,          -- 创建时间
    updated_at TIMESTAMP,          -- 最后更新时间
    platform TEXT,                 -- 接入平台(cli/telegram/feishu/...)
    user_id TEXT,                  -- 用户标识
    title TEXT,                    -- 会话标题(自动生成的摘要)
    status TEXT,                   -- 状态:active / archived / deleted
    total_turns INTEGER,           -- 总对话轮数
    total_cost REAL                -- 累计成本(美元)
);
 
-- 消息表:存储每条对话消息
CREATE TABLE messages (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    session_id TEXT,               -- 所属会话 ID
    role TEXT,                     -- 角色:user / assistant / system / tool
    content TEXT,                  -- 消息内容
    tool_calls TEXT,               -- 工具调用记录(JSON 格式)
    created_at TIMESTAMP,          -- 发送时间
    tokens_used INTEGER,           -- 消耗的 Token 数
    FOREIGN KEY (session_id) REFERENCES sessions(id)
);
 
-- 工具调用日志表:详细记录每次工具调用
CREATE TABLE tool_calls (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    message_id INTEGER,            -- 关联的消息 ID
    tool_name TEXT,                -- 工具名称
    parameters TEXT,               -- 调用参数(JSON)
    result TEXT,                   -- 执行结果
    duration_ms INTEGER,           -- 执行耗时(毫秒)
    success BOOLEAN,               -- 是否成功
    created_at TIMESTAMP,
    FOREIGN KEY (message_id) REFERENCES messages(id)
);
 
-- 记忆表:存储 MEMORY.md 的历史版本
CREATE TABLE memory_history (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    content TEXT,                  -- MEMORY.md 的内容
    change_reason TEXT,            -- 变更原因(如"自动更新""用户编辑")
    created_at TIMESTAMP
);
 
-- 用户画像表:存储 USER.md 的历史版本
CREATE TABLE user_profile_history (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    content TEXT,                  -- USER.md 的内容
    change_reason TEXT,
    created_at TIMESTAMP
);

FTS5 全文索引:

FTS5 是 SQLite 的全文搜索引擎,它让 Hermes 能够以极快的速度搜索历史对话内容。

-- 创建 FTS5 虚拟表用于全文搜索
CREATE VIRTUAL TABLE messages_fts USING fts5(
    content,                       -- 要索引的字段
    content='messages',            -- 数据来源表
    content_rowid='id'             -- 关联的 rowid
);
 
-- 自动同步触发器:当 messages 表插入/更新/删除时,FTS5 索引自动更新
CREATE TRIGGER messages_fts_insert AFTER INSERT ON messages BEGIN
    INSERT INTO messages_fts(rowid, content) VALUES (new.id, new.content);
END;
 
CREATE TRIGGER messages_fts_delete AFTER DELETE ON messages BEGIN
    INSERT INTO messages_fts(messages_fts, rowid, content)
    VALUES ('delete', old.id, old.content);
END;

有了 FTS5,搜索历史对话就变得非常高效:

-- 搜索包含"Kubernetes"的历史消息
SELECT m.*, rank
FROM messages_fts
JOIN messages m ON messages_fts.rowid = m.id
WHERE messages_fts MATCH 'Kubernetes'
ORDER BY rank;

即使你的历史对话有几十万条,这个查询也能在毫秒级返回结果。

Tips

FTS5 默认使用简单的分词器,对英文支持很好,但对中文的支持有限。如果你主要用中文和 Hermes 交流,建议启用 SQLite 的 ICU 扩展或使用第三方中文分词器(如 jieba)。配置方式是在创建 FTS5 表时指定分词器:CREATE VIRTUAL TABLE ... USING fts5(..., tokenize='icu zh_CN')

5.2 MEMORY.md 的结构与管理

MEMORY.md 是 Hermes 最核心的创新之一。它不是简单的日志文件,而是 Agent 的**"工作笔记"**——Agent 在这里记录环境信息、经验教训、工作约定,以及任何它认为值得记住的东西。

MEMORY.md 的结构:

# MEMORY.md
 
# 这是 Hermes Agent 自动维护的工作笔记
 
# 请不要手动编辑此文件(除非你清楚自己在做什么)
 
## 环境信息
 
- 项目根目录: /home/user/projects
- 操作系统: Ubuntu 22.04
- Python 版本: 3.11.4
- Node.js 版本: 22.3.0
 
## 工作约定
 
- 代码风格: PEP 8
- Commit message: 英文,遵循 Conventional Commits
- 测试框架: pytest
- 优先使用 asyncio 而非同步 I/O
 
## 常用工具链
 
- 包管理: uv
- 代码格式化: ruff
- 类型检查: mypy
- Web 框架: FastAPI
 
## 经验教训
 
- 2026-04-10: Docker 容器访问宿主机服务时,不能用 localhost,要用 host.docker.internal
- 2026-04-12: 使用 OpenRouter 时需要在 header 中加 HTTP-Referer
- 2026-04-15: SQLite 的 FTS5 默认不支持中文分词,需要启用 ICU 扩展
 
## 项目备忘
 
- myapp 项目的数据库密码在 .env 文件中
- myapp 的测试数据库每次运行测试前会自动清空
- 文档站点的构建命令: cd docs && mkdocs build
 
## 偏好设置
 
- 代码注释偏好中文
- 错误处理偏好早失败(fail-fast)模式
- REST API 设计偏好 OpenAPI 规范

MEMORY.md 的管理机制:

  1. 自动更新。 Agent 在每次任务完成后,会自动评估"这次任务中有没有值得记住的东西"。如果有,它会生成一段简短的笔记,追加到 MEMORY.md 中。

  2. 字符限制。 MEMORY.md 有约 2200 字符的上限。当内容接近上限时,系统会触发"记忆压缩"——调用 LLM 对现有内容进行摘要和精简,保留最重要的信息,删除次要的。

  3. 版本历史。 每次 MEMORY.md 更新时,旧版本会自动保存到 SQLite 的 memory_history 表中。如果你发现 Agent 最近"忘了"什么重要的东西,可以从历史版本中找回。

注意

MEMORY.md 虽然是 Agent 自动维护的,但你也可以手动编辑它。如果你发现 Agent 记错了什么,或者想主动告诉 Agent 一些重要信息,直接编辑 ~/.hermes/MEMORY.md 就行。修改后,建议重启 Agent 或发送 /refresh 命令,让 Agent 重新加载记忆。

5.3 USER.md 用户画像存储

如果说 MEMORY.md 是 Agent 的"工作笔记",那么 USER.md 就是 Agent 的"用户档案"——它记录了关于你(用户)的一切信息,让 Agent 越来越懂你。

USER.md 的结构:

# USER.md
 
# 这是关于用户的画像信息
 
# Agent 会根据这个文件调整自己的行为和回复风格
 
## 沟通风格
 
- 偏好简洁直接的回复,不喜欢冗长
- 技术术语不需要解释(假设用户已了解)
- 代码示例优先于文字描述
 
## 技术背景
 
- 全栈开发者,5 年 Python 经验
- 熟悉 FastAPI、PostgreSQL、Docker、Kubernetes
- 正在学习 Rust
 
## 工作习惯
 
- 主要工作时段: 晚上 9 点到凌晨 1 点
- 常用编辑器: VS Code + Neovim
- 操作系统: macOS(主力)+ Ubuntu(服务器)
- 偏好深色主题
 
## 项目信息
 
- 当前主要项目: 一个基于 FastAPI 的 SaaS 平台
- 项目阶段: MVP 开发中
- 技术栈: FastAPI + SQLAlchemy + React + PostgreSQL
 
## 偏好设置
 
- 时区: Asia/Shanghai (UTC+8)
- 语言: 中文优先,技术术语保留英文
- 代码风格: Black formatter, 88 字符行宽

USER.md 的自动生成与更新:

和 MEMORY.md 类似,USER.md 也是由 Agent 自动维护的。但它的更新频率更低、内容更稳定。

Agent 会在以下场景更新 USER.md:

  • 用户明确告诉 Agent 自己的偏好("我喜欢简洁的回复")
  • Agent 在长期互动中观察到的规律("用户总是在晚上 9 点后发消息")
  • 用户纠正了 Agent 的某种行为("请不要用这么多表情符号")

USER.md 同样有字符限制(约 1375 字符),迫使 Agent 学会"抓重点"——只记录最关键的用户信息。

Tips

USER.md 是你塑造 Agent 行为的最直接方式。如果你希望 Agent 以某种特定方式与你互动,直接在对话中告诉它,比如"以后回复我时,先给出结论再解释原因"。Agent 会把这条偏好记录到 USER.md 中,并在后续的对话中遵循。如果它没有遵循,你可以提醒它"看看你的 USER.md",它通常会立刻纠正。

5.4 Cron 定时任务调度器

Hermes 内置了一个 Cron 定时任务调度器,让 Agent 可以在指定的时间自动执行预设的任务。

你可以把它理解为 Hermes 的"闹钟"和"日程表"。

设置定时任务的方式:

# 方式一:通过对话自然语言设置
hermes
> 每天早上 9 点检查 Hacker News 的 AI 新闻,发摘要到我的 Telegram
 
# 方式二:通过命令行精确设置
hermes cron add "0 9 * * *" \
  --task "搜索 Hacker News 的 AI 标签,提取前 10 条新闻的标题和摘要,发送到 Telegram"
 
# 方式三:编辑配置文件

定时任务的配置存储在 SQLite 数据库中:

CREATE TABLE cron_jobs (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT,                     -- 任务名称
    schedule TEXT,                 -- Cron 表达式,如 "0 9 * * *"
    task_description TEXT,         -- 任务描述(自然语言)
    enabled BOOLEAN,               -- 是否启用
    last_run TIMESTAMP,            -- 上次执行时间
    next_run TIMESTAMP,            -- 下次执行时间
    run_count INTEGER,             -- 已执行次数
    fail_count INTEGER,            -- 失败次数
    created_at TIMESTAMP
);

Cron 表达式快速参考:

格式: 分 时 日 月 星期

0 9 * * *      # 每天早上 9:00
0 */6 * * *    # 每 6 小时一次
0 0 * * 1      # 每周一凌晨
0 0 1 * *      # 每月 1 号凌晨
*/15 * * * *   # 每 15 分钟

注意

Cron 任务在后台执行时,如果遇到需要用户审批的危险操作,默认会被拒绝(因为没有用户在终端前确认)。如果你的定时任务涉及危险操作,可以在配置中设置 cron.auto_approve_safe_tools = true,让已知安全的工具自动通过审批。但对于真正危险的操作(如删除文件、执行 shell 命令),建议避免在无人值守的定时任务中使用。

5.5 数据备份与恢复策略

既然 Hermes 的所有数据都存储在本地,备份就变得非常重要。如果硬盘损坏或误删文件,你可能会丢失所有的对话历史、记忆和技能。

备份策略:

Hermes 的数据主要存储在以下几个位置:

数据类型存储位置备份方式
对话历史~/.hermes/data/conversations.db定期复制 + SQLite 导出
MEMORY.md~/.hermes/MEMORY.md版本控制(Git)
USER.md~/.hermes/USER.md版本控制(Git)
配置文件~/.config/hermes/版本控制(Git)
自定义工具~/.hermes/custom_tools/版本控制(Git)
技能文件~/.hermes/skills/版本控制(Git)

推荐的备份脚本:

#!/bin/bash
# hermes-backup.sh - Hermes 数据备份脚本
# 建议添加到 crontab,每天自动运行
 
BACKUP_DIR="$HOME/hermes-backups"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/hermes_backup_$DATE.tar.gz"
 
# 创建备份目录
mkdir -p "$BACKUP_DIR"
 
# 打包所有 Hermes 数据
tar -czf "$BACKUP_FILE" \
  "$HOME/.hermes/" \
  "$HOME/.config/hermes/"
 
# 保留最近 30 天的备份,删除旧的
find "$BACKUP_DIR" -name "hermes_backup_*.tar.gz" -mtime +30 -delete
 
echo "备份完成: $BACKUP_FILE"

添加到定时任务:

# 编辑 crontab
crontab -e
 
# 添加以下行(每天凌晨 2 点自动备份)
0 2 * * * /path/to/hermes-backup.sh >> /var/log/hermes-backup.log 2>&1

Tips

如果你的 Hermes 部署在云服务器上,建议把备份文件同步到对象存储(如 AWS S3、阿里云 OSS)或另一台机器上。不要把备份和原始数据放在同一个硬盘上——否则硬盘坏了,备份也一起没了。可以使用 rclone 工具来自动化这个同步过程。


6. Layer 5: 平台适配层(15+ 平台、6 种终端后端)

6.1 平台适配器的设计模式

Layer 5 是 Hermes 的"外交部门"——它负责和外面的世界打交道。

不同的消息平台,有着不同的 API 格式、消息类型和交互方式。Telegram 用 Bot API,飞书用开放平台的 webhook,Discord 用 Gateway 事件,微信用企业微信的接口……如果让 Agent 核心层直接去处理这些差异,代码会变得非常混乱。

Hermes 的解决方案是适配器模式(Adapter Pattern)——为每个平台写一个适配器,把平台的"方言"翻译成 Hermes 的"普通话"。

用户发送消息(通过 Telegram)
    ↓
[Telegram 适配器] 接收 Telegram 的 Update 对象
    ↓
[Telegram 适配器] 转换成 Hermes 内部的 Message 对象
    ↓
[Agent 核心层] 处理 Message,生成回复
    ↓
[Telegram 适配器] 把 Hermes 的回复转换成 Telegram 的 sendMessage 调用
    ↓
用户收到回复(在 Telegram 中)

每个适配器都需要实现以下接口:

# 平台适配器的标准接口(简化版)
class PlatformAdapter(ABC):
    @abstractmethod
    async def initialize(self) -> None:
        """初始化适配器,建立连接"""
        pass
 
    @abstractmethod
    async def receive_message(self) -> Message:
        """接收来自平台的消息"""
        pass
 
    @abstractmethod
    async def send_message(self, message: Message) -> None:
        """发送消息到平台"""
        pass
 
    @abstractmethod
    async def send_file(self, file_path: str, caption: str = None) -> None:
        """发送文件到平台"""
        pass
 
    @abstractmethod
    def format_text(self, text: str, style: TextStyle) -> str:
        """将文本格式化为平台支持的格式"""
        pass
 
    @property
    @abstractmethod
    def supported_features(self) -> list[str]:
        """返回该平台支持的功能列表"""
        pass

当前支持的平台:

平台接入方式支持功能
TelegramBot API文本、图片、文件、按钮、Markdown
DiscordBot Gateway文本、Embed、文件、Reaction
SlackBolt SDK / Webhook文本、Block Kit、文件、按钮
飞书开放平台 Webhook文本、富文本、卡片、文件
企业微信企业微信 API文本、Markdown、文件、图文
钉钉钉钉开放平台文本、Markdown、ActionCard
微信个人号/公众号 API文本、图片、文件
WhatsAppWhatsApp Business API文本、图片、文件
SignalSignal CLI / API文本、文件
MatrixMatrix Client-Server API文本、HTML、文件
MattermostMattermost API文本、Markdown、文件
EmailSMTP/IMAP文本、HTML、附件
SMSTwilio / 短信网关纯文本
Home AssistantWebSocket API文本、事件触发
VS CodeACP 协议文本、代码块、Diff

Tips

不是所有平台的所有功能都完美支持。比如,某些平台不支持 Markdown 格式,Hermes 会自动降级为纯文本;某些平台有消息长度限制,Hermes 会自动拆分长消息。在配置平台接入时,建议先测试一下常用的功能(文本、代码块、文件传输),看看是否符合你的需求。

6.2 6 种终端后端的选择与配置

除了消息平台,Hermes 还支持 6 种终端后端(Terminal Backend)。终端后端决定了 Agent 执行命令和代码的环境。

后端描述适用场景
local直接在宿主机上执行个人开发、测试
docker在 Docker 容器中执行隔离要求高的场景
ssh通过 SSH 在远程服务器上执行远程运维、多服务器管理
sandbox在轻量级沙箱中执行安全敏感环境
wsl在 WSL(Windows Subsystem for Linux)中执行Windows 开发者
cloud在云函数/Serverless 环境中执行弹性伸缩场景

配置方式:

# 查看当前终端后端
hermes config get terminal.backend
 
# 切换到 Docker 后端
hermes config set terminal.backend docker
 
# Docker 后端的额外配置
hermes config set terminal.docker.image "hermes-sandbox:latest"
hermes config set terminal.docker.volumes '["/home/user/projects:/workspace"]'
 
# 切换到 SSH 后端
hermes config set terminal.backend ssh
hermes config set terminal.ssh.host "192.168.1.100"
hermes config set terminal.ssh.user "deploy"
hermes config set terminal.ssh.key "~/.ssh/deploy_key"

Docker 后端的工作原理:

Agent 请求执行命令: python script.py
    ↓
[Hermes] 启动 Docker 容器(如果尚未运行)
    ↓
[Hermes] 在容器中执行: python script.py
    ↓
[Hermes] 捕获 stdout / stderr
    ↓
[Hermes] 销毁临时容器(或保留复用)
    ↓
[Hermes] 把结果返回给 Agent

Docker 后端的最大优势是隔离性。即使 Agent 执行了恶意或错误的命令(如 rm -rf /),破坏范围也仅限于容器内部,不会影响宿主机。

注意

Docker 后端虽然提供了隔离,但不是"绝对安全"的。如果容器以特权模式运行,或者挂载了敏感目录,恶意代码仍然可能逃逸容器。最安全的做法是:非特权容器 + 最小挂载 + 只读根文件系统。对于不可信的任务,建议使用 sandbox 后端,它提供了更严格的隔离。

6.3 消息格式转换与统一接口

不同平台的消息格式千差万别。Hermes 定义了一个统一的消息接口(Unified Message Interface),所有平台适配器都围绕这个接口工作。

统一消息结构:

@dataclass
class Message:
    id: str                      # 消息唯一 ID
    platform: str                # 来源平台
    platform_message_id: str     # 平台原生的消息 ID
    session_id: str              # 所属会话
    user_id: str                 # 发送者 ID
    user_name: str               # 发送者名称
    content: str                 # 消息文本内容
    content_type: str            # 内容类型: text / code / image / file / mixed
    attachments: list[Attachment]  # 附件列表
    reply_to: str                # 回复的消息 ID(如果有)
    mentions: list[str]          # @提及的用户列表
    timestamp: datetime          # 发送时间
    metadata: dict               # 平台特有的额外数据
 
@dataclass
class Attachment:
    type: str                    # 类型: image / video / audio / document
    url: str                     # 文件 URL
    filename: str                # 文件名
    mime_type: str               # MIME 类型
    size_bytes: int              # 文件大小

格式转换示例:

以 Telegram 为例,当用户发送一条带图片的消息时:

# Telegram 的原始格式(Bot API)
telegram_update = {
    "update_id": 123456789,
    "message": {
        "message_id": 42,
        "from": {"id": 987654321, "first_name": "张三"},
        "chat": {"id": 987654321, "type": "private"},
        "date": 1713600000,
        "caption": "帮我看看这张图里的代码有什么问题",
        "photo": [
            {"file_id": "AgACAgIAAxkBAA...", "width": 320, "height": 240},
            {"file_id": "AgACAgIAAxkBAA...", "width": 800, "height": 600},
        ]
    }
}
 
# Telegram 适配器转换成 Hermes 的统一消息
hermes_message = Message(
    id="msg_tg_987654321_42",
    platform="telegram",
    platform_message_id="42",
    session_id="sess_tg_987654321",
    user_id="987654321",
    user_name="张三",
    content="帮我看看这张图里的代码有什么问题",
    content_type="mixed",
    attachments=[
        Attachment(
            type="image",
            url="https://api.telegram.org/file/bot<token>/photos/xxx.jpg",
            filename="photo.jpg",
            mime_type="image/jpeg",
            size_bytes=0,  # 需要额外请求获取大小
        )
    ],
    reply_to=None,
    mentions=[],
    timestamp=datetime.fromtimestamp(1713600000),
    metadata={"telegram_chat_type": "private"},
)

这种"统一接口"的设计,让 Agent 核心层完全不需要关心消息来自哪个平台。它看到的永远是标准的 Message 对象,处理逻辑完全一致。

6.4 平台特性的处理

不同平台有不同的"超能力"。Hermes 的适配器会尽可能利用这些平台特性,提升用户体验。

富文本渲染:

Telegram 和 Discord 原生支持 Markdown,Agent 的回复可以直接渲染为格式化的文本。但微信和企业微信对 Markdown 的支持有限,适配器会自动降级为纯文本,或者用平台的原生富文本格式(如企业微信的 markdown 消息类型)。

# Agent 生成的回复(内部格式)
reply_text = """
## 分析结果
 
- **问题**: 循环变量未初始化
- **位置**: `main.py` 第 42 行
- **建议**: 在使用 `i` 之前添加 `i = 0`
 
```python
# 修复后的代码
for i in range(10):
    print(i)

"""

Telegram 适配器 → 直接发送 Markdown

微信适配器 → 转换为纯文本(或图文消息)

飞书适配器 → 转换为富文本卡片


**交互按钮:**

Telegram、Discord 和 Slack 支持内联按钮(Inline Buttons)。Hermes 的适配器可以把"选择型"的回复转换为按钮:

```python
# Agent 的回复包含选择
"我找到了 3 个可能的解决方案,你想看哪个?\n1. 方案 A\n2. 方案 B\n3. 方案 C"

# Telegram 适配器会渲染为:
# [方案 A] [方案 B] [方案 C]
# 用户点击按钮即可选择,不需要手动输入数字

文件传输:

当 Agent 生成文件(如代码、报告、图片)时,适配器会根据平台的能力选择最佳传输方式:

  • Telegram:直接发送文件
  • 微信:上传到文件助手或群文件
  • Email:作为附件发送
  • CLI:保存到指定目录并显示路径

常见问题

Q:某个平台我配置了但收不到消息,怎么排查?

A:按照以下步骤排查:

  1. 检查平台适配器是否已启用:hermes gateway status
  2. 检查 Webhook URL 是否正确配置,并且公网可访问
  3. 检查平台侧的事件订阅是否正确设置
  4. 查看 Hermes 的日志:tail -f ~/.hermes/logs/gateway.log
  5. 尝试手动触发一个测试消息,看日志里有没有收到

Q:可以在多个平台上同时使用同一个 Agent 吗?

A:可以!GatewayRunner 支持同时接入多个平台。你只需要为每个平台分别配置适配器,它们会共享同一个 Agent 实例和同一套记忆数据。这意味着你在 Telegram 上和 Agent 的对话,Agent 在 Slack 上也能记得。不过要注意:如果多个平台同时发来消息,Agent 是按顺序处理的(单线程),可能会有延迟。


7. 自学习闭环:Hermes 的灵魂

如果说五层架构是 Hermes 的"骨架",那么自学习闭环就是它的"灵魂"。这是 Hermes 与 OpenClaw 以及市面上绝大多数 Agent 框架最根本的区别所在。

7.1 完整闭环流程详解:执行 → 评估 → 创建 → 改进

Nous Research 对 Harness Engineering 的官方定义给出了五个核心层次:指令层(如何与模型对话)、约束层(允许做什么)、反馈层(错误如何回流)、记忆层(什么持久化)、编排层(多工具如何串联)。自学习闭环正是贯穿这五个层次的"活性机制"——它让系统不是被动地执行指令,而是主动地从经验中成长。

让我们用一个完整的例子,来走一遍自学习闭环的四个阶段。

场景: 你让 Hermes 帮你"把项目里的所有 Python 文件按照 PEP 8 规范格式化一遍"。

阶段一:执行(Execute)

Agent 收到任务后,开始规划和执行:

步骤 1: 搜索项目中的所有 .py 文件
  → 调用 tool: file_search(pattern="**/*.py")
  → 结果: 找到 15 个 Python 文件

步骤 2: 检查是否有格式化工具可用
  → 调用 tool: shell_exec(command="which black ruff autopep8")
  → 结果: 发现 black 和 ruff 已安装

步骤 3: 先用 black 格式化一个文件试试
  → 调用 tool: shell_exec(command="black src/main.py --check")
  → 结果: 发现 23 处格式问题

步骤 4: 执行格式化
  → 调用 tool: shell_exec(command="black src/main.py")
  → 结果: 格式化成功

步骤 5-17: 对其余 14 个文件重复上述过程...

步骤 18: 用 ruff 检查一遍,确保没有遗漏
  → 调用 tool: shell_exec(command="ruff check .")
  → 结果: 全部通过

这个执行过程涉及了 18 次工具调用。Agent 不是一次性把所有事情做完,而是逐步探索、观察结果、调整策略——这和人类解决新问题的思维方式是一致的。

阶段二:评估(Evaluate)

任务完成后,Agent 会运行一次自我回顾(Self-Review)。这是 Nous Research 官方描述的核心机制——每 5 次左右工具调用,Hermes 会问自己四个问题:

  1. 有效吗? —— 任务目标达成了吗?有没有遗漏?
  2. 什么太慢? —— 哪些步骤可以优化?有没有不必要的重复?
  3. 用户拒绝了什么? —— 用户有没有中途干预、纠正或取消某个操作?
  4. 有可复用模式吗? —— 这个任务的解决思路,能不能抽象成一个通用的方法?

在这个例子中,Agent 的自我评估可能是这样的:

## 任务回顾: Python 代码格式化
 
### 有效性评估
 
- ✅ 成功格式化了 15 个 Python 文件
- ✅ 通过了 ruff 检查
- ⚠️ 文件较多时,逐个执行效率较低
 
### 效率评估
 
- 问题: 对每个文件单独调用 black,产生了 15 次工具调用
- 优化: black 支持批量处理,可以用 `black .` 一次性格式化整个目录
- 节省时间: 约 60%(15 次调用 → 1 次调用)
 
### 用户反馈
 
- 用户没有干预或纠正
- 用户对结果表示满意
 
### 可复用模式
 
- 这是一个典型的"批量代码格式化"任务
- 通用模式: 搜索文件 → 选择工具 → 批量执行 → 验证结果
- 建议创建 Skill: "batch_format_python"

Tips

自我回顾不是每次任务都一定会触发。官方的设计是:每完成约 5 次工具调用的任务后,系统会评估是否值得进行一次回顾。如果任务非常简单(比如只调用了 1-2 个工具),回顾的成本可能大于收益,系统就会跳过。这种"选择性回顾"的机制,既保证了学习的发生,又避免了不必要的开销。

阶段三:创建(Create)

如果自我回顾发现"有可复用的模式",系统就会触发 Skill 自动生成

但这里有一个非常重要的规则——技能不会在每次任务后自动生成。根据 Nous Research 的官方描述,Skill 的创建需要满足特定的触发条件:

触发条件一:检测到重复模式(通常涉及 5+ 工具调用)

Agent 会维护一个"任务指纹"数据库。每次完成任务后,它计算任务的模式指纹(涉及哪些工具、工具的调用顺序、参数特征等)。如果某个指纹出现了多次(或一次但工具调用次数超过阈值),就认为这是一个"值得固化的模式"。

触发条件二:用户进行了纠正

如果用户说"不对,你应该这样做",Agent 会把用户的纠正视为高价值信号。即使用户纠正的是一件小事,Agent 也会记录下来——因为这代表了用户的真实偏好。

触发条件三:遇到错误并最终找到了可行路径

如果 Agent 在执行过程中遇到了错误(如工具调用失败、返回了异常数据),然后通过尝试不同的方法最终解决了问题,这个"试错 → 成功"的过程会被视为一个值得学习的模式。

触发条件四:发现了非显而易见的工作流

有些任务的解决方案需要多个工具以特定顺序协作,这种"组合智慧"是人类可能想不到的。当 Agent 自己发现了这样的工作流时,它会意识到"这个方法很有价值,应该记下来"。

在我们的例子中,Agent 满足了触发条件一(18 次工具调用,远超 5 次阈值),所以会生成一个 Skill:

# Skill: batch_format_python
 
# 自动生成于: 2026-04-15
 
# 触发原因: 任务涉及 18 次工具调用,检测到可复用的批量格式化模式
 
## 描述
 
批量格式化项目中的所有 Python 文件,确保符合 PEP 8 规范。
 
## 适用场景
 
- 项目中有多个 Python 文件需要统一格式
- 需要确保代码风格一致性
- 在提交代码前进行格式化检查
 
## 执行流程
 
1. 搜索项目中的所有 .py 文件
2. 检查可用的格式化工具(black / ruff / autopep8)
3. 优先使用 black 进行批量格式化: `black .`
4. 使用 ruff 进行静态检查: `ruff check .`
5. 如果有错误,尝试自动修复: `ruff check . --fix`
6. 报告结果
 
## 注意事项
 
- 批量格式化前,建议先运行 `black --check` 查看有哪些文件需要修改
- 如果项目中有特定的格式化配置(如 pyproject.toml),工具会自动读取
- 格式化会修改文件内容,确保文件已提交到版本控制
 
## 历史表现
 
- 创建后已使用: 3 次
- 成功率: 100%
- 平均工具调用次数: 3 次(相比首次的 18 次,效率提升 83%)

阶段四:改进(Improve)

Skill 创建后,并不是一成不变的。每次 Skill 被再次使用时,Agent 都会观察执行效果,并在必要时对 Skill 进行修补和优化。

比如,两周后你又让 Agent 格式化 Python 文件。这次 Agent 直接调用了 batch_format_python Skill,流程简化为:

步骤 1: 调用 Skill "batch_format_python"
  → 执行: black .
  → 结果: 报错!black 的版本更新了,某个参数已弃用

步骤 2: 错误检测与修复
  → Agent 发现 black 的新版本不再支持旧参数
  → Agent 自动修改 Skill 文件,更新命令
  → 更新后的命令: black . --line-length 88

步骤 3: 重新执行
  → 执行: black . --line-length 88
  → 结果: 成功

步骤 4: Skill 更新
  → 把修正后的命令写回 Skill 文件
  → 添加注释: "2026-04-29: 适配 black 24.x 版本"

关键:无需用户干预,Agent 自主完成!

整个过程用户只需要说"帮我格式化 Python 文件",Agent 会自动调用已有的 Skill、自动检测错误、自动修复 Skill、自动完成任务。用户甚至不知道中间发生了什么——只看到一个成功的结果,和一条简短的日志:"Skill 'batch_format_python' 已自动更新以适配新版本的 black"。

7.2 触发条件详解

根据 Nous Research 的官方描述,我们再来系统梳理一下自学习闭环的触发条件:

触发条件描述优先级
5+ 工具调用任务涉及 5 次或更多工具调用,表明复杂度足够高
错误修复遇到错误后找到了可行的替代路径
用户纠正用户明确纠正了 Agent 的做法最高
非显而易见的工作流Agent 自主发现了高效的工具组合方式
周期性任务相同或相似的任务在固定周期重复出现

用户纠正为什么优先级最高?

因为用户的纠正代表了"真实的人类偏好",这是最有价值的学习信号。Agent 可能会误判什么是最优方案,但用户知道自己想要什么。当用户说"不要这样做,要那样做"时,Agent 会把这条纠正视为"黄金规则",优先记录和应用。

7.3 技能的四个信任等级

在深入了解 Skill 的生成算法之前,我们需要先理解 Hermes 的技能信任等级体系。根据 Nous Research 的官方设计,所有 Skill 被分为四个信任等级,这个分级机制是安全架构的重要组成部分。

信任等级英文名来源安全策略
内置Built-in随 Hermes 核心框架一起发布完全信任,自动启用
官方OfficialNous Research 官方维护的技能库高信任,需手动安装但无需额外审批
可信Verified经过社区审核的第三方技能中信任,安装时提示风险说明
社区Community未经审核的社区贡献低信任,使用时需要额外审批

内置技能(Built-in):

内置技能是 Hermes 核心代码库的一部分,随框架一起安装。它们经过 Nous Research 团队的严格测试,是"开箱即用"的。当前 Hermes 包含 74 个内置技能,涵盖了最常用的开发工作流。

内置技能的特点是:

  • 与 Hermes 核心版本同步更新
  • 有完整的单元测试覆盖
  • 不会自动连接外部网络(除非用户明确配置)
  • 执行时不需要额外的用户审批

官方技能(Official):

官方技能由 Nous Research 维护,但不随核心框架一起发布。它们存放在官方的技能仓库中,用户需要手动安装:

hermes skills browse          # 浏览官方技能库
hermes skills install k8s     # 安装 Kubernetes 相关技能
hermes skills install git-pr  # 安装 Git PR 工作流技能

当前官方可选技能有 44 个。这些技能同样经过官方测试,但因为它们针对特定场景(如 Kubernetes、MLOps、特定 SaaS 工具),不适合所有用户,所以没有内置。

可信技能(Verified):

可信技能来自社区贡献者,但经过了 Nous Research 或核心维护者的审核。审核内容包括:

  • 代码安全性检查(是否包含恶意操作)
  • 功能正确性验证
  • 文档完整性检查
  • 依赖项安全扫描

审核通过后,技能会被标记为"Verified",在 Skills Hub 中显示特殊的信任徽章。

社区技能(Community):

社区技能是任何人都可以上传和分享的 Skill,未经审核。当前 Skills Hub 上有 521 个社区技能,加上内置和官方的,总计 639 个技能

社区技能的使用策略是"谨慎乐观":

  • 安装时会显示明确的"未审核"警告
  • 首次执行时,所有涉及的工具调用都需要用户审批
  • 用户可以查看 Skill 的源代码(所有 Skill 都是明文文档),自行判断安全性
  • 使用几次后如果没有问题,可以选择"信任此 Skill",后续不再逐个审批

Tips

技能信任等级不是固定不变的。一个社区技能如果被大量用户使用、积累了良好的评价、且作者愿意配合审核,它可以被提升为"可信"甚至"官方"等级。反过来,如果一个官方技能长期无人维护、与新版 Hermes 不兼容,它也可能被降级。这种动态的等级机制,激励了技能作者持续维护和改进自己的作品。

7.4 Skill 自动生成的算法逻辑

Skill 自动生成背后的算法,是 Hermes 最精妙的技术实现之一。让我们掀开盖子,看看里面是怎么运转的。

步骤一:任务模式提取

Agent 完成任务后,系统会提取任务的"模式指纹":

# 任务模式指纹(简化版)
task_pattern = {
    "tool_sequence": [        # 工具调用序列
        "file_search",
        "shell_exec",
        "shell_exec",
        "shell_exec",
        ...
    ],
    "tool_categories": [      # 涉及的类别
        "filesystem",
        "system",
    ],
    "parameter_patterns": {   # 参数模式
        "file_search.pattern": "**/*.py",
        "shell_exec.command": "black*",
    },
    "execution_time_ms": 15000,
    "success": True,
    "user_intervention": False,
}

步骤二:模式匹配与去重

系统会把当前任务的模式,和已有的 Skill 库进行比对:

  • 如果匹配度 > 90%,认为这个任务已经被 Skill 覆盖了,不需要新建
  • 如果匹配度在 50%-90% 之间,认为这是对现有 Skill 的扩展或变体,更新现有 Skill
  • 如果匹配度 < 50%,认为这是一个全新的模式,创建新的 Skill

步骤三:Skill 内容生成

对于需要新建的 Skill,系统会调用 LLM 生成 Skill 文档。输入包括:

  • 任务的原始需求
  • 完整的工具调用历史(含参数和结果)
  • 自我回顾的评估报告
  • 类似 Skill 的参考模板

LLM 基于这些信息,生成结构化的 Skill 文档——包括描述、适用场景、执行流程、注意事项等。

步骤四:质量校验

生成的 Skill 不是直接生效的,而是要经过一轮质量校验:

  1. 语法校验 —— Skill 文件格式是否正确?
  2. 引用校验 —— Skill 中引用的工具是否都存在?
  3. 安全校验 —— Skill 中是否包含危险操作?是否需要标记为 requires_approval?
  4. 效果校验 —— 用同一个任务测试 Skill 的效果,确认它能复现成功的结果

只有通过所有校验的 Skill,才会被正式加入 Skill 库。

7.5 技能进化的版本管理

Skill 不是静态的文档,而是会不断进化的"活知识"。Hermes 为每个 Skill 维护了版本历史:

skills/
├── batch_format_python/
│   ├── skill.md           # 当前版本
│   ├── skill.v1.md        # 版本 1(创建时)
│   ├── skill.v2.md        # 版本 2(修复了 black 参数)
│   └── skill.v3.md        # 版本 3(增加了 ruff 自动修复步骤)

每次 Skill 被修改时,旧版本会被保留,新版本会成为默认使用的版本。这种版本管理的好处是:

  • 如果新版本的 Skill 出了问题,可以方便地回滚到旧版本
  • 可以对比不同版本的差异,观察 Skill 的进化轨迹
  • 多个 Agent 实例可以共享 Skill,但各自保持独立的版本偏好

注意

Skill 的版本管理是自动的,但你也可以手动干预。如果你发现某个 Skill 的最新版本不如旧版本好用,可以手动恢复旧版本:hermes skills restore batch_format_python --version 2。或者你也可以编辑 Skill 文件,手动优化它的内容。Agent 会尊重你的手动修改,并在未来的自动更新中保留你的改动。

7.6 社区实测数据:重复任务成功率提升 30%+

自学习闭环的效果如何?让我们看看社区用户的实测数据。

根据 Nous Research 在社区中收集的数据,以及本书作者对数十位用户的访谈,我们总结出了以下关键指标:

指标一:重复任务效率提升

任务类型首次执行(工具调用次数)复用时(工具调用次数)效率提升
Python 代码格式化18 次3 次83%
部署到 Kubernetes25 次5 次80%
数据库迁移15 次4 次73%
生成周报12 次2 次83%
API 接口测试20 次6 次70%

指标二:成功率提升

根据社区问卷(N=120),用户报告了以下体验:

  • 78% 的用户 表示,Agent 在处理重复任务时的成功率明显提升
  • 平均提升幅度约 35% —— 从首次执行的约 65% 成功率,提升到复用 Skill 后的约 88% 成功率
  • 成功率提升的主要原因
    • Skill 固化了的正确路径(避免重复犯错)
    • Skill 中记录了注意事项(提前规避已知问题)
    • Skill 的参数经过优化(更精确的调用)

指标三:用户干预减少

  • 首次执行复杂任务时,用户平均需要干预 3.2 次(纠正、确认、补充信息)
  • Skill 复用时,用户平均只需要干预 0.4 次
  • 干预次数减少约 87%

这些数据表明,自学习闭环不是一个"炫技"的功能,而是能带来实实在在的效率提升的核心机制。

7.7 与强化学习的类比

自学习闭环的设计,和机器学习中的**强化学习(Reinforcement Learning)**有一些有趣的相似之处。

在强化学习中:

  • Agent 在环境中执行动作
  • 环境 返回奖励(正向或负向)
  • Agent 根据奖励调整策略,目标是最大化长期累积奖励

在 Hermes 的自学习闭环中:

  • Agent 执行任务(执行动作)
  • 结果 告诉 Agent 任务是否成功(奖励信号)
  • Skill 的创建和改进 就是策略的调整

但两者之间也有重要的区别:

维度强化学习Hermes 自学习闭环
学习速度需要大量试错(数百万次)几次成功体验即可
目标定义需要人工设计奖励函数目标隐含在任务完成度中
泛化能力需要大量数据才能泛化基于 LLM 的推理能力,少量数据即可抽象
可解释性策略通常是黑盒(神经网络)Skill 是人类可读的文档
安全性可能学到危险策略有命令审批和预算机制约束

Hermes 的自学习闭环,可以看作是一种**"轻量级强化学习"**——它借鉴了强化学习的核心思想(从经验中学习),但通过 LLM 的推理能力大大减少了所需的试错次数,同时通过 Skill 文档的形式保证了可解释性和可审计性。


8. 记忆系统架构:四层温度模型

8.1 热记忆(即时):当前会话上下文

Hermes 的记忆系统采用了 Nous Research 官方定义的四层温度模型。这个模型的核心思想是:不同重要程度的信息,应该存储在不同"温度"的记忆中,并以不同的频率被检索和使用。

热记忆(Hot Memory) 是最"热"的一层——它就在 Agent 的"眼前",是 Agent 当前能直接看到的所有信息。

热记忆包括:

  • 当前会话的系统提示(System Prompt)
  • MEMORY.md 的内容(Agent 的工作笔记)
  • USER.md 的内容(用户画像)
  • 当前会话的最近 N 轮对话历史
  • 当前任务相关的 Skill 内容
  • 可用的工具描述(按需加载)

热记忆的特点是:访问速度极快(内存中)、信息完整、但容量有限。 热记忆的总 Token 数不能超过模型的上下文窗口上限。当热记忆接近上限时,系统会启动"降温"机制——把较旧的信息转移到温记忆或冷记忆中。

热记忆的容量限制:
┌─────────────────────────────────────────┐
│  系统提示 + MEMORY.md + USER.md          │  ← 固定占用
│  (~500-1000 tokens)                     │
├─────────────────────────────────────────┤
│  当前会话对话历史                         │  ← 动态占用
│  (~剩余空间的 60%)                       │
├─────────────────────────────────────────┤
│  工具描述 + Skill 内容                    │  ← 按需加载
│  (~剩余空间的 40%)                       │
└─────────────────────────────────────────┘
        总容量 = 模型的上下文窗口上限

Tips

如果你觉得 Agent "忘了"刚刚说过的话,可能是因为当前会话的对话历史太长,旧的消息被"挤出"了热记忆。你可以发送 /summary 命令,让 Agent 生成会话摘要,把之前的对话压缩成一段简短的总结。这样既能保留关键信息,又能释放热记忆空间。

8.2 温记忆(持久):MEMORY.md + USER.md

温记忆(Warm Memory) 是热记忆的"后备存储"。它不像热记忆那样随时在 Agent 的"眼前",但每次新会话开始时,它会被加载到热记忆中。

温记忆的核心载体就是两个文件:

  • MEMORY.md(约 2200 字符上限)
  • USER.md(约 1375 字符上限)

这两个文件的字符限制,是 Nous Research 刻意设计的"有界记忆"机制。根据官方的设计理念:有限容量不是缺陷,而是特性。

为什么有限容量是"特性"?让我们深入理解这个设计哲学:

假设一:无限记忆 → 信息膨胀 → 检索噪声 → 效率下降

如果 Agent 可以把所有事情都记下来,它的"笔记"会越来越厚。每次做决策时,它都要在厚厚的笔记中翻找相关信息。笔记越厚,翻找越慢,找到错误信息的概率也越高。最终,Agent 会被自己的记忆淹没。

这就像一个从不扔东西的囤积者——他的房子里堆满了物品,需要某样东西时,反而很难找到。

假设二:有限容量 → 被迫整合 → 精简上下文 → 效率提升

当 Agent 知道"我只能记这么点东西"时,它被迫学会优先级管理。每次更新 MEMORY.md 时,它都要判断:这条信息重要吗?值得替换掉已有的某条信息吗?有没有办法把两条信息合并成一条更精炼的?

这种"被迫精简"的过程,实际上提升了信息的质量。留下来的,都是 Agent 认为最重要、最有用的信息。

就像一个背包容量有限的旅行者——他不能把所有东西都带着,只能精选最必要的物品。这个约束,反而让他的行囊更高效。

有界记忆的设计理念:

无限记忆                    有界记忆
    ↓                         ↓
什么都记                    只记最重要的
    ↓                         ↓
上下文膨胀                  上下文精简
    ↓                         ↓
检索噪声大                  检索精准
    ↓                         ↓
缓存失效                    缓存命中率高
    ↓                         ↓
效率下降                    效率提升

注意

有界记忆的设计,依赖于 LLM 的"摘要能力"。如果 LLM 在压缩记忆时丢失了关键信息,效果就会打折扣。因此,Nous Research 在 MEMORY.md 的更新算法中加入了"关键信息保留"策略——某些类型的信息(如环境配置、安全规则)被标记为"不可删除",在压缩时优先保留。你也可以通过配置,手动标记某些信息为"高优先级"。

8.3 冷记忆(检索):SQLite + FTS5 + LLM 摘要

冷记忆(Cold Memory) 是存储量最大、但访问频率最低的一层。它包括:

  • SQLite 数据库中的所有历史对话
  • 过去的 MEMORY.md 版本
  • 过去的 USER.md 版本
  • 工具调用日志
  • Skill 的历史版本

冷记忆的特点是:存储量大(GB 级别)、访问需要检索、检索结果需要进一步处理。

当 Agent 需要查找某个久远的记忆时,流程是这样的:

Agent: "用户之前提到过一个 Docker 网络问题的解决方法,我不记得具体是什么了"
    ↓
[冷记忆检索] 使用 FTS5 搜索关键词 "Docker" "网络"
    ↓
FTS5 返回: 3 条相关对话(来自 2 个月前的会话)
    ↓
[LLM 摘要] 把 3 条对话的内容发送给 LLM,请求生成摘要
    ↓
LLM 返回摘要: "2026-02-20,用户在部署 Flask 应用时遇到 Docker 容器无法访问宿主机服务的问题。解决方案是使用 host.docker.internal 替代 localhost。"
    ↓
[加载到热记忆] 把摘要加入当前上下文
    ↓
Agent: "我想起来了!Docker 容器访问宿主机要用 host.docker.internal"

这个"检索 → 摘要 → 加载"的流程,有几个关键设计:

  1. FTS5 负责快速筛选。 从海量历史记录中,秒级定位到相关记录。
  2. LLM 负责精炼。 原始对话记录可能很长、很杂乱,LLM 把它提炼成一段简洁的摘要。
  3. 只加载摘要到热记忆。 不是把完整的对话记录塞进上下文,而是只加载精华部分,节省 Token。

8.4 外部记忆(扩展):Honcho、Mem0 等 8 种

外部记忆(External Memory) 是 Hermes 记忆系统的"扩展卡"。它允许 Agent 接入第三方记忆服务,突破本地存储的限制。

根据 Nous Research 的官方文档,Hermes 当前支持以下外部记忆服务:

服务类型特点
Honcho用户建模行为模式推导、工作习惯分析、自适应回复
Mem0记忆层跨平台记忆同步、记忆语义检索
OpenViking向量数据库大规模语义检索、知识图谱
Pinecone向量数据库云端托管、高并发、实时更新
Weaviate向量数据库开源、GraphQL 接口、多模态
Chroma向量数据库轻量级、本地优先、易用
Qdrant向量数据库Rust 实现、高性能、过滤检索
Milvus向量数据库分布式、企业级、大规模

外部记忆的接入方式:

# ~/.config/hermes/config.yaml
memory:
  external:
    provider: honcho # 选择外部记忆服务
    api_key: "${HONCHO_API_KEY}" # API 密钥(从环境变量读取)
    project_id: "my-project" # 项目 ID
 
    # Honcho 特有的配置
    behavior_analysis: true # 启用行为模式分析
    habit_tracking: true # 启用工作习惯追踪
    style_adaptation: true # 启用回复风格自适应

外部记忆不是必需的。对于个人用户来说,SQLite + FTS5 的冷记忆已经完全够用。外部记忆主要适用于:

  • 需要跨设备同步记忆的用户
  • 企业级部署,需要集中式记忆管理
  • 需要大规模语义检索的高级场景

8.5 记忆的生命周期管理

信息在 Hermes 的记忆系统中,会经历一个完整的生命周期:

诞生: 信息首次产生(用户输入、工具结果、Agent 输出)
    ↓
热记忆: 立即加载到当前上下文
    ↓
评估: 这条信息重要吗?值得长期记住吗?
    ↓
    ├─ 是 → 写入温记忆(MEMORY.md / USER.md)
    │         ↓
    │      定期压缩:内容超过字符限制时,触发 LLM 摘要
    │         ↓
    │      历史归档:旧版本保存到 SQLite
    │
    └─ 否 → 保留在会话历史中(冷记忆)
              ↓
           定期清理:超过保留期限的会话自动归档或删除

会话保留策略:

# 会话数据保留配置
retention:
  session_keep_days: 90 # 会话保留 90 天
  archive_after_days: 30 # 30 天后归档(从热记忆中移除)
  compress_after_turns: 20 # 超过 20 轮后自动摘要压缩
  max_sessions_per_user: 100 # 每个用户最多保留 100 个活跃会话

8.6 隐私保护:纯本地存储的安全优势

Hermes 的一个核心安全特性是:默认情况下,所有记忆数据都存储在本地。

这意味着:

  • 你的对话历史不会上传到任何云端服务器
  • 你的 MEMORY.md 和 USER.md 只存在于你自己的硬盘上
  • 即使 Nous Research 倒闭了,你的数据依然安全

这种"本地优先"的设计,在当前这个数据隐私日益敏感的时代,是一个巨大的竞争优势。

常见问题

Q:如果使用外部记忆服务(如 Honcho),数据还安全吗?

A:这取决于你选择的服务。Honcho 等第三方服务有自己的隐私政策,你需要仔细阅读。好消息是:外部记忆是可选的,不是强制的。如果你不信任任何第三方服务,完全可以只用本地存储。另外,即使使用外部服务,核心的 MEMORY.md 和 USER.md 仍然保存在本地,外部服务只是作为补充。

Q:我的 SQLite 数据库文件会不会很大?

A:以典型的使用强度计算(每天 50 轮对话,每轮平均 1000 Token),一年的数据量大约是 200-300 MB。对于现代硬盘来说,这完全在可接受范围内。如果你确实需要清理旧数据,可以使用 hermes session cleanup --before 2026-01-01 命令删除指定日期之前的会话。


9. Honcho 用户建模模块

9.1 Honcho 是什么

Honcho 是 Nous Research 开发的一个用户建模(User Modeling)模块,它的目标是让 Agent 不仅能"记住"用户说过什么,还能"理解"用户是什么样的人。

这个模块是可选的——你不启用它,Hermes 依然能正常工作。但启用之后,Agent 会获得一种"读心术"般的能力:它能从你的行为中推导出你的工作习惯、沟通风格、甚至情绪状态,然后自动调整自己的行为来配合你。

你可以把 Honcho 想象成一个**"用户行为分析师"**。它坐在一旁,默默地观察你和 Agent 的每一次互动,然后画出一幅"用户画像"——不是静态的表单,而是动态演化的模型。

9.2 行为模式推导机制

Honcho 的核心能力,是从海量交互数据中自动推导行为模式

它的分析维度包括:

维度一:沟通风格。

Honcho 会分析你的消息特征:

  • 消息的平均长度(简洁型 vs 啰嗦型)
  • 使用的语言风格(正式 vs 随意)
  • 表情符号和标点符号的使用习惯
  • 提问的方式(直接提问 vs 描述背景后提问)

基于这些分析,Agent 会调整它的回复风格来匹配你。如果你喜欢简洁,Agent 就会少说废话;如果你喜欢详细解释,Agent 就会多给背景信息。

维度二:技术偏好。

Honcho 会观察你在技术话题上的选择:

  • 你经常提到哪些编程语言、框架、工具
  • 你在解决问题时偏好什么思路(暴力枚举 vs 优雅算法)
  • 你对新技术的态度(尝鲜型 vs 保守型)

这些信息帮助 Agent 在给你建议时,优先考虑你熟悉和偏好的技术栈。

维度三:工作节律。

Honcho 会记录你的活跃时间模式:

  • 一天中什么时段你最活跃
  • 工作日和周末的使用模式差异
  • 任务类型的时段分布(上午喜欢写代码、晚上喜欢读文档)

基于这些节律,Agent 可以做出更贴心的安排——比如不会在凌晨 3 点给你发非紧急的通知。

维度四:情绪触发点。

这是一个更微妙但更有价值的维度。Honcho 会尝试识别:

  • 什么类型的问题会让你感到沮丧(如反复出错的配置、复杂的权限问题)
  • 什么类型的话题会让你兴奋(如新功能的探索、性能优化的挑战)
  • 你的耐心阈值(在第几次重试失败后你会放弃)

当然,Honcho 不会"读心"——它只能基于可观察的行为做推断。但这些推断,足以让 Agent 在互动中更加"体贴"。

9.3 工作习惯分析

Honcho 的工作习惯分析,可以细到令人惊叹的程度。以下是一些真实的能力示例:

代码风格推断:

通过分析你在代码相关对话中的偏好,Honcho 可以推断出:

  • 你喜欢什么命名规范(snake_case vs camelCase)
  • 你的注释风格(详细文档字符串 vs 简洁行内注释)
  • 你的错误处理偏好(异常捕获 vs 提前返回)
  • 你的导入排序习惯

然后,当 Agent 帮你生成或修改代码时,它会自动遵循这些风格。

作息规律分析:

Honcho 的用户作息报告(示例):

活跃时段:
- 工作日: 21:00 - 01:00 (峰值 22:30)
- 周末: 14:00 - 18:00, 21:00 - 02:00
- 几乎不在 08:00 - 12:00 活跃

任务类型分布:
- 21:00-23:00: 代码开发 (65%), 调试 (25%), 文档 (10%)
- 23:00-01:00: 学习研究 (40%), 自动化任务 (35%), 代码审查 (25%)

建议的定时任务时段:
- 日报生成: 00:30(用户睡前最后查看)
- 代码检查: 20:45(用户开始活跃前完成)
- 备份任务: 03:00(用户完全不活跃的时段)

情绪触发点识别:

Honcho 的情绪分析(示例):

高挫败感场景:
- Docker 网络配置问题 (挫败指数: 8.5/10)
- 权限相关的错误 (挫败指数: 7.2/10)
- 第三方 API 的文档不清晰 (挫败指数: 6.8/10)

应对策略:
- 遇到 Docker 问题时,主动提供更详细的步骤说明
- 遇到权限问题时,先解释"为什么需要这个权限"再给出解决方案
- 遇到文档不清的 API 时,主动搜索替代方案或社区讨论

9.4 自适应回复风格调整

基于 Honcho 的分析,Agent 的自适应回复风格调整体现在方方面面:

示例一:沟通风格的匹配。

如果你通常发短消息、直接提问:

你: 怎么改端口?

Agent(适配简洁风格):
在 config.yaml 里改 server.port。
或者命令行: hermes config set server.port 8080

如果你通常发长消息、喜欢描述背景:

你: 我现在在部署一个 FastAPI 应用,想把它跑在 8080 端口上,
    但是默认好像是用 8000,我想知道怎么改成 8080?

Agent(适配详细风格):
好的,把 FastAPI 的端口从 8000 改成 8080 很简单。

FastAPI 默认使用 8000 端口,这通常是在启动命令里指定的。
你有几种方式可以改:

方式一:修改启动命令
  uvicorn main:app --host 0.0.0.0 --port 8080

方式二:修改代码中的配置
  import uvicorn
  uvicorn.run(app, host="0.0.0.0", port=8080)

方式三:通过 Hermes 的配置(如果你在用 Hermes 的网关功能)
  hermes config set server.port 8080

推荐方式一,最简单直接。

示例二:技术深度的适配。

如果你被 Honcho 标记为"资深开发者",Agent 不会浪费口舌解释基础概念。如果你被标记为"初学者",Agent 会主动给出更多背景解释和类比。

你: 帮我解释一下 asyncio

Agent(对资深用户):
asyncio 的核心是事件循环 + 协程调度。
你遇到的问题大概率是:
1. 在同步代码里调了 async 函数(忘了 await)
2. 创建了事件循环但没正确关闭
3. 用了阻塞式 I/O 导致事件循环卡住

具体是哪种情况?贴一下代码。

---

Agent(对初学者):
asyncio 是 Python 里做"多任务并发"的一种方式。

你可以把它想象成一个"餐厅经理":
- 服务员 A 去给顾客 1 点菜(开始一个任务)
- 在等顾客 1 想的时候,服务员 A 去给顾客 2 倒水(不等上一个任务完成,就开始下一个)
- 顾客 1 想好了,服务员 A 再回来记录(任务恢复)

关键点:一个服务员(一个线程)可以同时服务多个顾客(多个任务),
关键是"不等"——利用了等待的时间去做别的事。

在代码里,"async def" 定义一个可以"暂停"的函数,
"await" 就是"暂停点"——在这里,函数暂停,去做别的事,等条件满足再回来。

想要一个具体的代码示例吗?

9.5 配置与调优

Honcho 模块默认是禁用的,因为涉及隐私数据的分析。如果你希望启用它,需要明确配置:

# ~/.config/hermes/config.yaml
honcho:
  enabled: true # 启用 Honcho
  analysis_level: "standard" # 分析级别: minimal / standard / deep
 
  # 各维度分析的开关
  dimensions:
    communication_style: true # 沟通风格分析
    tech_preferences: true # 技术偏好分析
    work_rhythm: true # 工作节律分析
    emotion_tracking: false # 情绪追踪(默认关闭,更敏感)
 
  # 隐私设置
  privacy:
    local_only: true # 分析结果只保存在本地
    anonymize_before_cloud: true # 如需上传到外部服务,先匿名化
    retention_days: 365 # 分析数据保留 365 天

分析级别的区别:

级别数据收集分析深度隐私影响
minimal只收集消息元数据(时间、长度、类型)基础模式识别极低
standard收集消息内容,但不存储原始文本多维度行为建模
deep收集完整交互数据,用于精细建模情绪和习惯深度分析

注意

Honcho 的 deep 级别会收集更多数据,包括消息内容的完整文本。虽然这些数据默认只保存在本地,但如果你对隐私非常敏感,建议使用 minimal 或 standard 级别。你也可以随时运行 hermes honcho export 导出 Honcho 收集的所有数据,查看它到底知道些什么,或者运行 hermes honcho reset 清空所有分析数据,从头开始。


10. 安全架构

10.1 命令审批机制

我们在前面已经多次提到了"命令审批",这一节来系统地讲解它的工作原理和配置方法。

审批机制的触发条件:

一个工具调用是否需要审批,由以下因素共同决定:

  1. 工具自身的 requires_approval 标记。 每个工具在注册时都会声明自己是否属于需要审批的类型。
  2. 用户的全局配置。 你可以在配置中设置 terminal.require_approval = true/false
  3. 当前的后端环境。 在 Docker 沙箱中执行的命令,审批要求可能比在本地执行更宽松(因为隔离性更强)。
  4. 用户的实时选择。 在某次审批中,用户可以选择"允许本次会话的所有同类操作",这会临时绕过后续的同类审批。

默认需要审批的操作:

操作类型示例风险等级
删除文件/目录rm, rmdir
修改系统配置编辑 /etc/ 下的文件
执行任意 Shell 命令bash -c "..."
网络出站连接curl 到外部 URL
安装软件包pip install, apt install
修改环境变量export PATH=...

审批界面(CLI 模式):

⚠️  Agent 请求执行需要审批的操作
 
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
工具: terminal_exec
描述: 在终端执行命令
风险等级: 🔴
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
命令:
  rm -rf ./temp_build/
 
影响分析:
 将删除目录: /home/user/project/temp_build/
 该目录包含 47 个文件,总大小 12.3 MB
 此操作不可撤销
 
建议:
 目录内容看起来是构建产物(.o 文件、缓存等)
  ⚠️  但目录名 "temp_build" 不是标准的构建目录名
 
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
请选择:
  [Y] 确认执行      [N] 拒绝
  [E] 编辑命令      [D] 查看详情
  [A] 允许本次会话的所有 rm 操作
 
>

这个界面设计体现了几个安全原则:

  1. 信息透明。 用户能看到完整的命令、影响分析和风险评估。
  2. 不可撤销性提醒。 对于危险操作,明确提示"此操作不可撤销"。
  3. 智能建议。 系统会尝试分析命令的意图,给出参考建议(如"这看起来是构建产物")。
  4. 分级响应。 用户可以选择单次确认、编辑后确认、或批量授权。

10.2 沙箱执行环境

除了命令审批,Hermes 还提供了沙箱执行环境,作为第二层安全防护。

沙箱的类型:

沙箱类型隔离级别资源开销适用场景
进程级沙箱低(仅限制系统调用)极低快速脚本执行
Docker 沙箱中(容器隔离)通用开发和测试
Firejail 沙箱中高(命名空间隔离)本地安全执行
gVisor 沙箱高(用户态内核)高风险不可信代码
Kata 沙箱最高(轻量虚拟机)很高多租户安全隔离

Docker 沙箱的配置:

terminal:
  backend: docker
  docker:
    image: "hermes-sandbox:latest" # 沙箱镜像
    network: "none" # 禁用网络(可选)
    cap_drop: ["ALL"] # 丢弃所有 Linux capabilities
    read_only: true # 根文件系统只读
    tmpfs:
      - "/tmp:size=100m" # 临时目录,限制大小
    volumes:
      - "/home/user/projects:/workspace:rw" # 只挂载工作目录
    user: "1000:1000" # 以非 root 用户运行

这个配置实现了以下安全目标:

  • 最小权限 —— 容器没有不必要的 capabilities
  • 网络隔离 —— 可选禁用网络,防止数据外泄
  • 文件系统隔离 —— 只挂载必要的目录,且可以设为只读
  • 资源限制 —— 临时目录有大小限制,防止磁盘耗尽攻击
  • 非特权运行 —— 即使容器逃逸,攻击者也只是一个普通用户

10.3 API Key 安全存储

Hermes 需要调用多个外部服务的 API(如 OpenAI、Claude、各种平台 API)。这些 API 的密钥(Key)必须安全存储。

密钥存储方式:

方式安全性便利性推荐度
环境变量⭐⭐⭐
密钥管理文件(权限 600)中高⭐⭐⭐⭐
系统密钥环(Keyring)⭐⭐⭐⭐⭐
硬件安全模块(HSM)最高⭐⭐⭐

推荐配置(使用系统密钥环):

# 安装 keyring 支持
pip install keyring
 
# 将 API Key 存入系统密钥环
hermes config set model.openai.api_key --secure
# 系统会提示你输入密钥,并自动存入操作系统的密钥环
 
# 验证存储
hermes config get model.openai.api_key
# 输出: ***(已脱敏,不会显示明文)

使用系统密钥环的好处是:

  • 密钥以加密形式存储,即使有人拿到了你的硬盘,也无法直接读取密钥
  • 支持生物识别解锁(如 macOS 的 Touch ID、Windows 的 Hello)
  • 与操作系统的权限系统集成,只有授权进程可以访问

注意

绝对不要把 API Key 直接写在配置文件里,尤其是当配置文件可能被提交到 Git 仓库时。每年都有无数开发者因为把密钥提交到 GitHub 而造成安全事故。如果你不小心这样做了,立即到对应的服务商后台撤销该 Key 并重新生成。

10.4 权限最小化原则

权限最小化(Principle of Least Privilege)是安全设计的基本原则:每个组件、每个工具、每个操作,都只拥有完成其工作所必需的最小权限。

Hermes 在多个层面贯彻了这一原则:

层面一:工具级别的权限控制。

每个工具在注册时声明自己需要什么权限:

Tool(
    name="file_read",
    required_permissions=["filesystem.read"],
    # 只需要读权限,不需要写权限
)
 
Tool(
    name="file_write",
    required_permissions=["filesystem.write"],
    dangerous=True,
    requires_approval=True,
    # 需要写权限,标记为危险,需要审批
)

层面二:会话级别的权限控制。

你可以为不同的会话设置不同的权限级别:

# 创建一个只读会话(Agent 只能读文件,不能修改)
hermes chat --readonly
 
# 创建一个受限会话(Agent 只能使用白名单中的工具)
hermes chat --allow-tools "file_read,web_search,db_query"

层面三:平台级别的权限控制。

不同平台的接入,可以设置不同的权限:

gateway:
  platforms:
    telegram:
      enabled: true
      permissions: ["read", "write", "execute"] # 完全权限
 
    slack:
      enabled: true
      permissions: ["read", "write"] # 不能执行命令
      readonly_channels: ["general", "announcements"] # 某些频道只读

10.5 与 OpenClaw 分级沙箱的对比

OpenClaw 在安全性方面有一个业界公认的优势:分级沙箱(Tiered Sandbox)。让我们对比一下两者的安全策略:

维度HermesOpenClaw
命令审批✅ 交互式审批✅ 交互式审批
沙箱隔离✅ Docker / Firejail / gVisor✅ ✅ 分级沙箱(业界最佳)
分级策略按工具和用户配置分级按操作危险度自动分级
网络隔离可选禁用网络默认受限网络
文件系统隔离按需挂载默认只读 + 白名单写入
密钥管理系统密钥环环境变量 + 加密存储
审计日志SQLite 本地存储结构化日志 + 可选外发

OpenClaw 的分级沙箱确实是业界的标杆。它把操作分为多个危险等级,每个等级对应不同的隔离强度。比如:

  • Level 1(只读操作): 不需要沙箱,直接执行
  • Level 2(写操作): 在 Firejail 沙箱中执行,限制文件系统访问范围
  • Level 3(系统命令): 在 Docker 沙箱中执行,完全隔离
  • Level 4(网络操作): 在 gVisor 沙箱中执行,网络完全隔离

Hermes 目前的沙箱机制没有 OpenClaw 那么精细的分级,但提供了更灵活的配置选项。根据 Nous Research 的公开路线图,更精细的分级沙箱是未来的重点开发方向之一。

Tips

如果你当前对安全性有极高要求(如处理敏感数据、生产环境部署),建议在使用 Hermes 时:

  1. 始终使用 Docker 或 gVisor 后端
  2. 禁用网络访问(除非任务确实需要)
  3. 文件系统只挂载必要目录,且设为只读
  4. 定期审查 SQLite 中的工具调用日志,检查是否有异常操作
  5. 关注 Hermes 的版本更新,安全相关的改进通常会优先发布

11. 性能与可扩展性

11.1 Python 轻量架构的优势

Hermes 选择 Python 作为主力开发语言(代码库中 Python 占比 93.6%),这个决策在 AI 开源项目中并不罕见,但值得深入理解其背后的考量。

优势一:生态丰富。

Python 在 AI/ML 领域拥有无可比拟的生态系统。从 LLM 调用(OpenAI SDK、Anthropic SDK)到数据处理(Pandas、NumPy)到 Web 服务(FastAPI、Flask)到数据库(SQLAlchemy、sqlite3),几乎所有 Hermes 需要的功能,Python 生态中都有成熟、活跃的解决方案。

这意味着 Nous Research 可以把精力集中在 Agent 的核心逻辑上,而不是重复造轮子。

优势二:开发效率高。

Python 的语法简洁、表达力强,非常适合快速迭代和原型验证。对于一个需要不断实验、快速响应社区反馈的开源项目来说,开发效率比运行效率更重要。

优势三:社区门槛低。

Python 是全球最普及的编程语言之一。选择 Python,意味着更多开发者能够阅读、理解、修改 Hermes 的源代码。这直接降低了贡献门槛,有利于社区生态的发展。

优势四:与 LLM 的天然亲和。

大多数 LLM 的训练数据中,Python 代码占比很高。这意味着 LLM 在生成和理解 Python 代码方面,通常比其他语言表现更好。对于 Hermes 这种"让 LLM 生成 Skill"的系统来说,这是一个实际的工程优势。

常见问题

Q:Python 的性能会不会成为瓶颈?

A:对于 Hermes 的使用场景来说,Python 的运行时性能完全够用。Agent 的主要耗时不在 Python 代码本身,而在 LLM API 调用(通常几秒到几十秒)和外部工具执行(如网络请求、文件操作)。Python 代码的执行时间(毫秒级)在这些耗时面前几乎可以忽略。如果确实有性能敏感的部分(如大量数据的文本处理),可以用 Rust 或 C 编写扩展模块,Python 通过 FFI 调用。

11.2 资源占用基准

让我们看看 Hermes 在各种场景下的资源占用情况。

基准测试环境:

  • CPU: 4 核 Intel/AMD 或 ARM
  • 内存: 8 GB
  • 存储: SSD
  • 操作系统: Ubuntu 22.04 / macOS 14

空闲状态:

指标数值
CPU 占用< 1%
内存占用80-150 MB
磁盘 I/O几乎为零
网络仅心跳/保活包

单次对话任务(平均 10 轮):

指标数值
CPU 占用(峰值)10-30%
内存占用(峰值)200-400 MB
磁盘写入~50 KB(对话历史)
网络出站~100-500 KB(LLM API 请求)
总耗时30-120 秒(取决于 LLM 响应速度)

长期运行(7×24 小时 Gateway 模式):

指标数值
日均内存增长~5-10 MB(SQLite 缓存等)
重启建议周期每月一次(清理内存碎片)
日志增长~10-50 MB/天(取决于日志级别)

Tips

如果你发现 Hermes 的内存占用持续增长不下降,可能是某个地方有内存泄漏。可以尝试以下排查步骤:

  1. 降低日志级别:hermes config set logging.level WARNING
  2. 限制会话历史保留数量:hermes config set retention.max_sessions_per_user 50
  3. 定期重启 Gateway 服务:设置一个 cron 任务每周重启一次
  4. 如果问题持续,在 GitHub 上提交 Issue,附上 hermes debug memory 的输出

11.3 并发处理能力

当前版本的 Hermes,Agent 核心层是单线程的。这意味着:

  • 同一时刻,Agent 只能处理一个任务
  • 如果多个平台同时发来消息,它们会按顺序排队处理
  • 一个复杂任务(如需要 50 轮对话)会阻塞后续任务

这个设计的选择,是出于以下考虑:

  1. 上下文一致性。 Agent 的状态(热记忆中的上下文)是单例的。如果同时处理多个任务,不同任务的上下文会互相干扰,导致 Agent "精神分裂"。
  2. 资源控制。 LLM API 调用是主要的资源消耗点。单线程处理天然地实现了"速率限制",不会因为并发请求过多而耗尽 API 配额或预算。
  3. 简化设计。 并发控制是一个复杂的问题(锁、竞态条件、死锁等)。单线程设计大大降低了系统的复杂度,减少了 Bug 的可能性。

但这并不意味着 Hermes 不能处理"并发需求"。对于需要并行处理多个子任务的场景,Hermes 提供了子 Agent 委托机制

# 使用 delegate_task 工具,将子任务委托给独立的子 Agent
hermes -q "帮我同时做三件事:
  1. 检查服务器 A 的磁盘空间
  2. 检查服务器 B 的内存使用
  3. 检查服务器 C 的 CPU 负载
  用 delegate_task 并行执行"

子 Agent 的特性:

  • 每个子 Agent 有独立的对话上下文和 task_id
  • 最多支持 3 个子 Agent 并行
  • 子 Agent 的深度最多 2 层(防止递归爆炸)
  • 父 Agent 可以实时查看子 Agent 的进度

11.4 大规模记忆数据的性能表现

随着使用时间的增长,SQLite 数据库中的数据会越来越多。Hermes 在大规模数据下的性能表现如何?

测试数据:

数据规模会话数消息数数据库大小
小型1001,0005 MB
中型1,00010,00050 MB
大型10,000100,000500 MB
超大型100,0001,000,0005 GB

FTS5 全文搜索性能:

数据规模首次搜索耗时缓存后搜索耗时
小型< 10 ms< 1 ms
中型< 50 ms< 5 ms
大型< 200 ms< 20 ms
超大型< 1 s< 100 ms

会话列表加载性能:

数据规模加载耗时
小型< 10 ms
中型< 50 ms
大型< 200 ms
超大型< 500 ms

从数据可以看出,SQLite + FTS5 的组合,在百万级数据量下依然能保持良好的性能。对于个人用户和小团队来说,这个性能完全够用。

但如果数据量增长到千万级,SQLite 可能会成为瓶颈。此时可以考虑:

  1. 归档旧数据(导出到文件,从数据库中删除)
  2. 升级到 PostgreSQL(Hermes 支持通过配置切换数据库)
  3. 使用外部向量数据库(如 Pinecone、Milvus)做语义检索

11.5 扩展方向:插件机制、模块化拆分

Hermes 的架构设计,为未来的扩展预留了充足的空间。

方向一:官方插件市场。

当前 Hermes 的扩展主要通过自定义工具和 Skill 实现。未来计划推出更正式的插件机制(Plugin System),允许开发者打包和分发更复杂的扩展:

插件包结构:
my-plugin/
├── plugin.yaml          # 插件元数据
├── tools/               # 自定义工具
├── skills/              # 预设技能
├── adapters/            # 自定义平台适配器
├── middleware/          # 中间件(拦截和修改消息)
├── ui/                  # 自定义 UI 组件(Web 界面)
└── requirements.txt     # 依赖

方向二:核心模块的独立化。

长期来看,Hermes 的五层架构可能会进一步拆分为独立的微服务或库:

  • hermes-core —— Agent 核心层,作为独立库发布
  • hermes-gateway —— GatewayRunner,独立部署
  • hermes-tools —— ToolRegistry 和内置工具集合
  • hermes-memory —— 记忆系统,支持多种后端
  • hermes-sdk —— 官方 SDK,供第三方开发者使用

这种拆分的好处是:

  • 开发者可以只使用自己需要的模块
  • 不同模块可以独立版本迭代
  • 企业用户可以根据需求定制部署方案

方向三:多语言支持。

虽然 Hermes 的核心是 Python,但工具层和适配器层可以用其他语言实现。未来可能会支持:

  • Rust 工具 —— 性能敏感的操作(如大规模数据处理)
  • JavaScript/TypeScript 适配器 —— 前端和 Node.js 生态的集成
  • Go 网关 —— 高并发的 GatewayRunner 实现

Tips

如果你有兴趣为 Hermes 贡献代码,建议从以下方向入手:

  1. 新平台适配器 —— 为你常用的消息平台写一个适配器
  2. 新工具 —— 开发一个解决特定问题的自定义工具,然后贡献给社区
  3. Skill 模板 —— 把你常用的工作流封装成 Skill,分享到 Skills Hub
  4. 文档翻译 —— 帮助把官方文档翻译成更多语言
  5. Bug 修复 —— 在 GitHub Issues 中寻找 good-first-issue 标签的问题

12. 系统设计哲学总结

12.1 简单优于复杂

Hermes 的设计团队有一个明确的偏好:在功能完备和简单清晰之间,永远选择后者。

这个哲学体现在无数个设计决策中:

  • 用 SQLite 而不是分布式数据库
  • 用单线程而不是复杂的并发模型
  • 用配置文件而不是 Web 管理界面(至少目前如此)
  • 用 47 个精心设计的工具,而不是 200 个功能重复的工具

"简单是可靠的先决条件。" —— Edsger Dijkstra

复杂系统的问题在于:每一个额外的组件、每一条额外的规则、每一个额外的依赖,都是一个潜在的故障点。当故障发生时,在简单系统中定位问题只需要排查少数几个地方,在复杂系统中则需要排查几十个甚至上百个地方。

Hermes 的追求是:用简单的方式解决复杂的问题,而不是用复杂的方式解决简单的问题。

12.2 本地优先,隐私至上

在云计算和 SaaS 大行其道的时代,Hermes 选择了一条反潮流的路线:数据默认保存在本地。

这个选择有其代价——用户需要自己负责备份、需要自己维护服务器、需要自己处理升级。但换来的收益是:你的数据完全属于你。

  • 没有服务商可以看到你的对话内容
  • 没有广告商可以基于你的数据推送广告
  • 没有政府可以轻易调取你的记录(除非你自愿)
  • 没有公司倒闭会导致你的数据丢失

对于很多人来说,这种"数据主权"比"便利性"更重要。

12.3 自动化一切可自动化的事

Hermes 的终极愿景,是让 Agent 能够自动化一切可自动化的事——不仅包括执行层面的自动化(调用工具、处理数据),还包括认知层面的自动化(学习经验、优化策略、生成知识)。

自学习闭环就是这个愿景的核心实现。它让 Agent 从"被动执行指令"进化到"主动积累经验",从"一次性工具"进化到"持续性伙伴"。

12.4 越用越聪明,而不是越用越笨

很多软件系统的宿命是"越用越笨"——随着功能的增加、配置的累积、数据的膨胀,系统变得越来越慢、越来越不稳定、越来越难以维护。

Hermes 的设计目标是相反的:越用越聪明。

  • 用得越久,Skill 库越丰富,处理任务越快
  • 用得越久,USER.md 越精准,回复越贴合你的习惯
  • 用得越久,MEMORY.md 越精炼,关键信息保留得越好
  • 用得越久,Agent 对你的理解越深,协作越默契

这种"正向积累"的特性,是 Hermes 区别于绝大多数软件系统的根本所在。

12.5 对开发者友好的可扩展设计

最后但同样重要的是,Hermes 始终把开发者体验放在很高的优先级。

  • 代码库结构清晰,新开发者能在 30 分钟内理解整体架构
  • 自定义工具的接口简单,几行代码就能扩展 Agent 的能力
  • 文档全面且接地气,不是干巴巴的 API 参考,而是带有场景和示例的指南
  • 社区友好,提问能得到及时、友善的回应
  • 开源许可证宽松(MIT),允许商业使用和二次开发

这些看似"软实力"的因素,实际上决定了一个开源项目的长期生命力。技术可以复制,但社区文化、设计品味和开发者体验,是很难复制的核心竞争力。


本章小结

在这一章中,我们像解剖学家一样,一层一层地拆开了 Hermes 的架构,理解了它内部的每一个器官是如何工作的。

我们从五层架构的总览开始,理解了入口层、核心层、工具层、持久化层和平台层各自的分工,以及它们如何通过清晰的接口协同工作。

Layer 1(入口与编排层),我们了解了 HermesCLI 的设计理念——简洁、直观、渐进;以及 GatewayRunner 如何把来自十几个平台的消息翻译成 Agent 能理解的统一格式。

Layer 2(Agent 核心层),我们深入剖析了同步对话循环的工作原理,理解了 Agent 是如何一步步接收需求、规划步骤、调用工具、迭代推进的。我们学习了预算机制如何防止 Agent 失控,Token 计数如何控制成本,上下文窗口管理如何在有限空间内最大化信息价值,以及错误恢复机制如何让 Agent 在面对各种意外时从容应对。

Layer 3(工具与注册层),我们认识了 ToolRegistry 这个"工具柜台",理解了单例模式和自注册机制如何让工具管理变得异常简洁。我们浏览了 47 个内置工具的分类架构,学习了安全审批流程如何保护系统,以及自定义工具接口如何让开发者轻松扩展 Agent 的能力。

Layer 4(状态与持久化层),我们探索了 SQLite + FTS5 的数据库设计,理解了 MEMORY.md 和 USER.md 这两份"活文档"如何动态记录 Agent 的经验和用户画像。我们学习了 Cron 定时任务如何让 Agent 7×24 小时自动工作,以及备份策略如何保护你的数据资产。

Layer 5(平台适配层),我们了解了适配器模式如何让 Hermes 同时支持 15+ 个平台,6 种终端后端如何满足不同的安全隔离需求,以及统一消息接口如何让 Agent 核心层完全不必关心平台的差异。

自学习闭环一节,我们揭开了 Hermes 最核心的秘密——执行、评估、创建、改进四个阶段如何构成一个有机的进化循环。我们理解了触发条件(5+ 工具调用、用户纠正、错误修复)、Skill 自动生成的算法逻辑、版本管理机制,以及社区实测数据如何证明这个机制能带来 30%+ 的效率提升。

记忆系统架构一节,我们深入理解了四层温度模型——热记忆的即时性、温记忆的持久性、冷记忆的检索能力、外部记忆的扩展性。我们明白了 Nous Research 官方强调的"有界记忆"设计哲学:有限容量不是缺陷,而是迫使 Agent 学会优先级管理的特性。

Honcho 用户建模一节,我们了解了 Agent 如何从你的行为中推导出沟通风格、技术偏好、工作节律甚至情绪触发点,然后自动调整回复风格来匹配你。

安全架构一节,我们系统学习了命令审批机制、沙箱执行环境、API Key 安全存储、权限最小化原则,以及与 OpenClaw 分级沙箱的对比。

性能与可扩展性一节,我们了解了 Python 轻量架构的优势、资源占用基准、并发处理策略、大规模数据下的性能表现,以及未来的扩展方向。

最后,我们用五个设计哲学原则——简单优于复杂、本地优先隐私至上、自动化一切可自动化的事、越用越聪明、对开发者友好的可扩展设计——总结了 Hermes 架构背后的思想内核。

理解架构,不是为了成为架构师,而是为了成为一个更明白、更自信、更有掌控感的使用者。当你知道系统内部是怎么运转的,你就不会再害怕它、不会盲目依赖它、不会在它出问题时手足无措。你会知道该调什么参数、该看哪个日志、该从哪里入手排查问题。

这就是了解架构的最大价值。