Telegram 对话 Bot
Telegram Bot API 同时提供收消息与发消息接口。本文主路径使用生产环境更常见的 Webhook,本地调试可改用 getUpdates;核验日期为 2026-09-14。当前网络环境无法稳定访问 Telegram 官方站点,也未使用真实 Bot 发送消息,验证等级保持“官方资料整理”。
getUpdates(长轮询)和 Webhook 是互斥的更新接收方式;设置 Webhook 后不能继续用getUpdates。- 私聊中用户必须先启动 Bot。群聊中能收到哪些普通消息受 Bot Privacy Mode、管理员权限和消息类型影响。
- 默认建议只处理私聊、命令、对 Bot 的回复或显式提及,不要为了 AI 对话直接关闭 Privacy Mode。
- Bot API 本身不提供 LLM;普通规则回复和 AI 回复使用同一套
sendMessage。
- 在 Telegram 中能访问官方
@BotFather。 - 有一个 HTTPS 公网回调地址;本地调试也可暂不配置 Webhook,使用
getUpdates。 - 服务端能保存 Bot Token 和 Webhook Secret,不把 Token 写入前端或访问日志。
- 已准备测试私聊或测试群,并明确群聊触发规则。
- 向
@BotFather发送/newbot,按提示设置名称和唯一用户名,保存 Bot Token。 - 私聊机器人并点击 Start;群聊场景把机器人加入测试群。
- 在 BotFather 的 Bot Settings 中确认 Group Privacy。普通场景保持启用,只通过命令、提及或回复触发。
- 生成不少于 128 位随机强度的
WEBHOOK_SECRET,调用setWebhook注册 HTTPS URL。 - 服务端校验
X-Telegram-Bot-Api-Secret-Token,快速返回 2xx,并在后台处理更新。
Webhook 地址要求
Section titled “Webhook 地址要求”- 使用公开可访问的 HTTPS 地址和有效证书,不在 URL 中放 Bot Token。
- Telegram 云端 Bot API 的 Webhook 常用端口限制以当前官方文档为准,标准
443最容易穿过网络和代理策略。 secret_token由调用方生成,平台会原样放入X-Telegram-Bot-Api-Secret-Token;服务端使用常量时间比较。- 使用
allowed_updates只订阅实际处理的事件类型,减少不必要数据和模型触发。
Webhook 会收到 Update JSON。消息文本通常位于 message.text,稳定事件 ID 是 update_id;回复目标来自 message.chat.id,论坛主题还要保留 message.message_thread_id。
{ "update_id": 900000001, "message": { "message_id": 27, "from": { "id": 10001 }, "chat": { "id": -100000000001, "type": "supergroup" }, "text": "/ping" }}以 update_id 做事件去重。会话键推荐使用 telegram:{chat.id}:{message_thread_id || 0};私聊可再加入用户 ID。不要把显示名或用户名作为身份主键。
注册与检查 Webhook
Section titled “注册与检查 Webhook”curl -X POST 'https://api.telegram.org/botBOT_TOKEN/setWebhook' \ -H 'Content-Type: application/json' \ -d '{"url":"https://bot.example.com/telegram/events","secret_token":"WEBHOOK_SECRET","allowed_updates":["message"]}'const response = await fetch(`https://api.telegram.org/bot${process.env.BOT_TOKEN}/setWebhook`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ url: 'https://bot.example.com/telegram/events', secret_token: process.env.WEBHOOK_SECRET, allowed_updates: ['message'], }),});console.log(await response.json());import osimport requests
response = requests.post( f"https://api.telegram.org/bot{os.environ['BOT_TOKEN']}/setWebhook", json={ "url": "https://bot.example.com/telegram/events", "secret_token": os.environ["WEBHOOK_SECRET"], "allowed_updates": ["message"], }, timeout=15,)response.raise_for_status()print(response.json())注册后调用 getWebhookInfo 检查当前地址、证书状态、pending_update_count、最近错误时间和 last_error_message:
curl 'https://api.telegram.org/botBOT_TOKEN/getWebhookInfo'积压事件确认可以丢弃时,可在重新注册或删除 Webhook 时使用 drop_pending_updates=true。该参数会丢弃尚未处理的 Update,属于故障恢复操作,不应作为日常清队列手段。
调试长轮询前先调用 deleteWebhook,然后用 getUpdates 携带 offset=上一条 update_id + 1。生产中不要同时启动多个没有协调 offset 的轮询实例。
普通 API 双向回复
Section titled “普通 API 双向回复”处理 /ping 时调用 sendMessage,并传入原消息 ID 形成明确回复:
async function reply(update, text) { const message = update.message; const response = await fetch(`https://api.telegram.org/bot${process.env.BOT_TOKEN}/sendMessage`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ chat_id: message.chat.id, message_thread_id: message.message_thread_id, text, reply_parameters: { message_id: message.message_id }, }), }); const result = await response.json(); if (!response.ok || !result.ok) throw new Error(JSON.stringify(result));}Webhook 路由应先验证 Secret、记录去重键并返回 2xx,再异步解析命令:
const normalizedText = update.message.text.trim();const fallbackText = '无法识别该命令,请发送 /help';await reply(update, normalizedText === '/ping' ? 'pong' : fallbackText);不要用固定字符串作为条件。重复事件命中同一 update_id 后直接确认,不能再次调用发送接口。
AI 对话扩展
Section titled “AI 对话扩展”将 message.text 标准化后交给厂商无关的 generateReply:
const conversationKey = `telegram:${message.chat.id}:${message.message_thread_id ?? 0}`;const answer = await generateReply({ messages: await history.withUserMessage(conversationKey, message.text), signal: AbortSignal.timeout(20_000),});await reply(update, answer);- 群聊只在命令、提及或回复 Bot 时调用模型。
- 将 Bot 命令从模型自由文本中分流,权限相关命令走确定性业务逻辑。
- 长答案按 Telegram 当前长度限制切分,保持代码块完整,并限制消息发送速率。
- 发生模型超时时返回简短可重试提示,不在 Webhook 请求内无限等待。
- 调用模型前移除 Bot 命令实体和提及,但保留用户原始文本用于审计摘要;不要用显示用户名做权限判断。
安全与可靠性
Section titled “安全与可靠性”- 同时校验 Webhook Secret 与 URL 路由随机性;Webhook 地址不要含 Bot Token。
- Token 泄露后立即通过
@BotFather撤销,替换服务端配置并重新注册 Webhook。 - 使用
update_id做事件去重,对同一会话串行或加锁,防止上下文乱序。 - 忽略 Bot 自身或其他 Bot 消息,限制输入长度、附件大小和每日模型预算。
- 防范提示词注入;用户内容不能修改工具白名单或服务端权限。
- 对
429读取retry_after后退避,不做紧密重试。 - 监控
pending_update_count、最近 Webhook 错误、处理耗时、去重命中率和每会话队列深度。 - 变更 Webhook 前先读取
getWebhookInfo保存旧配置,失败时可以恢复原地址和订阅类型。
getUpdates 没有数据:检查是否仍设置了 Webhook;两者不能同时使用。
群里只收到命令,收不到普通文本:这是 Privacy Mode 的常见表现。优先采用命令、提及或回复触发;只有明确需要且完成隐私评估后才调整模式。
Webhook 一直重试:确认服务在平台时限内返回 2xx。模型调用放到队列或后台任务,并确保 update_id 去重。
机器人回复到了错误主题:论坛群需要把入站的 message_thread_id 传回 sendMessage。
pending_update_count 持续增长:检查公网连通、证书、Secret 校验和响应时延;不要先用 drop_pending_updates 掩盖根因。
last_error_message 显示超时:Webhook 入口只做验证、去重、入队和快速 2xx,模型生成放到后台任务。
切换到 getUpdates 后仍报冲突:确认 deleteWebhook 已成功,并且没有另一个轮询实例占用更新流。