Bot Framework ActivityHandler如何向聊天回传处理进度消息
最优实现方案
你提到的两种方案都不可取,核心问题是会造成代码耦合甚至逻辑错误:
- 在
HeartbeatInteractive中导入MyBot类会直接产生循环依赖:你的Bot文件本身已经导入了HeartbeatInteractive,反向导入会直接导致模块加载失败,同时业务处理逻辑会和Bot实现强绑定,后续如果要把IP查询逻辑复用到API、命令行等其他场景,根本无法拆分。 - 在处理IP的逻辑文件中新增
ActivityHandler完全没有必要:ActivityHandler是用来处理入口会话事件的,主动发送进度消息不需要新建该类实例,平白增加冗余逻辑还会打乱会话上下文。
正确的实现思路是通过异步回调解耦业务层和Bot层,完全不需要在业务逻辑文件中引入任何Bot框架相关依赖,只把发送消息的能力作为参数传入业务逻辑即可。
具体实现代码
1. 修改Bot层代码
在消息处理方法中定义进度回调,复用当前会话的TurnContext发送消息,将回调作为参数传入IP处理逻辑:
from botbuilder.core import ActivityHandler, TurnContext from botbuilder.schema import ChannelAccount import HeartbeatInteractive class MyBot(ActivityHandler): async def on_message_activity(self, turn_context: TurnContext): if turn_context.activity.text.startswith('device'): search_word = str(turn_context.activity.text) ip = search_word.strip().split()[1] # 定义异步进度回调,绑定当前会话上下文 async def send_progress(msg: str): await turn_context.send_activity(msg) # 传入回调执行业务逻辑,注意这里要加await,因为init改成异步了 await HeartbeatInteractive.init(ip, progress_cb=send_progress)
2. 修改HeartbeatInteractive业务逻辑
不要引入任何Bot框架依赖,在每个进度节点调用传入的回调即可:
# 注意该文件不需要导入任何botbuilder相关包 async def init(ip: str, progress_cb = None): # 第一个进度节点 if progress_cb: await progress_cb(f"已启动IP {ip} 的关联信息查询...") # 执行第一步查询逻辑 # step1_result = query_device_base_info(ip) if progress_cb: await progress_cb("已拉取设备基础信息,开始检测网络连通性...") # 执行第二步查询逻辑 # step2_result = check_network_reach(step1_result) if progress_cb: await progress_cb("连通性检测通过,正在采集设备运行指标...") # 后续步骤按相同逻辑触发回调 # final_result = collect_metrics(step2_result) if progress_cb: await progress_cb(f"IP {ip} 查询完成,结果:\n{final_result}")
注意事项
- 所有回调必须用异步实现:Bot Framework的消息发送是异步IO操作,同步回调会阻塞事件循环导致消息发不出去。
- 不要在业务逻辑层长期持有
TurnContext引用:TurnContext是单次消息请求的上下文,生命周期和当前收到的消息绑定,长期持有容易引发上下文失效、内存泄漏问题,只暴露最小粒度的发送能力即可。 - 如果IP查询总耗时超过15秒,部分聊天渠道(比如Microsoft Teams)会主动断开单次请求的连接,这种场景下需要先给用户回复“查询任务已提交,后续进度将实时推送”,再把查询逻辑扔到后台任务中执行,后续发进度时调用
continue_conversation方法获取持久化会话引用发送,不能再使用单次请求的TurnContext。 - 如果IP查询逻辑跑在独立子线程/子进程中,不能直接跨线程/进程调用回调,需要把回调调度回Bot主事件循环执行,否则会抛出协程上下文错误。
内容的提问来源于stack exchange,提问作者Johnny Pastrami
相关产品推荐
相关产品推荐

