跳到主要内容

会话

Hermes Agent 会自动将每次对话保存为一个会话。会话支持对话恢复、跨会话搜索以及完整的对话历史管理。

会话工作原理

每次对话——无论来自 CLI、Telegram、Discord、Slack、WhatsApp、Signal、Matrix、Teams 还是其他任何消息平台——都会作为会话存储完整的消息历史。会话通过两个互补的系统进行追踪:

  1. SQLite 数据库~/.hermes/state.db)——结构化会话元数据,支持 FTS5 全文搜索
  2. JSONL 转录文件~/.hermes/sessions/)——包含工具调用的原始对话转录(网关)

SQLite 数据库存储以下信息:

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

计入上下文的内容

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

媒体附件作为轮次作用域的输入进行处理:

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

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

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

提示

当会话变长时使用 /compress,需要全新线程时使用 /new,只有在想从存储中删除旧的已结束会话时才使用 hermes sessions prune。压缩会减少活动上下文,它不是隐私删除操作。

会话来源

每个会话都标注了来源平台:

来源说明
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 恢复之前的对话:

继续上次会话

# 恢复最近一次 CLI 会话
hermes --continue
hermes -c

# 或使用 chat 子命令
hermes chat --continue
hermes chat -c

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

按名称恢复

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

# 按名称恢复会话
hermes -c "my project"

# 如果存在同名系列(my project、my project #2、my project #3),
# 此命令会自动恢复最新的一个
hermes -c "my project" # → 恢复 "my project #3"

恢复指定会话

# 通过 ID 恢复指定会话
hermes --resume 20250305_091523_a1b2c3d4
hermes -r 20250305_091523_a1b2c3d4

# 通过标题恢复
hermes --resume "refactoring auth"

# 或使用 chat 子命令
hermes chat --resume 20250305_091523_a1b2c3d4

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

恢复时的对话摘要

恢复会话时,Hermes 会在输入提示符前以样式化面板显示上次对话的简明摘要:

恢复 Hermes 会话时显示的「上次对话」摘要面板预览。

恢复模式会在返回实时提示符前显示包含最近用户和 Assistant 轮次的简明摘要面板。

