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

MSTeams消息扩展Bot中AdaptiveCard随机消失问题求助

问题分析与解决方案:Teams消息扩展AdaptiveCard非固定模式下消失

原因分析

  • 临时会话上下文回收:非固定的消息扩展属于临时会话,Teams客户端会在请求完成后快速回收会话资源。如果卡片响应时序稍慢,客户端可能已清理会话上下文,导致卡片渲染后被自动移除;固定扩展使用持久会话,上下文不会被立即回收,因此卡片能稳定显示。
  • 无效卡片触发自动清理:当前代码生成的AdaptiveCard仅包含type和version字段,缺少body等核心内容,属于不完整卡片。非固定模式下Teams客户端对卡片有效性校验更严格,会自动丢弃无效卡片;固定模式下校验逻辑宽松,允许基础卡片显示。
  • 实例化方式导致上下文丢失:每次处理请求时新建ActionHandler实例,可能导致Bot Framework的上下文绑定不完整,非固定会话下这种不完整的上下文无法维持卡片的持久化状态。

解决方案

1. 修复AdaptiveCard的完整性

补充卡片必要结构,确保符合Teams的AdaptiveCard规范:

const card = CardFactory.adaptiveCard({
    type: 'AdaptiveCard',
    version: '1.5',
    body: [
        {
            type: 'TextBlock',
            text: '卡片内容示例',
            size: 'medium'
        }
    ]
});

2. 复用ActionHandler实例(Nest.js依赖注入)

将ActionHandler注册为Nest.js的提供者,避免每次请求新建实例,确保上下文正确绑定:

// 在模块中注册ActionHandler
@Module({
    controllers: [BotController],
    providers: [ActionHandler]
})
export class BotModule {}

// 在BotController中注入ActionHandler
@Controller()
export class BotController {
    constructor(private readonly actionHandler: ActionHandler) {}

    @Post(['/api/messages'])
    public async messageExtensionCall(
        @I18n() i18n: I18nContext,
        @Req() req: Request,
        @Res() res: Response
    ): Promise<void> {
        const botFrameworkAuthentication = ...;
        const adapter = new CloudAdapter(botFrameworkAuthentication);

        await adapter.process(req, res, async (context) => {
            const actionId = context.activity.value.commandId;
            switch (actionId) {
                case 'Some_Action':
                    await this.actionHandler.run(context); // 使用注入的实例
                    break;
                default:
                    Logger.warn(`Unsupported action ${actionId}`);
                    break;
            }
        });
    }
}

3. 配置会话状态持久化

为Bot添加会话状态存储,避免临时会话的上下文被快速回收:

import { MemoryStorage, ConversationState } from 'botbuilder';

// 在BotController中添加状态配置
@Controller()
export class BotController {
    private readonly conversationState: ConversationState;

    constructor(private readonly actionHandler: ActionHandler) {
        const storage = new MemoryStorage(); // 生产环境建议使用Azure Blob等持久化存储
        this.conversationState = new ConversationState(storage);
    }

    @Post(['/api/messages'])
    public async messageExtensionCall(
        @I18n() i18n: I18nContext,
        @Req() req: Request,
        @Res() res: Response
    ): Promise<void> {
        const botFrameworkAuthentication = ...;
        const adapter = new CloudAdapter(botFrameworkAuthentication);
        adapter.use(this.conversationState); // 注册会话状态

        await adapter.process(req, res, async (context) => {
            // ... 原有逻辑
        });
    }
}

4. 明确响应的返回格式

确保MessagingExtensionActionResponse结构完整,避免模糊的返回值:

public override async handleTeamsMessagingExtensionSubmitAction(
    context: TurnContext,
    action: MessagingExtensionAction
): Promise<MessagingExtensionActionResponse> {
    try {
        const card = CardFactory.adaptiveCard({
            type: 'AdaptiveCard',
            version: '1.5',
            body: [{ type: 'TextBlock', text: '提交成功' }]
        });

        return {
            composeExtension: {
                type: 'result',
                attachmentLayout: 'list',
                attachments: [card]
            }
        };
    } catch (error) {
        Logger.error('Cannot create submit action response.', error);
        // 返回明确的错误响应,而非空对象
        return {
            composeExtension: {
                type: 'message',
                text: '卡片生成失败,请重试'
            }
        };
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 09:20:58