Appearance
Telegram(Bot API)
状态:通过 grammY 实现的机器人私信和群组功能已生产就绪。默认为长轮询模式;也支持 webhook 模式。
快速配置
第一步:在 BotFather 创建机器人 token
打开 Telegram,与 @BotFather 对话(确认 handle 完全一致)。运行 /newbot,按提示操作并保存 token。
第二步:配置 token 和私信策略
json5
{
channels: {
telegram: {
enabled: true,
botToken: "123:abc",
dmPolicy: "pairing",
groups: { "*": { requireMention: true } },
},
},
}环境变量回退:TELEGRAM_BOT_TOKEN=...(仅限默认账号)。Telegram 不使用 openclaw channels login telegram;在配置/环境变量中设置 token 后启动 Gateway 即可。
第三步:启动 Gateway 并批准首个私信
bash
openclaw gateway
openclaw pairing list telegram
openclaw pairing approve telegram <CODE>配对码有效期 1 小时。
第四步:将机器人添加到群组
将机器人添加到群组,然后设置 channels.telegram.groups 和 groupPolicy 以匹配你的访问模型。
说明: token 解析顺序具有账号感知能力。实际上,配置值优先于环境变量回退,
TELEGRAM_BOT_TOKEN仅适用于默认账号。
Telegram 端设置
隐私模式与群组可见性: Telegram 机器人默认启用隐私模式,这限制了它能接收的群组消息。如果机器人需要看到所有群组消息,要么通过 /setprivacy 禁用隐私模式,要么将机器人设为群组管理员。切换隐私模式后,需要将机器人移出再重新加入每个群组使变更生效。
BotFather 常用开关:
/setjoingroups:允许/禁止加入群组/setprivacy:群组可见性行为
访问控制与激活
私信策略
channels.telegram.dmPolicy 控制私信访问:
pairing(默认)allowlist(allowFrom中至少需要一个发送方 ID)open(allowFrom需包含"*")disabled
channels.telegram.allowFrom 接受数字 Telegram 用户 ID,telegram: / tg: 前缀会被标准化。dmPolicy: "allowlist" 且 allowFrom 为空时拦截所有私信,配置验证会报错。
运营建议:对于单Owner机器人,优先使用 dmPolicy: "allowlist" 加显式数字 allowFrom ID,以便访问策略持久保存在配置中(而非依赖之前的配对批准)。
常见混淆:DM 配对批准不代表该发送者在所有地方都获得了授权。配对只授予私信访问权限,群组发送者授权仍需通过配置白名单明确设置。如果你希望"我配对一次后,私信和群组命令都能使用",请将你的数字 Telegram 用户 ID 填入 channels.telegram.allowFrom。
查找你的 Telegram 用户 ID(更安全的方式):
- 给你的机器人发消息。
- 运行
openclaw logs --follow。 - 读取
from.id。
官方 Bot API 方式:
bash
curl "https://api.telegram.org/bot<bot_token>/getUpdates"群组策略与白名单
两个控制层同时生效:
允许哪些群组(
channels.telegram.groups)- 未配置
groups:groupPolicy: "open"时任意群组可通过群组 ID 检查;groupPolicy: "allowlist"(默认)时群组被拦截直到添加groups条目(或"*") - 已配置
groups:作为白名单(显式 ID 或"*")
- 未配置
允许哪些发送方进入群组(
channels.telegram.groupPolicy)openallowlist(默认)disabled
groupAllowFrom 用于群组发送方过滤;未设置时回退到配置中的 allowFrom(而非配对存储)。条目应为数字 Telegram 用户 ID。负数的群组/超级群组 ID 属于 channels.telegram.groups,不要放在 groupAllowFrom 里。
群组发送方授权不继承 DM 配对存储的批准(2026.2.25+)。对于单Owner机器人的实用模式:将你的用户 ID 填入 channels.telegram.allowFrom,留空 groupAllowFrom,并在 channels.telegram.groups 下允许目标群组。
允许某个特定群组内任意成员的示例:
json5
{
channels: {
telegram: {
groups: {
"-1001234567890": {
groupPolicy: "open",
requireMention: false,
},
},
},
},
}提及行为
群组回复默认需要提及。提及来源:
- 原生
@botusername提及 - 提及模式正则(
agents.list[].groupChat.mentionPatterns,回退messages.groupChat.mentionPatterns)
会话级命令切换:
/activation always/activation mention
这些命令仅更新会话状态,不修改全局配置。持久化请使用配置。
运行时行为
- Telegram 由 Gateway 进程独占。
- 路由确定性:Telegram 入站消息始终回复到 Telegram(模型不选择渠道)。
- 入站消息规范化为共享渠道信封,包含回复元数据和媒体占位符。
- 群组会话按群组 ID 隔离。Forum 话题在会话键后追加
:topic:<threadId>保持隔离。 - 私信可携带
message_thread_id;OpenClaw 使用线程感知的会话键并在回复中保留线程 ID。 - 长轮询使用 grammY runner,按聊天/线程顺序处理。整体 runner sink 并发度使用
agents.defaults.maxConcurrent。
功能详情
实时流式预览(消息编辑)
OpenClaw 可以实时流式传输局部回复:
channels.telegram.streaming:off | partial | block | progress(默认:partial)progress在 Telegram 上映射为partial(跨渠道命名兼容)
对于仅文本回复,OpenClaw 保持同一预览消息并执行最终就地编辑(不发第二条消息)。对于复杂回复(如媒体负载),OpenClaw 回退到正常最终投递,然后清理预览消息。
Telegram 独有的推理流:
/reasoning stream在生成时将推理内容发送到实时预览- 最终答案不包含推理文本
格式化与 HTML 回退
出站文本使用 Telegram parse_mode: "HTML"。Markdown 风格文本渲染为 Telegram 安全 HTML;原始模型 HTML 经过转义以减少解析失败。若 Telegram 拒绝解析后的 HTML,OpenClaw 会以纯文本重试。
链接预览默认启用,可通过 channels.telegram.linkPreview: false 禁用。
原生命令与自定义命令
Telegram 命令菜单注册在启动时通过 setMyCommands 处理。
commands.native: "auto"为 Telegram 启用原生命令
添加自定义命令菜单条目:
json5
{
channels: {
telegram: {
customCommands: [
{ command: "backup", description: "Git backup" },
{ command: "generate", description: "Create an image" },
],
},
},
}常见配置失败:
setMyCommands failed且错误为BOT_COMMANDS_TOO_MUCH:Telegram 菜单条目过多,减少插件/技能/自定义命令,或禁用channels.telegram.commands.native。setMyCommands failed且错误为网络/fetch 错误:通常是出站 DNS/HTTPS 到api.telegram.org被阻断。
内联按钮
配置内联键盘作用范围:
json5
{
channels: {
telegram: {
capabilities: {
inlineButtons: "allowlist",
},
},
},
}范围选项:off | dm | group | all | allowlist(默认)。
回调点击以文本形式传给 Agent:callback_data: <value>。
Forum 话题与线程行为
Forum 超级群组:
- 话题会话键追加
:topic:<threadId> - 回复和输入状态针对话题线程
- 话题配置路径:
channels.telegram.groups.<chatId>.topics.<threadId>
每话题 Agent 路由: 每个话题可通过设置话题配置中的 agentId 路由到不同 Agent,实现独立的工作区、记忆和会话。
json5
{
channels: {
telegram: {
groups: {
"-1001234567890": {
topics: {
"1": { agentId: "main" }, // General 话题 → main agent
"3": { agentId: "zu" }, // 开发话题 → zu agent
"5": { agentId: "coder" } // 代码审查 → coder agent
}
}
}
}
}
}Thread-bound ACP 绑定: /acp spawn <agent> --thread here|auto 可将当前 Telegram 话题绑定到新 ACP 会话,需要 channels.telegram.threadBindings.spawnAcpSessions=true。
音频、视频与 Sticker
Telegram 区分语音消息和音频文件:
- 默认:音频文件行为
- 在 Agent 回复中添加
[[audio_as_voice]]标签强制以语音消息发送
Telegram 区分视频文件和圆形视频消息(video note),video note 不支持字幕,提供的文本会单独发送。
Sticker 处理:
- 静态 WEBP:下载并处理(占位符
<media:sticker>) - 动态 TGS:跳过
- 视频 WEBM:跳过
启用 sticker 动作:
json5
{
channels: {
telegram: {
actions: {
sticker: true,
},
},
},
}反应通知
Telegram 反应通过 message_reaction 更新到达。
channels.telegram.reactionNotifications:off | own | all(默认:own)channels.telegram.reactionLevel:off | ack | minimal | extensive(默认:minimal)
Exec 审批
Telegram 支持在审批人私信中进行 exec 审批,也可以选择在原始聊天或话题中发布审批提示。
channels.telegram.execApprovals.target:dm | channel | both(默认:dm)channels.telegram.execApprovals.approvers:允许批准/拒绝的 Telegram 用户 ID 列表(可选;如果allowFrom或defaultTo中已能推断出 owner,可不填)
Telegram 在以下情况自动启用原生 exec 审批:enabled 未设置或为 "auto",且至少一个审批人能被解析(来自 execApprovals.approvers 或账号的数字 owner 配置)。显式设置 enabled: false 可关闭 Telegram 作为原生审批客户端。
Telegram 同时渲染其他聊天渠道使用的共享审批按钮。这些按钮存在时是主要审批 UX;只有当工具结果说明聊天审批不可用或手动审批是唯一路径时,才应包含手动 /approve 命令。
审批解析行为:
- 以
plugin:前缀的 ID 始终通过插件审批解析。 - 其他审批 ID 先尝试
exec.approval.resolve。 - 如果 Telegram 也授权了插件审批且 Gateway 返回该审批未知/已过期,Telegram 会通过
plugin.approval.resolve重试一次。 - 真实的 exec 审批拒绝/错误不会静默回落到插件审批解析。
Exec 审批默认 30 分钟后过期。
仅解析出的审批人可以批准或拒绝。相关文档:Exec 审批
长轮询 vs Webhook
默认:长轮询。
Webhook 模式:
- 设置
channels.telegram.webhookUrl - 设置
channels.telegram.webhookSecret(设置 webhook URL 时必填) - 可选
channels.telegram.webhookPath(默认/telegram-webhook) - 本地监听默认绑定到
127.0.0.1:8787
故障排查
机器人不响应未提及的群组消息:
- 如果
requireMention=false,Telegram 隐私模式必须允许完整可见性(BotFather:/setprivacy-> Disable,然后移出重新加入机器人) openclaw channels status --probe可检查显式数字群组 ID;通配符"*"无法探针检查- 快速会话测试:
/activation always
机器人完全看不到群组消息:
- 如果
channels.telegram.groups存在,群组必须在列表中(或包含"*") - 确认机器人已加入群组
- 查看日志:
openclaw logs --follow
命令部分或完全不生效:
- 授权你的发送方身份(配对和/或数字
allowFrom) - 即使群组策略为
open,命令授权仍然生效
网络不稳定/轮询问题:
- 某些主机 DNS 优先解析
api.telegram.org的 IPv6;损坏的 IPv6 出站可能导致间歇性 API 失败 - 通过代理路由 Telegram API 调用:yaml
channels: telegram: proxy: socks5://<user>:<password>@proxy-host:1080 - RFC 2544 基准范围地址(
198.18.0.0/15)默认允许用于 Telegram 媒体下载。如果你的透明代理或 fake-IP(如 Clash、Mihomo、Surge)将api.telegram.org重写到 RFC 2544 范围以外的私有地址,可以启用旁路选项:yamlchannels: telegram: network: dangerouslyAllowPrivateNetwork: true⚠️ 此选项会削弱 Telegram 媒体的 SSRF 保护,仅在你信任的受控代理环境中使用。如果你的代理已将 Telegram 媒体解析到
198.18.x.x,不需要开启此选项。
更多帮助:渠道故障排查
常见问题
Q: 机器人加到群组后收不到群友消息,只回自己被 @ 的消息?
A: 这是 Telegram 机器人的默认"隐私模式"限制。你需要在 BotFather 里输入 /setprivacy 并选择 Disable,然后把机器人移出群组再重新拉进去,才能获取群消息读取权限。
Q: 为什么在群里发了 /activation always 但过了一会儿又必须 @ 才能唤醒了?
A: 命令只会影响当前会话的临时状态。如果想彻底改变群组唤醒策略,需要在配置文件中设置 channels.telegram.groups.群组ID.requireMention: false。
Q: setMyCommands 启动报错 BOT_COMMANDS_TOO_MUCH 怎么办?
A: Telegram 对菜单命令数量有限制。你需要减少加载的插件、全局技能,或者在配置中直接禁用原生命令同步:channels.telegram.commands.native: false。
错误回复控制
当 agent 遇到交付或 provider 错误时,Telegram 可以选择回复错误文本或静默抑制。两个配置键控制此行为:
| 配置键 | 可选值 | 默认值 | 说明 |
|---|---|---|---|
channels.telegram.errorPolicy | reply, silent | reply | reply 发送友好错误消息到聊天;silent 完全抑制错误回复 |
channels.telegram.errorCooldownMs | 毫秒数 | 60000 | 对同一聊天发送错误回复的最短间隔,防止故障期间刷屏 |
支持每账号、每群组和每话题覆盖(与其他 Telegram 配置键相同的继承关系):
json5
{
channels: {
telegram: {
errorPolicy: "reply",
errorCooldownMs: 120000,
groups: {
"-1001234567890": {
errorPolicy: "silent", // 在这个群组里静默错误
},
},
},
},
}