C # Microsoft Bot Framework с luis, направляющим результат в QNA Maker и граф API - PullRequest
0 голосов
/ 14 сентября 2018

Я создал бота на основе ботов Microsoft и использовал Луиса для сопоставления намерений. Некоторые из намерений направляют его в QNA, а некоторые другие намерения направляют его в граф api.

Мой вопрос Каков наилучший подход для определения того, следует ли ему перейти к qna для поиска связанных намерений в qna или следует ли перейти к графику api для получения результатов.

На данный момент я сделал это, используя несколько Luis Intents для сопоставления правильного намерения, а затем перенаправил его в соответствии с необходимыми функциональными возможностями намерения (направить ли это в диалоговое окно qna или graph api).

` [LuisModel («идентификатор модели», «ключ»)]

[Serializable]
public class RootDialog : DispatchDialog
{

    //this intent directs to graph api dialog
    [LuisIntent(DialogMatches.GraphApiIntent)]
    public async Task RunGraphapiIntent(IDialogContext context, IActivity activity)
    {
            UserMessage = (activity as IMessageActivity).Text;
            await context.Forward(new GraphApiDailog(), EndDialog, context.Activity, CancellationToken.None);
    }

      //This intent directs to qna dialog
      [LuisIntent(DialogMatches.BlogMatch)]
      public async Task RunBlogDialogQna(IDialogContext context, LuisResult result)
      {
        var userQuestion = (context.Activity as Activity).Text;
        (context.Activity as Activity).Text = DialogMatches.BlogMatch;
        await context.Forward(new BasicQnAMakerDialog(), this.EndDialog, context.Activity, CancellationToken.None);
      }
      `

Но этот подход требует, чтобы я соответствовал всем намерениям, используя [LuisIntent("intentstring")] .. Поскольку у меня может быть 50 или 100 намерений, нецелесообразно писать 50 функций для 50 намерений.

Я нашел способ вызова API для извлечения намерений из высказываний в Быстрый старт: анализ текста с использованием C #

используется «https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/df67dcdb-c37d-46af-88e1-8b97951ca1c2?subscription-key=&q=turn на свету спальни» API для получения намерения.

Опять же, мой вопрос: как я узнаю, следует ли мне перенаправить его в QnaDialog или Graph Api Dialog для извлечения данных с использованием намеренного результата, который я получил?

Заранее спасибо

1 Ответ

0 голосов
/ 16 сентября 2018

Если вы хотите, чтобы вещи масштабировались, вам будет лучше, если вы создадите собственную службу Nlp, которая вызывает Luis API для определения намерения. Я думаю, что лучший способ обработать перенаправление диалога по намерению - это создать что-то вроде IntentDetectorDialog, единственной задачей которого является анализ высказывания пользователя и пересылка в диалог, соответствующий обнаруженному намерению.

Вот аккуратный подход, который я использовал некоторое время:

public abstract class BaseDialog : IDialog<BaseResult>
{
    public bool DialogForwarded { get; protected set; }

    public async Task StartAsync(IDialogContext context)
    {
        context.Wait(OnMessageReceivedAsync);
    }

    public async Task OnMessageReceivedAsync(
        IDialogContext context,
        IAwaitable<IMessageActivity> result)
    {
        var message = await result;

        var dialogFinished = await HandleMessageAsync(context, message);

        if (DialogForwarded) return;

        if (!dialogFinished)
        {
            context.Wait(OnMessageReceivedAsync);
        }
        else
        {
            context.Done(new DefaultDialogResult());
        }
    }

    protected abstract Task<bool> HandleMessageAsync(IDialogContext context, IMessageActivity message);

    protected async Task ForwardToDialog(IDialogContext context, 
        IMessageActivity message, BaseDialog dialog)
    {
        DialogForwarded = true;
        await context.Forward(dialog, (dialogContext, result) =>
        {
            // Dialog resume callback
            // this method gets called when the child dialog calls context.Done()
            DialogForwarded = false;
            return Task.CompletedTask;
        }, message);
    }
}

Базовый диалог, родительский для всех других диалогов, будет обрабатывать общий поток диалога. Если диалог еще не закончен, он уведомит каркас бота, вызвав context.Wait, иначе он завершит диалог с context.Done. Это также заставит все дочерние диалоги реализовать метод HandleMessageAsync, который возвращает bool, указывающий, закончился ли диалог или нет. А также предоставляет многократно используемый метод ForwardToDialog, который наш IntentDetectorDialog будет использовать для обработки намеренного перенаправления.

public class IntentDetectorDialog : BaseDialog
{
    private readonly INlpService _nlpService;

    public IntentDetectorDialog(INlpService nlpService)
    {
        _nlpService = nlpService;
    }

    protected override async Task<bool> HandleMessageAsync(IDialogContext context, IMessageActivity message)
    {
        var intentName = await _nlpService.AnalyzeAsync(message.Text);

        switch (intentName)
        {
            case "GoToQnaDialog":
                await ForwardToDialog(context, message, new QnaDialog());
                break;
            case "GoToGraphDialog":
                await ForwardToDialog(context, message, new GraphDialog());
                break;
        }

        return false;
    }
}

Это IntentRedetectorDialog: сын BaseDialog, единственное задание которого состоит в том, чтобы определить намерение и перейти к соответствующему диалогу. Чтобы сделать вещи более масштабируемыми, вы можете реализовать IntentDialogFactory, которая может создавать диалоги на основе обнаруженного намерения.

public class QnaDialog : BaseDialog
{
    protected override async Task<bool> HandleMessageAsync(IDialogContext context, IMessageActivity message)
    {
        if (message.Text == "My name is Javier")
        {
            await context.PostAsync("What a cool name!");

            // question was answered -> end the dialog
            return true;
        }
        else
        {
            await context.PostAsync("What is your name?");

            // wait for the user response
            return false;
        }
    }
}

И, наконец, у нас есть QnaDialog: тоже сын BaseDialog, чья единственная работа - спрашивать имя пользователя и ждать ответа.

Редактировать

Исходя из ваших комментариев, в вашем NlpService вы можете иметь:

public class NlpServiceDispatcher : INlpService
{
    public async Task<NlpResult> AnalyzeAsync(string utterance)
    {
        var qnaResult = await _qnaMakerService.AnalyzeAsync(utterance);

        var luisResult = await _luisService.AnalyzeAsync(utterance);

        if (qnaResult.ConfidenceThreshold > luisResult.ConfidenceThreshold)
        {
            return qnaResult;
        }
        else
        {
            return luisResult;
        }
    }
}

Затем измените IntentDetectorDialog на:

public class UtteranceAnalyzerDialog : BaseDialog
{
    private readonly INlpService _nlpService;

    public UtteranceAnalyzerDialog(INlpService nlpService)
    {
        _nlpService = nlpService;
    }

    protected override async Task<bool> HandleMessageAsync(IDialogContext context, IMessageActivity message)
    {
        var nlpResult = await _nlpService.AnalyzeAsync(message.Text);

        switch (nlpResult)
        {
            case QnaMakerResult qnaResult:
                await context.PostAsync(qnaResult.Answer);
                return true;

            case LuisResult luisResult:
                var dialog = _dialogFactory.BuildDialogByIntentName(luisResult.IntentName);
                await ForwardToDialog(context, message, dialog);
                break;
        }

        return false;
    }
}

И вот оно у тебя! Вам не нужно повторять высказывания в Luis и QnaMaker, вы можете просто использовать оба и установить свою стратегию на основе более уверенного результата!

...