Telegram 对话 Bot
Telegram Bot API 同时提供收消息与发消息接口。本文主路径使用生产环境更常见的 Webhook,本地调试可改用 getUpdates;核验日期为 2026-09-08,未使用真实 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 会收到 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())调试长轮询前先调用 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,再异步执行 reply(update, '/ping' ? 'pong' : ...)。重复事件不能重复调用发送接口。
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 请求内无限等待。
安全与可靠性
Section titled “安全与可靠性”- 同时校验 Webhook Secret 与 URL 路由随机性;Webhook 地址不要含 Bot Token。
- Token 泄露后立即通过
@BotFather撤销,替换服务端配置并重新注册 Webhook。 - 使用
update_id做事件去重,对同一会话串行或加锁,防止上下文乱序。 - 忽略 Bot 自身或其他 Bot 消息,限制输入长度、附件大小和每日模型预算。
- 防范提示词注入;用户内容不能修改工具白名单或服务端权限。
- 对
429读取retry_after后退避,不做紧密重试。
getUpdates 没有数据:检查是否仍设置了 Webhook;两者不能同时使用。
群里只收到命令,收不到普通文本:这是 Privacy Mode 的常见表现。优先采用命令、提及或回复触发;只有明确需要且完成隐私评估后才调整模式。
Webhook 一直重试:确认服务在平台时限内返回 2xx。模型调用放到队列或后台任务,并确保 update_id 去重。
机器人回复到了错误主题:论坛群需要把入站的 message_thread_id 传回 sendMessage。