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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 13:00:15