Hermes Agent 会自动将每一次对话保存为一个会话(Session)。会话功能支持对话恢复、跨会话搜索以及完整的对话历史管理。
会话工作原理
Section titled “会话工作原理”无论是来自 CLI,还是 Telegram、Discord、Slack、WhatsApp、Signal、Matrix、Teams 或任何其他消息平台的对话,都会作为包含完整消息历史记录的会话进行存储。会话由两个互补的系统进行跟踪:
- SQLite 数据库 (
~/.hermes/state.db) —— 结构化的会话元数据,支持FTS5全文搜索。 - JSONL 副本 (
~/.hermes/sessions/) —— 原始对话副本,包含工具调用(网关)。
SQLite 数据库存储以下内容:
- 会话 ID、来源平台、用户 ID
- 会话标题(唯一的、人类可读的名称)
- 模型名称与配置
- 系统提示词快照
- 完整消息历史(角色、内容、工具调用、工具结果)
- 令牌计数(输入/输出)
- 时间戳(开始时间、结束时间)
- 父会话 ID(用于因压缩触发的会话拆分)
哪些内容会被计入上下文 (What Counts Toward Context)
Section titled “哪些内容会被计入上下文 (What Counts Toward Context)”Hermes 会存储会话历史以便恢复对话,但它不会重复发送处理过的每一个字节。在每一轮对话中,模型会看到选定的系统提示词、当前的对话窗口以及 Hermes 为该轮对话显式注入的任何内容。
媒体附件作为单轮作用域的输入进行处理:
- 图片可以直接原生附加到下一次模型调用中,或者当当前活跃的模型不支持原生视觉功能时,会被预先分析并转化为文本描述。
- 当配置了语音转文本时,音频会被转录为文本。
- 文本文件可以包含其提取出的文本;其他文件类型通常由保存的本地路径和简短备注来表示。
- 附件路径以及提取/衍生出的文本可以出现在对话记录中,但原始的图片、音频或二进制文件字节不会被重复复制到未来的提示词中。
例如,如果用户发送了一张图片并让 Hermes 用它制作一个迷因(meme),Hermes 可能会通过视觉功能对该图片进行一次检查,然后运行一个图像处理脚本。未来的对话轮次不会在上下文中自动携带原始的 JPEG 文件。它们只携带写入到对话中的内容,例如用户的请求、简短的图片描述、本地缓存路径或助手的最终回复。
导致上下文增长的最常见原因不是媒体文件本身,而是冗长的文本:粘贴的对话记录、完整的日志、庞大的工具输出、长篇的 diff 差异对比、重复的状态报告以及详细的论证转储。相较于将大型产物复制到聊天中,更推荐使用摘要、文件路径、聚焦的片段以及基于工具的查找。
每个会话都会标记其来源平台:
| 来源 | 描述 |
|---|---|
| cli | 交互式 CLI (hermes 或 hermes chat) |
| telegram | Telegram 消息软件 |
| discord | Discord 服务器/私聊 |
| slack | Slack 工作区 |
| WhatsApp 消息软件 | |
| signal | Signal 消息软件 |
| matrix | Matrix 房间和私聊 |
| mattermost | Mattermost 频道 |
| 电子邮件 (IMAP/SMTP) | |
| sms | 通过 Twilio 发送的短信 |
| dingtalk | 钉钉 |
| feishu | 飞书/Lark |
| wecom | 企业微信 |
| weixin | 微信个人号 |
| bluebubbles | 通过 BlueBubbles macOS 服务器发送的 Apple iMessage |
| qqbot | 通过官方 API v2 接入的 QQ 机器人 |
| homeassistant | Home Assistant 对话 |
| webhook | 传入的 Webhooks |
| api-server | API 服务器请求 |
| acp | ACP 编辑器集成 |
| cron | 定时任务 (Cron jobs) |
| batch | 批处理运行 |
CLI 会话恢复
Section titled “CLI 会话恢复”使用 --continue 或 --resume 从 CLI 恢复之前的对话:
继续最后一次会话
Section titled “继续最后一次会话”# 恢复最近的一次 CLI 会话hermes --continuehermes -c
# 或者使用 chat 子命令hermes chat --continuehermes chat -c这将从 SQLite 数据库中查找最近的 cli 会话并加载其完整的对话历史。
如果您为会话命了名(见下文 会话命名),可以按名称恢复:
# 恢复命名的会话hermes -c "my project"
# 如果存在系列变体(my project, my project #2, my project #3),# 这将自动恢复最近的一个hermes -c "my project" # → 恢复 "my project #3"恢复特定会话
Section titled “恢复特定会话”# 按 ID 恢复特定会话hermes --resume 20250305_091523_a1b2c3d4hermes -r 20250305_091523_a1b2c3d4
# 按标题恢复hermes --resume "refactoring auth"
# 或者使用 chat 子命令hermes chat --resume 20250305_091523_a1b2c3d4当您退出 CLI 会话时会显示会话 ID,也可以通过 hermes sessions list 查找。
恢复时的对话回顾
Section titled “恢复时的对话回顾”当您恢复会话时,Hermes 会在输入提示符之前的样式面板中显示先前对话的简要回顾:
(无图)
恢复模式会在返回实时提示符之前,显示包含近期用户和助手轮次的紧凑回顾面板。
回顾功能:
- 显示用户消息(金色 ●)和助手回答(绿色 ◆)
- 截断长消息(用户消息 300 字符,助手消息 200 字符/3 行)
- 折叠工具调用为带有工具名称的计数(例如:
[3 tool calls: terminal, web_search]) - 隐藏系统消息、工具结果和内部推理过程
- 上限为最后 10 次交流,并带有 ”… N earlier messages …” 指示器
- 使用暗淡样式以区别于当前的活跃对话
若要禁用回顾并保持极简的单行行为,请在 ~/.hermes/config.yaml 中设置:
display: resume_display: minimal # 默认:full跨平台移交(Cross-Platform Handoff)
Section titled “跨平台移交(Cross-Platform Handoff)”在 CLI 会话中使用 /handoff <platform> 可以将实时对话转移到消息平台的家频道(home channel)。代理会从 CLI 停止的地方完全接续 —— 相同的会话 ID、完整的角色感知副本、工具调用及所有内容。
# 在 CLI 会话中/handoff telegram执行流程:
- 验证: CLI 验证
<platform>已启用并设置了家频道(在目标聊天中运行一次/sethome即可完成配置)。 - 挂起: CLI 将会话标记为待处理(pending)并对网关进行阻塞式轮询。如果代理处于回复中,则拒绝移交 —— 需等待当前响应完成后再试。
- 网关接管: 网关监听器声明移交请求,并要求目标适配器开启一个新线程:
- Telegram —— 开启一个新的论坛话题(如果聊天启用了 Bot API 9.4+ 话题模式,则为私聊话题或论坛超级群话题)。
- Discord —— 在家文本频道下创建一个 1440 分钟自动归档的线程。
- Slack —— 发送一条种子消息,并将其
ts作为线程锚点。 - WhatsApp / Signal / Matrix / SMS —— 无原生线程支持,直接回退到家频道。
-
重新绑定: 网关将目标键(destination key)重新绑定到您现有的 CLI 会话 ID,然后伪造一个用户轮次,要求代理进行确认和总结。回复将发送至新线程。
-
退出: 当网关确认成功后,CLI 会打印
/resume提示并正常退出:↻ 移交完成。会话现已在 telegram 上激活。稍后在 CLI 上通过以下命令恢复:/resume my-session-title -
从此刻起,对话在平台上继续。在新线程中回复即可 —— 任何在该频道获得授权的人员都共享同一个会话。由于线程会话不以
user_id为键,因此线程中后续的任何真实用户消息都会无缝加入。
恢复至 CLI: 当您想回到桌面端时,只需运行 /resume <title>(或在 Shell 中运行 hermes -r "<title>"),即可从平台停止的地方继续。
失败模式:
- 未配置家频道 → CLI 拒绝移交并提示
/sethome指引。 - 平台未启用 / 网关未运行 → CLI 在 60 秒后超时并显示明确消息,您的 CLI 会话保持原状。
- 线程创建失败(权限不足、话题模式关闭) → 直接回退到家频道并完成移交;虽然没有线程隔离,但移交本身仍然有效。
- adapter.send 失败(速率限制、瞬时 API 错误) → 移交标记为失败并显示原因;记录会清除以便您重试。
值得注意的局限性: 对于不支持线程且家频道为多用户群组的平台,伪造的轮次会以私聊风格(DM-style)的会话为键。这适用于个人私聊类的家频道(典型配置),但对于真正的共享群聊并不理想。Telegram / Discord / Slack 均支持线程(这是绝大多数情况),因此多数配置不会遇到此问题。
会话命名(Session Naming)
Section titled “会话命名(Session Naming)”为会话提供人类可读的标题,以便您能够轻松地找到并恢复它们。
自动生成的标题
Section titled “自动生成的标题”在第一次交流后,Hermes 会自动为每个会话生成一个简短的描述性标题(3-7 个单词)。此操作在后台线程中使用快速辅助模型运行,因此不会增加任何延迟。您在通过 hermes sessions list 或 hermes sessions browse 浏览会话时会看到自动生成的标题。
自动命名在每个会话中仅触发一次,如果您已手动设置标题,则会跳过此操作。
手动设置标题
Section titled “手动设置标题”在任何聊天会话(CLI 或网关)中使用 /title 斜杠命令:
/title my research project标题会立即生效。如果会话尚未在数据库中创建(例如,您在发送第一条消息之前运行 /title),它将进入队列并在会话开始后立即应用。
您也可以从命令行重命名现有会话:
hermes sessions rename 20250305_091523_a1b2c3d4 "refactoring auth module"- 唯一性 —— 任意两个会话不能共用同一个标题。
- 最大 100 个字符 —— 保持列表输出整洁。
- 已清洗 —— 控制字符、零宽字符和 RTL(从右至左)覆盖字符会被自动剔除。
- 支持标准 Unicode —— 表情符号、中日韩文字(CJK)、带重音符号的字符均可正常使用。
压缩时的自动谱系(Auto-Lineage)
Section titled “压缩时的自动谱系(Auto-Lineage)”当会话上下文被压缩(通过 /compress 手动压缩或自动压缩)时,Hermes 会创建一个新的延续会话。如果原会话有标题,新会话会自动获得一个编号标题:
"my project" → "my project #2" → "my project #3"当您按名称恢复(hermes -c "my project")时,它会自动选择该谱系中最近的一个会话。
消息平台中的 /title
Section titled “消息平台中的 /title”/title 命令适用于所有网关平台(Telegram, Discord, Slack, WhatsApp):
/title My Research—— 设置会话标题/title—— 显示当前标题
会话管理命令(Session Management Commands)
Section titled “会话管理命令(Session Management Commands)”Hermes 通过 hermes sessions 提供了一套完整的会话管理命令:
列出会话(List Sessions)
Section titled “列出会话(List 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 |
导出会话(Export Sessions)
Section titled “导出会话(Export Sessions)”# 将所有会话导出到 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 对象,具有完整的会话元数据和所有消息。
删除会话(Delete a Session)
Section titled “删除会话(Delete a Session)”# 删除特定会话(需确认)hermes sessions delete 20250305_091523_a1b2c3d4
# 无需确认直接删除hermes sessions delete 20250305_091523_a1b2c3d4 --yes重命名会话(Rename a Session)
Section titled “重命名会话(Rename a Session)”# 设置或更改会话标题hermes sessions rename 20250305_091523_a1b2c3d4 "debugging auth flow"
# 在 CLI 中,多单词标题不需要引号hermes sessions rename 20250305_091523_a1b2c3d4 debugging auth flow如果标题已被其他会话占用,则会显示错误。
清理旧会话(Prune Old Sessions)
Section titled “清理旧会话(Prune Old Sessions)”# 删除超过 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会话统计(Session Statistics)
Section titled “会话统计(Session Statistics)”hermes sessions stats输出示例:
Total sessions: 142Total messages: 3847 cli: 89 sessions telegram: 38 sessions discord: 15 sessionsDatabase size: 12.4 MB若要获取更深层的分析数据 —— 如令牌使用量、成本预估、工具使用细分和活跃模式 —— 请使用 hermes insights。
会话搜索工具(Session Search Tool)
Section titled “会话搜索工具(Session Search Tool)”代理内置了 session_search 工具,利用 SQLite 的 FTS5 引擎在所有过往对话中执行全文搜索。
- FTS5 搜索:匹配消息并按相关性排序。
- 分组:按会话对结果进行分组,并提取前 N 个唯一会话(默认 3 个)。
- 加载与截断:加载每个会话的对话内容,并将其截断至约 10 万字符(以匹配项为中心)。
- 摘要:发送至快速摘要模型以生成针对性的总结。
- 返回:返回每个会话的摘要,包含元数据和周边上下文。
FTS5 查询语法
Section titled “FTS5 查询语法”该搜索支持标准的 FTS5 查询语法:
- 简单关键词:
docker deployment - 短语:
"exact phrase" - 布尔逻辑:
docker OR kubernetes,python NOT java - 前缀:
deploy*
可选参数 (Optional parameters)
Section titled “可选参数 (Optional parameters)”- sort — 可选
newest(最新)或oldest(最旧),在 FTS5(全文检索)排序的基础上生效。省略此参数则仅按相关性排序(默认值;适用于探索性召回)。对于 “我们在哪里留下了 X” 这类问题,使用newest;对于 “X 是如何开始的” 这类问题,使用oldest。 - role_filter — 以逗号分隔的需要包含的角色。探索发现默认值为
user,assistant(工具输出通常是噪音)。传入user,assistant,tool可包含工具输出(用于调试工具行为),或传入tool以仅搜索工具输出。
系统提示词会引导代理在以下情况下自动使用会话搜索:
“当用户提到过往对话中的内容,或者你怀疑存在相关的先验上下文时,请在要求用户重复之前,先使用
session_search进行召回。”
各平台会话跟踪 (Per-Platform Session Tracking)
Section titled “各平台会话跟踪 (Per-Platform Session Tracking)”网关会话 (Gateway Sessions)
Section titled “网关会话 (Gateway Sessions)”在消息平台上,会话由基于消息源构建的确定性会话键(session key)进行索引:
| 聊天类型 | 默认键格式 | 行为 |
|---|---|---|
| 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 隔离的群组会话
Section titled “共享 vs 隔离的群组会话”默认情况下,Hermes 在 config.yaml 中设置 group_sessions_per_user: true。这意味着:
- Alice 和 Bob 可以在同一个 Discord 频道中与 Hermes 交谈,而无需共享对话副本历史。
- 一个用户长时间的工具密集型任务不会污染另一个用户的上下文窗口。
- 中断处理也保持在用户级别,因为正在运行的代理键与隔离的会话键匹配。
如果您想要一个共享的 “房间大脑(room brain)”,请设置:
group_sessions_per_user: false这将使群组/频道恢复为每个房间单一的共享会话,这保留了共享的对话上下文,但也意味着共享令牌成本、中断状态和上下文增长。
会话重置策略 (Session Reset Policies)
Section titled “会话重置策略 (Session Reset Policies)”网关会话会根据可配置的策略自动重置:
- idle —— 在不活动 N 分钟后重置。
- daily —— 在每天的特定小时重置。
- both —— 无论哪种情况(闲置或每日定时)先发生即重置。
- none —— 永不自动重置。
在会话自动重置之前,代理会获得一个轮次,用于保存对话中的任何重要记忆或技能。
拥有活跃后台进程 的会话无论策略如何,都永远不会自动重置。
存储位置 (Storage Locations)
Section titled “存储位置 (Storage Locations)”| 内容 | 路径 | 描述 |
|---|---|---|
| SQLite 数据库 | ~/.hermes/state.db | 所有会话元数据 + 带有 FTS5 的消息 |
| 网关副本 | ~/.hermes/sessions/ | 每个会话的 JSONL 副本 + sessions.json 索引 |
| 网关索引 | ~/.hermes/sessions/sessions.json | 将会话键(session keys)映射到活跃会话 ID |
SQLite 数据库使用 WAL(预写日志)模式,支持并发读取和单写入者,非常适合网关的多平台架构。
数据库架构 (Database Schema)
Section titled “数据库架构 (Database Schema)”state.db 中的核心表:
- sessions —— 会话元数据(ID、来源、用户 ID、模型、标题、时间戳、令牌计数)。标题具有唯一索引(允许标题为 NULL,但非 NULL 的标题必须唯一)。
- messages —— 完整的消息历史记录(角色、内容、工具调用、工具名称、令牌计数)。
- messages_fts —— FTS5 虚拟表,用于跨消息内容进行全文搜索。
会话过期与清理
Section titled “会话过期与清理”- 网关会话根据配置的重置策略自动重置。
- 在重置前,代理会保存即将过期会话中的记忆和技能。
- 选择性开启自动清理:当
sessions.auto_prune为true时,早于sessions.retention_days(默认 90 天)的已结束会话将在 CLI/网关启动时被清理。 - 在执行了实际删除行的清理操作后,会对
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.jsonlhermes sessions prune --older-than 30 --yes