Frameworks Microsoft Bot Framework-第一次交互后多回合上下文丢失

Frameworks Microsoft Bot Framework-第一次交互后多回合上下文丢失,frameworks,bots,Frameworks,Bots,我最近将我的代码从sdkv3移到了v4,我正在尝试利用multi-turn特性 我已经看过GitHub的样品了。这些示例对于多回合很有效,但我注意到的一个问题是,只有在显示初始答案(带有提示)后立即单击提示时,它才能识别上下文。 我希望能够在任何给定的时间确定是否单击了提示。我已经在状态对象(dialogInstance.state)中存储了前面的所有提示。我有一个自定义主机,它发送replytoid并使用它可以获得适当的状态 但问题是,我无法使用对话框instance.State 示例代码使用

我最近将我的代码从sdkv3移到了v4,我正在尝试利用multi-turn特性

我已经看过GitHub的样品了。这些示例对于多回合很有效,但我注意到的一个问题是,只有在显示初始答案(带有提示)后立即单击提示时,它才能识别上下文。 我希望能够在任何给定的时间确定是否单击了提示。我已经在状态对象(
dialogInstance.state
)中存储了前面的所有提示。我有一个自定义主机,它发送replytoid并使用它可以获得适当的状态

但问题是,我无法使用
对话框instance.State

示例代码使用DialogExtensions类。“DialogExtensions”类通过检查
ContinueDialogAsync
方法的结果是否返回null来尝试收集上一个上下文

如果没有以前的上下文(没有带有提示的以前的答案),那么对ContinueDialogAsync的调用将返回一个状态为空的结果

我在想,我需要检查
对话框状态
,如果新消息在任何给定点引用了任何旧消息,那么它可以开始继续旧的对话

我甚至不确定这是否可能。 如有任何帮助/建议,将不胜感激。
谢谢,

我最终实现了一个适用于自定义bot主机/直接通道bot客户端的东西

关键是,只要选择了一个选项,对qnamaker api的调用就应该与旧的上下文对象一起发生,即使它不在上下文中

首先让我解释一下它在当前版本的代码中是如何工作的。 机器人程序代码试图解决多回合对话的方式是,如果有提示/选项,则存储当前答案,并以“等待”模式返回对话状态。当收到下一个问题时,它将自动假定新问题是旧问题的提示/选项的一部分。然后,它会将旧状态传递给QnAMaker。 我注意到的是,即使第二轮中的问题不是提示/选项的一部分(用户手动键入的内容,是一个完全不同的问题),它仍然会将oldstate对象发送给QnAMaker。 如果新问题不是oldstate的提示/选项的一部分,那么qnamakerapi调用似乎会忽略oldstate。通过获取手动键入的新问题的答案,它将正常工作。 这是关键。如果我们能专注于qnamaker的问题,那么我们就能解决最初的问题

我意识到让机器人返回等待状态只是一种机制,它可以创建一个条件,以便在下一轮中提取旧状态。但是,如果我可以在选择选项的任何时候重建旧状态,那么对qnamaker的调用也同样有效

这就是我现在所做的。 在我的自定义bot主机代码(这是一个直连客户端)中,每当单击提示时,我都会发送用原始问题填充的ReplyToID字段。然后在bot代码中,我对其进行了更改,以便如果存在replytoid,则使用reply to id中的数据构建一个新的oldstate对象。下面是表示oldstate的QnABotState类。它是一个非常简单的类,包含以前的qna问题id和问题文本

public int PreviousQnaId { get; set; }

public string PreviousUserQuery { get; set; }

现在,问题是Activity对象包含ReplyToId,但不包含ReplyToQuery(或类似的内容)。活动对象用于将数据从bot客户端发送到bot。因此,要么我必须使用不同的字段,要么将PreviousUserQuery作为空字符串发送。我有一种预感,它只适用于以前的qnaid

//starting the process to get the old context (create an object that will hold the Process function's current state from the dialog state)
            //if there is replyToId field is present, then it is a direct channel request who is replying to an old context
            //get the reply to id from summary field
            var curReplyToId = "";            
            curReplyToId = dialogContext.Context.Activity.ReplyToId;
            var curReplyToQuery = "";



            var oldState = GetPersistedState(dialogContext.ActiveDialog);

            //if oldstate is null also check if there is replytoid populated, if it is then it maybe a new conversation but it is actually an "out of turn option" selection.
            if (oldState == null)
            {
                if (!string.IsNullOrEmpty(curReplyToId))
                {
                    //curReplyToId is not empty. this is an option that was selected out-of-context
                    int prevQnaId = -1;
                    int.TryParse(curReplyToId, out prevQnaId);

                    oldState = new QnABotState() { PreviousQnaId = prevQnaId, PreviousUserQuery = curReplyToQuery };
                }

            }
有了它,我对qnamaker api的调用将接收一个oldstate对象,即使它是在上下文之外调用的

我尝试了这个代码,它成功了。没有上一个qna查询并没有什么不同。它只在填充之前的qnaid字段的情况下工作

但是,请注意,这不适用于其他频道。它适用于可以设置ReplyToId字段的频道,例如Direct Channel Client

以下是来自我的bot主机的代码:

  // to create a new message
    Activity userMessage = new Activity
    {
        From = new ChannelAccount(User.Identity.Name),
        Text = questionToBot,
        Type = ActivityTypes.Message,
        Value = paramChatCode,// + "|" + "ShahID-" + DateTime.Now.TimeOfDay,
        Id = "ShahID-" + DateTime.Now.TimeOfDay,
        ChannelData = botHostId//this will be added as the bot host identifier
    };
    //userMessage.Type = "imBack";
    if (paramPreviousChatId > 0)
    {
        //we have a valid replytoid (as a part of dialog)
        userMessage.ReplyToId = paramPreviousChatId.ToString();

    }