📚 本文是 Telegram 专题的开发者向教程。还不会用 Telegram 的,先看 Telegram 完全指南 把下载、汉化、加机器人搞明白了再回来。

你会用 Telegram,但你有没有想过——那些@搜资源、@翻译、@定时提醒的机器人,其实你自己也能写一个

Telegram 的机器人生态能长成今天这样,靠的就是 Bot API 完全免费开放:注册一个 bot 不花一分钱,接口文档齐全,用 Python 几十行代码就能让一个机器人跑起来。比接微信个人号、比做个网页后台都省事,也没有那些乱七八糟的审核。

这篇就带你从零写一个:先用 BotFather 建 bot 拿 token,再用 python-telegram-bot 写出第一个自动回复机器人,最后部署到服务器常驻。全程真实代码,跟着敲就能跑通。

30 秒速答

  • 要花钱吗:不用。BotFather 建 bot 免费,python-telegram-bot 是开源库(LGPLv3)
  • 需要什么基础:一点点 Python(装环境、跑脚本),没有就走无代码路线
  • 核心三步:BotFather 建 bot 拿 token → pip 装 python-telegram-bot 写代码 → run_polling 跑起来
  • 怎么常驻:本地跑通后,部署到服务器用 systemd 托管
  • 能做什么:自动回复、定时提醒、按钮菜单、接大模型 API 做问答,思路都是同一套

一、先建机器人:BotFather 拿 token

所有 Telegram bot 都绕不开 BotFather——它是官方用来管理机器人的「机器人之父」。

  1. 在 Telegram 搜索框搜 @BotFather(带蓝色对勾认证的那个),点进去
  2. /newbot
  3. 按提示先给机器人起个显示名(随便起,会显示在聊天里),再起个用户名(必须 xxx_bot 结尾,别人@它就用这个)
  4. 成功后会返回一大段消息,里面有一行:
Use this token to access the HTTP API:
1234567890:AAFxxxxxxxxxxxxxxxxxxxxxxxxxxxx

这串 token 就是你的机器人的身份密钥,后面写代码要填它。复制下来先存好。

到手后可以顺手给机器人设个头像、描述、命令列表(/setcommands),这些都能在 BotFather 里发对应命令完成,不影响先跑起来。具体的命令菜单怎么配,看第六节。

二、装环境,写第一个自动回复机器人

装库

Python 3.10+,一行命令:

pip install "python-telegram-bot[job-queue]"

[job-queue] 是把定时任务的依赖(APScheduler)一起装上,第四节用得上。只写最基础的自动回复,裸 pip install python-telegram-bot 也行。

第一个 bot:回显机器人

新建 bot.py

import os
from telegram import Update
from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes

TOKEN = os.environ["BOT_TOKEN"] # 从环境变量读,别硬编码

async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text("你好!我是你写的第一个机器人,随便发点什么我复读给你。")

async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text(update.message.text)

def main():
app = Application.builder().token(TOKEN).build()
app.add_handler(CommandHandler("start", start)) # /start 命令
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, echo)) # 普通文字消息
app.run_polling() # 会一直阻塞,按 Ctrl+C 才停

if __name__ == "__main__":
main()

token 别直接写在代码里,用环境变量塞进去:

# Linux / macOS
export BOT_TOKEN="1234567890:AAFxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
python bot.py

# Windows PowerShell
$env:BOT_TOKEN="1234567890:AAFxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
python bot.py

终端不报错、挂着不动就说明连上了。回到 Telegram 找到你的机器人,发 /start,再随便发一句话,它就会复读给你。

这段代码到底在干嘛(三句讲清)

  1. Application.builder().token(...) 是 v20 以后的新写法,替代了老教程里已经删掉的 Updater,你搜到的旧文章认这个就行
  2. add_handler 是「注册事件」:CommandHandler("start", start) 意思是用户发 /start 就调用 start 函数;MessageHandler(filters.TEXT...) 是普通文字消息走 echo
  3. run_polling() 是「轮询」:程序不断问 Telegram 服务器「有没有新消息」,有就拿回来交给对应的 handler 处理。它会自己起事件循环,所以 main() 不用写成 async

这里有个新手最常踩的坑:**处理函数都要加 async、调用 Telegram 的地方要加 await**。v20 改成 asyncio 之后,老教程里不带 async/await 的同步写法会直接报错。

