You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用C#在单个Bot中同时集成3个QnA Service

在单个C# Bot中集成多个QnA Service的实现方案

嘿,你的思路完全没问题——把多个QnA的配置(KB ID、订阅密钥)存入数组/集合是完全可行的,而且这正是实现多QnA服务集成的核心思路之一。我来基于你现有的QnaDialog代码,一步步给你拆解具体的实现方案:

1. 先搞定多QnA服务的配置存储

首先,我们可以把所有QnA服务的配置信息整理成数组,直接用QnAMakerAttribute来存储每个服务的密钥、KB ID、默认回复和置信度阈值,这样后续调用起来很方便:

// 从配置文件读取多组QnA配置,初始化数组
private readonly QnAMakerAttribute[] _qnaConfigs = new[]
{
    new QnAMakerAttribute(
        ConfigurationManager.AppSettings["QnaSubscriptionKey1"],
        ConfigurationManager.AppSettings["QnaKnowledgeBaseId1"],
        "抱歉,我暂时没法回答这个问题",
        0.5), // 置信度阈值,得分高于这个值才会被考虑
    new QnAMakerAttribute(
        ConfigurationManager.AppSettings["QnaSubscriptionKey2"],
        ConfigurationManager.AppSettings["QnaKnowledgeBaseId2"],
        "抱歉,我暂时没法回答这个问题",
        0.5),
    new QnAMakerAttribute(
        ConfigurationManager.AppSettings["QnaSubscriptionKey3"],
        ConfigurationManager.AppSettings["QnaKnowledgeBaseId3"],
        "抱歉,我暂时没法回答这个问题",
        0.5)
};

2. 重写QnAMakerDialog的核心方法,实现多服务调用

默认的QnAMakerDialog只会调用单个服务,所以我们需要重写RecognizeAsync方法,让它循环遍历所有QnA服务,获取结果后筛选出最匹配的那个:

public class MultiQnaDialog : QnAMakerDialog
{
    private readonly QnAMakerAttribute[] _qnaConfigs;

    public MultiQnaDialog()
    {
        // 初始化多QnA配置数组
        _qnaConfigs = new[]
        {
            new QnAMakerAttribute(
                ConfigurationManager.AppSettings["QnaSubscriptionKey1"],
                ConfigurationManager.AppSettings["QnaKnowledgeBaseId1"],
                "暂无匹配结果",
                0.5),
            new QnAMakerAttribute(
                ConfigurationManager.AppSettings["QnaSubscriptionKey2"],
                ConfigurationManager.AppSettings["QnaKnowledgeBaseId2"],
                "暂无匹配结果",
                0.5),
            new QnAMakerAttribute(
                ConfigurationManager.AppSettings["QnaSubscriptionKey3"],
                ConfigurationManager.AppSettings["QnaKnowledgeBaseId3"],
                "暂无匹配结果",
                0.5)
        };
    }

    protected override async Task<QnAMakerResults> RecognizeAsync(IDialogContext context, IMessageActivity message)
    {
        QnAMakerResults bestResults = null;
        double highestScore = 0;

        // 循环调用每个QnA服务
        foreach (var config in _qnaConfigs)
        {
            var qnaService = new QnAMakerService(config);
            var results = await qnaService.GetAnswersAsync(message.Text);

            // 如果当前服务返回了有效结果,且得分高于之前的最高分,就更新最佳结果
            if (results?.Answers != null && results.Answers.Any())
            {
                var topAnswer = results.Answers.First();
                if (topAnswer.Score > highestScore)
                {
                    highestScore = topAnswer.Score;
                    bestResults = results;
                }
            }
        }

        // 如果所有服务都没匹配到,返回默认提示
        return bestResults ?? new QnAMakerResults
        {
            Answers = new List<QnAMakerAnswer>
            {
                new QnAMakerAnswer { Answer = "抱歉,我暂时没法回答这个问题" }
            }
        };
    }
}

3. 关键逻辑的灵活调整

这里我用的是“取最高分结果”的逻辑,你可以根据自己的业务需求改:

  • 优先级优先:按数组顺序调用,找到第一个符合置信度的结果就直接返回,不用再调用后面的服务
  • 合并结果:把所有符合阈值的答案收集起来,一起返回给用户
  • 自定义权重:给不同的知识库设置权重,比如某类知识库的得分乘以1.2再比较

4. 进阶方案:用依赖注入管理多服务

如果你的Bot是基于ASP.NET Core的,用依赖注入来管理多个QnA服务会更整洁,代码可维护性更高:

// 在Startup.cs里注册多个QnAMakerService实例
services.AddSingleton<QnAMakerService>(sp =>
    new QnAMakerService(new QnAMakerAttribute(
        Configuration["QnaSubscriptionKey1"],
        Configuration["QnaKnowledgeBaseId1"],
        "暂无匹配",
        0.5)));

services.AddSingleton<QnAMakerService>(sp =>
    new QnAMakerService(new QnAMakerAttribute(
        Configuration["QnaSubscriptionKey2"],
        Configuration["QnaKnowledgeBaseId2"],
        "暂无匹配",
        0.5)));

// 在Dialog中注入所有QnA服务
public class MultiQnaDialog : QnAMakerDialog
{
    private readonly IEnumerable<QnAMakerService> _qnaServices;

    public MultiQnaDialog(IEnumerable<QnAMakerService> qnaServices)
    {
        _qnaServices = qnaServices;
    }

    protected override async Task<QnAMakerResults> RecognizeAsync(IDialogContext context, IMessageActivity message)
    {
        QnAMakerResults bestResults = null;
        double highestScore = 0;

        foreach (var service in _qnaServices)
        {
            var results = await service.GetAnswersAsync(message.Text);
            if (results?.Answers != null && results.Answers.Any())
            {
                var topAnswer = results.Answers.First();
                if (topAnswer.Score > highestScore)
                {
                    highestScore = topAnswer.Score;
                    bestResults = results;
                }
            }
        }

        return bestResults ?? new QnAMakerResults
        {
            Answers = new List<QnAMakerAnswer> { new QnAMakerAnswer { Answer = "抱歉,我暂时没法回答这个问题" } }
        };
    }
}

这样就完成了多个QnA Service在单个Bot里的集成,你可以直接把这段代码和你现有的Bot逻辑结合起来用~

内容的提问来源于stack exchange,提问作者Fermin Maniti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:23:26