Telegram 私聊挤成一个话题?让每条新消息自己开一个话题

你在 Telegram 里用 Hermes 同时跟进三件事:一个线上报错的排查、一份周报的初稿、还有帮朋友改的一段脚本。你特意打开了 /topic 模式,让每件事各占一个话题,互不打扰。听起来很完美——直到你在手机上手滑,从主页直接往对话框里打了句话。
那句话没有进任何话题,而是落在了“你最近用过的那个话题”里。于是周报的上下文里突然出现了报错日志的结论,模型开始一本正经地把两件事混在一起讲。你往回翻半天才发现是哪一步出的错。
/topic 模式本身没有坏,它只是默认做了一个保守选择:根会话里的消息当成“接着上次聊”。如果你希望每条根会话消息都从头开始,Hermes 在 10 月 19 日合入了一个开关,叫 dm_topic_auto_transfer。
先搞清楚 /topic 模式现在的行为
在私聊里发 /topic,Hermes 会检查这个 bot 是否允许创建话题(BotFather 里的 Threaded Mode 要打开),然后为这个私聊开启多会话话题模式,顺手建一个置顶的 System 话题放状态和命令,并列出以前那些没有绑定话题的旧会话,问你要不要恢复。
开启之后,根会话(General / All Messages)就变成了一个“大厅”:普通提示会被拒绝,并提示你去 All Messages 里新建话题;而 /status、/sessions、/usage、/help 这类系统命令照旧能在根部用。
每个话题是一个独立会话:自己的历史、模型状态、工具执行和会话 id。隔离键是 agent:main:telegram:dm:{chat_id}:{thread_id}——也就是说,同一个私聊里的不同话题,对 Hermes 来说就是不同的对话。
问题就出在前面说的那个保守选择上:有些客户端在根会话里打字时不会带 message_thread_id。对这类消息,Hermes 默认把它当“上一次对话的延续”,直接答在你最近活跃的那个话题里(文档里叫 lobby recovery)。为了避免你忘了自己开着话题模式、在根部连打十条提示,这种大厅提醒还有限流:每(profile, 会话)30 秒最多一条。
打开开关:一条配置
在 profile 的 config.yaml 里加一行:
gateway:
platforms:
telegram:
extra:
dm_topic_auto_transfer: true # 默认 false
顶层的 telegram.extra.dm_topic_auto_transfer 也认(桌面端设置里显示的就是这个键)。关键点是它是 opt-in 的:不写这一行,行为和以前完全一样,还是回退到最近活跃的话题。
打开之后,你在根会话里打的每一条普通消息会这样走:
- Hermes 立刻新建一个话题(默认名字是 “Hermes Chat”,之后由自动标题管线改掉);
- 在这个话题里开一个新会话;
- 你的回复发在话题内部。
换句话说,根会话从“大厅”变成了“入口”:随手一打,就开了一间新房间。
哪些东西不会被转移
这个开关只处理“人在根会话里打的普通消息”,其它情况一概不动,这点在设计上划得很清楚:
- 斜杠命令不转移。在根会话里敲
/status,它还是大厅命令,不会给你新建一个话题。 - 内部唤醒和路由事件不转移。cron 触发、其它平台路由过来的事件、后台任务,都不会被塞进新话题。
- 非私聊不动。群组、频道里的消息跟这个话题模式无关。
- 未授权的发送者不动。授权检查在大厅阶段就完成了。
- 建话题失败就回退。如果 BotFather 里 Threaded Mode 被关掉了,创建话题会失败,Hermes 退回默认行为——答在你最近活跃的那个话题里,而不是把消息丢掉。
还有一个细节值得知道:转移发生在适配器入口、会话分配之前(具体实现在 Telegram 插件里的 telegram_topic_transfer.py),所以这一轮对话、它对应的会话、以及回复的位置,用的都是新话题,不会出现“会话在 A、回复在 B”的错位。
两个容易踩的小坑
第一,新话题里的第一条回复没有引用锚点。 因为你的原始消息在话题外面,Telegram 不允许跨话题引用,所以 Hermes 只按 message_thread_id 发送,不带 reply 锚点。看起来像“没回复到你那条消息”,但内容是在新话题里的,这是预期行为。
第二,多 bot 场景是按 bot 读配置的。 如果你用同一个 gateway 跑多个 Telegram bot(比如一个私人助手、一个团队群助手),这个开关读的是收到消息的那个 bot 的配置,而不是启动时的那个 bot。多 profile 共用 gateway 时要留意这点,别以为改了默认 profile 就全生效了。
顺带说一个相关的体验改进:话题的自动重命名。Hermes 生成会话标题之后,会尽量把 Telegram 话题名也改成一样的——“New Topic” 变成 “数据库迁移方案”。这是 best-effort 的,失败只写日志,不影响会话;如果你手动命名了话题、不想被改,文档里也有对应的关闭方式。
什么时候值得开,什么时候别开
值得开的场景:你把 Telegram 当成“多线程工作台”,每个话题对应一件事,且你经常从手机主页直接进对话。这时候每条消息独立开话题,等于强制“换个话题就换个上下文”,反而更干净。
不太值得开的场景:你其实只想跟 Hermes 一对一聊天,偶尔才用话题分隔。那每条根消息都新建话题会让列表迅速变长,而且自动标题还没来得及改名前,你会看到一排 “Hermes Chat”。
如果你更在意“一个话题一条长期任务线”的边界感,本站之前写的 会话边界指南 讲了话题、会话和上下文之间到底怎么对应;Telegram 内联选择器那篇 讲的是在聊天里直接选模型/会话的交互;如果你在折腾让两个 bot 互相说话,peer bot 互通 是另一条线。想从零把 Telegram 接起来,安装指南 里有平台配置的起点。
小结
dm_topic_auto_transfer 是个很小的开关,但它回答了一个具体问题:“我在根会话里随手打的这句话,到底属于哪段对话?“以前答案是”上次那个“,现在是“一个新对话”。默认保持旧行为是对的——毕竟大多数人不希望每条消息都开新话题——但对把 Telegram 当工作台的人来说,打开它之后,“上下文串味”这类事故基本就没了。