三、加一点真实功能:关键词问答

光复读没意思,我们让它能干点活——做一个按关键词回复的小 bot:

import os
from telegram import Update
from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes

TOKEN = os.environ["BOT_TOKEN"]

# 关键词规则表,key 是触发词,value 是回复内容
REPLY_MAP = {
"价格": "我们月付 19.9 元,年付 199 元,随时退。",
"帮助": "发 /help 看命令,或者输入「价格」了解套餐。",
"客服": "人工客服工作日 9:00-18:00 在线,稍后会有真人接上。",
}

async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text(
"您好!输入「价格」查套餐,「帮助」看说明,「客服」转人工。"
)

async def keyword_reply(update: Update, context: ContextTypes.DEFAULT_TYPE):
text = update.message.text
for key, reply in REPLY_MAP.items():
if key in text:
await update.message.reply_text(reply)
return
await update.message.reply_text("没听懂,输入「帮助」看看我能做什么。")

def main():
app = Application.builder().token(TOKEN).build()
app.add_handler(CommandHandler("start", start))
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, keyword_reply))
app.run_polling()

if __name__ == "__main__":
main()

逻辑很简单:收到文字 → 在 REPLY_MAP 里找有没有命中关键词 → 命中就回对应的、没命中就回「没听懂」。这就是绝大多数「机器人客服」「机器人查询」的底层原理——别觉得神奇,就一个字典查找

想让它更聪明,把 REPLY_MAP 换成一次大模型 API 调用就行,判断逻辑不用动。

四、进阶:定时提醒 + 按钮菜单

定时提醒(JobQueue)

想让机器人每天固定时间给你发消息(比如每天早上 8 点提醒打卡),用内置的 JobQueue:

import os
import datetime
from zoneinfo import ZoneInfo
from telegram.ext import Application, ContextTypes

TOKEN = os.environ["BOT_TOKEN"]
CHAT_ID = 123456789 # 换成你自己的数字 id,@userinfobot 能查

async def daily_reminder(context: ContextTypes.DEFAULT_TYPE):
await context.bot.send_message(chat_id=CHAT_ID, text="早上好,今天也要加油!")

def main():
app = Application.builder().token(TOKEN).build()
# 坑点:time 不传 tzinfo 会按 UTC 算,早上 8 点会变成北京时间下午 4 点
app.job_queue.run_daily(
daily_reminder,
time=datetime.time(hour=8, minute=0, tzinfo=ZoneInfo("Asia/Shanghai")),
)
app.run_polling()

if __name__ == "__main__":
main()

三个说明:

  • 时区run_daily 的时间不传 tzinfo 就按 UTC 走,这是定时 bot 最常见的翻车点,必须传 tzinfo
  • Windows 用户zoneinfo 在 Windows 上需要时区数据,先 pip install tzdata
  • chat_id 怎么拿:Telegram 里找 @userinfobot 发一条消息,它会告诉你数字 ID;群 ID 就把它拉进群再问一次

按钮菜单(InlineKeyboard)

想做个点按钮的交互菜单(很多 bot 都是这种),用 InlineKeyboardButton:

import os
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Application, CommandHandler, CallbackQueryHandler, ContextTypes

TOKEN = os.environ["BOT_TOKEN"]

async def menu(update: Update, context: ContextTypes.DEFAULT_TYPE):
keyboard = [
[InlineKeyboardButton("查价格", callback_data="price")],
[InlineKeyboardButton("转人工", callback_data="human")],
]
await update.message.reply_text(
"请选择:",
reply_markup=InlineKeyboardMarkup(keyboard),
)

async def button_click(update: Update, context: ContextTypes.DEFAULT_TYPE):
query = update.callback_query
await query.answer() # 必须先 answer,否则客户端按钮一直转圈
if query.data == "price":
await query.edit_message_text("月付 19.9 元,年付 199 元。")
elif query.data == "human":
await query.edit_message_text("已为你转接人工客服。")

def main():
app = Application.builder().token(TOKEN).build()
app.add_handler(CommandHandler("start", menu))
app.add_handler(CallbackQueryHandler(button_click))
app.run_polling()

if __name__ == "__main__":
main()

