1

我正在尝试构建一个机器人。起初我使用的是Node.js,但因为显然 c# 更适合我的客户,所以我开始在 c# 中创建 Bot。我还创建了一个 LUIS 应用程序。

现在,这个 Bot 背后的想法是,它会在最后结合您的结果并根据您的答案挑选解决方案之前询问您一系列问题。我遇到的问题是我不知道如何设置机器人来做到这一点。在节点中,它谈到了瀑布,但我在 c# 版本中看不到类似的东西。另外,我不确定它是否应该在我应该集中注意力的 LUIS 中。

例如,假设我希望用户选择一个对象,然后根据该对象提出 3 个问题,例如:

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

最后说“你想要一台黑色、小巧、轻便的相机。” 我似乎无法让它发挥作用。我知道你们中的一些人会说使用 FormFlow,但问题是动态的,对象也是动态的,这就是我使用 LUIS 的原因。

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

4

2 回答 2

1

这是另一种选择,如果你想手动处理这个,你可以为你的每个问题设置不同的 context.Wait 方法,有一种瀑布方法。

因此,假设您有一个带有 ChooseCategory 意图的 LuisDialog。在该方法中,您将确定类别并基于一些自定义逻辑,您将提出一个新问题。

这可以通过以下方式完成:PromptDialog/ResumeAfter 或手动 context.PostAsync/context.Wait(它基本上定义了将侦听下一条消息的方法)。

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

[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 "answer 1":
            // do something
            break;
        case "answer 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)
{
  //...
}
于 2016-11-14T20:38:41.803 回答
1

如果 FormFlow 过于严格,您应该考虑使用 Dialogs。它们允许进行更开放的对话。

我会做以下事情:

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

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

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

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)在对话框中提问

在 Dialog 中,使用 PromptDialog 来询问问题 1。使用问题 1 的答案的开关来确定要问问题 2 的内容。像这样继续对话。

[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 语句来确定接下来要问什么问题。

单击此处了解有关对话框的更多信息

于 2016-11-15T06:13:29.080 回答