我有一个问题......不幸的是,网上的所有样本都太浅了,并没有真正涵盖这个问题:
我有一个扩展LuisDialog的RootDialog。 RootDialog负责确定用户想要做什么。它可能是多件事,但其中一个将启动新订单。为此,RootDialog会将调用转发给NewOrderDialog,NewOrderDialog的职责是找出一些基本细节(用户想要订购什么,他喜欢使用哪个地址),最后它将确认订购并返回RootDialog。
RootDialog的代码非常简单:
[Serializable]
public class RootDialog : LuisDialog<object>
{
public RootDialog() : base(new LuisService(new LuisModelAttribute(ConfigurationManager.AppSettings["LuisAppId"], ConfigurationManager.AppSettings["LuisAPIKey"], domain: "westus.api.cognitive.microsoft.com")))
{
}
[LuisIntent("Order.Place")]
public async Task PlaceOrderIntent(IDialogContext context, LuisResult result)
{
await context.Forward(new NewOrderDialog(), OnPlaceOrderIntentCompleted, context.Activity, CancellationToken.None);
context.Wait(MessageReceived);
}
private async Task OnPlaceOrderIntentCompleted(IDialogContext context, IAwaitable<object> result)
{
await context.PostAsync("Your order has been placed. Thank you for shopping with us.");
context.Wait(MessageReceived);
}
}
我还为NewOrderDialog考虑了一些代码:
[Serializable]
public class NewOrderDialog : LuisDialog<object>
{
private string _product;
private string _address;
public NewOrderDialog() : base(new LuisService(new LuisModelAttribute(ConfigurationManager.AppSettings["LuisAppId"], ConfigurationManager.AppSettings["LuisAPIKey"], domain: "westus.api.cognitive.microsoft.com")))
{
}
[LuisIntent("Order.RequestedItem")]
public async Task RequestItemIntent(IDialogContext context, LuisResult result)
{
EntityRecommendation item;
if (result.TryFindEntity("Item", out item))
{
_product = item.Entity;
await context.PostAsync($"Okay, I understood you want to order: {_product}.");
}
else
{
await context.PostAsync("I couldn't understand what you would like to buy. Can you try it again?");
}
context.Wait(MessageReceived);
}
[LuisIntent("Order.AddedAddress")]
public async Task AddAddressIntent(IDialogContext context, LuisResult result)
{
EntityRecommendation item;
if (result.TryFindEntity("Address", out item))
{
_address = item.Entity;
await context.PostAsync($"Okay, I understood you want to ship the item to: {_address}.");
}
else
{
await context.PostAsync("I couldn't understand where you would like to ship the item. Can you try it again?");
}
context.Wait(MessageReceived);
}
}
列出的代码不起作用。输入Order.Place意图后,它会立即执行“成功”操作。回调,然后抛出此异常:
异常:通过IDialogStack指定的多个简历处理程序完成IDialog方法执行。 [文件类型&#39; text / plain&#39;]
所以我有几个问题:
答案 0 :(得分:3)
所以第一个问题是你在&#34; Order.Place&#34;中做了context.Forward
和context.Wait
,根据定义,这是错误的。您需要选择:转发到新对话框或等待当前。根据你的帖子,你想转发,所以只需删除等待电话。
除此之外,您还有1个LUIS对话框,并且您正在尝试转发到新的LUIS对话框...我怀疑这是否会起作用;我可以想象这些是两种不同的LUIS模型,否则就会出错。
根据您的评论,我现在明白您要对第二个对话框执行的操作。问题(这与你的第二个问题有关)是使用LUIS可能会让人感到困惑。例如:
activity.Text
可能会再次进入LUIS(到第二个对话框的模型),并且不会检测到任何内容。第二个对话框将处于Wait
状态,供用户输入。现在,用户如何知道他需要输入地址或产品?你在哪里提示用户?看到这个问题?
我怀疑你的第三个问题是你在#1中遇到的错误的副作用,我已经提供了解决方案。
如果你澄清一点,我可能会更有帮助。你在第二个对话框中尝试用LUIS做什么看起来不行,但也许有一个解释可能有意义。
通常情况是:我从LUIS
获得意图(&#34; Order.Place&#34;)然后我启动FormFlow或一组提示以获取信息以下订单(地址,产品等)或者如果您想继续使用LUIS
,您可能需要查看Luis Action Binding。您可以在https://blog.botframework.com/2017/04/03/luis-action-binding-bot/上阅读更多内容。
答案 1 :(得分:-1)
你知道Bing Location Control for Microsoft Bot Framework吗?它可以用来处理'他喜欢使用哪个地址'来获取和验证用户的地址。
以下是一些示例代码:
[LuisModel("xxx", "yyy")]
[Serializable]
public class RootDialog : LuisDialog<object>
{
...
[LuisIntent("Find Location")]
public async Task FindLocationIntent(IDialogContext context, LuisResult result)
{
try
{
context.Call(new FindUserLocationDialog(), ResumeAfterLocationDialog);
}
catch (Exception e)
{
// handle exceptions
}
}
public async Task ResumeAfterLocationDialog(IDialogContext context, IAwaitable<object> result)
{
var resultLocation = await result;
await context.PostAsync($"Your location is {resultLocation}");
// do whatever you want
context.Wait(this.MessageReceived);
}
}
对于“FindUserLocationDialog()”,您可以从第58行开始关注sample。
修改强>
1)你能尝试使用:
[LuisIntent("Order.Place")]
public async Task PlaceOrderIntent(IDialogContext context, LuisResult result)
{
context.Forward(new NewOrderDialog(), OnPlaceOrderIntentCompleted, context.Activity, CancellationToken.None);
// or this
// context.Call(new NewOrderDialog(), OnPlaceOrderIntentCompleted);
}
2)我会说这取决于你如何构建你的意图。您的“Order.Place”意图是否包含实体?这意味着,如果您的用户说“我想订购产品X 的订单发送到地址Y ”,您的意图是否已经接收了这些实体?
我建议您检查“Order.Place”意图下的产品和地址。获得并验证产品和地址后,您可以将其转发到另一个对话框(非LUIS)以处理剩余的订单处理。
[LuisIntent("Order.Place")]
public async Task PlaceOrderIntent(IDialogContext context, LuisResult result)
{
EntityRecommendation item;
if (result.TryFindEntity("Item", out item))
{
_product = item.Entity;
}
if (result.TryFindEntity("Address", out item))
{
_address = item.Entity;
}
if (_product == null)
{
PromptDialog.Text(context, this.MissingProduct, "Enter the product");
}
else if (_address == null)
{
PromptDialog.Text(context, this.MissingAddress, "Enter the address");
}
// both product and address present
context.Forward(new NewOrderDialog(), OnPlaceOrderIntentCompleted, **object with _product and _address**, CancellationToken.None);
}
private async Task MissingProduct(IDialogContext context, IAwaitable<String> result)
{
_product = await result;
// perform some validation
if (_address == null)
{
PromptDialog.Text(context, this.MissingAddress, "Enter the address");
}
else
{
// both product and address present
context.Forward(new NewOrderDialog(), OnPlaceOrderIntentCompleted, **object with _product and _address**, CancellationToken.None);
}
}
private async Task MissingAddress(IDialogContext context, IAwaitable<String> result)
{
_address = await result;
// perform some validation
// both product and address present
context.Forward(new NewOrderDialog(), OnPlaceOrderIntentCompleted, **object with _product and _address**, CancellationToken.None);
}
这些方面的东西。可能需要包含try / catch。
3)我认为它与'Order.Place'LUIS意图中的'context.Wait(MessageReceived)'有关