You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AsyncTeleBot无register_next_step_handler属性,异步Telegram机器人开发受阻

问题背景

我用pyTelegramBot开发问答记忆类Telegram机器人,同步版TeleBot的register_next_step_handler方法能正常实现等待用户输入的逻辑,示例代码如下:

...

@bot.message_handler(func=lambda msg: msg.text is not None and '/start' in msg.text)
def send_welcome(msg):
    global cur_user
    cur_user = msg.from_user.id
    keyboard = types.InlineKeyboardMarkup()
    keyboard.add(types.InlineKeyboardButton('Да', callback_data='old'),
                 types.InlineKeyboardButton('Нет', callback_data='new'))
    keyboard.add(types.InlineKeyboardButton('Пора остановиться', callback_data='stop_bot'))
    greet = 'Бла...бла...бла\nМы знакомы?'
    bot.send_message(msg.chat.id, greet, reply_markup=keyboard)

...

@bot.callback_query_handler(func=lambda call: True)
def query_processing(call):
    global user
    global cur_user
    if call.data == 'new':
        user = dict.fromkeys(user, None)
        nxt = bot.send_message(call.message.chat.id, 'Как звать?')
        bot.register_next_step_handler(nxt, get_name_ask_goal)

...

但由于需要处理消息等待、支持多用户同时操作,切换到AsyncTeleBot后发现没有register_next_step_handler方法,无法实现等待输入的逻辑,且找不到解决方案。另外尝试的异步代码运行时报错TypeError: An asyncio.Future, a coroutine or an awaitable is required,代码如下:

...
bot = AsyncTeleBot(os.getenv('token2'))
...

async def beep(chat_id) -> None:
    """Send the beep message."""
    await bot.send_message(chat_id, text='Beep!')
    aioschedule.clear(chat_id)

async def scheduler():
    global chat_id
    aioschedule.every(5).seconds.do(beep, chat_id).tag(chat_id)
    while True:
        await aioschedule.run_pending()
        await asyncio.sleep(1)

async def main():
    await asyncio.gather(scheduler(), bot.polling(non_stop=True))

if __name__ == "__main__":
    asyncio.run(main(), debug=True)
...
疑问解答

1. 适合需求的其他库

  • python-telegram-bot:v13及以上版本为异步架构,内置ConversationHandler组件,专门用于管理多用户对话流程,完美替代register_next_step_handler的功能,支持状态持久化,文档完善。
  • aiogram:纯异步的Telegram机器人框架,原生支持对话状态管理,用FSMContext(有限状态机)来追踪用户当前对话阶段,轻量高效,适合处理多用户并发场景。

2. 保存用户消息的简单方案

内存存储(适合测试/小型机器人)

用字典存储用户对话状态和消息内容,键为用户ID,值为当前状态或已保存的信息:

# 示例:存储用户状态和输入的信息
user_data = {}
# 结构:{user_id: {"state": "waiting_for_name", "name": None, "goal": None}}

@bot.message_handler(...)
async def handle_input(msg):
    user_id = msg.from_user.id
    current_state = user_data.get(user_id, {}).get("state")
    
    if current_state == "waiting_for_name":
        user_data.setdefault(user_id, {})["name"] = msg.text
        user_data[user_id]["state"] = "waiting_for_goal"
        await bot.send_message(user_id, "你的目标是什么?")
    elif current_state == "waiting_for_goal":
        user_data[user_id]["goal"] = msg.text
        await bot.send_message(user_id, f"已保存:姓名{msg.text},目标{user_data[user_id]['goal']}")

持久化存储(适合生产环境)

  • SQLite:轻量文件型数据库,无需额外服务,用sqlite3或asyncio兼容的aiosqlite操作,适合存储用户对话数据。
  • Redis:内存型键值数据库,适合高并发场景,快速读写用户状态,支持过期时间,适合临时对话状态存储。

3. 能否将asyncio与线程式的TeleBot配合使用?

可以,但不推荐。同步版TeleBot并非线程安全,多用户并发操作时容易出现数据竞争或异常。如果非要这么做,需要:

  • 用asyncio.run_in_executor将同步TeleBot的操作放到线程池中执行,避免阻塞事件循环;
  • 对共享资源(如全局用户数据)加线程锁,防止并发冲突。

但这种方式维护成本高,不如直接迁移到异步框架(如python-telegram-bot v13+或aiogram)更可靠。另外你之前的aioschedule报错,是因为do方法传入了异步函数但未正确处理,需要用asyncio.create_task包装:

# 修改scheduler中的代码
aioschedule.every(5).seconds.do(lambda: asyncio.create_task(beep(chat_id))).tag(chat_id)

同时要注意避免使用全局chat_id,应该根据实际场景传递正确的用户ID。

内容的提问来源于stack exchange,提问作者Pavel Stepanov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 23:20:39