对话框将其变量值保留在MS BotFramework v4中的新对话中 [英] Dialogs keep their variable values in new conversation in MS BotFramework v4

查看:57
本文介绍了对话框将其变量值保留在MS BotFramework v4中的新对话中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用MS BotFramework v4.根据用户输入的内容,有一个 RootDialog 可以启动 Dialog_A Dialog_B .

I'm using MS BotFramework v4. There is a RootDialog which starts Dialog_A or Dialog_B depending on what the user input is.

如果在对话之后开始新的对话并且机器人没有重新启动,则已经为其分配了值(不是初始值)的对话框的私有变量不会重置为初始值,从而导致意外行为.如何避免这种情况?

If a new conversation is started after a conversation and the bot isn't restarted, private variables of dialogs to which a value (which is not the initial value) has already be assigned, are not reseted to their initial value leading to unexpected behavior. How can this be avoided?

让我们假设以下情况:这些对话框中的每一个都有一些私有变量来控制是输出长介绍消息还是简短介绍消息.长对话框仅应在第一次启动此对话框时输出.如果对话再次到达对话框,则只应打印短消息.

Let's assume the following scenario: Each of these dialogs has some private variables to control whether to output a long or a short introduction message. The long one should only be be outputted on the first time this dialog is started. If the conversation again reaches the dialog only the short message should be printed.

实现看起来像这样:

RootDialog.cs

public class RootDialog : ComponentDialog
{
    private bool isLongWelcomeText = true;
    // Some more private variables follow here

    public RootDialog() : base("rootId") {
        AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[] {
            WelcomeStep,
            DoSomethingStep,
            FinalStep
        });
    }

    private async Task<DialogTurnContext> WelcomeStep(WaterfallStepContext ctx, CancellationToken token) {
        if(isLongWelcomeText) {
            await ctx.SendActivityAsync(MessageFactory.Text("A welcome message and some detailed bla bla about the bot"));
            isLongWelcomeText = false;
        } else {
            await ctx.SendActivityAsync(MessageFactory.Text("A short message that hte bot is waiting for input"));
        }
    }

    private async Task<DialogTurnContext> DoSomethingStep(WaterfallStepContext ctx, CancellationToken token) {
        // call Dialog_A or Dialog_B depending on the users input
        // Dialog X starts
        await ctx.BeginDialogAsync("Dialog_X", null, token);
    }

    private async Task<DialogTurnContext> FinalStep(WaterfallStepContext ctx, CancellationToken token) {
        // After dialog X has ended, RootDialog continues here and simply ends
        await ctx.EndDialogAsync(null, token);
    }
}

Dialog_A Dialog_B 的结构相同.

