gpt4 book ai didi

c# - 机器人框架 : Loop through Prompts

转载 作者:行者123 更新时间:2023-11-30 23:07:16 25 4
gpt4 key购买 nike

我最近接触了 Microsoft 的 Bot Framework,这将是我第一次接触 C# 中的异步编程。我正在创建一个设计为选择树的提示。使用 XML 文档,我设计了用户可以选择的主题层次结构——然后我使用 HelpTopicSelector 类抽象了 XML 的解析。

流程如下:

  • User types "help"
  • Context forwards to HelpDialog
  • Help Dialog creates prompt with list of options provided by the HelpTopicSelector
  • When user selects a prompt option, HelpTopicSelector "selects" the choise and updates a new list of choices from the subtree
  • Create another prompt with updated topics
  • Repeat until the last selected topic is the last node - call Context.Done

帮助对话框是从基本对话框中调用的,如下所示:

    private async Task ActivityRecievedAsync(IDialogContext context, IAwaitable<object> result)
{
Activity activity = await result as Activity;

if (activity.Text == "test")
{
await context.PostAsync("works");
}
else if(activity.Text == "help")
{
await context.Forward(new HelpDialog(), this.ResumeAfterHelp, activity.AsMessageActivity(), System.Threading.CancellationToken.None);
await context.PostAsync("Done Selection!");
}

context.Wait(ActivityRecievedAsync);
}

我几乎可以肯定我的代码中的问题在于我的 HelpDialog 的“循环”性质,但我真的不知道为什么它会失败。

class HelpDialog : IDialog
{
public async Task StartAsync(IDialogContext context)
{
await context.PostAsync("Reached Help Dialog!");
context.Wait(ActivityRecievedAsync);
}

private async Task ActivityRecievedAsync(IDialogContext context, IAwaitable<object> result)
{
var message = await result;
await context.PostAsync("HelpDialog: Activity Received");
await HandleTopicSelection(context);

context.Wait(ActivityRecievedAsync);
}

private async Task HandleTopicSelection(IDialogContext context)
{
List<string> topics = HelpTopicSelector.Instance.Topics;
PromptDialog.Choice<string>(context, TopicSelectedAsync, topics, "Select A Topic:");

// Unecessary?
context.Wait(ActivityRecievedAsync);
}

private async Task TopicSelectedAsync(IDialogContext context, IAwaitable<string> result)
{
string selection = await result;

if (HelpTopicSelector.Instance.IsQuestionNode(selection))
{
await context.PostAsync($"You asked: {selection}");
HelpTopicSelector.Instance.Reset();
context.Done<string>(selection);
}
else
{
HelpTopicSelector.Instance.SelectElement(selection);
await HandleTopicSelection(context);
}

// Unecessary?
context.Wait(ActivityRecievedAsync);
}
}

我的期望:

  • 我相信 await 关键字应该在等待的任务完成之前阻止任务的执行。
  • 同样,我相信 Context.Wait 在 Tasks 结束时被调用以循环回 AcitivtyReceived 方法,这有效地使机器人等待用户输入。
  • 假设逻辑正确,帮助对话框进入 StartAsync 方法并将控制权交给 ActivityReceivedAsync,后者响应 Context 传递的“消息” .Forward 父对话框。然后,它等待负责提示的HandleTopic 方法。提示在 TopicSelectedAsync 中继续执行,如 ResumeAfter 参数所示。
  • TopicSelectedAsync 方法检查所选主题是否位于 XML 树的末尾,如果是,则通过调用 Context.Done 结束对话。否则,它会等待另一个 HandleTopic 方法,该方法递归地创建另一个提示 - 有效地创建一个循环,直到对话结束。

鉴于这看起来有多么骇人听闻,我对遇到错误并不感到惊讶。机器人模拟器抛出“堆栈为空”异常

.尝试使用断点进行调试后,我注意到 HelpDialog 在进入 TopicSelectedAsync 方法时突然结束并退出(特别是在等待结果时)。 Visual Studio 抛出以下异常:

invalid need: Expected Call, have Poll.

额外注意:我最初尝试在我的 BasicDialog 类中编写此逻辑,而不转发到任何其他对话框。令我惊讶的是,它几乎可以完美运行。

最佳答案

此调查对话框示例与您的场景相似:https://github.com/Microsoft/BotBuilder-Samples/blob/45d0f8767d6b71b3a11b060c893521d5150ede7f/CSharp/core-proactiveMessages/startNewDialogWithPrompt/SurveyDialog.cs

修改为帮助对话框:

[Serializable]
public class HelpDialog : IDialog
{
public async Task StartAsync(IDialogContext context)
{
PromptDialog.Choice<string>(context, TopicSelectedAsync, HelpTopicSelector.Instance.Topics, "Select A Topic:", attempts: 3, retry: "Please select a Topic");
}

private async Task TopicSelectedAsync(IDialogContext context, IAwaitable<object> result)
{
try
{
string selection = await result as string;

if (HelpTopicSelector.Instance.IsQuestionNode(selection))
{
await context.PostAsync($"You asked: {selection}");
HelpTopicSelector.Instance.Reset();
context.Done<string>(selection);
}
else
{
await this.StartAsync(context);
}
}
catch (TooManyAttemptsException)
{
await this.StartAsync(context);
}
}
}

像这样从父对话框调用它(使用 context.Call() 而不是 .Forward()):

 private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
Activity activity = await result as Activity;

if (activity.Text == "test")
{
await context.PostAsync("works");
context.Wait(MessageReceivedAsync);
}
else if (activity.Text == "help")
{
context.Call(new HelpDialog(), ResumeAfterHelp);
await context.PostAsync("Called help dialog!");
}
}

private async Task ResumeAfterHelp(IDialogContext context, IAwaitable<object> result)
{
var selection = await result as string;
context.Wait(MessageReceivedAsync);
}

当为 Context.Wait() 提供方法时,您实际上是在提供延续委托(delegate)。从用户那里收到的下一条消息将被发送到最后一个 .Wait() 上的方法。如果您正在转发或调用单独的对话框,则父级不应同时调用 .Wait()。此外,在调用 context.Done() 时,同一对话框中不应再有 .Wait()。

关于c# - 机器人框架 : Loop through Prompts,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47476712/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com