多轮 QnA Maker 对话仍处于预览阶段,目前没有 SDK 可帮助您构建知道如何与后续提示 API 交互的机器人。您最终处于控制之中,因此您可以让您的机器人随心所欲地处理显示文本。所有“显示文本”都是您在知识库中插入答案的值,以便在调用 generateAnswer 后与答案一起返回。
让您的显示文本与您链接到的问题的文本相匹配会非常有帮助,因为这样提示的显示文本可用于访问正确的后续 QnA 对,只要包含上下文在 API 调用中。这就是this sample 中发生的事情。听起来您希望在不让提示的显示文本与后续问题的文本匹配的情况下使其工作。这可能会很棘手,但您可以这样做。
请记住,在进行后续提示时,您指定的不仅仅是显示文本。您还可以链接到特定的 QnA 对。这允许 API 将该 QnA ID 与显示文本一起返回给您。您尚未提及您的机器人所针对的频道,但如果您使用的频道支持 postBack 或 messageBack 操作,那么您可以将 QnA ID 不可见地传递给您的机器人,然后您的机器人可以使用它来访问答案。如果你走这条路,你甚至可能不需要担心对话框或状态。你也没有提到你用什么语言编写你的机器人,但这里有一个如何在 Node.js 中实现的例子:
async testQnAMaker(turnContext) {
var qna = new QnAMaker({
knowledgeBaseId: '<GUID>',
endpointKey: '<GUID>',
host: 'https://<APPNAME>.azurewebsites.net/qnamaker'
});
var value = turnContext.activity.value;
var qnaId = value && value.qnaId;
// qnaId will be undefined if value is empty
var results = await qna.getAnswers(turnContext, { qnaId });
var firstResult = results[0];
if (firstResult) {
var answer = firstResult.answer;
var resultContext = firstResult.context;
var prompts = resultContext && resultContext.prompts;
if (prompts && prompts.length) {
var card = CardFactory.heroCard(
answer,
[],
prompts.map(prompt => ({
type: 'messageBack',
title: prompt.displayText,
displayText: prompt.displayText,
text: prompt.displayText,
value: { qnaId: prompt.qnaId }
}))
);
answer = MessageFactory.attachment(card);
}
await turnContext.sendActivity(answer);
} else {
await turnContext.sendActivity("I can't answer that");
}
}
请注意,这确实有一些限制。因为它通过从活动的 value 属性中检索 QnA ID 来工作,所以如果用户手动键入按钮的文本而不是单击按钮,它可能无法找到正确的 QnA 对。
如果您想在不依赖 QnA ID 的情况下让显示文本独立工作,您可以保存自己的映射,以便您的机器人知道哪些显示文本值对应于每个上下文中的每个 QnA ID。但是,您也可以考虑仅添加显示文本作为 QnA 对中问题的替代措辞。因此,“我如何为服务 A 付款”和“我如何为服务 B 付款”都可以将“我如何为它付款”作为问题的一种形式。由于您现在在多个 QnA 对中存在重复的短语,因此您需要将调用中的上下文传递给 generateAnswer 以使其正常工作。
有关多轮对话的更多信息,请参阅this answer。