基于C#的LUIS与QnA Maker集成聊天机器人问题排查
解决QnA候选选择时LUIS误识别的问题
这个问题我之前在开发Bot Framework + LUIS + QnA Maker的C#机器人时也踩过坑——核心原因是:当用户回复QnA候选的序号或问题文本时,这条输入会再次走LUIS意图识别流程,而LUIS可能把它误匹配到了其他业务意图,导致没有触发预期的QnA结果返回。
下面是几个能有效解决问题的方案,按可靠性排序:
1. 用会话状态标记锁定QnA选择流程
这是最稳妥的方案,通过会话状态标记当前机器人处于「等待用户选择QnA候选」的状态,直接跳过LUIS识别,优先处理用户的选择。
实现步骤:
首先定义一个状态类来存储会话状态:
// 存储机器人会话状态的类 public class BotConversationState { // 标记是否正在等待用户选择QnA候选 public bool IsWaitingForQnASelection { get; set; } // 保存QnA返回的候选结果,方便后续匹配 public List<QnAMakerResult> PendingQnACandidates { get; set; } }
当QnA返回多个候选问题时,设置状态并展示候选:
// 获取会话状态 var conversationStateProp = _conversationState.CreateProperty<BotConversationState>("BotState"); var botState = await conversationStateProp.GetAsync(turnContext, () => new BotConversationState()); // 假设已经调用QnA Maker得到了多个候选结果 var qnaResults = await _qnaMaker.GetAnswersAsync(turnContext); if (qnaResults.Count > 1) { // 设置状态为等待选择 botState.IsWaitingForQnASelection = true; botState.PendingQnACandidates = qnaResults.ToList(); await _conversationState.SaveChangesAsync(turnContext); // 构建候选提示文本,引导用户输入序号 var promptText = "我找到几个相关问题,请输入序号选择:\n"; for (int i = 0; i < qnaResults.Count; i++) { promptText += $"{i+1}. {qnaResults[i].Questions.First()}\n"; } await turnContext.SendActivityAsync(promptText); }
在处理用户下一次输入时,先检查状态,优先处理选择:
var conversationStateProp = _conversationState.CreateProperty<BotConversationState>("BotState"); var botState = await conversationStateProp.GetAsync(turnContext, () => new BotConversationState()); // 如果处于等待QnA选择的状态,直接处理 if (botState.IsWaitingForQnASelection) { var userInput = turnContext.Activity.Text.Trim(); QnAMakerResult selectedResult = null; // 先匹配用户输入的序号 if (int.TryParse(userInput, out int selectionIndex) && selectionIndex > 0 && selectionIndex <= botState.PendingQnACandidates.Count) { selectedResult = botState.PendingQnACandidates[selectionIndex - 1]; } // 再匹配用户输入的问题文本 else { selectedResult = botState.PendingQnACandidates .FirstOrDefault(r => r.Questions.Any(q => q.Equals(userInput, StringComparison.OrdinalIgnoreCase))); } // 返回对应的答案或提示 if (selectedResult != null) { await turnContext.SendActivityAsync(selectedResult.Answer); } else { await turnContext.SendActivityAsync("抱歉,我没理解你的选择,请输入对应的序号或者问题文本~"); } // 重置状态,回到正常流程 botState.IsWaitingForQnASelection = false; botState.PendingQnACandidates = null; await _conversationState.SaveChangesAsync(turnContext); return; // 跳过后续的LUIS识别流程 } // 否则继续执行原有的LUIS意图识别逻辑 var luisResult = await _luisRecognizer.RecognizeAsync(turnContext, cancellationToken); // ... 你的LUIS意图处理代码
2. 优化LUIS模型减少误识别
如果不想依赖会话状态,可以通过调整LUIS模型来降低误识别概率:
- 新增专用意图:创建一个
QnASelectionIntent,添加大量示例 utterances(比如"1"、"第一个"、"选第二个问题"、重复知识库中的问题文本等),让LUIS能识别这类输入为该意图,然后在代码中判断如果是这个意图,直接触发QnA的候选匹配逻辑。 - 调整意图阈值:提高
NoIntent的置信度阈值,或者降低其他业务意图的阈值,确保用户的选择输入不会被误匹配到业务意图。 - 添加短语列表:把QnA知识库中的常见问题关键词添加到LUIS的短语列表,增强LUIS对这类文本的识别敏感度。
3. 引导用户输入标准化内容
在展示QnA候选时,明确引导用户输入数字序号,比如:
我找到以下相关问题,请输入对应的数字序号选择:
- 如何修改个人信息?
- 个人信息审核需要多久?
用户输入数字的话,LUIS通常不会把纯数字匹配到业务意图,能有效减少误识别的情况。
内容的提问来源于stack exchange,提问作者user8662086
相关产品推荐
相关产品推荐

