Telegram 配置
Hermes Agent 以功能完整的对话机器人形式集成到 Telegram。连接后,你可以从任意设备与 Agent 聊天、发送语音备忘录并自动转录、接收定时任务结果,以及在群组中使用 Agent。该集成基于 python-telegram-bot,支持文本、语音、图片和文件附件。
第一步:通过 BotFather 创建机器人
每个 Telegram 机器人都需要由 @BotFather(Telegram 官方机器人管理工具)签发 API Token。
- 打开 Telegram,搜索 @BotFather,或访问 t.me/BotFather
- 发送
/newbot - 选择一个显示名称(如"Hermes Agent")——可以是任意名称
- 选择一个用户名——必须唯一且以
bot结尾(如my_hermes_bot) - BotFather 回复你的 API Token,格式如下:
123456789:ABCdefGHIjklMNOpqrSTUvwxYZ
请妥善保管机器人 Token。任何持有此 Token 的人都可以控制你的机器人。如果泄露,请立即通过 BotFather 的 /revoke 命令撤销。
第二步:自定义机器人(可选)
以下 BotFather 命令可改善用户体验。向 @BotFather 发送:
| 命令 | 用途 |
|---|---|
/setdescription | 用户开始聊天前显示的"这个机器人能做什么?"文字 |
/setabouttext | 机器人资料页的简短文字 |
/setuserpic | 上传机器人头像 |
/setcommands | 定义命令菜单(聊天中的 / 按钮) |
/setprivacy | 控制机器人是否能看到群组中的所有消息(参见第三步) |
对于 /setcommands,一套实用的起始命令:
help - Show help information
new - Start a new conversation
sethome - Set this chat as the home channel
第三步:隐私模式(群组中的关键设置)
Telegram 机器人有一个默认开启的隐私模式。这是在群组中使用机器人时最常见的困惑来源。
隐私模式开启时,机器人只能看到:
- 以
/命令开头的消息 - 直接回复机器人消息的内容
- 服务消息(成员加入/离开、置顶消息等)
- 机器人作为管理员的频道消息
隐私模式关闭时,机器人接收群组中的每条消息。
如何关闭隐私模式
- 向 @BotFather 发消息
- 发送
/mybots - 选择你的机器人
- 进入 Bot Settings → Group Privacy → Turn off
更改隐私设置后,必须将机器人从群组中移除再重新添加。 Telegram 会在机器人加入群组时缓存隐私状态,除非移除并重新添加,否则不会更新。
禁用隐私模式的替代方案:将机器人提升为群组管理员。管理员机器人无论隐私设置如何都能收到所有消息,并且无需切换全局隐私模式。
第四步:获取你的用户 ID
Hermes Agent 使用数字 Telegram 用户 ID 来控制访问权限。你的用户 ID 不是用户名——它是一个类似 123456789 的数字。
方法一(推荐): 向 @userinfobot 发消息——它会立即回复你的用户 ID。
方法二: 向 @get_id_bot 发消息——另一个可靠的选择。
保存这个数字,下一步会用到。
第五步:配置 Hermes
方式 A:交互式配置(推荐)
hermes gateway setup
在提示时选择 Telegram。向导会询问机器人 Token 和允许的用户 ID,然后自动写入配置。
方式 B:手动配置
在 ~/.hermes/.env 中添加以下内容:
TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrSTUvwxYZ
TELEGRAM_ALLOWED_USERS=123456789 # 多用户时用逗号分隔
启动网关
hermes gateway
机器人应在几秒内上线。在 Telegram 上给它发消息以验证。
从 Docker 终端发送生成的文件
如果你的终端后端是 docker,请注意 Telegram 附件由网关进程发送,而非从容器内部发送。这意味着最终的 MEDIA:/... 路径必须在运行网关的主机上可读。
常见问题:
- Agent 在 Docker 内写入文件到
/workspace/report.txt - 模型输出
MEDIA:/workspace/report.txt - Telegram 投递失败,因为
/workspace/report.txt只存在于容器内,不在主机上
推荐方式:
terminal:
backend: docker
docker_volumes:
- "/home/user/.hermes/cache/documents:/output"
然后:
- 在 Docker 内将文件写入
/output/... - 在
MEDIA:中使用主机可见的路径,例如:MEDIA:/home/user/.hermes/cache/documents/report.txt
如果你已有 docker_volumes: 部分,将新挂载添加到同一列表。YAML 中的重复键会静默覆盖前面的值。
支持的 MEDIA: 文件扩展名
网关从 Agent 回复中提取 MEDIA:/path/to/file 标签,并将引用的文件作为平台原生附件发送。所有网关平台支持的扩展名:
| 类别 | 扩展名 |
|---|---|
| 图片 | png, jpg, jpeg, gif, webp, bmp, tiff, svg |
| 音频 | mp3, wav, ogg, m4a, opus, flac, aac |
| 视频 | mp4, mov, webm, mkv, avi |
| 文档 | pdf, txt, md, csv, json, xml, html, yaml, yml, log |
| Office | docx, xlsx, pptx, odt, ods, odp |
| 压缩包 | zip, rar, 7z, tar, gz, bz2 |
| 书籍/安装包 | epub, apk, ipa |
列表中的所有类型在支持的平台(Telegram、Discord、Signal、Slack、WhatsApp、飞书、Matrix 等)上都以原生附件形式投递;不支持原生附件的平台会回退为链接或纯文本提示。粗体类别是最近几个版本新增的——如果你之前依靠模型说 here is the file: /path/to/report.docx,请改用 MEDIA:/path/to/report.docx 以实现原生投递。
Webhook 模式
默认情况下,Hermes 使用长轮询连接 Telegram——网关向 Telegram 服务器发出出站请求以获取新更新。这对本地和常驻部署效果很好。
对于云部署(Fly.io、Railway、Render 等),Webhook 模式更经济。这些平台可以在收到入站 HTTP 流量时自动唤醒挂起的机器,但对出站连接不能。由于轮询是出站的,轮询模式的机器人永远无法休眠。Webhook 模式反转了方向——Telegram 将更新推送到你的机器人 HTTPS URL,从而实现空闲时休眠的部署。
| 轮询(默认) | Webhook | |
|---|---|---|
| 方向 | 网关 → Telegram(出站) | Telegram → 网关(入站) |
| 适合 | 本地、常驻服务器 | 支持自动唤醒的云平台 |
| 配置 | 无需额外配置 | 设置 TELEGRAM_WEBHOOK_URL |
| 空闲费用 | 机器必须保持运行 | 消息间隔期间机器可以休眠 |
配置
在 ~/.hermes/.env 中添加以下内容:
TELEGRAM_WEBHOOK_URL=https://my-app.fly.dev/telegram
TELEGRAM_WEBHOOK_SECRET="$(openssl rand -hex 32)" # 必须设置
# TELEGRAM_WEBHOOK_PORT=8443 # 可选,默认 8443
| 变量 | 是否必须 | 说明 |
|---|---|---|
TELEGRAM_WEBHOOK_URL | 是 | Telegram 将向其发送更新的公开 HTTPS URL。URL 路径会自动提取(如从上例中提取 /telegram)。 |
TELEGRAM_WEBHOOK_SECRET | 是(设置 TELEGRAM_WEBHOOK_URL 时) | Telegram 在每个 Webhook 请求中回显的密钥 Token,用于验证。未设置时网关拒绝启动——参见 GHSA-3vpc-7q5r-276h。使用 openssl rand -hex 32 生成。 |
TELEGRAM_WEBHOOK_PORT | 否 | Webhook 服务器监听的本地端口(默认:8443)。 |
设置 TELEGRAM_WEBHOOK_URL 后,网关启动 HTTP Webhook 服务器而不是轮询。未设置时使用轮询模式——与之前版本的行为一致。
云部署示例(Fly.io)
- 将环境变量添加到 Fly.io 应用密钥:
fly secrets set TELEGRAM_WEBHOOK_URL=https://my-app.fly.dev/telegram
fly secrets set TELEGRAM_WEBHOOK_SECRET=$(openssl rand -hex 32)
- 在
fly.toml中暴露 Webhook 端口:
[[services]]
internal_port = 8443
protocol = "tcp"
[[services.ports]]
handlers = ["tls", "http"]
port = 443
- 部署:
fly deploy
网关日志应显示:[telegram] Connected to Telegram (webhook mode)。
代理支持
如果 Telegram API 被屏蔽或需要通过代理路由流量,可以设置 Telegram 专用代理 URL。此设置优先于通用的 HTTPS_PROXY / HTTP_PROXY 环境变量。
方式一:config.yaml(推荐)
telegram:
proxy_url: "socks5://127.0.0.1:1080"
方式二:环境变量
TELEGRAM_PROXY=socks5://127.0.0.1:1080
支持的协议:http://、https://、socks5://。
代理对主 Telegram 连接和备用 IP 传输均有效。如果未设置 Telegram 专用代理,网关会回退到 HTTPS_PROXY / HTTP_PROXY / ALL_PROXY(或 macOS 系统代理自动检测)。
主频道
在任意 Telegram 聊天(私信或群组)中使用 /sethome 命令,将其设为主频道。定时任务(Cron 任务)的结果会投递到此频道。
也可以在 ~/.hermes/.env 中手动设置:
TELEGRAM_HOME_CHANNEL=-1001234567890
TELEGRAM_HOME_CHANNEL_NAME="My Notes"
群组聊天 ID 是负数(如 -1001234567890)。你的个人私信 ID 与你的用户 ID 相同。
语音消息
接收语音(语音转文字)
你在 Telegram 上发送的语音消息会由 Hermes 配置的 STT 提供商自动转录,并作为文本注入对话。
local使用机器上运行的faster-whisper——无需 API 密钥groq使用 Groq Whisper,需要GROQ_API_KEYopenai使用 OpenAI Whisper,需要VOICE_TOOLS_OPENAI_KEY
发送语音(文字转语音)
当 Agent 通过 TTS 生成音频时,它以原生 Telegram 语音气泡形式投递——即圆形、可内联播放的那种。
- OpenAI 和 ElevenLabs 原生生成 Opus——无需额外配置
- Edge TTS(默认免费提供商)输出 MP3,需要 ffmpeg 转换为 Opus:
# Ubuntu/Debian
sudo apt install ffmpeg
# macOS
brew install ffmpeg
没有 ffmpeg 时,Edge TTS 音频以普通音频文件形式发送(仍可播放,但使用矩形播放器而非语音气泡)。
在 config.yaml 的 tts.provider 键下配置 TTS 提供商。
群组聊天使用
Hermes Agent 在 Telegram 群组中运行时需要注意以下几点:
- 隐私模式决定机器人能看到哪些消息(参见第三步)
TELEGRAM_ALLOWED_USERS仍然有效——即使在群组中,也只有授权用户才能触发机器人- 可以使用
telegram.require_mention: true防止机器人响应普通群组消息 - 设置
telegram.require_mention: true后,群组消息在以下情况下被接受:- 回复机器人消息的内容
@botusername提及/command@botusername(Telegram 机器人菜单命令,含机器人名称)- 匹配
telegram.mention_patterns中配置的正则唤醒词
- 使用
telegram.ignored_threads使 Hermes 在特定 Telegram 话题中保持静默,即使该群组允许自由响应或提及触发 - 如果
telegram.require_mention未设置或为 false,Hermes 保持之前的开放群组行为,响应能看到的普通群组消息
排查:私信可用但群组不响应
如果机器人在私聊中响应但在群组中保持静默,请按顺序检查以下几点:
- Telegram 投递: 关闭 BotFather 隐私模式、将机器人提升为管理员,或直接提及机器人。Telegram 不投递给机器人的群组消息,Hermes 无法响应。
- 更改隐私后重新加入: 更改 BotFather 隐私设置后,将机器人从群组中移除再重新添加。Telegram 可能对已有成员保留旧的投递行为。
- Hermes 授权: 确保发送者在
TELEGRAM_ALLOWED_USERS或TELEGRAM_GROUP_ALLOWED_USERS中,或通过TELEGRAM_GROUP_ALLOWED_CHATS允许该群组聊天。 - 提及过滤器: 如果设置了
telegram.require_mention: true,普通群组消息会被忽略,除非是斜杠命令、对机器人的回复、@botusername提及或配置的mention_patterns匹配。
Telegram 群组和超级群组的负数聊天 ID 是正常的。如果使用基于聊天的授权,请将这些 ID 放在 TELEGRAM_GROUP_ALLOWED_CHATS 中,而非发送者用户白名单。
群组触发配置示例
在 ~/.hermes/config.yaml 中添加:
telegram:
require_mention: true
mention_patterns:
- "^\\s*chompy\\b"
ignored_threads:
- 31
- "42"
此示例允许所有常规直接触发方式,以及以 chompy 开头的消息(即使不使用 @mention)。Telegram 话题 31 和 42 中的消息在提及检查和自由响应检查之前始终被忽略。
mention_patterns 说明
- 使用 Python 正则表达式
- 匹配不区分大小写
- 同时检查文本消息和媒体说明文字
- 无效的正则模式会在网关日志中记录警告并被忽略,不会导致机器人崩溃
- 如果希望模式只在消息开头匹配,请使用
^锚点
私信话题(Bot API 9.4)
Telegram Bot API 9.4(2026 年 2 月)引入了私信话题——机器人可以直接在一对一私信中创建论坛式话题帖,无需超级群组。这让你可以在与 Hermes 的现有私信中运行多个独立的工作空间。
使用场景
如果你同时处理多个长期项目,话题可以隔离各自的上下文:
- 话题"网站" — 处理生产 Web 服务
- 话题"研究" — 文献综述和论文探索
- 话题"通用" — 杂项任务和快速问答
每个话题拥有独立的对话会话、历史记录和上下文窗口——彼此完全隔离。
配置
在配置中添加话题之前,用户必须在与机器人的私信中启用话题模式:
- 在 Telegram 中打开与 Hermes 机器人的私聊
- 点击顶部的机器人名称,打开聊天信息
- 启用话题(将聊天转为论坛的开关)
没有此操作,Hermes 会在启动时记录 The chat is not a forum 并跳过话题创建。这是 Telegram 客户端设置——机器人无法以编程方式启用它。
在 ~/.hermes/config.yaml 的 platforms.telegram.extra.dm_topics 下添加话题:
platforms:
telegram:
extra:
dm_topics:
- chat_id: 123456789 # 你的 Telegram 用户 ID
topics:
- name: General
icon_color: 7322096
- name: Website
icon_color: 9367192
- name: Research
icon_color: 16766590
skill: arxiv # 在此话题中自动加载技能
字段说明:
| 字段 | 是否必须 | 说明 |
|---|---|---|
name | 是 | 话题显示名称 |
icon_color | 否 | Telegram 图标颜色代码(整数) |
icon_custom_emoji_id | 否 | 话题图标的自定义表情 ID |
skill | 否 | 在此话题新会话中自动加载的技能(Skill) |
thread_id | 否 | 话题创建后自动填充——不要手动设置 |
工作原理
- 网关启动时,Hermes 为每个尚无
thread_id的话题调用createForumTopic thread_id自动保存回config.yaml——后续重启时跳过 API 调用- 每个话题映射到独立的会话键:
agent:main:telegram:dm:{chat_id}:{thread_id} - 每个话题有独立的对话历史、记忆刷新和上下文窗口
技能绑定
带有 skill 字段的话题在该话题新会话启动时会自动加载对应技能。其工作方式与在对话开头输入 /skill-name 完全一致——技能内容注入到第一条消息中,后续消息可在对话历史中看到它。
例如,带有 skill: arxiv 的话题在会话重置时(因空闲超时、每日重置或手动 /reset)会预加载 arxiv 技能。
在配置之外创建的话题(如手动调用 Telegram API)会在收到 forum_topic_created 服务消息时自动发现。网关运行期间也可以向配置添加话题——它们会在下次缓存未命中时被识别。
多会话私信模式(/topic)
一种类似 ChatGPT 的多会话私信——一个机器人,多个并行对话。与上面运营商策划的 extra.dm_topics 不同,此模式由用户驱动:无需配置,无需预先声明话题名称。用户通过 /topic 开启,然后点击 Telegram 的 + 按钮创建任意数量的话题,每个话题都是完全独立的 Hermes 会话。
/topic 子命令
| 形式 | 上下文 | 效果 |
|---|---|---|
/topic | 根私信,尚未启用 | 检查 BotFather 能力,启用多会话模式,创建置顶 System 话题 |
/topic | 根私信,已启用 | 显示状态:可恢复的未关联会话 |
/topic | 话题内部 | 显示当前话题的会话绑定 |
/topic help | 任意位置 | 内联使用说明 |
/topic off | 根私信 | 禁用多会话模式并清除此聊天的所有话题绑定 |
/topic <session-id> | 话题内部 | 将之前的 Telegram 会话恢复到当前话题 |
只有授权用户(通过 TELEGRAM_ALLOWED_USERS / 平台认证配置的白名单)可以运行 /topic。未授权的发送者会收到拒绝而非激活。
私信话题与多会话私信模式的区别
extra.dm_topics(配置驱动) | /topic(用户驱动) | |
|---|---|---|
| 谁来激活 | 运营商,在 config.yaml 中 | 终端用户,通过发送 /topic |
| 话题列表 | 配置中声明的固定集合 | 用户可自由创建/删除话题 |
| 话题名称 | 由运营商选择 | 由用户选择;自动重命名以匹配 Hermes 会话标题 |
| 根私信行为 | 不变——正常聊天 | 变为系统大厅(非命令消息被拒绝) |
| 主要用途 | 带可选技能绑定的永久工作空间 | 临时并行会话 |
| 持久化 | extra.dm_topics 在配置中 | telegram_dm_topic_mode + telegram_dm_topic_bindings SQLite 表 |
这两个功能可以在同一个机器人上共存——你从某用户的私信运行 /topic,extra.dm_topics 继续为其他聊天管理运营商声明的话题。
前提条件
在 @BotFather 中,打开你的机器人 → Bot Settings → Threads Settings:
- 开启 Threaded Mode(启用
has_topics_enabled) - 不要禁用用户创建话题(保持
allows_users_to_create_topics开启)
用户首次运行 /topic 时,Hermes 调用 getMe 验证这两个标志。如果任一标志关闭,Hermes 会发送 BotFather Threads Settings 页面的截图并说明需要切换的内容——直到满足前提条件才会激活。
激活流程
在根私信中发送:
/topic
Hermes 将:
- 检查
getMe().has_topics_enabled和allows_users_to_create_topics - 如果两者都为 true,为此私信启用多会话话题模式
- 创建并置顶一个 System 话题(尽力而为)
- 回复用户可恢复的之前未关联 Telegram 会话列表
激活后,根私信变为大厅:普通提示词被拒绝,并引导用户前往 All Messages。系统命令(/status、/sessions、/usage、/help 等)在根目录仍然有效。
创建新话题(用户端流程)
- 在 Telegram 中打开机器人私信
- 点击机器人界面顶部的 All Messages,然后发送任意消息
- Telegram 为该消息创建新话题
- Hermes 在该话题内回复——该话题现在是一个独立会话
每个话题都有独立的对话历史、模型状态、工具执行和会话 ID。隔离键为 agent:main:telegram:dm:{chat_id}:{thread_id}——与配置驱动的私信话题隔离方式相同。
话题自动重命名
当 Hermes 为话题生成会话标题(首次对话后通过自动标题流程),Telegram 话题本身也会重命名以匹配——例如"New Topic"变为"数据库迁移计划"。重命名是尽力而为:失败时记录日志但不影响会话。
话题内的 /new
重置当前话题的会话(新会话 ID,清空历史),不影响其他话题。Hermes 回复提示:如需并行工作,通常创建另一个话题(通过 All Messages)才是你想要的。
恢复之前的会话
在话题内发送:
/topic <session-id>
这会将当前话题绑定到已有的 Hermes 会话,而不是开始新会话。适合继续话题模式启用前开始的对话。限制条件:
- 目标会话必须属于同一 Telegram 用户
- 目标会话不能已经绑定到另一个话题
Hermes 确认会话标题,并重放最后一条 Assistant 消息以提供上下文。
要发现会话 ID,在根私信中发送 /topic(无参数)——Hermes 会列出用户的未关联 Telegram 会话。
话题内的 /topic(无参数)
显示当前话题的绑定:会话标题、会话 ID,以及 /new 与创建另一个话题的提示。
底层实现
- 激活状态持久化到
state.db中的telegram_dm_topic_mode(chat_id, user_id, enabled, ...) - 每个话题绑定持久化到
telegram_dm_topic_bindings(chat_id, thread_id, session_id, ...)中,session_id上有ON DELETE CASCADE——删除会话时自动清除其话题绑定 - 话题模式的 SQLite 迁移是按需的:在首次调用
/topic时运行,网关启动时不运行。在此配置文件中,用户运行/topic之前state.db不会变化 - 每条入站私信消息查找其
(chat_id, thread_id)绑定。如果存在,查找会通过SessionStore.switch_session()将消息路由到绑定会话,确保磁盘上的会话键到会话 ID 的映射保持一致 - 话题内的
/new将绑定行重写为指向新会话 ID,确保下一条消息在新会话上 extra.dm_topics中声明的话题永远不会自动重命名——即使启用了多会话模式,运营商选择的名称也会保留- 启用了论坛的私信中的通用(置顶)话题被视为根大厅,无论 Telegram 是以
message_thread_id=1还是不带thread_id投递其消息 - 根大厅提示有频率限制,每个聊天每 30 秒最多一条——忘记话题模式已开启并在根目录输入十条提示的用户不会收到十条回复
- BotFather 配置截图有频率限制,每个聊天每 5 分钟最多发送一次——在 Threads Settings 仍然禁用时重复尝试
/topic不会重复上传同一张图片 - 在话题内启动的
/background <prompt>会将结果投递回同一话题;后台会话不触发所属话题的自动重命名 /topic本身由机器人的用户授权检查控制——未授权的私信收到拒绝而非激活
禁用多会话模式
在根私信中发送 /topic off。Hermes 关闭该行,清除聊天的 (thread_id → session_id) 绑定,根私信恢复为普通 Hermes 聊天。Telegram 中现有的话题不会被删除——它们只是不再作为独立会话被隔离。稍后重新运行 /topic 可重新开启。
如果需要手动清理(如批量重置多个聊天),直接删除行:
sqlite3 ~/.hermes/state.db \
"UPDATE telegram_dm_topic_mode SET enabled = 0 WHERE chat_id = '<your_chat_id>'; \
DELETE FROM telegram_dm_topic_bindings WHERE chat_id = '<your_chat_id>';"
降级 Hermes
如果你降级到 /topic 之前的 Hermes 版本,该功能会直接停止工作——telegram_dm_topic_mode 和 telegram_dm_topic_bindings 表保留在 state.db 中,但被旧代码忽略。私信恢复到原生的每线程隔离(每个 message_thread_id 仍通过 build_session_key 获得独立会话),因此现有的 Telegram 话题继续作为并行会话工作。根私信不再是大厅——消息像以前一样进入 Agent。重新升级后多会话模式在原处精确恢复。
群组论坛话题技能绑定
启用了话题模式的超级群组(也称为"论坛话题")已经实现了每话题的会话隔离——每个 thread_id 映射到独立对话。但你可能希望在特定群组话题中收到消息时自动加载技能,就像私信话题技能绑定的工作方式一样。
使用场景
一个有不同工作流程话题的团队超级群组:
- 工程话题 → 自动加载
software-development技能 - 研究话题 → 自动加载
arxiv技能 - 通用话题 → 无技能,通用助手
配置
在 ~/.hermes/config.yaml 的 platforms.telegram.extra.group_topics 下添加话题绑定:
platforms:
telegram:
extra:
group_topics:
- chat_id: -1001234567890 # 超级群组 ID
topics:
- name: Engineering
thread_id: 5
skill: software-development
- name: Research
thread_id: 12
skill: arxiv
- name: General
thread_id: 1
# 无技能——通用用途
字段说明:
| 字段 | 是否必须 | 说明 |
|---|---|---|
chat_id | 是 | 超级群组的数字 ID(以 -100 开头的负数) |
name | 否 | 话题的人类可读标签(仅供参考) |
thread_id | 是 | Telegram 论坛话题 ID——在 t.me/c/<group_id>/<thread_id> 链接中可见 |
skill | 否 | 在此话题新会话中自动加载的技能 |
工作原理
- 当消息到达已映射的群组话题时,Hermes 在
group_topics配置中查找chat_id和thread_id - 如果匹配的条目有
skill字段,该技能会为会话自动加载——与私信话题技能绑定完全一样 - 没有
skill键的话题仅获得会话隔离(现有行为,不变) - 未映射的
thread_id或chat_id值静默通过——无错误,无技能
与私信话题的区别
| 私信话题 | 群组话题 | |
|---|---|---|
| 配置键 | extra.dm_topics | extra.group_topics |
| 话题创建 | 如果 thread_id 缺失,Hermes 通过 API 创建话题 | 管理员在 Telegram 界面创建话题 |
thread_id | 创建后自动填充 | 必须手动设置 |
icon_color / icon_custom_emoji_id | 支持 | 不适用(管理员控制外观) |
| 技能绑定 | ✓ | ✓ |
| 会话隔离 | ✓ | ✓(论坛话题已内置) |
要查找话题的 thread_id,在 Telegram Web 或桌面版中打开话题并查看 URL:https://t.me/c/1234567890/5——最后一个数字(5)就是 thread_id。超级群组的 chat_id 是以 -100 为前缀的群组 ID(如群组 1234567890 变为 -1001234567890)。
最新 Bot API 功能
- Bot API 9.4(2026 年 2 月): 私信话题——机器人可通过
createForumTopic在一对一私信中创建论坛话题。Hermes 将此用于两个不同的功能:运营商策划的私信话题(配置驱动,固定话题列表)和用户驱动的多会话私信模式(通过/topic激活,用户无限创建话题)。 - 隐私政策: Telegram 现在要求机器人拥有隐私政策。通过 BotFather 的
/setprivacy_policy设置,否则 Telegram 可能自动生成占位符。如果你的机器人面向公众,这一点尤为重要。 - Bot API 9.5(2026 年 3 月):通过
sendMessageDraft的原生流式输出。 Hermes 使用 Telegram 的原生流式草稿 API,在私信中随着 token 到达而渲染 Agent 回复的动画预览。降低了你过去在使用旧版editMessageText轮询路径处理慢速模型时看到的每次编辑抖动。
流式传输(gateway.streaming.transport)
当流式输出启用时(gateway.streaming.enabled: true),Hermes 从四种传输方式中选择一种:
| 值 | 行为 |
|---|---|
auto(默认) | 在支持的聊天中启用原生草稿流式输出(目前是 Telegram 私信);否则回退到旧版基于编辑的路径。如果草稿帧失败,会优雅回退。 |
draft | 强制原生草稿。如果聊天不支持草稿(例如群组/话题),记录降级并回退到编辑模式。 |
edit | 对所有聊天类型使用旧版渐进式 editMessageText 轮询。 |
off | 完全禁用流式输出(仅最终回复,无渐进式更新)。 |
在 ~/.hermes/config.yaml 中:
gateway:
streaming:
enabled: true
transport: auto # auto | draft | edit | off
在私信中使用 auto(默认)你会看到什么 —— 当 Agent 生成回复时,Telegram 显示动画草稿预览,token 逐个更新。回复完成后,它会作为常规消息投递,草稿预览在客户端自然清除。草稿没有消息 ID,因此最终答案会保留在你的聊天历史中。
群组和超级群组、论坛话题呢? Telegram 限制 sendMessageDraft 只能用于私信(DM)。网关会透明地回退到其他所有内容的基于编辑的路径 —— 和以前相同的 UX。
如果草稿帧失败怎么办? 任何失败(暂时性网络错误、服务端拒绝、较旧的 python-telegram-bot 安装)都会将该响应的其余部分回退到基于编辑的路径。下一个响应会获得新的尝试。
斜杠命令访问控制
默认情况下,每个被允许的用户都可以运行所有斜杠命令。要将你的允许列表拆分为管理员(完整的斜杠命令访问权限)和普通用户(仅你显式启用的命令),请将 allow_admin_from 和 user_allowed_commands 添加到平台的 extra 块:
gateway:
platforms:
telegram:
extra:
# 现有允许列表(不变)
allow_from:
- "123456789" # 管理员
- "555555555" # 普通用户
- "777777777" # 普通用户
# 新增 —— 管理员获得所有斜杠命令(内置 + 插件注册)
allow_admin_from:
- "123456789"
# 新增 —— 非管理员允许用户只能运行这些斜杠命令。
# /help 和 /whoami 始终被允许,以便用户可以看到他们的访问权限。
user_allowed_commands:
- status
- model
- history
# 可选:为群组分离管理员/命令列表
group_allow_admin_from:
- "123456789"
group_user_allowed_commands:
- status
行为:
- 在
allow_admin_from中列出的某作用域(DM 或群组)的用户可以运行每个已注册的斜杠命令 —— 内置命令和插件注册的命令 —— 通过实时注册表。 allow_from中但不在allow_admin_from中的用户只能运行user_allowed_commands中列出的命令,加上始终允许的基线:/help和/whoami。- 普通聊天(非斜杠消息)不受影响。非管理员用户仍然可以与 Agent 正常交谈,他们只是不能触发任意命令。
- 向后兼容: 如果未为某个作用域设置
allow_admin_from,该作用域的斜杠命令门控被禁用。现有安装无需更改即可继续工作。 - DM 管理员状态并不意味着群组管理员状态。每个作用域都有自己的管理员列表。
- 如果仅设置了
group_allow_admin_from,DM 作用域保持无限制(向后兼容)模式。
使用 /whoami 查看活动作用域、你的层级(管理员/用户/无限制)以及你可以运行哪些斜杠命令。
渲染:表格和链接预览
Telegram 的 MarkdownV2 没有原生表格语法——管道表格如果原样传递会渲染为带反斜杠转义的乱码。Hermes 会自动规范化 Markdown 表格:
- 小表格被展平为行组项目符号——每行在列标题下变为可读的项目列表。适合 2–4 列和短单元格。
- 较大或较宽的表格回退为带对齐列的围栏代码块,以防止内容折叠。同时添加一行提示让 Agent 知道在 Telegram 上后续回复应优先使用散文而非更多表格。
无需配置——适配器为每条消息选择合适的回退方式。如果你想要旧版的"始终代码块"行为,在 config.yaml 中设置 telegram.pretty_tables: false 可禁用表格规范化(默认:true)。
链接预览。 Telegram 会自动为机器人消息中的 URL 生成链接预览。如果你想取消这些预览(长 /tools 输出、提及十个链接的 Agent 回复等):
gateway:
platforms:
telegram:
extra:
disable_link_previews: true
启用后,Hermes 为每条出站消息附加 Telegram 的 LinkPreviewOptions(is_disabled=True),并在旧版 python-telegram-bot 上回退到旧版 disable_web_page_preview 参数。
群组白名单
Telegram 群组和论坛聊天有两个可以独立配置的访问控制:
- 发送者用户 ID(
group_allow_from/TELEGRAM_GROUP_ALLOWED_USERS)——仅适用于群组/论坛消息的发送者白名单。当你想让特定用户在群组中调用机器人而不将其加入TELEGRAM_ALLOWED_USERS(那样会给他们私信访问权限)时使用。 - 聊天 ID(
group_allowed_chats/TELEGRAM_GROUP_ALLOWED_CHATS)——基于聊天的白名单。这些群组/论坛的任何成员都可以与机器人互动。适合以群组成员身份作为访问信号的团队/支持机器人。
gateway:
platforms:
telegram:
extra:
# 全局访问(私信 + 群组)。这里的用户始终可以调用机器人。
allow_from:
- "123456789"
# 仅在群组/论坛中允许的发送者 ID。不授予私信访问权限。
group_allow_from:
- "987654321"
# 整个群组/论坛——任何成员均已授权。
group_allowed_chats:
- "-1001234567890"
等效环境变量:
TELEGRAM_ALLOWED_USERS="123456789"
TELEGRAM_GROUP_ALLOWED_USERS="987654321"
TELEGRAM_GROUP_ALLOWED_CHATS="-1001234567890"
行为说明:
TELEGRAM_ALLOWED_USERS覆盖所有聊天类型(私信、群组、论坛)。TELEGRAM_GROUP_ALLOWED_USERS只在群组/论坛中授权列出的发送者。除非列入TELEGRAM_ALLOWED_USERS,否则他们仍不能私信机器人。TELEGRAM_GROUP_ALLOWED_CHATS中的聊天授权该聊天的每个成员,无论发送者是谁。- 在任意这些配置中使用
*可允许任意发送者/聊天。 - 这在现有提及/模式触发器以及
group_topics+ignored_threads之上叠加。
从 PR #17686 之前迁移
在此拆分之前,TELEGRAM_GROUP_ALLOWED_USERS 是唯一的配置项,用户将聊天 ID 放入其中。为了向后兼容,TELEGRAM_GROUP_ALLOWED_USERS 中形如聊天 ID(以 - 开头)的值仍然被视为聊天 ID,并记录一次弃用警告。迁移方式:
# 旧(仍有效,但已弃用)
TELEGRAM_GROUP_ALLOWED_USERS="-1001234567890"
# 新
TELEGRAM_GROUP_ALLOWED_CHATS="-1001234567890"
交互式模型选择器
在 Telegram 聊天中不带参数发送 /model 时,Hermes 会显示用于切换模型的交互式内联键盘:
- 提供商选择——显示每个可用提供商及其模型数量的按钮(如"OpenAI (15)"、"✓ Anthropic (12)"表示当前提供商)。
- 模型选择——带有 Prev/Next 分页导航的模型列表,以及返回提供商的 Back 按钮和 Cancel。
当前模型和提供商显示在顶部。所有导航通过就地编辑同一条消息实现(不会产生聊天杂乱)。
如果知道确切的模型名称,直接输入 /model <name> 跳过选择器。也可以输入 /model <name> --global 在会话间持久化更改。
DNS-over-HTTPS 备用 IP
在某些受限网络中,api.telegram.org 可能解析到无法访问的 IP。Telegram 适配器包含一个备用 IP 机制,在保持正确 TLS 主机名和 SNI 的同时,透明地对备用 IP 进行重试连接。
工作原理
- 如果设置了
TELEGRAM_FALLBACK_IPS,直接使用这些 IP。 - 否则,适配器自动通过 DNS-over-HTTPS(DoH)查询 Google DNS 和 Cloudflare DNS 以发现
api.telegram.org的备用 IP。 - DoH 返回的、与系统 DNS 结果不同的 IP 作为备用使用。
- 如果 DoH 也被屏蔽,使用硬编码的种子 IP(
149.154.167.220)作为最后手段。 - 一旦备用 IP 成功,它就变为"粘性"——后续请求直接使用它,不再先重试主路径。
配置
# 明确的备用 IP(逗号分隔)
TELEGRAM_FALLBACK_IPS=149.154.167.220,149.154.167.221
或在 ~/.hermes/config.yaml 中:
platforms:
telegram:
extra:
fallback_ips:
- "149.154.167.220"
通常不需要手动配置。通过 DoH 的自动发现能处理大多数受限网络场景。只有在你的网络上 DoH 也被屏蔽时才需要 TELEGRAM_FALLBACK_IPS 环境变量。
代理支持
如果你的网络需要 HTTP 代理才能访问互联网(企业环境中常见),Telegram 适配器会自动读取标准代理环境变量并通过代理路由所有连接。
支持的变量
适配器按顺序检查以下环境变量,使用第一个设置的变量:
HTTPS_PROXYHTTP_PROXYALL_PROXYhttps_proxy/http_proxy/all_proxy(小写变体)
配置
启动网关前在环境中设置代理:
export HTTPS_PROXY=http://proxy.example.com:8080
hermes gateway
或添加到 ~/.hermes/.env:
HTTPS_PROXY=http://proxy.example.com:8080
代理对主传输和所有备用 IP 传输均有效。无需额外的 Hermes 配置——如果设置了环境变量,会自动使用。
这涵盖了 Hermes 用于 Telegram 连接的自定义备用传输层。其他地方使用的标准 httpx 客户端已原生支持代理环境变量。
消息表情反应
机器人可以为消息添加 Emoji 表情反应作为处理视觉反馈:
- 👀 机器人开始处理你的消息时
- ✅ 成功投递响应时
- ❌ 处理过程中发生错误时
表情反应默认禁用。在 config.yaml 中启用:
telegram:
reactions: true
或通过环境变量:
TELEGRAM_REACTIONS=true
与 Discord(表情反应是叠加的)不同,Telegram 的 Bot API 通过单次调用替换所有机器人表情反应。从 👀 到 ✅/❌ 的转换是原子的——你不会同时看到两者。
如果机器人在群组中没有添加表情反应的权限,表情反应调用会静默失败,消息处理照常继续。
频道专属提示词
为特定 Telegram 群组或论坛话题分配临时系统提示词。该提示词在每轮对话时在运行时注入——从不持久化到对话历史——因此更改立即生效。
telegram:
channel_prompts:
"-1001234567890": |
You are a research assistant. Focus on academic sources,
citations, and concise synthesis.
"42": |
This topic is for creative writing feedback. Be warm and
constructive.
键是聊天 ID(群组/超级群组)或论坛话题 ID。对于论坛群组,话题级提示词优先于群组级提示词:
- 群组
-1001234567890中话题42的消息 → 使用话题42的提示词 - 话题
99中的消息(无明确条目)→ 回退到群组-1001234567890的提示词 - 没有条目的群组中的消息 → 不应用频道提示词
数字 YAML 键自动规范化为字符串。
故障排查
| 问题 | 解决方案 |
|---|---|
| 机器人完全不响应 | 验证 TELEGRAM_BOT_TOKEN 是否正确。检查 hermes gateway 日志中的错误。 |
| 机器人回复"unauthorized" | 你的用户 ID 不在 TELEGRAM_ALLOWED_USERS 中。通过 @userinfobot 再次确认。 |
| 机器人忽略群组消息 | 隐私模式可能已开启。禁用它(第三步)或将机器人设为群组管理员。记住更改隐私设置后要移除并重新添加机器人。 |
| 语音消息未被转录 | 验证 STT 是否可用:安装 faster-whisper 进行本地转录,或在 ~/.hermes/.env 中设置 GROQ_API_KEY / VOICE_TOOLS_OPENAI_KEY。 |
| 语音回复是文件而非气泡 | 安装 ffmpeg(Edge TTS Opus 转换所需)。 |
| 机器人 Token 被撤销/无效 | 通过 BotFather 的 /revoke 然后 /newbot 或 /token 生成新 Token。更新 .env 文件。 |
| Webhook 未收到更新 | 验证 TELEGRAM_WEBHOOK_URL 是否可公开访问(用 curl 测试)。确保你的平台/反向代理将来自该 URL 端口的入站 HTTPS 流量路由到 TELEGRAM_WEBHOOK_PORT 配置的本地监听端口(两者无需相同)。确保 SSL/TLS 有效——Telegram 只向 HTTPS URL 发送。检查防火墙规则。 |
命令执行审批
当 Agent 尝试运行潜在危险的命令时,会在聊天中请求你的审批:
⚠️ This command is potentially dangerous (recursive delete). Reply "yes" to approve.
回复"yes"/"y"批准,或"no"/"n"拒绝。
Interactive Prompts (clarify)
当 Agent 调用 clarify 工具时——用于询问你更偏好哪种方案、获取任务后反馈,或在执行非简单决策前确认——Telegram 会用内联键盘按钮渲染问题:
❓ 我应该为仪表盘使用哪个框架?
[1. Next.js] [2. Remix] [3. Astro] [✏️ 其他(输入回答)]
点击按钮回答,或点击其他输入自由形式的回答(你发送的下一条消息即成为回答)。开放式的 clarify 调用(无预设选项)会跳过按钮,只捕获你的下一条消息。
通过 ~/.hermes/config.yaml 中的 agent.clarify_timeout 配置响应超时(默认 600 秒)。如果你在超时时间内未响应,Agent 会用一个哨兵消息解除阻塞并做出适应,而不是无限挂起。
安全
始终设置 TELEGRAM_ALLOWED_USERS 以限制谁可以与你的机器人互动。没有此设置,网关默认拒绝所有用户作为安全措施。
永远不要公开分享你的机器人 Token。如果泄露,立即通过 BotFather 的 /revoke 命令撤销。