如果漫游器处理了第一次对话,则一切都会按预期进行(将长欢迎文本显示给用户,并且在 WelcomeStep中将 isLongWelcomeText 设置为 false .然后,当我开始新的对话(新的sessionId和userId)时, isLongWelcomeText 仍设置为 false ,这导致漫游器将简短的欢迎文本输出为与新用户的新对话.

If the bot handles its first conversation, everything works as expected (the long welcome text is printed to the user and isLongWelcomeText is set to false in WelcomeStep. When I then start a new conversation (new conversationId and userId) isLongWelcomeText still is set to false which leads to the bot outputting the short welcome text in a new conversation to a new user.

在BotFramework v3中,对话框与所有变量值一起被序列化和反序列化.

In BotFramework v3 dialogs were serialized and deserialized together with all variable values.

如果我对BF v4的要求正确,对话框将不再序列化.

If I'm right in BF v4 dialogs aren't serialized anymore.

如何解决?有更好的方法吗?

How can this be fixed? Is there a better way to do this?

我正在使用 UserState ConversationState ,它们已序列化并在新对话中重置.但是我不想在状态下存储每个对话框的每个私有变量值.这不是要走的路.

I'm using UserState and ConversationState which are serialized and reset on new conversations. But I don't want to store every private variable value of each dialog in the states. This cannot be the way to go.

感谢advace

推荐答案

通常,您应该将其视为将实例成员变量放入对话框类的错误.在某些情况下它可能会起作用,但是这些情况不会涉及尝试在转弯之间保持某种状态.使用bot类的任何类型的内存变量来保持转弯之间的状态存在三个主要问题:

Generally you should think of it as a mistake to put instance member variables in a dialog class. There may be some cases when it could work, but those cases will not involve trying to persist some kind of state between turns. There are three main problems with using any kind of in-memory variables of your bot classes to persist state between turns:

  1. 范围不正确.这是您已经注意到的问题.您已经清楚地将 isLongWelcomeText 定义为应特定于用户和/或对话的内容,但是因为它是在机器人自身的内存中用于处理每个用户的每次对话,所以它不会无法区分不同的对话和用户.
  2. 它无法正确缩放.这意味着,即使您的机器人只是在一次对话中与一个用户交谈,如果该机器人部署在某些托管服务(如Azure)中,也可以横向扩展,然后将多个您的机器人实例可能正在运行.机器人的不同实例将具有不同的内存,因此,如果您要正确设计机器人,则需要采取行动,好像每个回合都将由完全不同的机器人实例(也许是在完全不同的服务器上)进行处理.一个实例无法访问另一实例的内存.
  3. 当应用重新启动时,它将丢失.即使您只有一个用户,一个对话,一个机器人实例,您仍然希望能够停止您的漫游器,然后在不破坏对话的情况下再次启动它.如果您正在使用漫游器的内存,则无法这样做.
  1. It won't be scoped correctly. This is the problem you noticed already. You've clearly defined your isLongWelcomeText as something that should be specific to a user and/or a conversation, but because it's in your bot's own memory that's used to process every conversation for every user then it won't be able to distinguish between different conversations and users.
  2. It won't scale correctly. This means that even if your bot is just talking to one user in one conversation, if the bot is deployed in some hosting service like Azure that scales sideways then multiple instances of your bot may be running. Different instances of your bot will have different memory, so if you want to design a bot correctly then you need to act as though every turn will be processed by a totally different instance of the bot, maybe on a totally different server. One instance can't access the memory of another instance.
  3. It will be lost when the app restarts. Even if you only have one user, one conversation, and one bot instance, you still want to be able to stop your bot and then start it again without ruining the conversation. If you're using the bot's memory then you can't do that.

后两个问题甚至在使用 MemoryStorage 时适用,而不仅仅是在使用内存中变量时适用.您可能已经猜到解决方案是使用bot状态(并且在部署bot时将bot状态连接到除 MemoryStorage 之外的其他存储类).

The second two problems even apply when you're using MemoryStorage and not just when you're using in-memory variables. You may have guessed that the solution is to use bot state (and to connect the bot state to some storage class other than MemoryStorage when the bot is deployed).

您是正确的,在v3中,对话框类的整个实例对象将被序列化为持久状态.这带来了自己的问题,并不总是合乎逻辑,因此在v4中,要序列化的内容是此处).您想让对话框保持跟踪的所有内容,都应放入关联的对话框实例的状态对象,而查看如何执行此操作的示例的最佳位置是SDK源代码本身.例如,您可以看到

You are correct that in v3 entire instance objects of dialog classes would get serialized into persistent state. That came with its own set of problems and didn't always make logical sense, so in v4 the things that gets serialized are DialogInstance objects. (Read about dialog instances here). Anything you want your dialog to keep track of, you should put in the associated dialog instance's state object, and the best place to see examples of how to do that is in the SDK source code itself. For example, you can see how a waterfall dialog keeps track of things like its custom values and what step it's on:

// Update persisted step index
var state = dc.ActiveDialog.State;
state[StepIndex] = index;

这篇关于对话框将其变量值保留在MS BotFramework v4中的新对话中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