【问题标题】:What is the best practice to use LUIS for dialog interruption使用 LUIS 进行对话中断的最佳做法是什么
【发布时间】:2020-03-27 12:30:03
【问题描述】:

Core-Bot 示例 (https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore/13.core-bot) 展示了一种处理中断的方法,例如当用户在对话框中间键入“帮助”或“取消”时。它使用文字比较:

private async Task<DialogTurnResult> InterruptAsync(DialogContext innerDc, 
  CancellationToken cancellationToken)
{
  if (innerDc.Context.Activity.Type == ActivityTypes.Message)
  {
    var text = innerDc.Context.Activity.Text.ToLowerInvariant();

    switch (text)
    {
      case "help":
      case "?":
        await innerDc.Context.SendActivityAsync($"Show Help...",
          cancellationToken: cancellationToken);
        return new DialogTurnResult(DialogTurnStatus.Waiting);
      case "cancel":
      case "quit":
        await innerDc.Context.SendActivityAsync($"Cancelling", 
          cancellationToken: cancellationToken);
        return await innerDc.CancelAllDialogsAsync();
      }
    }
  }
}

我想使用 LUIS 来确定用户是否尝试通过检查帮助意图来中断当前对话框。

问题是我不想对 LUIS 进行两次调用(即首先检查它是否是中断,然后在对话继续时获取意图),并且我无法通过识别器结果通过 OnContinueDialogAsync() 方法进入对话框。

var result = await InterruptAsync(innerDc, cancellationToken);
if (result != null)
{
    return result;
}

return await base.OnContinueDialogAsync(innerDc, cancellationToken);

我认为可以只进行一次调用,然后使用状态访问器将识别结果存储在用户状态中,但这对我来说感觉像是一种解决方法。

在中断和对话框中使用 LUIS 的推荐方式是什么?

【问题讨论】:

  • 您可以通过更新LuisHelper 中的ExecuteLuisQuery 方法来处理“帮助”意图,从而达到预期的效果。这样你就可以取消中断的东西。我不确定为什么要避免两次 LUIS 调用,因为开销非常小。也许您可以提供有关您的方案的更多信息,其中概述了您想要减少呼叫次数的原因?我敢打赌,您会遇到更多问题,并最终通过尝试缓存 LUIS 结果以避免进行额外的 API 调用,从而为您的应用程序增加不必要的复杂性。
  • 您说得对,两次 LUIS 调用可能不会明显变慢。然而,它是一项付费服务​​,通过这种结构,您拨打的电话几乎是所需电话的两倍。此外,除了被中断者捕获的句子外,LUIS 将接收两次。由于它背后有人工智能,我担心这可能会使机器学习算法出错。

标签: c# botframework


【解决方案1】:

以下是我将如何使用 Redis 缓存来做到这一点。

我会创建一个中断对话框,它可以被我需要启用中断的任何对话框继承。在此对话框中,我不会进行文字比较,而是调用 LUIS 识别器,它将返回意图。

protected override async Task<DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default)
{
    var result = await InterruptAsync(innerDc, cancellationToken);
    if (result != null)
    {
        return result;
    }

    return await base.OnContinueDialogAsync(innerDc, cancellationToken);
}


private async Task<DialogTurnResult> InterruptAsync(DialogContext innerDc, CancellationToken cancellationToken)
{
    if (innerDc.Context.Activity.Type == ActivityTypes.Message)
    {
        var luisResult = await _recognizer.RecognizeAsync<MyLuisModel>(innerDc.Context, cancellationToken);
        switch (luisResult.TopIntent().intent)
        {
            case MyLuisModel.Intent.Cancel:
                return await CancelAllDialogsAsync(innerDc, cancellationToken);

            case MyLuisModel.Intent.SignOut:
                return await SignOutAsync(innerDc, cancellationToken);

        }
    }

    return null;
}

然后,在识别器类中,我可以缓存每个话语的 LUIS 结果。您必须确保每次重新发布 LUIS 模型时都清除缓存,或者设置更短的缓存过期时间。

public virtual async Task<T> RecognizeAsync<T>(ITurnContext turnContext, CancellationToken cancellationToken) where T : IRecognizerConvert, new()
{
    var utterance = turnContext.Activity?.AsMessageActivity()?.Text;
    if (string.IsNullOrWhiteSpace(utterance)) return default;
    var cacheKey = Regex.Replace(utterance, @"[^A-Za-z0-9]+", "_");
    var matches = Regex.Match(cacheKey, @"[A-Za-z0-9]+");
    if (!matches.Success) return default;
    cacheKey = "MyBot_" + cacheKey + "_" + nameof(T);

    var recognizerResult = await _cacheClient.Db15.GetAsync<T>(cacheKey);

    if (recognizerResult != null) return recognizerResult;

    recognizerResult = await _recognizer.RecognizeAsync<T>(turnContext, cancellationToken);
    await _cacheClient.Db15.AddAsync(cacheKey, recognizerResult, TimeSpan.FromDays(1));

    return recognizerResult;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-27
    • 2012-10-09
    • 1970-01-01
    • 2017-10-07
    • 1970-01-01
    • 1970-01-01
    • 2019-08-27
    • 1970-01-01
    相关资源
    最近更新 更多