Skip to content

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.groupsgroupPolicy 以匹配你的访问模型。

说明: token 解析顺序具有账号感知能力。实际上,配置值优先于环境变量回退,TELEGRAM_BOT_TOKEN 仅适用于默认账号。

Telegram 端设置

隐私模式与群组可见性: Telegram 机器人默认启用隐私模式,这限制了它能接收的群组消息。如果机器人需要看到所有群组消息,要么通过 /setprivacy 禁用隐私模式,要么将机器人设为群组管理员。切换隐私模式后,需要将机器人移出再重新加入每个群组使变更生效。

BotFather 常用开关:

  • /setjoingroups:允许/禁止加入群组
  • /setprivacy:群组可见性行为

访问控制与激活

私信策略

channels.telegram.dmPolicy 控制私信访问:

  • pairing(默认)
  • allowlistallowFrom 中至少需要一个发送方 ID)
  • openallowFrom 需包含 "*"
  • disabled

channels.telegram.allowFrom 接受数字 Telegram 用户 ID,telegram: / tg: 前缀会被标准化。dmPolicy: "allowlist"allowFrom 为空时拦截所有私信,配置验证会报错。

运营建议:对于单Owner机器人,优先使用 dmPolicy: "allowlist" 加显式数字 allowFrom ID,以便访问策略持久保存在配置中(而非依赖之前的配对批准)。

常见混淆:DM 配对批准不代表该发送者在所有地方都获得了授权。配对只授予私信访问权限,群组发送者授权仍需通过配置白名单明确设置。如果你希望"我配对一次后,私信和群组命令都能使用",请将你的数字 Telegram 用户 ID 填入 channels.telegram.allowFrom

查找你的 Telegram 用户 ID(更安全的方式):

  1. 给你的机器人发消息。
  2. 运行 openclaw logs --follow
  3. 读取 from.id

官方 Bot API 方式:

bash
curl "https://api.telegram.org/bot<bot_token>/getUpdates"

群组策略与白名单

两个控制层同时生效:

  1. 允许哪些群组channels.telegram.groups

    • 未配置 groupsgroupPolicy: "open" 时任意群组可通过群组 ID 检查;groupPolicy: "allowlist"(默认)时群组被拦截直到添加 groups 条目(或 "*"
    • 已配置 groups:作为白名单(显式 ID 或 "*"
  2. 允许哪些发送方进入群组channels.telegram.groupPolicy

    • open
    • allowlist(默认)
    • 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.streamingoff | 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.reactionNotificationsoff | own | all(默认:own
  • channels.telegram.reactionLeveloff | ack | minimal | extensive(默认:minimal

Exec 审批

Telegram 支持在审批人私信中进行 exec 审批,也可以选择在原始聊天或话题中发布审批提示。

  • channels.telegram.execApprovals.targetdm | channel | both(默认:dm
  • channels.telegram.execApprovals.approvers:允许批准/拒绝的 Telegram 用户 ID 列表(可选;如果 allowFromdefaultTo 中已能推断出 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 范围以外的私有地址,可以启用旁路选项:
    yaml
    channels:
      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.errorPolicyreply, silentreplyreply 发送友好错误消息到聊天;silent 完全抑制错误回复
channels.telegram.errorCooldownMs毫秒数60000对同一聊天发送错误回复的最短间隔,防止故障期间刷屏

支持每账号、每群组和每话题覆盖(与其他 Telegram 配置键相同的继承关系):

json5
{
  channels: {
    telegram: {
      errorPolicy: "reply",
      errorCooldownMs: 120000,
      groups: {
        "-1001234567890": {
          errorPolicy: "silent", // 在这个群组里静默错误
        },
      },
    },
  },
}

相关链接