ByteNoteByteNote

字节笔记本

2026年6月21日

hermes教程-会话

API中转
¥120

会话如何工作

每次对话——无论是来自 CLI、Telegram、Discord、Slack、WhatsApp、Signal、Matrix、Teams 还是任何其他消息平台——都会作为包含完整消息历史的会话存储。会话在以下位置进行跟踪:

  1. SQLite 数据库 (~/.hermes/state.db) — 结构化的会话元数据,支持 FTS5 全文搜索,以及完整的消息历史

SQLite 数据库存储:

  • 会话 ID、来源平台、用户 ID
  • 会话标题(唯一的、人类可读的名称)
  • 模型名称和配置
  • 系统提示快照
  • 完整消息历史(角色、内容、工具调用、工具结果)
  • Token 计数(输入/输出)
  • 时间戳(started_at、ended_at)
  • 父会话 ID(用于压缩触发的会话拆分)

哪些内容计入上下文

Hermes 会存储会话历史以便恢复对话,但不会重复发送它处理过的每一个字节。在每一轮中,模型看到的是选定的系统提示、当前对话窗口以及 Hermes 为该轮显式注入的任何内容。

媒体附件作为轮次范围内的输入处理:

  • 图像可以原生附加到下一个模型调用,或者在当前模型不支持原生视觉时预先分析为文本描述。
  • 音频在配置了语音转文本时会被转录为文本。
  • 文本文档可以包含其提取的文本;其他文档类型通常通过保存的本地路径和简短注释来表示。
  • 附件路径和提取/派生的文本可以出现在记录中,但原始图像、音频或二进制文件字节不会重复复制到未来的提示中。

例如,如果用户发送一张图片并要求 Hermes 用它制作一个表情包,Hermes 可能会用视觉功能检查该图片一次,并运行一个图像处理脚本。未来的轮次不会自动携带原始 JPEG 到上下文中。它们只携带写入对话的内容,例如用户的请求、简短的图像描述、本地缓存路径或最终的助手响应。

上下文增长的最常见原因不是媒体文件本身,而是冗长的文本:粘贴的记录、完整的日志、大型工具输出、长差异、重复的状态报告以及详细的证明转储。优先使用摘要、文件路径、重点摘录和工具支持的查找,而不是将大型工件复制到聊天中。

提示

当会话变长时使用 /compress,需要新线程时使用 /new,只有在你想从存储中删除旧的已结束会话时才使用 hermes sessions prune。压缩会减少活动上下文;它不是隐私删除。向 /new 传递一个名称(例如 /new payments-refactor)可以预先设置新会话的初始标题——方便以后用 /resume <name> 或在 /sessions 选择器中找到它。

会话来源

每个会话都标记有其来源平台:

