微软Bot框架,路易斯和瀑布

本文关键字:路易斯 Bot 框架 微软 | 更新日期: 2023-09-27 18:18:03

我正在尝试建立一个机器人。起初我使用的是Node.js,但显然c#对我的客户端更好,所以我已经开始在c#中创建Bot。我还创建了一个LUIS应用程序。

现在,这个机器人背后的想法是,它会问你一系列问题,然后结合你的结果,最后根据你的答案选择一个解决方案。我的问题是,我不知道如何设置机器人来做到这一点。在node中,它谈到了瀑布,但我在c#版本中看不到任何类似的东西。此外,我不确定是否应该在路易斯,我应该集中我的注意力。

作为一个例子,假设我想让用户选择一个对象,然后根据该对象问3个问题,如:

  1. 它小吗?
  2. 它轻吗?
  3. 你喜欢什么颜色?

最后说:"你想要一个黑色,小,轻的相机。"我好像没法让它工作。我知道你们中的一些人会说使用FormFlow,但问题是动态的,对象也是动态的,这就是我使用LUIS的原因。

有人知道我在哪里可以找到一篇关于如何使用LUIS创建类似的流的好文章吗?

微软Bot框架,路易斯和瀑布

如果FormFlow限制太大,你应该考虑使用对话框。它们允许更开放的对话。

我会这样做:

1)要求用户选择一个类别。

如果可能的话,使用按钮为用户提供一个可供选择的类别列表。这意味着您不必向LUIS询问用户选择的类别。

否则,允许用户键入一个类别并将其传递给LUIS。来自LUIS的响应将包含一个Entity。实体将保存类别的名称。

2)转发到该类别的对话

根据从LUIS返回的实体,转发到负责询问下一个问题的适当对话框

[LuisIntent("AskQuestionAboutCategory")]
    public async Task AskQuestion(IDialogContext context, LuisResult result)
    {
       //get Entity from LUIS response
        string category = result.Entities.FirstOrDefault(e => e.Type == "Category")?.Entity;
        switch (category)
        {
            case "Category 1":
                //forward to Dialog for Category1
                await
                    context.Forward(new Category1Dialog(), ResumeAfter,
                        new Activity {Text = result.Query}, CancellationToken.None);
                break;
            case "Category 2":
                //forward to Dialog for Category2
                await
                    context.Forward(new Category2Dialog(), ResumeAfter,
                        new Activity {Text = result.Query}, CancellationToken.None);
                break;
        }
    }
    private async Task ResumeAfter(IDialogContext context, IAwaitable<object> result)
    {
        context.Wait(MessageReceived);
    }

3)对话框内提问

在对话框中,使用PromptDialog来询问问题1。在第1题的答案上使用一个开关,来决定第二题的问题。像这样继续对话。

[Serializable]
public class Category1Dialog : IDialog<object>
{
    public async Task StartAsync(IDialogContext context)
    {
        context.Wait(MessageReceivedAsync);
    }
    public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
    {
        var prompt = "what is the answer to question 1 ?";
        //ASK QUESTION 1
        PromptDialog.Text(context, ResumeAfterQuestion1, prompt);
    }
    private async Task ResumeAfterQuestion1(IDialogContext context, IAwaitable<string> result)
    {
        var input = await result;
        switch (input)
        {
            //ASK QUESTION 2, DEPENDING ON WHAT WAS ANSWERED FOR QUESTION 1
            case "Answer A":
                PromptDialog.Text(context, ResumeAfterQuestion2, "what is the answer to question 2 ?");
                break;
            case "Answer B":
                PromptDialog.Text(context, ResumeAfterQuestion2, "what is the answer to question 2 ?");
                break;
        }
    }

    private async Task ResumeAfterQuestion2(IDialogContext context, IAwaitable<string> result)
    {
        var input = await result;
        switch (input)
        {
            //ASK QUESTION 3
            case "Answer C":
                PromptDialog.Text(context, ResumeAfterQuestion3, "what is the answer to next question after Answer C ?");
        break;
            case "Answer D":
                PromptDialog.Text(context, ResumeAfterQuestion3, "what is the answer to next question after Answer D ?");
        break;
    }
    }

看起来你需要使用switch语句来决定接下来要问什么问题。

点击这里查看对话框

这里有另一种选择,如果你想手动处理这个,你可以设置不同的上下文。你的每个问题都有等待方法,有点像瀑布方法。

假设你有一个带有choocategory意图的LuisDialog。在这种方法中,您将确定类别,并根据一些自定义逻辑提出新问题。

这可以通过:PromptDialog/ResumeAfter或手动上下文来完成。PostAsync/上下文。等待(它基本上定义了侦听下一条消息的方法)。

我不知道你的自定义逻辑是如何的,但是你应该能够动态地决定哪个是下一个方法,将侦听即将到来的消息

[LuisIntent("Choose category")]
public async Task ChooseCategory(IDialogContext context, LuisResult result)
{
    // get category logic..
    await context.PostAsync("This is my first question?");
    context.Wait(CaptureFirstQuestionAnswerAsync);
}
public async Task CaptureFirstQuestionAnswerAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
{
    IMessageActivity message = await argument;
    switch (message.Text.ToLower())
    {
        case "answerswer 1":
            // do something
            break;
        case "answerswer 2":
           // do something different
            break;
        default:
           // do something ...
            break;
    }
    await context.PostAsync($"This is my second question?");
    context.Wait(CaptureSecondQuestionAnswerAsync);
}
public async Task CaptureSecondQuestionAnswerAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
{
  //...
}