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

如何在Bot Framework全对话中触发LUIS并保留上下文与认证参数

实现方案

第一步:存储authHeaders到Bot State

你无法跨对话访问authHeaders是因为仅将其作为对话启动参数传递,参数只能在当前对话及其子对话的options中读取,将其存储到UserState后,可在任意能拿到TurnContext的位置读取和修改。

// 主Bot文件中初始化State
const { UserState, MemoryStorage } = require('botbuilder');
const memoryStorage = new MemoryStorage();
const userState = new UserState(memoryStorage);
const AUTH_HEADERS_PROPERTY = 'authHeaders';
this.authHeadersAccessor = userState.createProperty(AUTH_HEADERS_PROPERTY);

// 在AUTH_DIALOG的showUserInfo方法中,拿到authHeaders后存入State
const authHeadersAccessor = stepContext.context.turnState.get('authHeadersAccessor');
await authHeadersAccessor.set(stepContext.context, authHeaders);
await userState.saveChanges(stepContext.context);

第二步:实现全局LUIS触发

两种可选方案,可根据项目结构选择:

方案1:子对话统一继承带中断逻辑的基类(推荐)

适合对话数量不多、需要灵活控制中断规则的场景,无需修改全局逻辑。

const { ComponentDialog, Dialog } = require('botbuilder-dialogs');
const { LuisRecognizer } = require('botbuilder-ai');

class BaseDialog extends ComponentDialog {
    constructor(dialogId) {
        super(dialogId);
    }

    // 每次收到新消息先触发中断逻辑
    async onContinueDialog(innerDc) {
        const interruptResult = await this.interrupt(innerDc);
        if (interruptResult) {
            return Dialog.EndOfTurn;
        }
        return await super.onContinueDialog(innerDc);
    }

    async interrupt(innerDc) {
        const luisRecognizer = new LuisRecogniser(luisConfig, innerDc.dialogs.telemetryClient);
        if (!luisRecognizer.isConfigured) return false;

        // 执行LUIS识别
        const luisResult = await luisRecognizer.executeLuisQuery(innerDc.context);
        const topIntent = LuisRecognizer.topIntent(luisResult);

        // 读取存储的authHeaders
        const authHeadersAccessor = innerDc.context.turnState.get('authHeadersAccessor');
        let authHeaders = await authHeadersAccessor.get(innerDc.context, {});

        // 匹配意图跳转对应对话
        switch(topIntent) {
            case 'Intent1':
                authHeaders.header1 = luisResult.entities;
                await authHeadersAccessor.set(innerDc.context, authHeaders);
                await userState.saveChanges(innerDc.context);
                // 清空当前对话栈跳转新对话
                await innerDc.cancelAllDialogs();
                await innerDc.beginDialog(DIALOG_A, authHeaders);
                return true;
            case 'Intent2':
                authHeaders.header2 = luisResult.entities;
                await authHeadersAccessor.set(innerDc.context, authHeaders);
                await userState.saveChanges(innerDc.context);
                await innerDc.cancelAllDialogs();
                await innerDc.beginDialog(DIALOG_B, authHeaders);
                return true;
            // 其他意图同理
            default:
                // 意图匹配当前对话则不中断,继续执行
                return false;
        }
    }
}

后续所有子对话(包括FLOW_DIALOG、DIALOG_A、DIALOG_B)统一继承BaseDialog即可实现全局LUIS触发。

方案2:onMessage阶段统一处理

适合对话数量多、不想修改每个子对话继承关系的场景。

this.onMessage(async (context, next) => {
    // 读取authHeaders
    const authHeaders = await this.authHeadersAccessor.get(context, {});
    // 执行LUIS识别
    const luisRecognizer = new LuisRecogniser(luisConfig, this.telemetryClient);
    const luisResult = await luisRecognizer.executeLuisQuery(context);
    const topIntent = LuisRecognizer.topIntent(luisResult);

    // 创建DialogContext
    const dc = await this.dialogs.createContext(context);

    switch(topIntent) {
        case 'Intent1':
            authHeaders.header1 = luisResult.entities;
            await this.authHeadersAccessor.set(context, authHeaders);
            await this.userState.saveChanges(context);
            await dc.cancelAllDialogs();
            await dc.beginDialog(DIALOG_A, authHeaders);
            break;
        case 'Intent2':
            authHeaders.header2 = luisResult.entities;
            await this.authHeadersAccessor.set(context, authHeaders);
            await this.userState.saveChanges(context);
            await dc.cancelAllDialogs();
            await dc.beginDialog(DIALOG_B, authHeaders);
            break;
        // 其他意图同理
        default:
            // 无匹配跳转意图则继续当前对话
            await dc.continueDialog();
            if (!dc.activeDialog) {
                await dc.beginDialog(FLOW_DIALOG, authHeaders);
            }
    }
    await next();
});

注意事项

  • 生产环境请将MemoryStorage替换为持久化存储(如Azure Cosmos DB、Blob存储),避免服务重启后用户认证信息丢失
  • 可根据业务需求在中断逻辑中添加例外规则,比如用户正在输入表单信息时禁止意图跳转
  • 切换对话前调用cancelAllDialogs()可以清空当前对话栈,避免残留的对话逻辑干扰新流程

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 18:15:02