集成QnAMaker与Luis遇“Exception Stack is empty”问题求助
I get exactly what's happening here—you're forwarding requests to QnAMakerDialog when LUIS hits the None intent, but after the QnA flow finishes, your bot throws a "Exception Stack is empty" error. This almost always boils down to incorrect dialog stack management when passing control between LUIS and QnAMaker. Let's break down the fix step by step:
Why This Happens
When you use context.Forward(), you push the QnAMakerDialog onto the top of the dialog stack. If the QnAMakerDialog ends by calling context.EndDialogAsync(), it pops itself and any parent dialogs (including your LuisDialog) off the stack. That leaves an empty stack when you try to return to LUIS, hence the error.
Step-by-Step Solution
1. Fix QnAMakerDialog's Exit Logic
Instead of letting QnAMakerDialog end with EndDialogAsync(), we'll override its response method to use DoneAsync()—this hands control back to the AfterQnADialog callback without clearing the entire stack.
Here's how to adjust your QnAMakerDialog implementation:
public class CustomQnAMakerDialog : QnAMakerDialog { protected override async Task RespondFromQnAMakerResultAsync(IDialogContext context, IMessageActivity message, QnAMakerResults result) { // Send the appropriate response if (result.Answers.Any()) { await context.PostAsync(result.Answers.First().Answer); } else { await context.PostAsync("Sorry I don't know that"); } // Critical: Use DoneAsync to pass control back to the callback, not EndDialogAsync await context.DoneAsync(result); } }
2. Adjust the AfterQnADialog Callback
Your callback needs to explicitly tell the LuisDialog to resume waiting for new messages, instead of letting it assume the stack is empty:
private async Task AfterQnADialog(IDialogContext context, IAwaitable<QnAMakerResults> result) { // No need to end anything here—just tell LUIS to wait for the next user message context.Wait(MessageReceivedAsync); }
3. Verify Your None Intent Handler
Make sure your LUIS None intent is forwarding to the custom QnAMakerDialog correctly:
[LuisIntent("None")] public async Task NoneIntent(IDialogContext context, LuisResult result) { var messageToForward = context.Activity.AsMessageActivity(); var qnaDialog = new CustomQnAMakerDialog(); // Use your custom dialog here await context.Forward(qnaDialog, AfterQnADialog, messageToForward, CancellationToken.None); }
Key Notes to Remember
- Never use
EndDialogAsync()in QnAMakerDialog when forwarding from LUIS—it will wipe the entire dialog stack. - Always call
context.Wait(MessageReceivedAsync)in the callback to reactivate your LuisDialog's message listener. - Using
DoneAsync()in QnAMakerDialog ensures the dialog stack only pops the QnAMaker instance, leaving your LuisDialog intact.
With these changes, your bot will correctly return to the LUIS stack after QnA processing, and the "Exception Stack is empty" error should disappear entirely.
内容的提问来源于stack exchange,提问作者Adam

