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

如何实现Telegram Bot发送消息后等待用户回复的模式

问题场景
  • 开发Telegram Bot时需要实现:机器人发送提示消息后,暂停常规命令响应逻辑,等待并捕获用户下一条回复的交互模式
  • 当前项目依赖NuGet包:
    • Telegram.Bot 16.0.1
    • Newtonsoft.Json
  • 现有业务代码(存在逻辑缺陷:发送提示后未等待用户输入,直接执行了置顶、发送通知逻辑):
case "Ask question❓":
    {
        await client.SendTextMessageAsync(chatId: msg.Chat.Id, $"Write your question, to pin it on the chat-forum «{msg.Chat.Title}»!\n❗Please note that your question must follow the rules of this chat-forum.", replyMarkup: new ReplyKeyboardRemove());
        await client.PinChatMessageAsync(chatId: msg.Chat.Id, messageId: msg.MessageId);
        await client.SendTextMessageAsync(chatId: msg.Chat.Id, $"🔥New question from {msg.From.Username}!", replyToMessageId: msg.MessageId, replyMarkup: GetButtons());
        break;
    }
实现方案

Telegram Bot本身是Webhook/长轮询的无状态模型,不存在原生的阻塞式「等待回复」接口,核心实现逻辑是自行维护用户会话状态,根据状态分流处理收到的消息。

步骤1:定义会话状态存储

单实例部署场景直接用线程安全的内存字典存储用户状态即可,无需额外依赖:

// 存储结构:Key为用户ID,Value为用户当前会话状态
private static readonly ConcurrentDictionary<long, UserSession> _sessionStore = new();

// 定义机器人状态枚举
public enum BotStatus
{
    Idle, // 空闲状态,走常规命令匹配逻辑
    WaitForQuestionSubmit // 等待用户提交问题
}

// 会话实体,存储状态和上下文数据
public class UserSession
{
    public BotStatus Status { get; set; }
    public string ForumName { get; set; }
    public int TriggerMessageId { get; set; }
}

步骤2:修改触发命令的处理逻辑

用户点击「Ask question❓」按钮时,仅发送提示消息、标记用户状态,不要执行需要等用户输入后才触发的置顶、发通知逻辑:

case "Ask question❓":
    {
        // 标记用户当前为等待提交问题状态,存入上下文
        _sessionStore[msg.From.Id] = new UserSession
        {
            Status = BotStatus.WaitForQuestionSubmit,
            ForumName = msg.Chat.Title,
            TriggerMessageId = msg.MessageId
        };
        // 发送输入提示
        await client.SendTextMessageAsync(
            chatId: msg.Chat.Id,
            text: $"Write your question, to pin it on the chat-forum «{msg.Chat.Title}»!\n❗Please note that your question must follow the rules of this chat-forum.",
            replyMarkup: new ReplyKeyboardRemove()
        );
        break;
    }

步骤3:在消息处理入口增加状态分流

每次收到用户新消息时,优先检查用户是否处于等待输入状态,如果是则直接走对应场景的处理逻辑,处理完重置状态,不再走常规命令匹配:

// 消息处理入口优先校验会话状态
if (_sessionStore.TryGetValue(msg.From.Id, out var session) && session.Status == BotStatus.WaitForQuestionSubmit)
{
    // 当前消息就是用户提交的问题内容
    string questionContent = msg.Text;
    // 执行后续业务逻辑
    await client.PinChatMessageAsync(chatId: msg.Chat.Id, messageId: session.TriggerMessageId);
    await client.SendTextMessageAsync(
        chatId: msg.Chat.Id,
        text: $"🔥New question from {msg.From.Username}:\n{questionContent}",
        replyToMessageId: session.TriggerMessageId,
        replyMarkup: GetButtons()
    );
    // 处理完成,重置用户状态为空闲
    session.Status = BotStatus.Idle;
    // 终止后续流程,不要进入常规命令匹配
    return;
}

// 原有常规命令匹配逻辑(比如上面的case "Ask question❓"分支)放在状态判断之后

扩展说明

  • 如果需要增加超时自动取消功能,给UserSession加个LastOperateTime时间戳字段,加个定时任务定期清理超过设定时长(比如10分钟)的等待状态,同时给用户发提示说明等待超时即可
  • 多交互场景可以直接扩展BotStatus枚举,比如增加WaitForEmailInput、WaitForFeedbackSubmit等值,对应不同的处理分支即可
  • 如果是多实例部署,把内存字典替换成Redis等共享存储即可,逻辑完全一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 07:27:15