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

Node.js版BotBuilder Teams机器人流式响应上下文丢失问题求助

解决Teams Bot流式返回时上下文丢失的问题

问题原因

BotBuilder的TurnContext生命周期绑定当前对话轮次,当主代码执行完(注册完流回调后,当前turn的处理流程结束),框架会自动回收上下文资源,后续流触发异步回调时,原上下文已失效,导致"已撤销"的错误。

解决方案

通过保存对话引用(ConversationReference),在流回调中借助BotAdapter重新创建有效上下文,同时调整消息发送逻辑:

  • 保存对话引用:在当前有效上下文阶段,提取对话的引用信息
  • 借助Adapter创建新上下文:在流回调中使用adapter.continueConversation发起新的对话轮次,获取可用的上下文
  • 调整消息处理逻辑:可以选择发送新消息累加内容,或先发送初始消息再逐步更新

修改后的代码示例

// 从当前上下文获取BotAdapter实例
const adapter = context.adapter;

try {
  const data = await postDataToEndpoint(url, reqBody, headers);
  // 保存对话引用,用于后续创建新上下文
  const conversationReference = TurnContext.getConversationReference(context.activity);
  // 发送初始加载提示,若需要更新消息则保存消息ID
  const initialMessage = await context.sendActivity(MessageFactory.text('正在处理,请稍候...'));
  const initialMessageId = initialMessage.id;
  let payloadText = '';

  console.log('外部上下文有效: ', context);

  data.on('data', async (chunk) => {
    try {
      // 累加流式返回的文本块
      payloadText += chunk.toString();
      // 通过adapter重新创建上下文,发起新的对话轮次
      await adapter.continueConversation(conversationReference, async (newContext) => {
        // 方案1:更新初始消息,替换为当前累加的文本
        await newContext.updateActivity({
          id: initialMessageId,
          text: payloadText,
          type: 'message',
          conversation: conversationReference.conversation
        });

        // 方案2:直接发送新的文本块(适合分段展示)
        // await newContext.sendActivity(MessageFactory.text(chunk.toString()));
      });
    } catch (streamErr) {
      console.error('流处理错误: ', streamErr);
    }
  });

  // 监听流结束事件
  data.on('end', async () => {
    await adapter.continueConversation(conversationReference, async (newContext) => {
      // 流结束后可以发送完成提示
      await newContext.sendActivity(MessageFactory.text('处理完成!'));
    });
  });

  // 监听流错误事件
  data.on('error', async (err) => {
    await adapter.continueConversation(conversationReference, async (newContext) => {
      const errorCardData: ErrorCardData = { error: err.message };
      const errorCardJson = AdaptiveCards.declare(errorCard).render(errorCardData);
      await newContext.sendActivity(
        MessageFactory.attachment(CardFactory.adaptiveCard(errorCardJson))
      );
    });
  });

} catch (err) {
  const errorCardData: ErrorCardData = { error: err.message };
  const errorCardJson = AdaptiveCards.declare(errorCard).render(errorCardData);
  await context.sendActivity(
    MessageFactory.attachment(CardFactory.adaptiveCard(errorCardJson))
  );
  await next();
}

关键注意点

  • 不要在流回调中直接使用原TurnContext,必须通过ConversationReference和adapter.continueConversation创建新上下文
  • 流回调中的异步操作要包裹try/catch,避免未处理的Promise错误
  • 若选择更新消息,需确保初始消息ID正确传递,且对话引用的conversation信息完整
  • 无需在流回调中调用next(),因为当前中间件的处理流程已在主代码执行完后结束

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 13:23:27