摘要内容:

  • 显示用户消息(金色 )和 Assistant 回复(绿色
  • 对长消息进行截断(用户消息 300 字符,Assistant 消息 200 字符/3 行)
  • 将工具调用折叠为数量加工具名称(例如 [3 tool calls: terminal, web_search]
  • 隐藏系统消息、工具结果和内部推理过程
  • 最多显示最后 10 轮对话,并用"... N earlier messages ..."指示器表示更早的内容
  • 使用淡化样式与当前对话区分

若要禁用摘要并保留简洁的单行显示,请在 ~/.hermes/config.yaml 中设置:

display:
resume_display: minimal # 默认值:full
提示

会话 ID 格式为 YYYYMMDD_HHMMSS_<hex>——CLI/TUI 会话使用 6 位十六进制后缀(例如 20250305_091523_a1b2c3),网关会话使用 8 位后缀(例如 20250305_091523_a1b2c3d4)。可以通过 ID(完整或唯一前缀)或标题恢复,两种方式均支持 -c-r

跨平台移交

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

# 在 CLI 会话内
/handoff telegram

发生了什么:

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

  2. CLI 将会话标记为待处理并阻塞轮询网关。如果 Agent 处于轮次中间,它会拒绝操作——请等待当前回复完成后再试。

  3. 网关监视器接管移交并请求目标适配器创建新线程:

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

  5. 当网关确认成功后,CLI 会打印 /resume 提示并干净地退出:

    ↻ 移交完成。会话现在在 telegram 上处于活动状态。
    稍后使用以下命令在 CLI 上恢复:/resume my-session-title
  6. 从那时起,对话就在平台上继续。在新线程中回复——该频道中任何被授权的用户共享同一会话,并且线程中稍后的任何真实用户消息都会无缝加入,因为线程会话键不包含 user_id

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

失败模式:

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

值得了解的局限性: 对于具有多用户群组主频道的非线程能力平台,合成轮次会作为 DM 风格的会话进行键控。这适用于自 DM 主频道(典型设置),但对于真正的共享群组聊天并不理想。线程化覆盖了 Telegram / Discord / Slack——到目前为止最常见的情况——因此大多数设置永远不会遇到这个问题。

会话命名

为会话设置人类可读的标题,便于查找和恢复。

自动生成标题

Hermes 在第一轮对话后自动为每个会话生成简短的描述性标题(3–7 个单词)。此操作在后台线程中使用快速辅助模型执行,不会增加任何延迟。浏览 hermes sessions listhermes sessions browse 时即可看到自动生成的标题。

自动生成标题每个会话只触发一次,若已手动设置标题则跳过。

手动设置标题

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

/title my research project

标题立即生效。如果会话尚未在数据库中创建(例如在发送第一条消息前执行 /title),标题会进入队列,等到会话开始后再应用。

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

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 提供完整的会话管理命令集:

列出会话

# 列出最近的会话(默认:最近 20 条)
hermes sessions list

# 按平台过滤
hermes sessions list --source telegram

# 显示更多会话
hermes sessions list --limit 50

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

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

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

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

导出会话

# 将所有会话导出到 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 对象,包含完整会话元数据和所有消息。

删除会话

# 删除指定会话(需要确认)
hermes sessions delete 20250305_091523_a1b2c3d4

# 不需确认直接删除
hermes sessions delete 20250305_091523_a1b2c3d4 --yes

重命名会话

# 设置或修改会话标题
hermes sessions rename 20250305_091523_a1b2c3d4 "debugging auth flow"

# 多词标题在 CLI 中不需要引号
hermes sessions rename 20250305_091523_a1b2c3d4 debugging auth flow

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

清理旧会话

# 删除 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
信息

清理操作只删除已结束的会话(已显式结束或自动重置的会话)。活跃会话不会被清理。

会话统计

hermes sessions stats

输出示例:

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

如需更深入的分析——Token 用量、成本估算、工具分布和活跃度模式——请使用 hermes insights

会话搜索工具

Agent 内置了 session_search 工具,使用 SQLite 的 FTS5 引擎对所有历史对话进行全文搜索。

工作原理

  1. FTS5 按相关性排序搜索匹配的消息
  2. 按会话分组结果,取前 N 个唯一会话(默认 3 个)
  3. 加载每个会话的对话内容,以匹配位置为中心截取约 10 万字符
  4. 发送给快速摘要模型进行针对性摘要
  5. 返回每个会话的摘要及元数据和上下文

FTS5 查询语法

搜索支持标准 FTS5 查询语法:

  • 简单关键词:docker deployment
  • 短语搜索:"exact phrase"
  • 布尔运算:docker OR kubernetespython NOT java
  • 前缀搜索:deploy*

使用时机

Agent 会在以下情况自动使用会话搜索:

"当用户引用过去对话中的内容,或你判断可能存在相关历史上下文时,先使用 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 无法获取共享聊天的参与者标识符时,退回到该房间的单一共享会话。

共享 vs 独立群组会话

默认情况下,config.yaml 中的 group_sessions_per_user: true 表示:

  • Alice 和 Bob 可以在同一个 Discord 频道中与 Hermes 对话,而不会共享对话历史
  • 某个用户执行大量工具调用的任务不会污染其他用户的上下文窗口
  • 中断处理也保持每用户独立,因为运行中的 Agent 键与独立会话键相匹配

如果你希望使用一个共享的"房间大脑",可以设置:

group_sessions_per_user: false

这将群组/频道回退到每个房间单一共享会话,能保留共享的对话上下文,但同时也会共享 Token 费用、中断状态和上下文增长。

会话重置策略

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

  • idle——不活跃超过 N 分钟后重置
  • daily——每天在指定时间重置
  • both——先触发者(空闲或每日)即重置
  • none——永不自动重置

自动重置前,Agent 会获得一个轮次来保存对话中重要的记忆或技能。

正在运行后台进程的会话无论何种策略均不会被自动重置。

存储位置

内容路径说明
SQLite 数据库~/.hermes/state.db所有会话元数据和消息,支持 FTS5
网关转录文件~/.hermes/sessions/每个会话的 JSONL 转录 + sessions.json 索引
网关索引~/.hermes/sessions/sessions.json将会话键映射到活跃会话 ID

SQLite 数据库使用 WAL 模式支持并发读取和单写入,非常适合网关的多平台架构。

数据库结构

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 虚拟表

会话过期与清理

自动清理

  • 网关会话根据配置的重置策略自动重置
  • 重置前,Agent 会保存过期会话中的记忆和技能
  • 可选的自动清理:当 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 中启用:

sessions:
auto_prune: true # 可选开启——默认为 false
retention_days: 90 # 保留已结束会话的天数
vacuum_after_prune: true # 清理后回收磁盘空间
min_interval_hours: 24 # 清理扫描的最短间隔

无论会话年龄多大,活跃会话永远不会被自动清理。

手动清理

# 清理 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 对性能产生了明显影响(已知失效场景:约 1000 个会话时 state.db 达 384 MB,导致 FTS5 插入和 /resume 列表变慢),可以启用自动清理。一次性清理请使用 hermes sessions prune,无需开启自动扫描。