Telegram
Hermes Agent 可作为完整功能的 Telegram bot 运行。连接后,你可以从任意设备与 agent 对话,发送会自动转写的语音消息,接收定时任务结果,并在群聊中使用它。该集成基于 python-telegram-bot,支持文本、语音、图片和文件附件。
第 1 步:通过 BotFather 创建 Bot
每个 Telegram bot 都需要由 Telegram 官方 bot 管理工具 @BotFather 签发的 API token。
- 打开 Telegram,搜索 @BotFather,或访问 t.me/BotFather
- 发送
/newbot - 选择一个显示名(例如
Hermes Agent),这个名字可以随意设置 - 选择一个用户名,它必须唯一且以
bot结尾(例如my_hermes_bot) - BotFather 会返回你的 API token。格式类似:
123456789:ABCdefGHIjklMNOpqrSTUvwxYZ
请妥善保管 bot token。任何拿到该 token 的人都可以控制你的 bot。如果泄露,请立即在 BotFather 中用 /revoke 撤销。
第 2 步:自定义 Bot(可选)
这些 BotFather 命令可以改善使用体验。给 @BotFather 发送消息并使用:
| Command | Purpose |
|---|---|
/setdescription | 设置用户开始聊天前看到的 “这个 bot 能做什么?” 描述 |
/setabouttext | 设置 bot 资料页中的简短介绍 |
/setuserpic | 为 bot 上传头像 |
/setcommands | 定义命令菜单(聊天中的 / 按钮) |
/setprivacy | 控制 bot 是否能看到群里的所有消息(见第 3 步) |
对于 /setcommands,一个实用的起始配置是:
help - Show help information
new - Start a new conversation
sethome - Set this chat as the home channel
第 3 步:隐私模式(群组中至关重要)
Telegram bot 默认开启 privacy mode。这是群聊中最常见的困惑来源。
开启 privacy mode 时,你的 bot 只能看到:
- 以
/命令开头的消息 - 直接回复给 bot 自己消息的内容
- 服务消息(成员加入/退出、置顶消息等)
- bot 拥有管理员权限的频道中的消息
关闭 privacy mode 时,bot 会收到群里的每一条消息。
如何关闭 privacy mode
- 私聊 @BotFather
- 发送
/mybots - 选中你的 bot
- 进入 Bot Settings → Group Privacy → Turn off
修改隐私设置后,必须把 bot 从已加入的群中移除并重新加入。Telegram 会在 bot 入群时缓存隐私状态,不重新加入就不会更新。
如果你不想全局关闭 privacy mode,也可以把 bot 提升为群管理员。管理员 bot 无论隐私设置如何,都能收到全部群消息。
第 4 步:找到你的用户 ID
Hermes Agent 使用数字型 Telegram user ID 做访问控制。它不是你的用户名,而是类似 123456789 的数字。
方法 1(推荐):私聊 @userinfobot,它会立即返回你的 user ID。
方法 2:私聊 @get_id_bot,这也是稳定可靠的选项。
把这个数字保存好;下一步会用到。
第 5 步:配置 Hermes
Option A: Interactive Setup (Recommended)
hermes gateway setup
在向导中选择 Telegram。它会询问你的 bot token 和允许的用户 ID,然后自动帮你写入配置。
Option B: Manual Configuration
把以下内容加入 ~/.hermes/.env:
TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrSTUvwxYZ
TELEGRAM_ALLOWED_USERS=123456789 # Comma-separated for multiple users
Start the Gateway
hermes gateway
几秒内 bot 就应该上线。给它发一条 Telegram 消息确认是否正常。
从 Docker 终端发送生成文件
如果你的终端 backend 是 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 的重复 key 会静默覆盖前面的值。
Webhook Mode
默认情况下,Hermes 通过 long polling 连接 Telegram,也就是由网关主动向 Telegram 服务器拉取更新。这种方式很适合本地部署和常驻环境。
对于 云部署(Fly.io、Railway、Render 等),webhook mode 往往更省成本。这类平台通常只能通过入站 HTTP 流量唤醒休眠机器,而 polling 属于出站连接,因此 polling bot 无法真正休眠。Webhook mode 则反过来,由 Telegram 把更新推送到你的 HTTPS URL,从而实现空闲休眠。
| Polling (default) | Webhook | |
|---|---|---|
| Direction | Gateway → Telegram (outbound) | Telegram → Gateway (inbound) |
| Best for | 本地部署、常驻服务器 | 支持自动唤醒的云平台 |
| Setup | 无需额外配置 | 设置 TELEGRAM_WEBHOOK_URL |
| Idle cost | 机器必须持续运行 | 机器可在消息间歇休眠 |
Configuration
把以下内容加入 ~/.hermes/.env:
TELEGRAM_WEBHOOK_URL=https://my-app.fly.dev/telegram
# TELEGRAM_WEBHOOK_PORT=8443 # optional, default 8443
# TELEGRAM_WEBHOOK_SECRET=mysecret # optional, recommended
| Variable | Required | Description |
|---|---|---|
TELEGRAM_WEBHOOK_URL | Yes | Telegram 发送更新的公网 HTTPS URL。路径会自动提取(例如上例中的 /telegram)。 |
TELEGRAM_WEBHOOK_PORT | No | 本地 webhook 服务器监听端口(默认:8443)。 |
TELEGRAM_WEBHOOK_SECRET | No | 用于验证更新确实来自 Telegram 的 secret token。生产环境强烈建议设置。 |
设置 TELEGRAM_WEBHOOK_URL 后,网关会启动 HTTP webhook 服务器而不再 polling;如果未设置,则继续使用 polling 模式。
Cloud deployment example (Fly.io)
- 把环境变量添加到 Fly.io secrets:
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)。
Proxy Support
如果 Telegram API 在你的网络中不可达,或你需要走代理,可设置 Telegram 专用代理 URL。它的优先级高于通用的 HTTPS_PROXY / HTTP_PROXY 环境变量。
Option 1: config.yaml(推荐)
telegram:
proxy_url: "socks5://127.0.0.1:1080"
Option 2: environment variable
TELEGRAM_PROXY=socks5://127.0.0.1:1080
支持的 scheme:http://、https://、socks5://。
该代理同时作用于 Telegram 主连接和 fallback IP 传输层。如果没有设置 Telegram 专用代理,网关会退回到 HTTPS_PROXY / HTTP_PROXY / ALL_PROXY(macOS 还支持系统代理自动检测)。
Home Channel
你可以在任意 Telegram 聊天(私聊或群聊)中执行 /sethome,把它指定为 home channel。定时任务(cron jobs)的结果会投递到这里。
你也可以手动在 ~/.hermes/.env 中设置:
TELEGRAM_HOME_CHANNEL=-1001234567890
TELEGRAM_HOME_CHANNEL_NAME="My Notes"
群聊 chat ID 是负数(例如 -1001234567890)。你的个人私聊 chat ID 与 user ID 相同。
Voice Messages
Incoming Voice(Speech-to-Text)
你在 Telegram 中发送的语音消息会自动由 Hermes 配置的 STT 大模型提供商(provider)转写,并作为文本注入当前对话。
local使用运行 Hermes 的机器上的faster-whisper,不需要 API keygroq使用 Groq Whisper,需要GROQ_API_KEYopenai使用 OpenAI Whisper,需要VOICE_TOOLS_OPENAI_KEY
Outgoing Voice(Text-to-Speech)
当 agent 通过 TTS 生成音频时,它会以 Telegram 原生语音气泡的形式发送,也就是圆形、可内联播放的那种。
- OpenAI 和 ElevenLabs 原生输出 Opus,无需额外配置
- Edge TTS(默认免费大模型提供商(provider))输出 MP3,因此需要 ffmpeg 把它转成 Opus:
# Ubuntu/Debian
sudo apt install ffmpeg
# macOS
brew install ffmpeg
如果没有 ffmpeg,Edge TTS 音频会作为普通音频文件发送(仍然可以播放,只是使用矩形播放器而不是语音气泡)。
在 config.yaml 的 tts.provider 下配置 TTS 大模型提供商(provider)。
群聊使用
Hermes Agent 可在 Telegram 群聊中工作,但要注意:
- privacy mode 决定 bot 能看到哪些群消息(见 第 3 步)
TELEGRAM_ALLOWED_USERS在群里依然生效,只有授权用户才能触发 bot- 你可以通过
telegram.require_mention: true让 bot 不响应普通群聊闲聊 - 当
telegram.require_mention: true时,以下消息会被接受:- slash commands
- 对 bot 消息的回复
@botusername提及- 命中
telegram.mention_patterns中任一 regex 唤醒词
- 可使用
telegram.ignored_threads让 Hermes 在特定 Telegram forum topics 中保持静默 - 如果
telegram.require_mention未设置或为 false,Hermes 会维持旧行为:对它能看到的普通群消息也进行响应
Example group trigger configuration
把以下内容加入 ~/.hermes/config.yaml:
telegram:
require_mention: true
mention_patterns:
- "^\\s*chompy\\b"
ignored_threads:
- 31
- "42"
这个示例允许所有常规的直接触发方式,另外还接受以 chompy 开头的消息,即使没有 @mention 也会触发。
Telegram topics 31 和 42 中的消息会始终被忽略,并且这一判断会在 mention / free-response 检查之前执行。
Notes on mention_patterns
- pattern 使用 Python 正则表达式
- 匹配时不区分大小写
- 同时会检查文本消息和媒体 caption
- 非法 regex 不会让 bot 崩溃,只会在网关日志中给出警告并忽略
- 如果希望只匹配消息开头,请使用
^
Private Chat Topics (Bot API 9.4)
Telegram Bot API 9.4(2026 年 2 月)引入了 Private Chat Topics。bot 可以直接在一对一私聊中创建论坛式 topic thread,而无需 supergroup。这使你能够在和 Hermes 的同一个 DM 中维护多个彼此隔离的工作区。
Use case
如果你同时在处理多个长期项目,topics 可以把上下文彻底分开:
- Topic
Website:处理生产 Web 服务相关工作 - Topic
Research:处理文献阅读和论文探索 - Topic
General:处理杂项任务和快速问题
每个 topic 都有自己的会话、历史和上下文,彼此完全隔离。
Configuration
在把 topics 写入配置前,用户必须先在与 bot 的 DM 中启用 Topics 模式:
- 打开你与 Hermes bot 的 Telegram 私聊
- 点击顶部 bot 名称,打开聊天信息
- 开启 Topics(把该私聊变成论坛式聊天的开关)
否则,Hermes 启动时会记录 The chat is not a forum,并跳过 topic 创建。这是 Telegram 客户端侧设置,bot 无法通过 API 自动替你开启。
把 topics 加到 ~/.hermes/config.yaml 的 platforms.telegram.extra.dm_topics:
platforms:
telegram:
extra:
dm_topics:
- chat_id: 123456789 # Your Telegram user ID
topics:
- name: General
icon_color: 7322096
- name: Website
icon_color: 9367192
- name: Research
icon_color: 16766590
skill: arxiv # Auto-load a skill in this topic
Fields:
| Field | Required | Description |
|---|---|---|
name | Yes | Topic 显示名称 |
icon_color | No | Telegram 图标颜色代码(整数) |
icon_custom_emoji_id | No | Topic 图标使用的自定义 emoji ID |
skill | No | 在该 topic 的新会话中自动加载的技能 |
thread_id | No | topic 创建后自动回填,不要手动设置 |
How it works
- 网关启动时,Hermes 会为尚未拥有
thread_id的 topic 调用createForumTopic - 创建完成后,
thread_id会自动写回config.yaml,后续重启就不会再次调用 API - 每个 topic 都会映射到一个独立会话 key:
agent:main:telegram:dm:{chat_id}:{thread_id} - 每个 topic 中的消息都拥有自己的对话历史、记忆刷新和上下文窗口
Skill binding
带有 skill 字段的 topic 会在新会话启动时自动加载该技能。效果与在对话开头手动输入 /skill-name 完全一致:技能内容会注入第一条消息,后续消息也会在历史中看到它。
例如,配置了 skill: arxiv 的 topic,在其会话因空闲超时、每日重置或手动 /reset 而重新开始时,都会自动预加载 arxiv 技能。
如果 topic 不是通过配置创建的(例如你手动调用 Telegram API 创建),只要收到 forum_topic_created 服务消息,Hermes 也会自动发现它。你也可以在网关运行期间把 topic 加进配置;下一次缓存失效时就会拾取到它。
Group Forum Topic Skill Binding
启用了 Topics mode 的 supergroup(也就是 forum topics)本身已经会按 topic 做会话隔离,每个 thread_id 都对应一段独立对话。但你可能还希望像 DM topic 一样,在特定群 topic 中自动加载某个技能。
Use case
一个团队 supergroup 按工作流拆出了多个 forum topic:
- Engineering topic → 自动加载
software-development技能 - Research topic → 自动加载
arxiv技能 - General topic → 不绑定技能,作为通用助手
Configuration
把 group topic 绑定加入 ~/.hermes/config.yaml 的 platforms.telegram.extra.group_topics:
platforms:
telegram:
extra:
group_topics:
- chat_id: -1001234567890 # Supergroup ID
topics:
- name: Engineering
thread_id: 5
skill: software-development
- name: Research
thread_id: 12
skill: arxiv
- name: General
thread_id: 1
# No skill — general purpose
Fields:
| Field | Required | Description |
|---|---|---|
chat_id | Yes | Supergroup 的数字 ID(以 -100 开头的负数) |
name | No | 人类可读的 topic 标签(仅用于说明) |
thread_id | Yes | Telegram forum topic ID,可在 t.me/c/<group_id>/<thread_id> 链接中看到 |
skill | No | 在该 topic 新会话中自动加载的技能 |
How it works
- 当消息出现在映射过的 group topic 中时,Hermes 会用
chat_id和thread_id在group_topics配置中查找 - 如果命中的条目带有
skill字段,该技能会自动加载到会话中,行为与 DM topic 技能绑定一致 - 没有
skill字段的 topic 仍然只做会话隔离(维持现有行为) - 未映射的
thread_id或chat_id会静默忽略,不报错,也不会加载技能
Differences from DM Topics
| DM Topics | Group Topics | |
|---|---|---|
| Config key | extra.dm_topics | extra.group_topics |
| Topic creation | 若 thread_id 缺失,由 Hermes 通过 API 创建 | 由管理员在 Telegram UI 中手动创建 |
thread_id | 创建后自动回填 | 必须手动设置 |
icon_color / icon_custom_emoji_id | 支持 | 不适用(外观由管理员控制) |
| Skill binding | ✓ | ✓ |
| Session isolation | ✓ | ✓(forum topics 本身已内建) |
查找 topic 的 thread_id 最简单的方法,是在 Telegram Web 或 Desktop 中打开该 topic,然后查看 URL:https://t.me/c/1234567890/5,最后那个数字(5)就是 thread_id。supergroup 的 chat_id 则是在 group ID 前加 -100,例如 group 1234567890 会变成 -1001234567890。
Recent Bot API Features
- Bot API 9.4 (Feb 2026):Private Chat Topics,bot 可通过
createForumTopic在一对一私聊中创建 forum topics。见上文 Private Chat Topics。 - Privacy policy:Telegram 现在要求 bot 提供隐私政策。可在 BotFather 中用
/setprivacy_policy设置,否则 Telegram 可能会自动生成占位内容。对于公开 bot,这一点尤其重要。 - Message streaming:Bot API 9.x 增加了长回复流式输出支持,可改善长篇 agent 回复的感知延迟。
Interactive Model Picker
在 Telegram 聊天中发送不带参数的 /model,Hermes 会显示一个交互式 inline keyboard,用于切换模型:
- 大模型提供商(provider)选择:显示每个可用大模型提供商(provider)及其模型数量(例如
OpenAI (15)、✓ Anthropic (12)) - 模型选择:分页展示模型列表,并提供 Prev / Next 导航、Back 返回大模型提供商(provider)列表,以及 Cancel
顶部会显示当前模型和大模型提供商(provider)。整个导航都通过原消息原地编辑完成,不会刷屏。
如果你已经知道确切的模型名,可以直接输入 /model <name> 跳过选择器。也可以使用 /model <name> --global 把修改持久化到后续会话中。
DNS-over-HTTPS Fallback IPs
在某些受限网络中,api.telegram.org 可能解析到不可达 IP。Telegram 适配器内置了 fallback IP 机制,会在保持正确 TLS hostname 和 SNI 的同时透明地重试其他 IP。
How it works
- 如果设置了
TELEGRAM_FALLBACK_IPS,优先直接使用这些 IP - 否则,适配器会通过 Google DNS 和 Cloudflare DNS 的 DNS-over-HTTPS(DoH)自动查询
api.telegram.org的候选 IP - 与系统 DNS 结果不同的 DoH IP 会被当作 fallback 使用
- 如果 DoH 也被封锁,则退回到硬编码种子 IP:
149.154.167.220 - 一旦某个 fallback IP 成功,它就会变成“粘性”地址,后续请求会优先直接使用它,而不是每次都先试主路径
Configuration
# Explicit fallback IPs (comma-separated)
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。
Proxy Support
如果你的网络需要通过 HTTP 代理访问互联网(企业环境中较常见),Telegram 适配器会自动读取标准代理环境变量,并把所有连接都经由代理发送。
Supported variables
适配器按以下顺序检查环境变量,使用第一个已设置的值:
HTTPS_PROXYHTTP_PROXYALL_PROXYhttps_proxy/http_proxy/all_proxy(小写形式)
Configuration
在启动网关前设置代理:
export HTTPS_PROXY=http://proxy.example.com:8080
hermes gateway
或者写入 ~/.hermes/.env:
HTTPS_PROXY=http://proxy.example.com:8080
该代理会同时作用于主传输层和所有 fallback IP 传输层。无需额外 Hermes 配置,只要设置了环境变量,就会自动生效。
这里覆盖的是 Hermes 为 Telegram 连接实现的自定义 fallback 传输层。其他地方使用的标准 httpx 客户端,本身就原生支持代理环境变量。
Message Reactions
bot 可以用表情 reaction 来显示处理状态:
- 👀 表示开始处理你的消息
- ✅ 表示回复已成功送达
- ❌ 表示处理时出错
默认情况下,reactions 是关闭的。可在 config.yaml 中启用:
telegram:
reactions: true
或使用环境变量:
TELEGRAM_REACTIONS=true
与 Discord 的叠加式 reaction 不同,Telegram Bot API 会在一次调用中替换 bot 的全部 reaction。因此从 👀 切换到 ✅ / ❌ 是原子完成的,你不会同时看到两个。
如果 bot 在群里没有添加 reaction 的权限,reaction 调用会静默失败,但消息处理仍会继续正常进行。
Per-Channel Prompts
你可以为特定 Telegram 群组或 forum topic 指定临时系统提示。该提示会在每轮运行时注入,但不会写入 transcript 历史,因此修改会立刻生效。
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.
key 可以是 chat ID(群组 / supergroup)或 forum topic ID。对于 forum 群组,topic 级 prompt 的优先级高于群级 prompt:
- 群
-1001234567890的 topic42中的消息 → 使用 topic42的 prompt - topic
99中的消息(未显式配置)→ 回退到群-1001234567890的 prompt - 群没有任何配置 → 不应用 channel prompt
纯数字 YAML key 会自动规范化为字符串。
Troubleshooting
| Problem | Solution |
|---|---|
| Bot 完全不响应 | 确认 TELEGRAM_BOT_TOKEN 正确,并查看 hermes gateway 日志 |
Bot 回复 unauthorized | 你的 user ID 不在 TELEGRAM_ALLOWED_USERS 中。请用 @userinfobot 再核对一次 |
| Bot 忽略群消息 | 很可能是 privacy mode 仍然开启。关闭它(见第 3 步)或把 bot 设为群管理员。修改后记得把 bot 移除再重新加入群。 |
| 语音消息未转写 | 确认 STT 可用:本地转写需安装 faster-whisper,否则请在 ~/.hermes/.env 中设置 GROQ_API_KEY 或 VOICE_TOOLS_OPENAI_KEY |
| 语音回复显示为普通文件而不是语音气泡 | 安装 ffmpeg(Edge TTS 转 Opus 需要它) |
| Bot token 被撤销或无效 | 在 BotFather 中使用 /revoke,然后重新用 /newbot 或 /token 生成新 token,并更新 .env |
| Webhook 收不到更新 | 确认 TELEGRAM_WEBHOOK_URL 可从公网访问(可用 curl 测试);确认平台或反向代理已把该 URL 对应端口的入站 HTTPS 流量路由到 TELEGRAM_WEBHOOK_PORT 监听的本地端口;确认 TLS 已启用,因为 Telegram 只向 HTTPS URL 推送;同时检查防火墙规则 |
Exec Approval
当 agent 尝试执行潜在危险命令时,它会在聊天中向你请求批准:
⚠️ This command is potentially dangerous (recursive delete). Reply "yes" to approve.
回复 yes / y 表示批准,回复 no / n 表示拒绝。
Security
务必设置 TELEGRAM_ALLOWED_USERS 来限制谁可以与你的 bot 交互。否则,出于安全考虑,网关默认会拒绝所有用户。
不要公开分享你的 bot token。如果泄露,请立即通过 BotFather 的 /revoke 命令撤销。
更多详情请参阅 Security documentation。你也可以使用 DM pairing 以更动态的方式授权用户。