按钮点下去会触发 callback_queryquery.data 就是你在 callback_data 里填的值。点按钮 + 判断 data 做分支,这就是那些「菜单型机器人」的完整骨架。

五、部署:让机器人 24 小时在线

前面都是在你电脑的终端里跑,关掉终端机器人就”死”了。要让机器人常驻,得部署到一台一直开着的服务器(云服务器 / VPS)。

先说清楚连接方式:本文用的 run_polling() 是机器人主动去 Telegram 拉消息,不需要公网 IP、不需要域名、不需要备案,丢在一台能上网的小机器上就能跑。只有用户量很大、对响应速度有要求时才需要换 webhook(那需要域名 + HTTPS 证书),个人用的 bot 基本用不上。

最简单的是 systemd 托管。把代码传到服务器后,写一个服务单元文件:

sudo tee /etc/systemd/system/mybot.service > /dev/null <<EOF
[Unit]
Description=my telegram bot
After=network.target

[Service]
Type=simple
WorkingDirectory=/home/you/bot
Environment="BOT_TOKEN=1234567890:AAFxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
ExecStart=/usr/bin/python3 /home/you/bot/bot.py
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

启用并启动:

sudo systemctl daemon-reload
sudo systemctl enable --now mybot
systemctl status mybot # 看到 active (running) 就说明机器人常驻了

进程崩了 systemd 会自动拉起(Restart=on-failure),服务器重启也会自动启动(enable)。看日志用 journalctl -u mybot -f

六、上线后必做:命令菜单、进群、隐私模式

机器人能跑之后,还有三件事做了才算像个正经 bot。

1. 设置命令菜单

在 BotFather 里发 /setcommands,选你的 bot,然后按格式一次性发:

start - 开始使用
help - 查看帮助
price - 查询价格

发完回到聊天界面,点输入框左边的「/」就能看到这个菜单列表,用户不用猜你支持什么命令。

2. 把机器人拉进群

群设置 → 添加成员 → 搜你的 bot 用户名(xxx_bot)加进去。刚加进去时它可能是「没有权限」状态,把群里的「机器人权限」打开,或者干脆设成管理员。

3. 关掉隐私模式(否则收不到群消息)

默认 bot 开着隐私模式,只能收到 / 开头和 @ 提及它的消息,群里的闲聊它一条都看不见。去 BotFather 发 /setprivacy → 选你的 bot → 选 Disable

改完这一步,把 bot 移出群再重新拉进来才生效,很多人卡在这里以为没改成功。

常见问题排查

Q:运行报 NameError: name 'Updater' is not defined
你在抄老教程。Updater 在 v20 已经删了,改用 Application.builder().token(...).build(),处理函数加 async/await,见第二节。

Q:运行报 KeyError: 'BOT_TOKEN'
环境变量没设上。确认你 export/$env: 的命令和跑 python bot.py 用的是同一个终端窗口,换窗口就没了。长期用建议写进 .env 或 systemd 的 Environment

Q:机器人跑起来了,但发消息没反应?
先看终端有没有报错。常见原因:token 复制错了(多了空格或少了字符)、网络连不上 Telegram 服务器(见下一条)。

Q:连接超时、ConnectionError 报错?
Telegram API 在国内无法直连,跑机器人的服务器/电脑需要能访问外网。这个和本文前面的部署是同一个前提——如果服务器还没配科学上网,先解决访问通道,参考 科学上网完全指南,或者直接用已经能连外网的机器先跑通本地逻辑。

Q:token 泄露了 / 想重置?
去 BotFather 对你的 bot 发 /token → 选「Revoke」即可作废旧 token 换新的。日常用环境变量存 token,别硬编码、别提交到公开仓库。

总结

走完这一篇,你已经掌握了 Telegram 机器人开发的全套骨架:BotFather 建 bot → python-telegram-bot 写 handler → run_polling 跑起来 → systemd 部署常驻。回显、关键词问答、定时提醒、按钮菜单这四个例子,拼一拼就能做出一个能用的机器人。

再往上是接大模型 API——用 ChatGPT、Kimi、DeepSeek 这些 API 替代 REPLY_MAP 的写死回复,你的机器人就从「字典查找」升级成「真·AI 问答」。这块的思路和选型,看这篇:AI 助手工具指南(想直接体验现成的 AI 问答,也别错过里面提到的那些现成大模型)。

相关阅读