来源描述
cli交互式 CLI(hermeshermes chat
telegramTelegram 信使
discordDiscord 服务器/私信
slackSlack 工作区
whatsappWhatsApp 信使
signalSignal 信使
matrixMatrix 房间和私信
mattermostMattermost 频道
email电子邮件(IMAP/SMTP)
sms通过 Twilio 的短信
dingtalk钉钉信使
feishu飞书/Lark 信使
wecom企业微信
weixin微信(个人微信)
bluebubbles通过 BlueBubbles macOS 服务器的 Apple iMessage
qqbotQQ 机器人(腾讯 QQ)通过官方 API v2
homeassistantHome Assistant 对话
webhook传入的 Webhook
api-serverAPI 服务器请求
acpACP 编辑器集成
cron计划任务
batch批处理运行

CLI 会话恢复

使用 --continue--resume 从 CLI 恢复之前的对话:

继续上一个会话

bash
## 恢复最近的 CLI 会话
hermes --continue
hermes -c
## 或者使用 chat 子命令
hermes chat --continue
hermes chat -c

这会从 SQLite 数据库中查找最近的 cli 会话,并加载其完整的对话历史。

按名称恢复

如果你已经为会话设置了标题(参见下面的 会话命名),你可以按名称恢复它:

bash
## 恢复一个命名的会话
hermes -c "my project"
## 如果有衍生变体(my project, my project #2, my project #3),
## 这会自动恢复最近的一个
hermes -c "my project"   # → 恢复 "my project #3"

恢复特定会话

bash
## 按 ID 恢复特定会话
hermes --resume 20250305_091523_a1b2c3d4
hermes -r 20250305_091523_a1b2c3d4
## 按标题恢复
hermes --resume "refactoring auth"
## 或者使用 chat 子命令
hermes chat --resume 20250305_091523_a1b2c3d4

会话 ID 在退出 CLI 会话时显示,也可以通过 hermes sessions list 找到。

恢复时的对话回顾

当你恢复一个会话时,Hermes 会在输入提示之前显示一个紧凑的回顾面板,展示之前的对话:

回顾内容:

  • 显示用户消息(金色 )和助手响应(绿色
  • 截断长消息(用户消息 300 字符,助手消息 200 字符 / 3 行)
  • 折叠工具调用为带有工具名称的计数(例如 [3 个工具调用: terminal, web_search]
  • 隐藏系统消息、工具结果和内部推理
  • 限制在最后 10 轮对话,并带有 "... N 条更早的消息 ..." 指示器
  • 使用暗淡样式以区别于活动对话

要禁用回顾并保持最小的一行行为,在 ~/.hermes/config.yaml 中设置:

yaml
display:
  resume_display: minimal   # 默认: full

提示

会话 ID 的格式为 YYYYMMDD_HHMMSS_<hex> — CLI/TUI 会话使用 6 字符十六进制后缀(例如 20250305_091523_a1b2c3),网关会话使用 8 字符后缀(例如 20250305_091523_a1b2c3d4)。你可以按 ID(完整或唯一前缀)或按标题恢复 — 两者都适用于 -c-r

跨平台交接

使用 /handoff <platform> 从 CLI 会话将实时对话转移到消息平台的主频道。代理会从 CLI 离开的地方精确继续——相同的会话 ID、完整的角色感知记录、工具调用等。

bash
## 在 CLI 会话内部
/handoff telegram

发生的情况:

  1. CLI 验证 <platform> 已启用并设置了主频道(在目标聊天中运行 /sethome 一次进行配置)。

  2. CLI 将会话标记为待处理并阻塞轮询网关。如果代理正在处理中则拒绝——先等待当前响应完成。

  3. 网关监视器认领交接,并要求目标适配器创建一个新线程:

    • Telegram — 打开一个新的论坛主题(如果聊天中启用了 Bot API 9.4+ 主题模式,则为私信主题;否则为论坛超级组主题)。
    • Discord — 在主文本频道下创建一个 1440 分钟自动归档的线程。
    • Slack — 发布一条种子消息,并将其 ts 作为线程锚点。
    • WhatsApp / Signal / Matrix / SMS — 没有原生线程,直接回退到主频道。
  4. 网关将目标键重新绑定到你现有的 CLI 会话 ID,然后伪造一个合成用户轮次,要求代理确认并总结。回复会出现在新线程中。

  5. 当网关确认成功时,CLI 打印一个 /resume 提示并干净退出:

    text
    ↻ 交接完成。会话现在在 telegram 上活跃。
      稍后在此 CLI 上恢复它:/resume my-session-title
  6. 从那时起,对话在平台上进行。在新线程中回复——该频道中任何授权用户共享同一个会话,并且线程中任何后续的真实用户消息都会无缝加入,因为线程会话不依赖 user_id

回到 CLI: 当你想要回到桌面时,只需运行 /resume <title>(或从 shell 运行 hermes -r "<title>"),从平台离开的地方继续。

失败模式:

  • 未配置主频道 → CLI 拒绝并提示 /sethome
  • 平台未启用 / 网关未运行 → CLI 在 60 秒后超时,显示清晰消息,你的 CLI 会话保持完整。
  • 线程创建失败(权限、主题模式关闭)→ 直接回退到主频道并仍然完成;没有线程隔离但交接本身有效。
  • adapter.send 失败(速率限制、临时 API 错误)→ 交接标记为失败并显示原因;记录被清除,你可以重试。

值得注意的限制: 对于不支持线程的平台,如果有多用户群组主频道,合成轮次会作为私信风格的会话键。这对于自私信主频道(典型设置)有效,但对于真正的共享群聊并不理想。线程覆盖了 Telegram / Discord / Slack——这是最常见的情况——所以大多数设置不会遇到这个问题。

会话命名

为会话设置人类可读的标题,以便轻松找到和恢复它们。

自动生成的标题

Hermes 会在第一次交流后自动为每个会话生成一个简短的描述性标题(3-7 个单词)。这会在后台线程中使用快速辅助模型运行,因此不会增加延迟。当你使用 hermes sessions listhermes sessions browse 浏览会话时,会看到自动生成的标题。

自动标题只会在每个会话中触发一次,如果你已经手动设置了标题,则会跳过。

手动设置标题

在任何聊天会话(CLI 或网关)中使用 /title 斜杠命令:

/title my research project

标题会立即应用。如果会话尚未在数据库中创建(例如,你在发送第一条消息之前运行 /title),它会被排队并在会话开始时应用。

你也可以从命令行重命名现有会话:

bash
hermes sessions rename 20250305_091523_a1b2c3d4 "refactoring auth module"

标题规则

  • 唯一 — 没有两个会话可以共享相同的标题
  • 最多 100 个字符 — 保持列表输出整洁
  • 清理 — 控制字符、零宽字符和 RTL 覆盖符会被自动去除
  • 普通 Unicode 没问题 — 表情符号、中日韩文字、重音字符都可以

压缩时的自动衍生

当会话的上下文被压缩时(手动通过 /compress 或自动),Hermes 会创建一个新的延续会话。如果原始会话有标题,新会话会自动获得一个编号标题:

"my project" → "my project #2" → "my project #3"

当你按名称恢复时(hermes -c "my project"),它会自动选择衍生链中最新的会话。

消息平台中的 /title

/title 命令在所有网关平台(Telegram、Discord、Slack、WhatsApp)中工作:

  • /title My Research — 设置会话标题
  • /title — 显示当前标题

会话管理命令

Hermes 通过 hermes sessions 提供一整套会话管理命令:

列出会话

bash
## 列出最近的会话(默认:最后 20 个)
hermes sessions list
## 按平台过滤
hermes sessions list --source telegram
## 显示更多会话
hermes sessions list --limit 50

当会话有标题时,输出显示标题、预览和相对时间戳:

text
Title                  Preview                                  Last Active   ID
────────────────────────────────────────────────────────────────────────────────────────────────
refactoring auth       Help me refactor the auth module please   2h ago        20250305_091523_a
my project #3          Can you check the test failures?          yesterday     20250304_143022_e
—                      What's the weather in Las Vegas?          3d ago        20250303_101500_f

当没有会话有标题时,使用更简单的格式:

text
Preview                                            Last Active   Src    ID
──────────────────────────────────────────────────────────────────────────────────────
Help me refactor the auth module please             2h ago        cli    20250305_091523_a
What's the weather in Las Vegas?                    3d ago        tele   20250303_101500_f

导出会话

bash
## 将所有会话导出到 JSONL 文件
hermes sessions export backup.jsonl
## 导出特定平台的会话
hermes sessions export telegram-history.jsonl --source telegram
## 导出单个会话
hermes sessions export session.jsonl --session-id 20250305_091523_a1b2c3d4

导出的文件每行包含一个 JSON 对象,包含完整的会话元数据和所有消息。

删除会话

bash
## 删除特定会话(需要确认)
hermes sessions delete 20250305_091523_a1b2c3d4
## 无需确认删除
hermes sessions delete 20250305_091523_a1b2c3d4 --yes

重命名会话

bash
## 设置或更改会话标题
hermes sessions rename 20250305_091523_a1b2c3d4 "debugging auth flow"
## 多词标题在 CLI 中不需要引号
hermes sessions rename 20250305_091523_a1b2c3d4 debugging auth flow

如果标题已被其他会话使用,会显示错误。

清理旧会话

bash
## 删除超过 90 天的已结束会话(默认)
hermes sessions prune
## 自定义时间阈值
hermes sessions prune --older-than 30
## 仅清理特定平台的会话
hermes sessions prune --source telegram --older-than 60
## 跳过确认
hermes sessions prune --older-than 30 --yes

信息

清理只删除已结束的会话(已明确结束或自动重置的会话)。活动会话永远不会被清理。

会话统计

bash
hermes sessions stats

输出:

text
Total sessions: 142
Total messages: 3847
  cli: 89 sessions
  telegram: 38 sessions
  discord: 15 sessions
Database size: 12.4 MB

要进行更深入的分析——Token 使用、成本估算、工具分解和活动模式——请使用 hermes insights

会话搜索工具

代理内置了一个 session_search 工具,它使用 SQLite 的 FTS5 引擎对所有过去的对话执行全文搜索——并允许代理滚动浏览它找到的任何会话。没有 LLM 调用,没有摘要,没有截断。每种形状都从数据库返回实际消息。

三种调用形状

该工具根据你设置的参数推断你想要什么。没有 mode 参数。

1. 发现 — 传递 query

python
session_search(query="auth refactor", limit=3)

运行 FTS5,按会话衍生链去重,返回前 N 个会话。每个结果包含:

  • session_idtitlewhensource
  • snippet — FTS5 高亮的匹配摘录
  • bookend_start — 会话的前 3 条用户+助手消息(目标/启动)
  • messages — FTS5 匹配前后各 5 条消息,锚点消息被标记(上下文中的命中)
  • bookend_end — 会话的最后 3 条用户+助手消息(结论/决策)
  • match_message_idmessages_beforemessages_after

书签 + 窗口一起重建目标 → 匹配 → 结论,而无需支付整个记录的成本。典型耗时:在真实会话数据库上为 15–50 毫秒。

2. 滚动 — 传递 session_id + around_message_id

python
session_search(session_id="20260510_174648_805cc2", around_message_id=590803, window=10)

返回以锚点为中心的 ±window 条消息窗口。没有 FTS5,没有书签——只有切片。在发现调用后,当你需要比默认 ±5 窗口更多的上下文时使用。

  • 向前滚动:将 messages[-1].id 作为 around_message_id 传回
  • 向后滚动:将 messages[0].id 作为 around_message_id 传回
  • 边界消息会出现在两个窗口中,作为方向标记
  • messages_beforemessages_after 小于 window 时,你已到达会话的开始或结束

典型耗时:每次滚动调用 1–2 毫秒。

3. 浏览 — 无参数:

python
session_search()

按时间顺序返回最近的会话(标题、预览、时间戳)。当用户问“我之前在做什么”但没有指定主题时很有用。

FTS5 查询语法

关键词模式支持标准的 FTS5 查询语法:

  • 简单关键词:docker deployment(FTS5 默认为 AND)
  • 短语:"exact phrase"
  • 布尔:docker OR kubernetespython NOT java
  • 前缀:deploy*

可选参数

  • sortnewestoldest,在 FTS5 排名之上。省略则仅按相关性排序(默认;适用于探索性回忆)。使用 newest 回答“我们在哪里留下了 X”的问题,使用 oldest 回答“X 是如何开始的”的问题。
  • role_filter — 逗号分隔的角色,用于包含。发现默认为 user,assistant(工具输出通常是噪音)。传递 user,assistant,tool 以包含工具输出(调试工具行为)或 tool 仅搜索工具输出。

何时使用

代理被提示自动使用会话搜索:

“当用户引用过去对话中的内容,或者你怀疑存在相关的先前上下文时,使用 session_search 来回忆它,而不是要求他们重复自己。”

典型触发词:“我们之前做过这个”、“还记得什么时候”、“上次”、“正如我提到的”,或者任何对当前窗口中不存在的项目/人/概念的引用。

按平台会话跟踪

网关会话

在消息平台上,会话通过从消息源构建的确定性会话键进行键控:

聊天类型默认键格式行为
Telegram 私信agent:main:telegram:dm:<chat_id>每个私信聊天一个会话
Discord 私信agent:main:discord:dm:<chat_id>每个私信聊天一个会话
WhatsApp 私信agent:main:whatsapp:dm:<canonical_identifier>每个私信用户一个会话(当映射存在时,LID/电话别名合并为一个身份)
群组聊天agent:main:<platform>:group:<chat_id>:<user_id>群组内每个用户一个会话(当平台暴露用户 ID 时)
群组线程/主题agent:main:<platform>:group:<chat_id>:<thread_id>所有线程参与者共享的会话(默认)。使用 thread_sessions_per_user: true 时为每个用户一个会话。
频道agent:main:<platform>:channel:<chat_id>:<user_id>频道内每个用户一个会话(当平台暴露用户 ID 时)

当 Hermes 无法获取共享聊天的参与者标识符时,它会回退到该房间的一个共享会话。

共享与隔离的群组会话

默认情况下,Hermes 在 config.yaml 中使用 group_sessions_per_user: true。这意味着:

  • Alice 和 Bob 可以在同一个 Discord 频道中与 Hermes 对话,而不会共享记录历史
  • 一个用户长时间的工具密集型任务不会污染另一个用户的上下文窗口
  • 中断处理也保持每个用户独立,因为运行代理键与隔离的会话键匹配

如果你想要一个共享的“房间大脑”,请设置:

yaml
group_sessions_per_user: false

这将群组/频道恢复为每个房间一个共享会话,这保留了共享的对话上下文,但也共享了 Token 成本、中断状态和上下文增长。

会话重置策略

网关会话根据可配置的策略自动重置:

  • idle — 在 N 分钟不活动后重置
  • daily — 在每天的特定小时重置
  • both — 以先到者为准(空闲或每日)
  • none — 从不自动重置

在自动重置会话之前,代理会获得一个轮次来保存对话中的任何重要记忆或技能。

具有活动后台进程的会话永远不会自动重置,无论策略如何。

存储位置

内容路径描述
SQLite 数据库~/.hermes/state.db所有会话元数据 + 消息,带 FTS5
网关消息~/.hermes/state.dbSQLite — 所有会话消息的规范存储
网关路由索引~/.hermes/sessions/sessions.json将会话键映射到活动会话 ID(原始元数据、过期标志)

SQLite 数据库使用 WAL 模式支持并发读取和单个写入,这很好地适应了网关的多平台架构。

注意 — 遗留 JSONL 记录

在 state.db 成为规范存储之前创建的会话可能在 ~/.hermes/sessions/ 中留有 *.jsonl 文件。Hermes 不再写入或读取它们。在验证 state.db 中存在相应会话后,可以安全删除。

数据库模式

state.db 中的关键表:

  • sessions — 会话元数据(id、source、user_id、model、title、timestamps、token counts)。标题有唯一索引(允许 NULL 标题,只有非 NULL 必须唯一)。
  • messages — 完整消息历史(role、content、tool_calls、tool_name、token_count)
  • messages_fts — 用于跨消息内容全文搜索的 FTS5 虚拟表

会话过期与清理

自动清理

  • 网关会话根据配置的重置策略自动重置
  • 在重置之前,代理会保存过期会话中的记忆和技能
  • 可选自动清理:当 sessions.auto_prunetrue 时,在 CLI/网关启动时清理超过 sessions.retention_days(默认 90 天)的已结束会话
  • 在真正删除行之后,state.db 会执行 VACUUM 以回收磁盘空间(SQLite 在普通 DELETE 后不会缩小文件)
  • 清理最多每 sessions.min_interval_hours(默认 24)运行一次;最后运行时间戳存储在 state.db 本身中,因此它在同一 HERMES_HOME 中的所有 Hermes 进程之间共享

默认是关闭的——会话历史对于 session_search 回忆很有价值,静默删除可能会让用户感到惊讶。在 ~/.hermes/config.yaml 中启用:

yaml
sessions:
  auto_prune: true          # 选择加入 — 默认为 false
  retention_days: 90        # 保留已结束会话的天数
  vacuum_after_prune: true  # 清理后回收磁盘空间
  min_interval_hours: 24    # 不要比这个更频繁地运行清理

活动会话永远不会被自动清理,无论其年龄如何。

手动清理

bash
## 清理超过 90 天的会话
hermes sessions prune
## 删除特定会话
hermes sessions delete <session_id>
## 在清理前导出(备份)
hermes sessions export backup.jsonl
hermes sessions prune --older-than 30 --yes

提示

数据库增长缓慢(典型:数百个会话 10-15 MB),会话历史为跨过去对话的 session_search 回忆提供支持,因此自动清理默认是禁用的。如果你正在运行高负载的网关/定时任务工作负载,其中 state.db 显著影响性能(观察到的失败模式:384 MB 的 state.db 包含约 1000 个会话,导致 FTS5 插入和 /resume 列表变慢),请启用它。使用 hermes sessions prune 进行一次性清理,而无需打开自动清理。


分享: