首页 > 解决方案 > 具有复杂对话流的顺序瀑布模型 Bot Framework C# v4

问题描述

我有 3 个独立的瀑布模型,它们由使用 Luis 的意图触发。我想按顺序链接这 3 个模型,我一直遵循PictureBot编码风格,每个对话框/瀑布都有它的状态属性。

3种瀑布方法如下,

到目前为止,我一直在通过聊天窗口传递值,因为 3 个瀑布步骤松散耦合,用户可以将它们作为机器人的独立组件/功能调用,所以我的问题是

  1. 如何链接 3 个模型,即如果用户触发了瀑布_1,并转到 2 或 3,则询问“用户”的对话框将被跳过?我在想每个瀑布都需要一个全局和本地获取器和设置器。

  2. 在 WaterFall_1 中,最后一个响应发送来自 Azure 搜索的查询结果,即“名称”,我应该立即 endDialog 还是 WaterFall_1 调用 WaterFall_2 和/如果 WaterFall_3 然后我为 3、2、1 结束对话框?

该图可能会提供更多上下文简单图

标签: c#botframework

解决方案


You have the general idea down, in your question 1. What you would need is a 'shared' or global state not unlike the state demonstrated in the Bot Framework's CafeBot (Look under samples => dotnet => #50).

If you have a 'global' state set, you could save the list of user names retrieved in your Waterfall 1 to that. Then, when your second or third waterfall are called via your LUIS intents, you pass in the state accessor to the Waterfall 1 results to the parent class of Waterfall 2, thus making them accessible to the other waterfalls.

You would not need to make them sequential, if you're relying on LUIS. You could use LUIS to have 'Search Users' trigger WF1, 'Do XYZ to Users' trigger 2, and 'Do ABC to Users' trigger 3. This would make your bot less rigid for your bot users, as they could do a search, then do either 2 OR 3, (or both) as needed.

I was able to simulate this by simply adding an extra, waterfall based class to the Bot Framework MessageRoutingBot (samples => dotnet => #09)

AlteredStateBot

Here is the waterfall setup for the 'Favorite Animal' prompt, including accessing the greetingState from the original sample bot:

public TestDialog(IStatePropertyAccessor<TestState> testStateAccessor, IStatePropertyAccessor<GreetingState> greetingStateAccessor, ILoggerFactory loggerFactory)
        : base(nameof(TestDialog))
    {
        TestStateAccessor = testStateAccessor ?? throw new ArgumentNullException(nameof(testStateAccessor));
        GreetingStateAccessor = greetingStateAccessor ?? throw new ArgumentNullException(nameof(greetingStateAccessor));

        // Add control flow dialogs
        var waterfallSteps = new WaterfallStep[]
        {
                InitializeStateStepAsync,
                PromptForAnimalStepAsync,
                // PromptForCityStepAsync,
                DisplayTestStateStepAsync,
        };
        AddDialog(new WaterfallDialog(ProfileDialog, waterfallSteps));

        // AddDialog(new TextPrompt(NamePrompt, ValidateName));
        AddDialog(new TextPrompt(AnimalPrompt));
    }

With the greetingState accessor pulled in, it allowed me to continue to call my user by name, from a second waterfall, without needing to reprompt for it:

 private async Task<DialogTurnResult> GreetUser(WaterfallStepContext stepContext)
    {
        var context = stepContext.Context;
        var testState = await TestStateAccessor.GetAsync(context);
        var greetingState = await GreetingStateAccessor.GetAsync(context);

        // Display their profile information and end dialog.
        await context.SendActivityAsync($"Hi {greetingState.Name}, who likes {testState.Animal}s, nice to meet you!");
        return await stepContext.EndDialogAsync();
    }

Hope this helps!


推荐阅读