Telegram (Bot API)
状态:通过 grammY 实现的机器人私聊 + 群组功能已可用于生产环境。默认使用长轮询;webhook 可选。快速设置(新手)
- 通过 @BotFather(直达链接)创建机器人。确认用户名确实是
@BotFather,然后复制令牌。 - 设置令牌:
- 环境变量:
TELEGRAM_BOT_TOKEN=... - 或配置:
channels.telegram.botToken: "..."。 - 如果两者都设置了,配置优先(环境变量回退仅适用于默认账户)。
- 环境变量:
- 启动 Gateway网关。
- 私聊访问默认为配对模式;首次联系时需批准配对码。
简介
- 由 Gateway网关管理的 Telegram Bot API 渠道。
- 确定性路由:回复始终发回 Telegram;模型不会选择渠道。
- 私聊共享智能体的主会话;群组保持隔离(
agent:<agentId>:telegram:group:<chatId>)。
设置(快速路径)
1)创建机器人令牌(BotFather)
- 打开 Telegram,与 @BotFather(直达链接)对话。确认用户名确实是
@BotFather。 - 运行
/newbot,然后按提示操作(名称 + 以bot结尾的用户名)。 - 复制令牌并安全保存。
/setjoingroups— 允许/禁止将机器人添加到群组。/setprivacy— 控制机器人是否能看到所有群组消息。
2)配置令牌(环境变量或配置)
示例:TELEGRAM_BOT_TOKEN=...(适用于默认账户)。
如果环境变量和配置都设置了,配置优先。
多账户支持:使用 channels.telegram.accounts,为每个账户设置令牌和可选的 name。请参阅 gateway/configuration 了解通用模式。
- 启动 Gateway网关。当令牌被解析后(配置优先,环境变量回退),Telegram 即启动。
- 私聊访问默认为配对模式。机器人首次被联系时需批准配对码。
- 对于群组:添加机器人,决定隐私/管理员行为(见下文),然后设置
channels.telegram.groups来控制提及门控 + 白名单。
令牌 + 隐私 + 权限(Telegram 端)
令牌创建(BotFather)
/newbot创建机器人并返回令牌(请保密)。- 如果令牌泄露,通过 @BotFather 撤销/重新生成令牌并更新配置。
群组消息可见性(隐私模式)
Telegram 机器人默认启用隐私模式,这会限制它们能接收到的群组消息。 如果你的机器人必须看到所有群组消息,有两种选择:- 使用
/setprivacy禁用隐私模式,或者 - 将机器人设为群组管理员(管理员机器人可以接收所有消息)。
群组权限(管理员权限)
管理员状态在群组内设置(Telegram 界面)。管理员机器人始终能接收所有 群组消息,因此如果需要完全可见性,请使用管理员身份。工作原理(行为)
- 入站消息被规范化为共享渠道信封,包含回复上下文和媒体占位符。
- 群组回复默认需要提及(原生 @提及或
agents.list[].groupChat.mentionPatterns/messages.groupChat.mentionPatterns)。 - 多智能体覆盖:在
agents.list[].groupChat.mentionPatterns上设置每个智能体的模式。 - 回复始终路由回同一个 Telegram 聊天。
- 长轮询使用 grammY runner,按聊天排序;总体并发受
agents.defaults.maxConcurrent限制。 - Telegram Bot API 不支持已读回执;没有
sendReadReceipts选项。
草稿流式传输
OpenClaw 可以使用sendMessageDraft 在 Telegram 私聊中流式传输部分回复。
要求:
- 在 @BotFather 中为机器人启用话题模式(论坛话题模式)。
- 仅限私聊话题(Telegram 在入站消息中包含
message_thread_id)。 channels.telegram.streamMode未设为"off"(默认:"partial","block"启用分块草稿更新)。
格式化(Telegram HTML)
- 出站 Telegram 文本使用
parse_mode: "HTML"(Telegram 支持的标签子集)。 - 类 Markdown 输入被渲染为 Telegram 安全的 HTML(粗体/斜体/删除线/代码/链接);块级元素被扁平化为带换行符/项目符号的文本。
- 来自模型的原始 HTML 会被转义,以避免 Telegram 解析错误。
- 如果 Telegram 拒绝 HTML 负载,OpenClaw 会以纯文本重试同一条消息。
命令(原生 + 自定义)
OpenClaw 在启动时将原生命令(如/status、/reset、/model)注册到 Telegram 的机器人菜单。
你可以通过配置向菜单添加自定义命令:
故障排除
- 日志中出现
setMyCommands failed通常意味着到api.telegram.org的出站 HTTPS/DNS 被阻止。 - 如果看到
sendMessage或sendChatAction失败,请检查 IPv6 路由和 DNS。
- 自定义命令仅为菜单条目;除非你在其他地方处理它们,否则 OpenClaw 不会实现它们。
- 命令名称会被规范化(去除前导
/,转为小写),且必须匹配a-z、0-9、_(1–32 个字符)。 - 自定义命令不能覆盖原生命令。冲突会被忽略并记录到日志。
- 如果
commands.native被禁用,则只注册自定义命令(如果没有自定义命令则清空)。
限制
- 出站文本按
channels.telegram.textChunkLimit分块(默认 4000)。 - 可选的换行分块:设置
channels.telegram.chunkMode="newline"以在空行(段落边界)处拆分,然后再按长度分块。 - 媒体下载/上传受
channels.telegram.mediaMaxMb限制(默认 5)。 - Telegram Bot API 请求在
channels.telegram.timeoutSeconds后超时(通过 grammY 默认 500)。设置更低的值以避免长时间挂起。 - 群组历史上下文使用
channels.telegram.historyLimit(或channels.telegram.accounts.*.historyLimit),回退到messages.groupChat.historyLimit。设为0以禁用(默认 50)。 - 私聊历史可通过
channels.telegram.dmHistoryLimit(用户轮次)限制。按用户覆盖:channels.telegram.dms["<user_id>"].historyLimit。
群组激活模式
默认情况下,机器人在群组中只响应提及(@botname 或 agents.list[].groupChat.mentionPatterns 中的模式)。要更改此行为:
通过配置(推荐)
channels.telegram.groups 会创建一个白名单 - 只有列出的群组(或 "*")会被接受。
论坛话题继承其父群组配置(allowFrom、requireMention、skills、prompts),除非你在 channels.telegram.groups.<groupId>.topics.<topicId> 下添加每个话题的覆盖。
允许所有群组且始终回复:
通过命令(会话级别)
在群组中发送:/activation always- 回复所有消息/activation mention- 需要提及(默认)
获取群组聊天 ID
将群组中的任意消息转发给 Telegram 上的@userinfobot 或 @getidsbot,即可看到聊天 ID(负数,如 -1001234567890)。
提示: 要获取你自己的用户 ID,私聊机器人,它会回复你的用户 ID(配对消息),或者在命令启用后使用 /whoami。
隐私提示: @userinfobot 是第三方机器人。如果你更注重隐私,可以将机器人添加到群组,发送一条消息,然后使用 openclaw logs --follow 读取 chat.id,或使用 Bot API 的 getUpdates。
配置写入
默认情况下,Telegram 允许写入由渠道事件或/config set|unset 触发的配置更新。
以下情况会发生配置写入:
- 群组升级为超级群组时,Telegram 发出
migrate_to_chat_id(聊天 ID 变更)。OpenClaw 可以自动迁移channels.telegram.groups。 - 你在 Telegram 聊天中运行
/config set或/config unset(需要commands.config: true)。
话题(论坛超级群组)
Telegram 论坛话题在每条消息中包含message_thread_id。OpenClaw:
- 将
:topic:<threadId>追加到 Telegram 群组会话键,使每个话题相互隔离。 - 发送输入指示器和回复时携带
message_thread_id,确保回复留在话题内。 - 通用话题(thread id
1)比较特殊:消息发送时省略message_thread_id(Telegram 会拒绝),但输入指示器仍包含它。 - 在模板上下文中暴露
MessageThreadId+IsForum,用于路由/模板。 - 话题级配置可在
channels.telegram.groups.<chatId>.topics.<threadId>下设置(skills、白名单、自动回复、系统提示词、禁用)。 - 话题配置继承群组设置(requireMention、白名单、skills、提示词、enabled),除非按话题覆盖。
message_thread_id。OpenClaw 保持私聊会话键不变,但在存在 thread id 时仍将其用于回复/草稿流式传输。
内联按钮
Telegram 支持带回调按钮的内联键盘。off— 禁用内联按钮dm— 仅私聊(群组目标被阻止)group— 仅群组(私聊目标被阻止)all— 私聊 + 群组allowlist— 私聊 + 群组,但仅限allowFrom/groupAllowFrom允许的发送者(与控制命令规则相同)
allowlist。
旧版:capabilities: ["inlineButtons"] = inlineButtons: "all"。
发送按钮
使用消息工具的buttons 参数:
callback_data: value
配置选项
Telegram 功能可在两个层级配置(上面展示了对象形式;旧版字符串数组仍受支持):channels.telegram.capabilities:全局默认功能配置,应用于所有 Telegram 账户,除非被覆盖。channels.telegram.accounts.<account>.capabilities:按账户的功能配置,覆盖该账户的全局默认值。
访问控制(私聊 + 群组)
私聊访问
- 默认:
channels.telegram.dmPolicy = "pairing"。未知发送者会收到配对码;消息在批准前被忽略(配对码 1 小时后过期)。 - 批准方式:
openclaw pairing list telegramopenclaw pairing approve telegram <CODE>
- 配对是 Telegram 私聊使用的默认令牌交换方式。详情:配对
channels.telegram.allowFrom接受数字用户 ID(推荐)或@username条目。这不是机器人用户名;请使用人类发送者的 ID。向导接受@username并在可能时将其解析为数字 ID。
查找你的 Telegram 用户 ID
更安全的方式(无需第三方机器人):- 启动 Gateway网关并私聊你的机器人。
- 运行
openclaw logs --follow并查找from.id。
- 私聊你的机器人。
- 使用你的机器人令牌获取更新,并读取
message.from.id:
- 私聊
@userinfobot或@getidsbot并使用返回的用户 ID。
群组访问
两个独立的控制: 1. 允许哪些群组(通过channels.telegram.groups 的群组白名单):
- 没有
groups配置 = 允许所有群组 - 有
groups配置 = 只允许列出的群组或"*" - 示例:
"groups": { "-1001234567890": {}, "*": {} }允许所有群组
channels.telegram.groupPolicy 的发送者过滤):
"open"= 允许的群组中所有发送者都可以发消息"allowlist"= 只有channels.telegram.groupAllowFrom中的发送者可以发消息"disabled"= 完全不接受群组消息 默认为groupPolicy: "allowlist"(除非添加groupAllowFrom,否则被阻止)。
groupPolicy: "allowlist" + groupAllowFrom + 在 channels.telegram.groups 中列出特定群组
长轮询 vs webhook
- 默认:长轮询(不需要公网 URL)。
- Webhook 模式:设置
channels.telegram.webhookUrl和channels.telegram.webhookSecret(可选channels.telegram.webhookPath)。- 本地监听器绑定到
0.0.0.0:8787,默认服务POST /telegram-webhook。 - 如果你的公网 URL 不同,请使用反向代理并将
channels.telegram.webhookUrl指向公网端点。
- 本地监听器绑定到
回复线程
Telegram 通过标签支持可选的线程回复:[[reply_to_current]]— 回复触发消息。[[reply_to:<id>]]— 回复特定消息 ID。
channels.telegram.replyToMode 控制:
first(默认)、all、off。
音频消息(语音 vs 文件)
Telegram 区分语音消息(圆形气泡)和音频文件(元数据卡片)。 OpenClaw 默认使用音频文件以保持向后兼容。 要在智能体回复中强制使用语音消息气泡,在回复中的任意位置包含此标签:[[audio_as_voice]]— 以语音消息而非文件形式发送音频。
asVoice: true 并附带兼容语音的音频 media URL
(当有 media 时 message 为可选):
贴纸
OpenClaw 支持接收和发送 Telegram 贴纸,并带有智能缓存。接收贴纸
当用户发送贴纸时,OpenClaw 根据贴纸类型进行处理:- 静态贴纸(WEBP): 下载并通过视觉能力处理。贴纸在消息内容中显示为
<media:sticker>占位符。 - 动态贴纸(TGS): 跳过(不支持 Lottie 格式处理)。
- 视频贴纸(WEBM): 跳过(不支持视频格式处理)。
Sticker— 包含以下属性的对象:emoji— 与贴纸关联的表情setName— 贴纸集名称fileId— Telegram 文件 ID(可用于发回同一贴纸)fileUniqueId— 用于缓存查找的稳定 IDcachedDescription— 可用时的缓存视觉描述
贴纸缓存
贴纸通过 AI 的视觉能力处理以生成描述。由于相同的贴纸经常被重复发送,OpenClaw 会缓存这些描述以避免冗余的 API 调用。 工作原理:- 首次遇到: 贴纸图像被发送给 AI 进行视觉分析。AI 生成描述(例如”一只卡通猫热情地挥手”)。
- 缓存存储: 描述与贴纸的文件 ID、表情和集合名称一起保存。
- 后续遇到: 再次看到同一贴纸时,直接使用缓存的描述,不再将图像发送给 AI。
~/.openclaw/telegram/sticker-cache.json
缓存条目格式:
- 通过避免对同一贴纸重复调用视觉能力来降低 API 成本
- 缓存贴纸的响应速度更快(无视觉处理延迟)
- 支持基于缓存描述的贴纸搜索功能
发送贴纸
智能体可以使用sticker 和 sticker-search 动作发送和搜索贴纸。这些功能默认禁用,必须在配置中启用:
fileId(必填)— 贴纸的 Telegram 文件 ID。可从接收贴纸时的Sticker.fileId获取,或从sticker-search结果获取。replyTo(可选)— 要回复的消息 ID。threadId(可选)— 论坛话题的消息线程 ID。
流式传输(草稿)
Telegram 可以在智能体生成回复时流式传输草稿气泡。 OpenClaw 使用 Bot API 的sendMessageDraft(非真实消息),然后将
最终回复作为普通消息发送。
要求(Telegram Bot API 9.3+):
- 启用话题的私聊(机器人的论坛话题模式)。
- 入站消息必须包含
message_thread_id(私聊话题线程)。 - 群组/超级群组/频道中的流式传输会被忽略。
channels.telegram.streamMode: "off" | "partial" | "block"(默认:partial)partial:用最新的流式文本更新草稿气泡。block:以更大的块更新草稿气泡(分块)。off:禁用草稿流式传输。
- 可选(仅适用于
streamMode: "block"):channels.telegram.draftChunk: { minChars?, maxChars?, breakPreference? }- 默认值:
minChars: 200、maxChars: 800、breakPreference: "paragraph"(受channels.telegram.textChunkLimit限制)。
- 默认值:
channels.telegram.blockStreaming: true。
推理流式传输(仅 Telegram):
/reasoning stream在回复生成时将推理过程流式传输到草稿气泡中,然后发送不包含推理过程的最终答案。- 如果
channels.telegram.streamMode为off,推理流式传输将被禁用。 更多上下文:流式传输 + 分块。
重试策略
出站 Telegram API 调用在遇到瞬态网络/429 错误时会以指数退避和抖动进行重试。通过channels.telegram.retry 配置。参见重试策略。
智能体工具(消息 + 表情回应)
- 工具:
telegram,sendMessage动作(to、content,可选mediaUrl、replyToMessageId、messageThreadId)。 - 工具:
telegram,react动作(chatId、messageId、emoji)。 - 工具:
telegram,deleteMessage动作(chatId、messageId)。 - 表情回应移除语义:参见 /tools/reactions。
- 工具门控:
channels.telegram.actions.reactions、channels.telegram.actions.sendMessage、channels.telegram.actions.deleteMessage(默认:启用),以及channels.telegram.actions.sticker(默认:禁用)。
表情回应通知
表情回应的工作原理: Telegram 表情回应作为独立的message_reaction 事件到达,而非消息负载中的属性。当用户添加表情回应时,OpenClaw:
- 从 Telegram API 接收
message_reaction更新 - 将其转换为系统事件,格式为:
"Telegram reaction added: {emoji} by {user} on msg {id}" - 使用与常规消息相同的会话键将系统事件入队
- 当该对话中的下一条消息到达时,系统事件被排出并添加到智能体上下文的前面
-
channels.telegram.reactionNotifications:控制哪些表情回应触发通知"off"— 忽略所有表情回应"own"— 当用户对机器人消息做出表情回应时通知(尽力而为;内存中)(默认)"all"— 对所有表情回应进行通知
-
channels.telegram.reactionLevel:控制智能体的表情回应能力"off"— 智能体不能对消息做表情回应"ack"— 机器人发送确认表情回应(处理时显示 👀)(默认)"minimal"— 智能体可以少量使用表情回应(指导原则:每 5-10 次交流 1 次)"extensive"— 智能体可以在适当时大量使用表情回应
message_thread_id,使用如 agent:main:telegram:group:{chatId}:topic:{threadId} 的会话键。这确保同一话题中的表情回应和消息保持在一起。
示例配置:
- Telegram 机器人必须在
allowed_updates中显式请求message_reaction(由 OpenClaw 自动配置) - 对于 webhook 模式,表情回应包含在 webhook 的
allowed_updates中 - 对于轮询模式,表情回应包含在
getUpdates的allowed_updates中
投递目标(CLI/定时任务)
- 使用聊天 ID(
123456789)或用户名(@name)作为目标。 - 示例:
openclaw message send --channel telegram --target 123456789 --message "hi"。
故障排除
机器人在群组中不响应非提及消息:- 如果你设置了
channels.telegram.groups.*.requireMention=false,Telegram 的 Bot API 隐私模式必须被禁用。- BotFather:
/setprivacy→ Disable(然后从群组中移除并重新添加机器人)
- BotFather:
openclaw channels status在配置期望接收非提及群组消息时会显示警告。openclaw channels status --probe可以额外检查显式数字群组 ID 的成员资格(无法审计通配符"*"规则)。- 快速测试:
/activation always(仅会话级别;持久化请使用配置)
- 如果设置了
channels.telegram.groups,群组必须被列出或使用"*" - 在 @BotFather 中检查隐私设置 → “Group Privacy” 应为 OFF
- 确认机器人确实是成员(而非只是没有读取权限的管理员)
- 检查 Gateway网关日志:
openclaw logs --follow(查找 “skipping group message”)
/activation always:
/activation命令更新会话状态但不会持久化到配置- 要持久化行为,将群组添加到
channels.telegram.groups并设置requireMention: false
/status 等命令不工作:
- 确保你的 Telegram 用户 ID 已授权(通过配对或
channels.telegram.allowFrom) - 即使在
groupPolicy: "open"的群组中,命令也需要授权
- Node 22+ 对
AbortSignal实例更严格;外部信号可能会立即中止fetch调用。 - 升级到规范化 abort 信号的 OpenClaw 版本,或在 Node 20 上运行 Gateway网关直到可以升级。
HttpError: Network request ... failed):
- 某些主机优先将
api.telegram.org解析为 IPv6。如果你的服务器没有可用的 IPv6 出口,grammY 可能会卡在仅 IPv6 的请求上。 - 修复方法:启用 IPv6 出口或者强制
api.telegram.org使用 IPv4 解析(例如,使用 IPv4 A 记录添加/etc/hosts条目,或在操作系统 DNS 栈中优先使用 IPv4),然后重启 Gateway网关。 - 快速检查:
dig +short api.telegram.org A和dig +short api.telegram.org AAAA确认 DNS 返回的内容。
配置参考(Telegram)
完整配置:配置 提供商选项:channels.telegram.enabled:启用/禁用渠道启动。channels.telegram.botToken:机器人令牌(BotFather)。channels.telegram.tokenFile:从文件路径读取令牌。channels.telegram.dmPolicy:pairing | allowlist | open | disabled(默认:pairing)。channels.telegram.allowFrom:私聊白名单(ID/用户名)。open需要"*"。channels.telegram.groupPolicy:open | allowlist | disabled(默认:allowlist)。channels.telegram.groupAllowFrom:群组发送者白名单(ID/用户名)。channels.telegram.groups:按群组的默认设置 + 白名单(使用"*"作为全局默认)。channels.telegram.groups.<id>.requireMention:提及门控默认值。channels.telegram.groups.<id>.skills:Skills 过滤(省略 = 所有 Skills,空 = 无 Skills)。channels.telegram.groups.<id>.allowFrom:按群组的发送者白名单覆盖。channels.telegram.groups.<id>.systemPrompt:群组的额外系统提示词。channels.telegram.groups.<id>.enabled:设为false时禁用该群组。channels.telegram.groups.<id>.topics.<threadId>.*:按话题覆盖(与群组字段相同)。channels.telegram.groups.<id>.topics.<threadId>.requireMention:按话题的提及门控覆盖。
channels.telegram.capabilities.inlineButtons:off | dm | group | all | allowlist(默认:allowlist)。channels.telegram.accounts.<account>.capabilities.inlineButtons:按账户覆盖。channels.telegram.replyToMode:off | first | all(默认:first)。channels.telegram.textChunkLimit:出站分块大小(字符数)。channels.telegram.chunkMode:length(默认)或newline,在空行(段落边界)处拆分后再按长度分块。channels.telegram.linkPreview:切换出站消息的链接预览(默认:true)。channels.telegram.streamMode:off | partial | block(草稿流式传输)。channels.telegram.mediaMaxMb:入站/出站媒体上限(MB)。channels.telegram.retry:出站 Telegram API 调用的重试策略(attempts、minDelayMs、maxDelayMs、jitter)。channels.telegram.network.autoSelectFamily:覆盖 Node 的 autoSelectFamily(true=启用,false=禁用)。在 Node 22 上默认禁用以避免 Happy Eyeballs 超时。channels.telegram.proxy:Bot API 调用的代理 URL(SOCKS/HTTP)。channels.telegram.webhookUrl:启用 webhook 模式(需要channels.telegram.webhookSecret)。channels.telegram.webhookSecret:webhook 密钥(设置 webhookUrl 时必填)。channels.telegram.webhookPath:本地 webhook 路径(默认/telegram-webhook)。channels.telegram.actions.reactions:Telegram 工具表情回应门控。channels.telegram.actions.sendMessage:Telegram 工具消息发送门控。channels.telegram.actions.deleteMessage:Telegram 工具消息删除门控。channels.telegram.actions.sticker:Telegram 贴纸动作门控 — 发送和搜索(默认:false)。channels.telegram.reactionNotifications:off | own | all— 控制哪些表情回应触发系统事件(未设置时默认:own)。channels.telegram.reactionLevel:off | ack | minimal | extensive— 控制智能体的表情回应能力(未设置时默认:minimal)。
agents.list[].groupChat.mentionPatterns(提及门控模式)。messages.groupChat.mentionPatterns(全局回退)。commands.native(默认为"auto"→ Telegram/Discord 启用,Slack 禁用)、commands.text、commands.useAccessGroups(命令行为)。通过channels.telegram.commands.native覆盖。messages.responsePrefix、messages.ackReaction、messages.ackReactionScope、messages.removeAckAfterReply。