你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

快速入门:QnA Maker 客户端库

注意

Azure Open AI On Your Data 利用大型语言模型 (LLM) 生成与 QnA Maker 类似的结果。 如果要将 QnA Maker 项目迁移到 Azure Open AI On Your Data,请查看我们的指南

QnA Maker 客户端库入门。 请按照以下步骤安装程序包并试用基本任务的示例代码。

注意

QnA Maker 服务将于 2025 年 3 月 31 日停用。 问答功能的较新版本现已作为 Azure AI 语言的一部分提供。 有关语言服务中的问答功能,请参阅问答。 从 2022 年 10 月 1 日开始,你将无法创建新的 QnA Maker 资源。 有关将现有 QnA Maker 知识库迁移到问题解答的信息,请参阅迁移指南

先决条件

注意

本文档不适用于最新版本。 若要了解如何将REST API最新版本,请参阅REST API 快速入门问题解答

  • 最新版本的 cURL。 快速入门中使用了 cURL 文档中所述的多个命令行开关。

  • 必须有 QnA Maker 资源,才能使用密钥和资源名称。 你在资源创建过程中输入了资源“名称” ,然后系统为你创建了密钥。 资源名称将用作终结点的子域。 若要检索密钥和资源名称,请在 Azure 门户中选择资源对应的“快速入门”。 资源名称是终结点 URL 的第一个子域:

    https://YOUR-RESOURCE-NAME.cognitiveservices.azure.com/qnamaker/v4.0

注意

以下 BASH 示例使用 \ 行继续符。 如果你的控制台或终端使用不同的行继续符,请使用此字符。

创建知识库

若要使用 REST API 和 cURL 创建知识库,需要准备好以下信息:

信息 cURL 配置 目的
QnA Maker 资源名称 代码 用于构造 URL
QnA Maker 资源密钥 Ocp-Apim-Subscription-Key 标头的 -h 参数 对 QnA Maker 服务进行身份验证
描述知识库的 JSON -d 参数 JSON 示例
JSON 大小(字节) Content-Size 标头的 -h 参数

cURL 命令将从 BASH shell 执行。 请使用自己的资源名称、资源密钥、JSON 值和 JSON 大小编辑此命令。

curl https://REPLACE-WITH-YOUR-RESOURCE-NAME.cognitiveservices.azure.com/qnamaker/v4.0/knowledgebases/create \
-X POST \
-H "Ocp-Apim-Subscription-Key: REPLACE-WITH-YOUR-RESOURCE-KEY" \
-H "Content-Type:application/json" \
-H "Content-Size:107" \
-d '{ name: "QnA Maker FAQ",urls: [ "https://learn.microsoft.com/azure/ai-services/qnamaker/faqs"]}'

QnA Maker 返回的 cURL 响应包含 operationId获取操作的状态时需要此 ID。

{
  "operationState": "NotStarted",
  "createdTimestamp": "2020-02-27T04:11:22Z",
  "lastActionTimestamp": "2020-02-27T04:11:22Z",
  "userId": "9596077b3e0441eb93d5080d6a15c64b",
  "operationId": "95a4f700-9899-4c98-bda8-5449af9faef8"
}

获取操作的状态

创建知识库时,响应包含用于确定状态的信息,因为操作是异步的。

信息 cURL 配置 目的
QnA Maker 资源名称 代码 用于构造 URL
操作 ID URL 路由 /operations/REPLACE-WITH-YOUR-OPERATION-ID
QnA Maker 资源密钥 Ocp-Apim-Subscription-Key 标头的 -h 参数 对 QnA Maker 服务进行身份验证

cURL 命令将从 BASH shell 执行。 请使用自己的资源名称、资源密钥和操作 ID 编辑此命令。

curl https://REPLACE-WITH-YOUR-RESOURCE-NAME.cognitiveservices.azure.com/qnamaker/v4.0/operations/REPLACE-WITH-YOUR-OPERATION-ID \
-X GET \
-H "Ocp-Apim-Subscription-Key: REPLACE-WITH-YOUR-RESOURCE-KEY"

cURL 响应包含状态。 如果操作状态为 succeeded,则 resourceLocation 包含知识库 ID。

{
   "operationState": "Succeeded",
   "createdTimestamp": "2020-02-27T04:54:07Z",
   "lastActionTimestamp": "2020-02-27T04:54:19Z",
   "resourceLocation": "/knowledgebases/fe3971b7-cfaa-41fa-8d9f-6ceb673eb865",
   "userId": "f596077b3e0441eb93d5080d6a15c64b",
   "operationId": "f293f218-d080-48f0-a766-47993e9b26a8"
}

发布知识库

在查询知识库之前,需要:

  • 发布知识库
  • 获取运行时终结点密钥

此任务将发布知识库。 获取运行时终结点密钥是一个独立的任务

信息 cURL 配置 目的
QnA Maker 资源名称 代码 用于构造 URL
QnA Maker 资源密钥 Ocp-Apim-Subscription-Key 标头的 -h 参数 对 QnA Maker 服务进行身份验证
知识库 ID URL 路由 /knowledgebases/REPLACE-WITH-YOUR-KNOWLEDGE-BASE-ID

cURL 命令将从 BASH shell 执行。 请使用自己的资源名称、资源密钥和知识库 ID 编辑此命令。

curl https://REPLACE-WITH-YOUR-RESOURCE-NAME.cognitiveservices.azure.com/qnamaker/v4.0/knowledgebases/REPLACE-WITH-YOUR-KNOWLEDGE-BASE-ID \
-v \
-X POST \
-H "Ocp-Apim-Subscription-Key: REPLACE-WITH-YOUR-RESOURCE-KEY" \
--data-raw ''

响应状态为 204,不包含结果。 使用 -v 命令行参数查看 cURL 命令的详细输出。 这包括 HTTP 状态。

获取已发布的知识库的运行时终结点密钥

在查询知识库之前,需要:

  • 发布知识库
  • 获取运行时终结点密钥

此任务获取运行时终结点密钥。 发布知识库是一个独立的任务

使用 QnA Maker 资源的所有知识库的运行时终结点密钥是相同的。

信息 cURL 配置 目的
QnA Maker 资源名称 代码 用于构造 URL
QnA Maker 资源密钥 Ocp-Apim-Subscription-Key 标头的 -h 参数 对 QnA Maker 服务进行身份验证

cURL 命令将从 BASH shell 执行。 请使用自己的资源名称和资源密钥编辑此命令。

curl https://REPLACE-WITH-YOUR-RESOURCE-NAME.cognitiveservices.azure.com/qnamaker/v4.0/endpointkeys \
-X GET \
-H "Ocp-Apim-Subscription-Key: REPLACE-WITH-YOUR-RESOURCE-KEY"

cURL 响应包含运行时终结点密钥。 通过查询从知识库获取答案时,只使用其中一个的密钥。

{
  "primaryEndpointKey": "93e88a14-694a-44d5-883b-184a68aa8530",
  "secondaryEndpointKey": "92c98c16-ca31-4294-8626-6c57454a5063",
  "installedVersion": "4.0.5",
  "lastStableVersion": "4.0.6"
}

从已发布的知识库查询答案

从知识库获取答案时所在的运行时不同于管理知识库时所在的运行时。 由于它是一个独立的运行时,因此需要使用运行时密钥进行身份验证。

信息 cURL 配置 目的
QnA Maker 资源名称 代码 用于构造 URL
QnA Maker 运行时密钥 Authorization 标头的 -h 参数 密钥是包含单词 Endpointkey 的字符串的一部分。 对 QnA Maker 服务进行身份验证
知识库 ID URL 路由 /knowledgebases/REPLACE-WITH-YOUR-KNOWLEDGE-BASE-ID
描述查询的 JSON -d 参数 请求正文参数和 JSON 示例
JSON 大小(字节) Content-Size 标头的 -h 参数

cURL 命令将从 BASH shell 执行。 请使用自己的资源名称、资源密钥和知识库 ID 编辑此命令。

curl https://REPLACE-WITH-YOUR-RESOURCE-NAME.azurewebsites.net/qnamaker/knowledgebases/REPLACE-WITH-YOUR-KNOWLEDGE-BASE-ID/generateAnswer \
-X POST \
-H "Authorization: EndpointKey REPLACE-WITH-YOUR-RUNTIME-KEY" \
-H "Content-Type:application/json" \
-H "Content-Size:159" \
-d '{"question": "How are QnA Maker and LUIS used together?","top": 6,"isTest": true,  "scoreThreshold": 20, "strictFilters": [], "userId": "sd53lsY="}'

成功的响应包含最相关的答案,以及客户端应用程序(例如聊天机器人)在向用户显示答案时所需的其他信息。

删除知识库

用完知识库后,请将其删除。

信息 cURL 配置 目的
QnA Maker 资源名称 代码 用于构造 URL
QnA Maker 资源密钥 Ocp-Apim-Subscription-Key 标头的 -h 参数 对 QnA Maker 服务进行身份验证
知识库 ID URL 路由 /knowledgebases/REPLACE-WITH-YOUR-KNOWLEDGE-BASE-ID

cURL 命令将从 BASH shell 执行。 请使用自己的资源名称、资源密钥和知识库 ID 编辑此命令。

curl https://REPLACE-WITH-YOUR-RESOURCE-NAME.cognitiveservices.azure.com/qnamaker/v4.0/knowledgebases/REPLACE-WITH-YOUR-KNOWLEDGE-BASE-ID \
-X DELETE \
-v \
-H "Ocp-Apim-Subscription-Key: REPLACE-WITH-YOUR-RESOURCE-KEY"

响应状态为 204,不包含结果。 使用 -v 命令行参数查看 cURL 命令的详细输出。 这包括 HTTP 状态。

其他资源

可以使用适用于 .NET 的 QnA Maker 客户端库执行以下操作:

  • 创建知识库
  • 更新知识库
  • 发布知识库
  • 获取预测运行时终结点密钥
  • 等待长时间运行的任务
  • 下载知识库
  • 从知识库获取答案
  • 删除知识库

参考文档 | 库源代码 | 包 (NuGet) | C# 示例

注意

2019 年 7 月 1 日之后创建的新资源将使用自定义子域名。 有关详细信息和区域终结点的完整列表,请参阅 Azure AI 服务的自定义子域名

先决条件

注意

本文档不适用于最新版本。 若要了解如何在最新版本中使用 C# API,请参阅 C# 快速入门问题解答

  • Azure 订阅 - 免费创建订阅
  • Visual Studio IDE 或最新版本的 .NET Core
  • 拥有 Azure 订阅后,在 Azure 门户中创建 QnA Maker 资源来获取创作密钥和资源名称。 部署后,选择”转到资源”。
    • 需要从创建的资源获取密钥和资源名称,以便将应用程序连接到 QnA Maker API。 稍后在本快速入门中将密钥和资源名称粘贴到下文的代码中。
    • 可以使用免费定价层 (F0) 试用该服务,然后再升级到付费层进行生产。

设置

CLI

在控制台窗口(例如 cmd、PowerShell 或 Bash)中,使用 dotnet new 命令创建名为 qna-maker-quickstart 的新控制台应用。 此命令将创建包含单个源文件的简单“Hello World”C# 项目:program.cs

dotnet new console -n qna-maker-quickstart

将目录更改为新创建的应用文件夹。 可使用以下代码生成应用程序:

dotnet build

生成输出不应包含警告或错误。

...
Build succeeded.
 0 Warning(s)
 0 Error(s)
...

在应用程序目录中,使用以下命令安装适用于 .NET 的 QnA Maker 客户端库:

dotnet add package Microsoft.Azure.CognitiveServices.Knowledge.QnAMaker --version 2.0.1

提示

想要立即查看整个快速入门代码文件? 可以在 GitHub 上找到它,其中包含此快速入门中的代码示例。

using 指令

从项目目录中,打开 Program.cs 文件,并添加以下 using 指令:

using Microsoft.Azure.CognitiveServices.Knowledge.QnAMaker;
using Microsoft.Azure.CognitiveServices.Knowledge.QnAMaker.Models;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

订阅密钥和资源终结点

在应用程序的 Main 方法中,添加变量和代码(如以下部分所示),以使用本快速入门中的常见任务。

  • 我们使用的订阅密钥和创作密钥是可互换的。 有关创作密钥的详细信息,请访问 QnA Maker 中的密钥

  • QNA_MAKER_ENDPOINT 的值采用 https://YOUR-RESOURCE-NAME.cognitiveservices.azure.com 格式。 转到 Azure 门户,并找到之前在“必备组件”部分创建的 QnA Maker 资源。 选择“资源管理”下的“密钥和终结点”页,找到创作(订阅)密钥和 QnA Maker 终结点 。

QnA Maker 创作终结点

  • QNA_MAKER_RUNTIME_ENDPOINT 的值采用 https://YOUR-RESOURCE-NAME.azurewebsites.net 格式。 转到 Azure 门户,并找到之前在“必备组件”部分创建的 QnA Maker 资源。 选择“自动化”下的“导出模板”页,找到运行时终结点 。

QnA Maker 运行时终结点

重要

完成后,请记住将密钥从代码中删除,并且永远不要公开发布该密钥。 对于生产来说,请使用安全的方式存储和访问凭据,例如 Azure Key Vault。 有关详细信息,请参阅 Azure AI 服务安全性一文。

var authoringKey = "PASTE_YOUR_QNA_MAKER_AUTHORING_SUBSCRIPTION_KEY_HERE";
var authoringURL = "PASTE_YOUR_QNA_MAKER_AUTHORING_ENDPOINT_HERE";
var queryingURL = "PASTE_YOUR_QNA_MAKER_RUNTIME_ENDPOINT_HERE";

对象模型

QnA Maker 使用两种不同的对象模型:

  • QnAMakerClient 对象可创建、管理、发布和下载知识库。
  • QnAMakerRuntime 对象可通过 GenerateAnswer API 查询知识库,并使用训练 API 发送新的建议问题(作为主动学习的一部分)。

使用示例知识库

本快速入门中的知识库以 2 个对话 QnA 对开始(这样做一是为了简化此示例,二是为了在 Update 方法中有高度可预测的 ID 供使用),将问题的跟进提示与新对相关联。 这是为本快速入门计划的,按特定顺序实现。

如果计划未来要使用依赖于现有 QnA 对的跟进提示来开发知识库,可选择执行以下操作:

  • 对于较大的知识库,请在支持自动化的文本编辑器或 TSV 工具中管理该知识库,然后立即使用更新完全替换知识库。
  • 对于较小的知识库,请完全在 QnA Maker 门户中管理跟进提示。

本快速入门中使用的 QnA 对的详细信息:

  • QnA 对的类型 - 更新后,此知识库中有 2 种类型的 QnA 对:chitchat 以及特定于域的信息。 如果你的知识库与某个会话应用程序(如聊天机器人)相关联,则这种情况很常见。
  • 尽管知识库答案可以按元数据进行筛选或使用跟进提示,但本快速入门并不会介绍此内容。 可在此处找到与语言无关的 generateAnswer 示例。
  • 答案文本为 markdown 格式,并且可以包含多种 markdown 格式,例如图像(可公开使用的基于 Internet 的图像)、链接(指向公开可用的 URL)和提要点,但本快速入门不涉及这些多样内容。

QnAMakerClient 对象模型

创作 QnA Maker 客户端是 QnAMakerClient 对象,使用包含密钥的 Microsoft.Rest.ServiceClientCredentials 向 Azure 进行身份验证。

创建客户端以后,使用知识库属性创建、管理和发布知识库。

通过发送 JSON 对象来管理知识库。 对于即时操作,方法通常返回一个指示状态的 JSON 对象。 对于长时间运行的操作,响应是操作 ID。 使用操作 ID 调用 client.Operations.GetDetailsAsync 方法,确定请求状态

QnAMakerRuntimeClient 对象模型

预测 QnA Maker 客户端是一个 QnAMakerRuntimeClient 对象,它使用 Microsoft.Rest.ServiceClientCredentials 向 Azure 进行身份验证;Microsoft.Rest.ServiceClientCredentials 包含预测运行时密钥,发布知识库后进行创作客户端调用 client.EndpointKeys.GetKeys 可返回该密钥。

使用 GenerateAnswer 方法从查询运行时获取答案。

代码示例

这些代码片段展示如何使用适用于 .NET 的 QnA Maker 客户端库执行以下操作:

对用于创作知识库的客户端进行身份验证

使用密钥将客户端对象实例化,并将它与资源一起使用来构建终结点,从而使用你的终结点和密钥创建一个 QnAMakerClient。 创建一个 ServiceClientCredentials 对象。

var client = new QnAMakerClient(new ApiKeyServiceClientCredentials(authoringKey))
{ Endpoint = authoringURL };

创建知识库

知识库为来自三个源的 CreateKbDTO 对象存储问答对:

  • 对于编辑内容,请使用 QnADTO 对象。
    • 若要使用元数据和跟进提示,请使用编辑上下文,因为此数据是在单独的 QnA 对级别添加的。
  • 对于文件,请使用 FileDTO 对象。 FileDTO 包括文件名以及用于访问该文件的公共 URL。
  • 对于 URL,请使用一列字符串来表示公开可用的 URL。

创建步骤还包括知识库的属性:

  • defaultAnswerUsedForExtraction - 找不到任何答案时返回的内容
  • enableHierarchicalExtraction - 在提取的 QnA 对之间自动创建提示关系
  • language - 创建资源的第一个知识库时,设置要在 Azure 搜索索引中使用的语言。

调用 CreateAsync 方法,然后将返回的操作 ID 传递给 MonitorOperation 方法以轮询状态。

以下代码的最后一行从来自 MonitorOperation 的响应返回知识库 ID。

private static async Task<string> CreateSampleKb(IQnAMakerClient client)
{
    var qna1 = new QnADTO
    {
        Answer = "Yes, You can use our [REST APIs](https://docs.microsoft.com/rest/api/cognitiveservices/qnamaker/knowledgebase) to manage your knowledge base.",
        Questions = new List<string> { "How do I manage my knowledgebase?" },
        Metadata = new List<MetadataDTO> {
            new MetadataDTO { Name = "Category", Value = "api" },
            new MetadataDTO { Name = "Language", Value = "REST" }
        },

    };

    var qna2 = new QnADTO
    {
        Answer = "Yes, You can use our [.NET SDK](https://www.nuget.org/packages/Microsoft.Azure.CognitiveServices.Knowledge.QnAMaker) with the [.NET Reference Docs](https://docs.microsoft.com/dotnet/api/microsoft.azure.cognitiveservices.knowledge.qnamaker?view=azure-dotnet) to manage your knowledge base.",
        Questions = new List<string> { "Can I program with C#?" },
        Metadata = new List<MetadataDTO> {
            new MetadataDTO { Name = "Category", Value = "api" },
            new MetadataDTO { Name = "Language", Value = ".NET" }
        }
    };

    var file1 = new FileDTO
    {
        FileName = "myfile.tsv",
        FileUri = "https://mydomain/myfile.tsv"

    };

    var createKbDto = new CreateKbDTO
    {
        Name = "QnA Maker .NET SDK Quickstart",
        QnaList = new List<QnADTO> { qna1, qna2 },
        //Files = new List<FileDTO> { file1 }

    };

    var createOp = await client.Knowledgebase.CreateAsync(createKbDto);
    createOp = await MonitorOperation(client, createOp);

    return createOp.ResourceLocation.Replace("/knowledgebases/", string.Empty);
}

请确保包括上述代码中引用的 MonitorOperation 函数,以便成功创建知识库。

更新知识库

可以更新知识库,方法是:将知识库 ID 和包含 addupdatedelete DTO 对象的 UpdatekbOperationDTO 传递给 UpdateAsync 方法。 使用 MonitorOperation 方法来确定更新是否成功。

private static async Task UpdateKB(IQnAMakerClient client, string kbId)
{

    var urls = new List<string> {
        "https://docs.microsoft.com/azure/cognitive-services/QnAMaker/troubleshooting"
    };

    var updateOp = await client.Knowledgebase.UpdateAsync(kbId, new UpdateKbOperationDTO
    {
        // Create JSON of changes
        Add = new UpdateKbOperationDTOAdd
        {
            QnaList = new List<QnADTO> {
                new QnADTO {
                    Questions = new List<string> {
                        "bye",
                        "end",
                        "stop",
                        "quit",
                        "done"
                    },
                    Answer = "goodbye",
                    Metadata = new List<MetadataDTO> {
                        new MetadataDTO { Name = "Category", Value="Chitchat" },
                        new MetadataDTO { Name = "Chitchat", Value = "end" },
                    }
                },
                new QnADTO {
                    Questions = new List<string> {
                        "hello",
                        "hi",
                        "start"
                    },
                    Answer = "Hello, please select from the list of questions or enter a new question to continue.",
                    Metadata = new List<MetadataDTO> {
                        new MetadataDTO { Name = "Category", Value="Chitchat" },
                        new MetadataDTO { Name = "Chitchat", Value = "begin" }
                    },
                    Context = new QnADTOContext
                    {
                        IsContextOnly = false,
                        Prompts = new List<PromptDTO>
                        {
                            new PromptDTO
                            {
                                DisplayOrder =1,
                                DisplayText= "Use REST",
                                QnaId=1

                            },
                            new PromptDTO
                            {
                                DisplayOrder =2,
                                DisplayText= "Use .NET NuGet package",
                                QnaId=2

                            },
                        }
                    }
                },
            },
            Urls = urls
        },
        Update = null,
        Delete = null
    }); ;

    // Loop while operation is success
    updateOp = await MonitorOperation(client, updateOp);
}

请确保包括上述代码中引用的 MonitorOperation 函数,以便成功更新知识库。

下载知识库

使用 DownloadAsync 方法,将知识库作为 QnADocumentsDTO 列表下载。 这不等同于“设置”页面中 QnA Maker 门户的导出,因为此方法的结果不是一个文件。

private static async Task DownloadKb(IQnAMakerClient client, string kbId)
{
    var kbData = await client.Knowledgebase.DownloadAsync(kbId, EnvironmentType.Prod);
    Console.WriteLine("KB Downloaded. It has {0} QnAs.", kbData.QnaDocuments.Count);

    // Do something meaningful with data
}

发布知识库

使用 PublishAsync 方法发布知识库。 这样会通过知识库 ID 获取当前保存的已训练模型,并在某个终结点上将其发布。 必须执行此步骤才能查询知识库。

private static async Task PublishKb(IQnAMakerClient client, string kbId)
{
    await client.Knowledgebase.PublishAsync(kbId);
}

获取查询运行时密钥

发布知识库后,需要查询运行时密钥来查询运行时。 此密钥并非用于创建原始客户端对象的密钥。

使用 EndpointKeys 方法获取 EndpointKeysDTO 类。

使用对象中返回的其中一个密钥属性来查询知识库。

private static async Task<String> GetQueryEndpointKey(IQnAMakerClient client)
{
    var endpointKeysObject = await client.EndpointKeys.GetKeysAsync();

    return endpointKeysObject.PrimaryEndpointKey;
}

需要运行时密钥才能查询知识库。

对用于生成答案的运行时进行身份验证

创建 QnAMakerRuntimeClient 来查询知识库,以通过主动学习生成答案或训练。

var runtimeClient = new QnAMakerRuntimeClient(new EndpointKeyServiceClientCredentials(primaryQueryEndpointKey))
{ RuntimeEndpoint = queryingURL };

使用 QnAMakerRuntimeClient:

  • 从知识库获取答案
  • 将新建议的问题发送到知识库中进行主动学习

从知识库生成答案

使用 RuntimeClient.GenerateAnswerAsync 方法从已发布的知识库中生成答案。 此方法接受知识库 ID 和 QueryDTO。 访问 QueryDTO 的其他属性,例如要在聊天机器人中使用的 TopContext

private static async Task GenerateAnswer(IQnAMakerRuntimeClient runtimeClient, string kbId)
{
    var response = await runtimeClient.Runtime.GenerateAnswerAsync(kbId, new QueryDTO { Question = "How do I manage my knowledgebase?" });
    Console.WriteLine("Endpoint Response: {0}.", response.Answers[0].Answer);

    // Do something meaningful with answer
}

这是查询知识库的一个简单示例。 若要了解高级查询方案,请参阅其他查询示例

删除知识库

结合使用 DeleteAsync 方法和知识库 ID 参数来删除知识库。

private static async Task DeleteKB(IQnAMakerClient client, string kbId)
{
    await client.Knowledgebase.DeleteAsync(kbId);
}

获取操作的状态

某些方法(例如 create 和 update)可能需要很长的时间,系统不会等待此过程完成,而是返回一个 operation。 使用操作中的操作 ID 进行轮询(使用重试逻辑),确定原始方法的状态。

以下代码块中的 loop 和 Task.Delay 用于模拟重试逻辑。 应将其替换为你自己的重试逻辑。

private static async Task<Operation> MonitorOperation(IQnAMakerClient client, Operation operation)
{
    // Loop while operation is success
    for (int i = 0;
        i < 20 && (operation.OperationState == OperationStateType.NotStarted || operation.OperationState == OperationStateType.Running);
        i++)
    {
        Console.WriteLine("Waiting for operation: {0} to complete.", operation.OperationId);
        await Task.Delay(5000);
        operation = await client.Operations.GetDetailsAsync(operation.OperationId);
    }

    if (operation.OperationState != OperationStateType.Succeeded)
    {
        throw new Exception($"Operation {operation.OperationId} failed to completed.");
    }
    return operation;
}

运行应用程序

从应用程序目录使用 dotnet run 命令运行应用程序。

dotnet run

可以在 GitHub 上找到此示例的源代码。

可以使用适用于 Node.js 的 QnA Maker 客户端库执行以下操作:

  • 创建知识库
  • 更新知识库
  • 发布知识库
  • 获取预测运行时终结点密钥
  • 等待长时间运行的任务
  • 下载知识库
  • 从知识库获取答案
  • 删除知识库

参考文档 | 包 (npm) | Node.js 示例

注意

2019 年 7 月 1 日之后创建的新资源将使用自定义子域名。 有关详细信息和区域终结点的完整列表,请参阅 Azure AI 服务的自定义子域名

先决条件

  • Azure 订阅 - 免费创建订阅
  • 最新版本的 Node.js
  • 有了 Azure 订阅后,在 Azure 门户中创建 QnA Maker 资源,以获取创作密钥和资源。 部署后,选择”转到资源”。
    • 需要从创建的资源获取密钥和资源名称,以便将应用程序连接到 QnA Maker API。 稍后在本快速入门中将密钥和资源名称粘贴到下文的代码中。
    • 可以使用免费定价层 (F0) 试用该服务,然后再升级到付费层进行生产。

设置

创建新的 Node.js 应用程序

在控制台窗口(例如 cmd、PowerShell 或 Bash)中,为应用创建一个新目录并导航到该目录。

mkdir qnamaker_quickstart && cd qnamaker_quickstart

运行 npm init -y 命令以使用 package.json 文件创建一个 node 应用程序。

npm init -y

安装客户端库

安装以下 NPM 包:

npm install @azure/cognitiveservices-qnamaker
npm install @azure/cognitiveservices-qnamaker-runtime
npm install @azure/ms-rest-js

应用的 package.json 文件将使用依赖项进行更新。

创建一个名为 index.js 的文件,并导入以下库:

const msRest = require("@azure/ms-rest-js");
const qnamaker = require("@azure/cognitiveservices-qnamaker");
const qnamaker_runtime = require("@azure/cognitiveservices-qnamaker-runtime");

为资源的 Azure 密钥和资源名称创建一个变量。

  • 我们使用的订阅密钥和创作密钥是可互换的。 有关创作密钥的详细信息,请访问 QnA Maker 中的密钥

  • QNA_MAKER_ENDPOINT 的值采用 https://YOUR-RESOURCE-NAME.cognitiveservices.azure.com 格式。 转到 Azure 门户,并找到之前在“必备组件”部分创建的 QnA Maker 资源。 选择“资源管理”下的“密钥和终结点”页,找到创作(订阅)密钥和 QnA Maker 终结点 。

QnA Maker 创作终结点

  • QNA_MAKER_RUNTIME_ENDPOINT 的值采用 https://YOUR-RESOURCE-NAME.azurewebsites.net 格式。 转到 Azure 门户,并找到之前在“必备组件”部分创建的 QnA Maker 资源。 选择“自动化”下的“导出模板”页,找到运行时终结点 。

QnA Maker 运行时终结点

重要

完成后,请记住将密钥从代码中删除,并且永远不要公开发布该密钥。 对于生产来说,请使用安全的方式存储和访问凭据,例如 Azure Key Vault。 有关详细信息,请参阅 Azure AI 服务安全性一文。

const subscription_key = "PASTE_YOUR_QNA_MAKER_AUTHORING_SUBSCRIPTION_KEY_HERE";
const endpoint = "PASTE_YOUR_QNA_MAKER_AUTHORING_ENDPOINT_HERE";
const runtime_endpoint = "PASTE_YOUR_QNA_MAKER_RUNTIME_ENDPOINT_HERE";

对象模型

QnA Maker 使用两种不同的对象模型:

  • QnAMakerClient 对象可创建、管理、发布和下载知识库。
  • QnAMakerRuntime 对象可通过 GenerateAnswer API 查询知识库,并使用训练 API 发送新的建议问题(作为主动学习的一部分)。

QnAMakerClient 对象模型

创作 QnA Maker 客户端是 QnAMakerClient 对象,使用包含密钥的凭据向 Azure 进行身份验证。

创建该客户端以后,使用知识库创建、管理和发布知识库。

通过发送 JSON 对象来管理知识库。 对于即时操作,方法通常返回一个指示状态的 JSON 对象。 对于长时间运行的操作,响应是操作 ID。 使用操作 ID 调用 client.operations.getDetails 方法,确定请求状态

QnAMakerRuntimeClient 对象模型

预测 QnA Maker 客户端是 QnAMakerRuntimeClient 对象,该对象使用 Microsoft.Rest.ServiceClientCredentials 向 Azure 进行身份验证。Microsoft.Rest.ServiceClientCredentials 包含预测运行时密钥,该密钥在发布知识库后从创作客户端调用 client.EndpointKeys.getKeys 返回。

代码示例

这些代码片段展示如何使用适用于 .NET 的 QnA Maker 客户端库执行以下操作:

对用于创作知识库的客户端进行身份验证

使用终结点和密钥实例化某个客户端。 使用密钥创建 ServiceClientCredentials 对象,并将其与终结点一起使用来创建 QnAMakerClient 对象。

const creds = new msRest.ApiKeyCredentials({ inHeader: { 'Ocp-Apim-Subscription-Key': subscription_key } });
const qnaMakerClient = new qnamaker.QnAMakerClient(creds, endpoint);
const knowledgeBaseClient = new qnamaker.Knowledgebase(qnaMakerClient);

创建知识库

知识库为来自三个源的 CreateKbDTO 对象存储问答对:

  • 对于编辑内容,请使用 QnADTO 对象。
    • 若要使用元数据和跟进提示,请使用编辑上下文,因为此数据是在单独的 QnA 对级别添加的。
  • 对于文件,请使用 FileDTO 对象。 FileDTO 包括文件名以及用于访问该文件的公共 URL。
  • 对于 URL,请使用一列字符串来表示公开可用的 URL。

创建步骤还包括知识库的属性:

  • defaultAnswerUsedForExtraction - 找不到任何答案时返回的内容
  • enableHierarchicalExtraction - 在提取的 QnA 对之间自动创建提示关系
  • language - 创建资源的第一个知识库时,设置要在 Azure 搜索索引中使用的语言。

使用知识库信息调用 create 方法。 知识库信息基本上是一个 JSON 对象。

当 create 方法返回时,请将返回的操作 ID 传递到 wait_for_operation 方法,以轮询状态。 操作完成时,wait_for_operation 方法会返回。 分析返回的操作的 resourceLocation 标头值,以获取新的知识库 ID。

const createKnowledgeBase = async (qnaClient, kbclient) => {

    console.log(`Creating knowledge base...`)

    const qna1 = {
        answer: "Yes, You can use our [REST APIs](https://docs.microsoft.com/rest/api/cognitiveservices/qnamaker/knowledgebase) to manage your knowledge base.",
        questions: ["How do I manage my knowledgebase?"],
        metadata: [
            { name: "Category", value: "api" },
            { name: "Language", value: "REST" }
        ]
    };

    const qna2 = {
        answer: "Yes, You can use our JS SDK on NPM for [authoring](https://www.npmjs.com/package/@azure/cognitiveservices-qnamaker), [query runtime](https://www.npmjs.com/package/@azure/cognitiveservices-qnamaker-runtime), and [the reference docs](https://docs.microsoft.com/en-us/javascript/api/@azure/cognitiveservices-qnamaker/?view=azure-node-latest) to manage your knowledge base.",
        questions: ["How do I manage my knowledgebase?"],
        metadata: [
            { name: "Category", value: "api" },
            { name: "Language", value: "JavaScript" }
        ]
    };

    const create_kb_payload = {
        name: 'QnA Maker JavaScript SDK Quickstart',
        qnaList: [
            qna1,
            qna2
        ],
        urls: [],
        files: [
            /*{
                fileName: "myfile.md",
                fileUri: "https://mydomain/myfile.md"
            }*/
        ],
        defaultAnswerUsedForExtraction: "No answer found.",
        enableHierarchicalExtraction: true,
        language: "English"
    };

    const results = await kbclient.create(create_kb_payload)

    if ( ! results._response.status.toString().startsWith("2")) {
        console.log(`Create request failed - HTTP status ${results._response.status}`)
        return
    }

    const operationResult = await wait_for_operation(qnaClient, results.operationId)

    if (!operationResult || !operationResult.operationState || !(operationResult.operationState = "Succeeded") || !operationResult.resourceLocation) {
        console.log(`Create operation state failed - HTTP status ${operationResult._response.status}`)
        return
    }

    // parse resourceLocation for KB ID
    const kbID = operationResult.resourceLocation.replace("/knowledgebases/", "");

    return kbID;
}

请确保包括上述代码中引用的 wait_for_operation 函数,以便成功创建知识库。

更新知识库

可以更新知识库,方法是:将知识库 ID 和包含 addupdatedelete DTO 对象的 UpdateKbOperationDTO 传递给 update 方法。 DTO 也基本上是 JSON 对象。 使用 wait_for_operation 方法来确定更新是否成功。

const updateKnowledgeBase = async (qnaClient, kbclient, kb_id) => {

    console.log(`Updating knowledge base...`)

    const urls = [
        "https://docs.microsoft.com/azure/cognitive-services/QnAMaker/troubleshooting"
    ]

    const qna3 = {
        answer: "goodbye",
        questions: [
            "bye",
            "end",
            "stop",
            "quit",
            "done"
        ],
        metadata: [
            { name: "Category", value: "Chitchat" },
            { name: "Chitchat", value: "end" }
        ]
    };

    const qna4 = {
        answer: "Hello, please select from the list of questions or enter a new question to continue.",
        questions: [
            "hello",
            "hi",
            "start"
        ],
        metadata: [
            { name: "Category", value: "Chitchat" },
            { name: "Chitchat", value: "begin" }
        ],
        context: {
            isContextOnly: false,
            prompts: [
                {
                    displayOrder: 1,
                    displayText: "Use REST",
                    qna: null,
                    qnaId: 1
                },
                {
                    displayOrder: 2,
                    displayText: "Use JS NPM package",
                    qna: null,
                    qnaId: 2
                },
            ]
        }
    };

    console.log(JSON.stringify(qna4))

    // Add new Q&A lists, URLs, and files to the KB.
    const kb_add_payload = {
        qnaList: [
            qna3,
            qna4
        ],
        urls: urls,
        files: []
    };

    // Bundle the add, update, and delete requests.
    const update_kb_payload = {
        add: kb_add_payload,
        update: null,
        delete: null,
        defaultAnswerUsedForExtraction: "No answer found. Please rephrase your question."
    };

    console.log(JSON.stringify(update_kb_payload))

    const results = await kbclient.update(kb_id, update_kb_payload)

    if ( ! results._response.status.toString().startsWith("2")) {
        console.log(`Update request failed - HTTP status ${results._response.status}`)
        return false
    }

    const operationResult = await wait_for_operation(qnaClient, results.operationId)

    if (operationResult.operationState != "Succeeded") {
        console.log(`Update operation state failed - HTTP status ${operationResult._response.status}`)
        return false
    }

    console.log(`Update operation state ${operationResult._response.status} - HTTP status ${operationResult._response.status}`)
    return true
}

请确保包括上述代码中引用的 wait_for_operation 函数,以便成功更新知识库。

下载知识库

使用 download 方法,将知识库作为 QnADocumentsDTO 列表下载。 这不等同于“设置”页中 QnA Maker 门户的导出,因为此方法的结果不是 TSV 文件。

const downloadKnowledgeBase = async (KBclient, kb_id) => {

    console.log(`Downloading knowledge base...`)

    var kbData = await KBclient.download(kb_id, "Prod");
    console.log(`Knowledge base downloaded. It has ${kbData.qnaDocuments.length} QnAs.`);

    // Do something meaningful with data
}

发布知识库

使用 publish 方法发布知识库。 这样会通过知识库 ID 获取当前保存的已训练模型,并在某个终结点上将其发布。 检查 HTTP 响应代码,验证发布是否成功。

const publishKnowledgeBase = async (kbclient, kb_id) => {

    console.log(`Publishing knowledge base...`)

    const results = await kbclient.publish(kb_id)

    if ( ! results._response.status.toString().startsWith("2")) {
        console.log(`Publish request failed - HTTP status ${results._response.status}`)
        return false
    }

    console.log(`Publish request succeeded - HTTP status ${results._response.status}`)

    return true
}

查询知识库

获取查询运行时密钥

发布知识库后,需要查询运行时密钥来查询运行时。 此密钥与用于创建原始客户端对象的密钥不同。

使用 EndpointKeys.getKeys 方法以获取 EndpointKeysDTO 类。

使用对象中返回的其中一个密钥属性来查询知识库。

const getEndpointKeys = async (qnaClient) => {

    console.log(`Getting runtime endpoint keys...`)

    const runtimeKeysClient = await qnaClient.endpointKeys;
    const results = await runtimeKeysClient.getKeys()

    if ( ! results._response.status.toString().startsWith("2")) {
        console.log(`GetEndpointKeys request failed - HTTP status ${results._response.status}`)
        return null
    }

    console.log(`GetEndpointKeys request succeeded - HTTP status ${results._response.status} - primary key ${results.primaryEndpointKey}`)

    return results.primaryEndpointKey
}

对用于生成答案的运行时进行身份验证

创建 QnAMakerRuntimeClient 来查询知识库,以通过主动学习生成答案或训练。

const queryRuntimeCredentials = new msRest.ApiKeyCredentials({ inHeader: { 'Authorization': 'EndpointKey ' + primaryQueryRuntimeKey } });
const runtimeClient = new qnamaker_runtime.QnAMakerRuntimeClient(queryRuntimeCredentials, runtime_endpoint);

使用 QnAMakerRuntimeClient 基于知识来获取答案,或者将新的建议问题发送到知识库以进行主动学习

从知识库生成答案

使用 RuntimeClient.runtime.generateAnswer 方法从已发布的知识库生成答案。 此方法接受知识库 ID 和 QueryDTO。 访问 QueryDTO 的其他属性,例如要在聊天机器人中使用的 Top 和 Context。

const generateAnswer = async (runtimeClient, runtimeKey, kb_id) => {

    console.log(`Querying knowledge base...`)

    const requestQuery = await runtimeClient.runtime.generateAnswer(
        kb_id,
        {
            question: "How do I manage my knowledgebase?",
            top: 1,
            strictFilters: [
                { name: "Category", value: "api" }
            ]
        }
    );
    console.log(JSON.stringify(requestQuery));

}

这是查询知识库的简单示例。 若要了解高级查询方案,请参阅其他查询示例

删除知识库

使用 delete 方法与知识库 ID 参数删除知识库。

const deleteKnowledgeBase = async (KBclient, kb_id) => {

    console.log(`Deleting knowledge base...`)

    const results = await KBclient.deleteMethod(kb_id)

    if ( ! results._response.status.toString().startsWith("2")) {
        console.log(`Delete operation state failed - HTTP status ${results._response.status}`)
        return false
    }

    console.log(`Delete operation state succeeded - HTTP status ${results._response.status}`)
    return true
}

获取操作的状态

某些方法(例如 create 和 update)可能需要很长的时间,系统不会等待此过程完成,而是返回一个 operation。 使用操作中的操作 ID 进行轮询(使用重试逻辑),确定原始方法的状态。

以下代码块中的 delayTimer 调用用于模拟重试逻辑。 将此项替换为你自己的重试逻辑。

const wait_for_operation = async (qnaClient, operation_id) => {

    let state = "NotStarted"
    let operationResult = undefined

    while ("Running" === state || "NotStarted" === state) {

        operationResult = await qnaClient.operations.getDetails(operation_id)
        state = operationResult.operationState;

        console.log(`Operation state - ${state}`)

        await delayTimer(1000);
    }

    return operationResult;
}
const delayTimer = async (timeInMs) => {
    return await new Promise((resolve) => {
        setTimeout(resolve, timeInMs);
    });
}

运行应用程序

从应用程序目录使用 node index.js 命令运行应用程序。

node index.js

可以在 GitHub 上找到此示例的源代码。

可以使用适用于 Python 的 QnA Maker 客户端库执行以下操作:

  • 创建知识库
  • 更新知识库
  • 发布知识库
  • 获取预测运行时终结点密钥
  • 等待长时间运行的任务
  • 下载知识库
  • 从知识库获取答案
  • 删除知识库

参考文档 | 库源代码 | 包 (PyPi) | Python 示例

注意

2019 年 7 月 1 日之后创建的新资源将使用自定义子域名。 有关详细信息和区域终结点的完整列表,请参阅 Azure AI 服务的自定义子域名

先决条件

注意

本文档不适用于最新版本。 若要了解如何在最新版本中使用 Python API,请参阅 Python 快速入门问题解答

  • Azure 订阅 - 免费创建订阅
  • Python 3.x
  • 有了 Azure 订阅后,在 Azure 门户中创建 QnA Maker 资源,以获取创作密钥和终结点。 部署后,选择”转到资源”。
    • 需要从创建的资源获取密钥和终结点,以便将应用程序连接到 QnA Maker API。 你稍后会在快速入门中将密钥和终结点粘贴到下方的代码中。
    • 可以使用免费定价层 (F0) 试用该服务,然后再升级到付费层进行生产。

设置

安装客户端库

在安装 Python 后,可以通过以下命令安装客户端库:

pip install azure-cognitiveservices-knowledge-qnamaker==0.2.0

创建新的 Python 应用程序

创建名为 quickstart-file.py 的新 Python 文件并导入以下库。

import os
import time

from azure.cognitiveservices.knowledge.qnamaker.authoring import QnAMakerClient
from azure.cognitiveservices.knowledge.qnamaker.runtime import QnAMakerRuntimeClient
from azure.cognitiveservices.knowledge.qnamaker.authoring.models import QnADTO, MetadataDTO, CreateKbDTO, OperationStateType, UpdateKbOperationDTO, UpdateKbOperationDTOAdd, EndpointKeysDTO, QnADTOContext, PromptDTO
from azure.cognitiveservices.knowledge.qnamaker.runtime.models import QueryDTO
from msrest.authentication import CognitiveServicesCredentials

为资源的 Azure 终结点和密钥创建变量。

  • 我们使用的订阅密钥和创作密钥是可互换的。 有关创作密钥的详细信息,请访问 QnA Maker 中的密钥

  • QNA_MAKER_ENDPOINT 的值采用 https://YOUR-RESOURCE-NAME.cognitiveservices.azure.com 格式。 转到 Azure 门户,并找到之前在“必备组件”部分创建的 QnA Maker 资源。 选择“资源管理”下的“密钥和终结点”页,找到创作(订阅)密钥和 QnA Maker 终结点 。

QnA Maker 创作终结点

  • QNA_MAKER_RUNTIME_ENDPOINT 的值采用 https://YOUR-RESOURCE-NAME.azurewebsites.net 格式。 转到 Azure 门户,并找到之前在“必备组件”部分创建的 QnA Maker 资源。 选择“自动化”下的“导出模板”页,找到运行时终结点 。

QnA Maker 运行时终结点

重要

完成后,请记住将密钥从代码中删除,并且永远不要公开发布该密钥。 对于生产来说,请使用安全的方式存储和访问凭据,例如 Azure Key Vault。 有关详细信息,请参阅 Azure AI 服务安全性一文。

subscription_key = 'PASTE_YOUR_QNA_MAKER_AUTHORING_SUBSCRIPTION_KEY_HERE'

authoring_endpoint = 'PASTE_YOUR_QNA_MAKER_AUTHORING_ENDPOINT_HERE'

runtime_endpoint = 'PASTE_YOUR_QNA_MAKER_RUNTIME_ENDPOINT_HERE'

对象模型

QnA Maker 使用两种不同的对象模型:

  • QnAMakerClient 对象可创建、管理、发布和下载知识库。
  • QnAMakerRuntime 对象可通过 GenerateAnswer API 查询知识库,并使用训练 API 发送新的建议问题(作为主动学习的一部分)。

使用示例知识库

本快速入门中的知识库以 2 个对话 QnA 对开始(这样做一是为了简化此示例,二是为了在 Update 方法中有高度可预测的 ID 供使用),将问题的跟进提示与新对相关联。 这是为本快速入门计划的,按特定顺序实现。

如果计划未来要使用依赖于现有 QnA 对的跟进提示来开发知识库,可选择执行以下操作:

  • 对于较大的知识库,请在支持自动化的文本编辑器或 TSV 工具中管理该知识库,然后立即使用更新完全替换知识库。
  • 对于较小的知识库,请完全在 QnA Maker 门户中管理跟进提示。

本快速入门中使用的 QnA 对的详细信息:

  • QnA 对的类型 - 更新后,此知识库中有 2 种类型的 QnA 对:chitchat 以及特定于域的信息。 如果你的知识库与某个会话应用程序(如聊天机器人)相关联,则这种情况很常见。
  • 尽管知识库答案可以按元数据进行筛选或使用跟进提示,但本快速入门并不会介绍此内容。 可在此处找到与语言无关的 generateAnswer 示例。
  • 答案文本为 markdown 格式,并且可以包含多种 markdown 格式,例如图像(可公开使用的基于 Internet 的图像)、链接(指向公开可用的 URL)和提要点,但本快速入门不涉及这些多样内容。

QnAMakerClient 对象模型

创作 QnA Maker 客户端是 QnAMakerClient 对象,使用包含密钥的 Microsoft.Rest.ServiceClientCredentials 向 Azure 进行身份验证。

创建客户端以后,使用知识库属性创建、管理和发布知识库。

通过发送 JSON 对象来管理知识库。 对于即时操作,方法通常返回一个指示状态的 JSON 对象。 对于长时间运行的操作,响应是操作 ID。 使用操作 ID 调用 operations.get_details 方法,确定请求状态

QnAMakerRuntimeClient 对象模型

预测 QnA Maker 客户端是 QnAMakerRuntimeClient 对象,该对象使用 Microsoft.Rest.ServiceClientCredentials 向 Azure 进行身份验证。Microsoft.Rest.ServiceClientCredentials 包含预测运行时密钥,该密钥在发布知识库后从创作客户端调用 client.EndpointKeysOperations.get_keys 返回。

使用 generate_answer 方法从查询运行时获取答案。

对用于创作知识库的客户端进行身份验证

使用终结点和密钥实例化某个客户端。 使用密钥创建 CognitiveServicesCredentials 对象,然后在终结点上使用该对象创建 QnAMakerClient 对象。

client = QnAMakerClient(endpoint=authoring_endpoint, credentials=CognitiveServicesCredentials(subscription_key))

创建知识库

使用客户端对象获取知识库操作对象。

知识库为来自三个源的 CreateKbDTO 对象存储问答对:

  • 对于编辑内容,请使用 QnADTO 对象。
    • 若要使用元数据和跟进提示,请使用编辑上下文,因为此数据是在单独的 QnA 对级别添加的。
  • 对于文件,请使用 FileDTO 对象。 FileDTO 包括文件名以及用于访问该文件的公共 URL。
  • 对于 URL,请使用一列字符串来表示公开可用的 URL。

调用 create 方法,然后将返回的操作 ID 传递给 Operations.getDetails 方法以轮询状态。

以下代码的最后一行返回 MonitorOperation 的响应中的知识库 ID。

def create_kb(client):
    print ("Creating knowledge base...")

    qna1 = QnADTO(
        answer="Yes, You can use our [REST APIs](https://docs.microsoft.com/rest/api/cognitiveservices/qnamaker/knowledgebase) to manage your knowledge base.",
        questions=["How do I manage my knowledgebase?"],
        metadata=[
            MetadataDTO(name="Category", value="api"),
            MetadataDTO(name="Language", value="REST"),
        ]
    )

    qna2 = QnADTO(
        answer="Yes, You can use our [Python SDK](https://pypi.org/project/azure-cognitiveservices-knowledge-qnamaker/) with the [Python Reference Docs](https://docs.microsoft.com/python/api/azure-cognitiveservices-knowledge-qnamaker/azure.cognitiveservices.knowledge.qnamaker?view=azure-python) to manage your knowledge base.",
        questions=["Can I program with Python?"],
        metadata=[
            MetadataDTO(name="Category", value="api"),
            MetadataDTO(name="Language", value="Python"),
        ]
    )

    urls = []
    files = [
        FileDTO(
            file_name = "structured.docx",
            file_uri = "https://github.com/Azure-Samples/cognitive-services-sample-data-files/raw/master/qna-maker/data-source-formats/structured.docx"
        )]

    create_kb_dto = CreateKbDTO(
        name="QnA Maker Python SDK Quickstart",
        qna_list=[
            qna1,
            qna2
        ],
        urls=urls,
        files=[],
        enable_hierarchical_extraction=True,
        default_answer_used_for_extraction="No answer found.",
        language="English"
    )
    create_op = client.knowledgebase.create(create_kb_payload=create_kb_dto)

    create_op_monitor = _monitor_operation(client=client, operation=create_op)

    # Get knowledge base ID from resourceLocation HTTP header
    knowledge_base_ID = create_op_monitor.resource_location.replace("/knowledgebases/", "")
    print("Created KB with ID: {}".format(knowledge_base_ID))

    return knowledge_base_ID

请确保包括上述代码中引用的 _monitor_operation 函数,以便成功创建知识库。

更新知识库

可以更新知识库,方法是:将知识库 ID 和包含 addupdatedelete DTO 对象的 UpdateKbOperationDTO 传递给 update 方法。 使用 Operation.getDetail 方法来确定更新是否成功。

def update_kb(client, kb_id):
    print ("Updating knowledge base...")

    qna3 = QnADTO(
        answer="goodbye",
        questions=[
            "bye",
            "end",
            "stop",
            "quit",
            "done"
            ],
        metadata=[
            MetadataDTO(name="Category", value="Chitchat"),
            MetadataDTO(name="Chitchat", value="end"),
        ]
    )

    qna4 = QnADTO(
        answer="Hello, please select from the list of questions or enter a new question to continue.",
        questions=[
            "hello",
            "hi",
            "start"
        ],
        metadata=[
            MetadataDTO(name="Category", value="Chitchat"),
            MetadataDTO(name="Chitchat", value="begin"),
        ],
        context = QnADTOContext(

            is_context_only = False,
            prompts = [

                PromptDTO(
                    display_order =1,
                    display_text= "Use REST",
                    qna_id=1

                ),
                PromptDTO(
                    display_order =2,
                    display_text= "Use .NET NuGet package",
                    qna_id=2
                ),
            ]
        )

    )

    urls = [
        "https://docs.microsoft.com/azure/cognitive-services/QnAMaker/troubleshooting"
    ]



    update_kb_operation_dto = UpdateKbOperationDTO(
        add=UpdateKbOperationDTOAdd(
            qna_list=[
                qna3,
                qna4
            ],
            urls = urls,
            files=[]
        ),
        delete=None,
        update=None
    )
    update_op = client.knowledgebase.update(kb_id=kb_id, update_kb=update_kb_operation_dto)
    _monitor_operation(client=client, operation=update_op)
    print("Updated knowledge base.")

请确保包括上述代码中引用的 _monitor_operation 函数,以便成功更新知识库。

下载知识库

使用 download 方法,将知识库作为 QnADocumentsDTO 列表下载。 这不等同于“设置”页中 QnA Maker 门户的导出,因为此方法的结果不是 TSV 文件。

def download_kb(client, kb_id):
    print("Downloading knowledge base...")
    kb_data = client.knowledgebase.download(kb_id=kb_id, environment="Prod")
    print("Downloaded knowledge base. It has {} QnAs.".format(len(kb_data.qna_documents)))

发布知识库

使用 publish 方法发布知识库。 这样会通过知识库 ID 获取当前保存的已训练模型,并在某个终结点上将其发布。

def publish_kb(client, kb_id):
    print("Publishing knowledge base...")
    client.knowledgebase.publish(kb_id=kb_id)
    print("Published knowledge base.")

查询知识库

获取查询运行时密钥

发布知识库后,需要查询运行时密钥来查询运行时。 此密钥与用于创建原始客户端对象的密钥不同。

使用 EndpointKeysOperations.get_keys 方法以获取 EndpointKeysDTO 类。

使用对象中返回的其中一个密钥属性来查询知识库。

def getEndpointKeys_kb(client):
    print("Getting runtime endpoint keys...")
    keys = client.endpoint_keys.get_keys()
    print("Primary runtime endpoint key: {}.".format(keys.primary_endpoint_key))

    return keys.primary_endpoint_key

对用于生成答案的运行时进行身份验证

创建 QnAMakerRuntimeClient 来查询知识库,以通过主动学习生成答案或训练。

runtimeClient = QnAMakerRuntimeClient(runtime_endpoint=runtime_endpoint, credentials=CognitiveServicesCredentials(queryRuntimeKey))

使用 QnAMakerRuntimeClient 基于知识来获取答案,或者将新的建议问题发送到知识库以进行主动学习

从知识库生成答案

使用 QnAMakerRuntimeClient.runtime.generate_answer 方法从已发布的知识库中生成答案。 此方法接受知识库 ID 和 QueryDTO。 访问 QueryDTO 的其他属性,例如要在聊天机器人中使用的 Top 和 Context。

def generate_answer(client, kb_id, runtimeKey):
    print ("Querying knowledge base...")

    authHeaderValue = "EndpointKey " + runtimeKey

    listSearchResults = client.runtime.generate_answer(kb_id, QueryDTO(question = "How do I manage my knowledgebase?"), dict(Authorization=authHeaderValue))

    for i in listSearchResults.answers:
        print(f"Answer ID: {i.id}.")
        print(f"Answer: {i.answer}.")
        print(f"Answer score: {i.score}.")

这是一个简单的查询知识库的示例。 若要了解高级查询方案,请参阅其他查询示例

删除知识库

使用 delete 方法与知识库 ID 参数删除知识库。

def delete_kb(client, kb_id):
    print("Deleting knowledge base...")
    client.knowledgebase.delete(kb_id=kb_id)
    print("Deleted knowledge base.")

获取操作的状态

某些方法(例如 create 和 update)可能需要很长的时间,系统不会等待此过程完成,而是返回一个 operation。 使用操作中的操作 ID 进行轮询(使用重试逻辑),确定原始方法的状态。

以下代码块中的 setTimeout 调用用于模拟异步代码。 将其替换为重试逻辑。

def _monitor_operation(client, operation):

    for i in range(20):
        if operation.operation_state in [OperationStateType.not_started, OperationStateType.running]:
            print("Waiting for operation: {} to complete.".format(operation.operation_id))
            time.sleep(5)
            operation = client.operations.get_details(operation_id=operation.operation_id)
        else:
            break
    if operation.operation_state != OperationStateType.succeeded:
        raise Exception("Operation {} failed to complete.".format(operation.operation_id))

    return operation

运行应用程序

在快速入门文件中使用 Python 命令运行应用程序。

python quickstart-file.py

可以在 GitHub 上找到此示例的源代码。

可以使用适用于 Java 的 QnA Maker 客户端库执行以下操作:

  • 创建知识库
  • 更新知识库
  • 发布知识库
  • 获取预测运行时终结点密钥
  • 等待长时间运行的任务
  • 下载知识库
  • 从知识库获取答案
  • 删除知识库

库源代码 | | 示例

注意

2019 年 7 月 1 日之后创建的新资源将使用自定义子域名。 有关详细信息和区域终结点的完整列表,请参阅 Azure AI 服务的自定义子域名

先决条件

  • Azure 订阅 - 免费创建订阅
  • JDK
  • 有了 Azure 订阅后,在 Azure 门户中创建 QnA Maker 资源,以获取创作密钥和终结点。 部署后,选择”转到资源”。
    • 需要从创建的资源获取密钥和终结点,以便将应用程序连接到 QnA Maker API。 稍后在快速入门中将密钥和终结点粘贴到下方的代码中。
    • 可以使用免费定价层 (F0) 试用该服务,然后再升级到付费层进行生产。

设置

安装客户端库

安装 Java 后,可以使用 MVN 存储库中的 Maven 来安装客户端库。

创建新的 Java 应用程序

创建一个名为 quickstart.java 的新文件,并导入以下库。

/* Download the following files.
 * - https://repo1.maven.org/maven2/com/microsoft/azure/cognitiveservices/azure-cognitiveservices-qnamaker/1.0.0-beta.1/azure-cognitiveservices-qnamaker-1.0.0-beta.1.jar
 * - https://repo1.maven.org/maven2/com/microsoft/azure/cognitiveservices/azure-cognitiveservices-qnamaker/1.0.0-beta.1/azure-cognitiveservices-qnamaker-1.0.0-beta.1.pom
 * Move the downloaded .jar file to a folder named "lib" directly under the current folder.
 * Rename the downloaded file to pom.xml.
 * At the command line, run
 * mvn dependency:copy-dependencies
 * This will download the .jar files depended on by azure-cognitiveservices-qnamaker-1.0.0-beta.1.jar to the folder "target/dependency" under the current folder. Move these .jar files to the "lib" folder as well.
 */
import com.microsoft.azure.cognitiveservices.knowledge.qnamaker.*;
import com.microsoft.azure.cognitiveservices.knowledge.qnamaker.models.*;

import java.io.*;
import java.lang.Object.*;
import java.time.format.DateTimeFormatter;  
import java.time.LocalDateTime; 
import java.util.*;
import java.net.*;

为资源的 Azure 终结点和密钥创建变量。

  • 我们使用的订阅密钥和创作密钥是可互换的。 有关创作密钥的详细信息,请访问 QnA Maker 中的密钥

  • QNA_MAKER_ENDPOINT 的值采用 https://YOUR-RESOURCE-NAME.cognitiveservices.azure.com 格式。 转到 Azure 门户,并找到之前在“必备组件”部分创建的 QnA Maker 资源。 选择“资源管理”下的“密钥和终结点”页,找到创作(订阅)密钥和 QnA Maker 终结点 。

QnA Maker 创作终结点

  • QNA_MAKER_RUNTIME_ENDPOINT 的值采用 https://YOUR-RESOURCE-NAME.azurewebsites.net 格式。 转到 Azure 门户,并找到之前在“必备组件”部分创建的 QnA Maker 资源。 选择“自动化”下的“导出模板”页,找到运行时终结点 。

QnA Maker 运行时终结点

重要

完成后,请记住将密钥从代码中删除,并且永远不要公开发布该密钥。 对于生产来说,请使用安全的方式存储和访问凭据,例如 Azure Key Vault。 有关详细信息,请参阅 Azure AI 服务安全性一文。

private static String authoring_key = "PASTE_YOUR_QNA_MAKER_AUTHORING_SUBSCRIPTION_KEY_HERE";
private static String authoring_endpoint = "PASTE_YOUR_QNA_MAKER_AUTHORING_ENDPOINT_HERE";
private static String runtime_endpoint = "PASTE_YOUR_QNA_MAKER_RUNTIME_ENDPOINT_HERE";

对象模型

QnA Maker 使用两种不同的对象模型:

  • QnAMakerClient 对象可创建、管理、发布和下载知识库。
  • QnAMakerRuntime 对象可通过 GenerateAnswer API 查询知识库,并使用训练 API 发送新的建议问题(作为主动学习的一部分)。

使用示例知识库

本快速入门中的知识库以 2 个对话 QnA 对开始(这样做一是为了简化此示例,二是为了在 Update 方法中有高度可预测的 ID 供使用),将问题的跟进提示与新对相关联。 这是为本快速入门计划的,按特定顺序实现。

如果计划未来要使用依赖于现有 QnA 对的跟进提示来开发知识库,可选择执行以下操作:

  • 对于较大的知识库,请在支持自动化的文本编辑器或 TSV 工具中管理该知识库,然后立即使用更新完全替换知识库。
  • 对于较小的知识库,请完全在 QnA Maker 门户中管理跟进提示。

本快速入门中使用的 QnA 对的详细信息:

  • QnA 对的类型 - 更新后,此知识库中有 2 种类型的 QnA 对:chitchat 以及特定于域的信息。 如果你的知识库与某个会话应用程序(如聊天机器人)相关联,则这种情况很常见。
  • 尽管知识库答案可以按元数据进行筛选或使用跟进提示,但本快速入门并不会介绍此内容。 可在此处找到与语言无关的 generateAnswer 示例。
  • 答案文本为 markdown 格式,并且可以包含多种 markdown 格式,例如图像(可公开使用的基于 Internet 的图像)、链接(指向公开可用的 URL)和提要点,但本快速入门不涉及这些多样内容。

QnAMakerClient 对象模型

创作 QnA Maker 客户端是一个 QnAMakerClient 对象,使用包含密钥的 MsRest::ServiceClientCredentials 向 Azure 进行身份验证。

创建客户端后,可使用客户端的 Knowledgebases 属性方法创建、管理和发布知识库。

对于即时操作,方法通常返回结果(如果有)。 对于长时间运行的操作,响应是 Operation 对象。 使用 operation.operationId 值调用 getDetails 方法,确定请求状态

QnAMakerRuntimeClient 对象模型

运行时 QnA Maker 客户端是一个 QnAMakerRuntimeClient 对象。

使用创作客户端发布知识库后,可使用运行时客户端的 generateAnswer 方法从知识库获取答案。

通过调用 QnAMakerRuntimeManager.authenticate 并传递运行时终结点密钥来创建运行时客户端。 要获取运行时终结点密钥,请使用创作客户端调用 getKeys

对用于创作知识库的客户端进行身份验证

使用创作终结点和订阅密钥实例化客户端。

/* Note QnAMakerManager.authenticate() does not set the baseUrl paramater value
 * as the value for QnAMakerClient.endpoint, so we still need to call withEndpoint().
 */
QnAMakerClient authoring_client = QnAMakerManager.authenticate(authoring_key).withEndpoint(authoring_endpoint);
Knowledgebases kb_client = authoring_client.knowledgebases();
Operations ops_client = authoring_client.operations();
EndpointKeys keys_client = authoring_client.endpointKeys();

创建知识库

知识库为来自三个源的 CreateKbDTO 对象存储问答对:

  • 对于编辑内容,请使用 QnADTO 对象。
    • 若要使用元数据和跟进提示,请使用编辑上下文,因为此数据是在单独的 QnA 对级别添加的。
  • 对于文件,请使用 FileDTO 对象。 FileDTO 包括文件名以及用于访问该文件的公共 URL。
  • 对于 URL,请使用一列字符串来表示公开可用的 URL。

调用 create 方法,然后将返回的操作的 operationId 属性传递给 getDetails 方法以轮询状态。

以下代码的最后一行返回知识库 ID。

public String create_kb () throws Exception {
    System.out.println("Creating KB...");

    String name = "QnA Maker FAQ from quickstart";

    var metadata = new MetadataDTO()
        .withName ("Category")
        .withValue ("api");

    List<MetadataDTO> metadata_list = Arrays.asList(new MetadataDTO[]{ metadata });

    var qna = new QnADTO()
        .withAnswer ("You can use our REST APIs to manage your knowledge base.")
        .withQuestions ( Arrays.asList(new String[]{ "How do I manage my knowledgebase?" }))
        .withMetadata (metadata_list);

    List<QnADTO> qna_list = Arrays.asList(new QnADTO[]{ qna });

    var urls = Arrays.asList(new String[]{ "https://docs.microsoft.com/en-in/azure/cognitive-services/qnamaker/faqs" });

    var payload = new CreateKbDTO().withName(name).withQnaList(qna_list).withUrls(urls);

    var result = kb_client.create(payload);
    var kb_id = wait_for_operation(result);

    System.out.println("Created KB with ID: " + kb_id + ".\n");
    return kb_id;
}

更新知识库

可以更新知识库,方法是调用 update 并传入知识库 ID 和 UpdateKbOperationDTO 对象。 而该对象可以包含:

将返回的操作的 operationId 属性传递给 getDetails 方法以轮询状态。

public void update_kb (String kb_id) throws Exception {
    System.out.println("Updating KB...");

    var update = new UpdateKbOperationDTOUpdate().withName ("New KB name");

    var payload = new UpdateKbOperationDTO().withUpdate((UpdateKbOperationDTOUpdate)update);

    var result = kb_client.update(kb_id, payload);
    wait_for_operation(result);

    System.out.println("Updated KB.");
}

下载知识库

使用 download 方法,将知识库作为 QnADocumentsDTO 列表下载。 这不等同于“设置”页中 QnA Maker 门户的导出,因为此方法的结果不是 TSV 文件。

public void download_kb(String kb_id) {
    System.out.println("Downloading KB...");

    var kb_data = kb_client.download(kb_id, EnvironmentType.PROD);
    System.out.println("KB Downloaded. It has " + kb_data.qnaDocuments().size() + " question/answer sets.");

    System.out.println("Downloaded KB.\n");
}

发布知识库

使用 publish 方法发布知识库。 这样会通过知识库 ID 获取当前保存的已训练模型,并在某个终结点上将其发布。

public void publish_kb(String kb_id) {
    System.out.println("Publishing KB...");
    kb_client.publish(kb_id);
    System.out.println("KB published.\n");
}

从知识库生成答案

发布知识库后,需要运行时终结点密钥来查询知识库。 这与用于创建创作客户端的订阅密钥不同。

使用 getKeys 方法获取 EndpointKeysDTO 对象。

通过调用 QnAMakerRuntimeManager.authenticate 并从 EndpointKeysDTO 对象传递运行时终结点密钥来创建运行时客户端。

使用 generateAnswer 方法从已发布的知识库生成答案。 此方法接受知识库 ID 和 QueryDTO 对象。

public void query_kb(String kb_id) {
    System.out.println("Sending query to KB...");
    
    var runtime_key = keys_client.getKeys().primaryEndpointKey();
    QnAMakerRuntimeClient runtime_client = QnAMakerRuntimeManager.authenticate(runtime_key).withRuntimeEndpoint(runtime_endpoint);
    var query = (new QueryDTO()).withQuestion("How do I manage my knowledgebase?");
    var result = runtime_client.runtimes().generateAnswer(kb_id, query);
    System.out.println("Answers:");
    for (var answer : result.answers()) {
        System.out.println(answer.answer().toString());
    };
    System.out.println();
}

这是查询知识库的简单示例。 若要了解高级查询方案,请参阅其他查询示例

删除知识库

使用 delete 方法与知识库 ID 参数删除知识库。

public void delete_kb(String kb_id) {
    System.out.println("Deleting KB...");
    kb_client.delete(kb_id);
    System.out.println("KB deleted.\n");
}

获取操作的状态

某些方法(例如 create 和 update)可能需要很长的时间,系统不会等待此过程完成,而是返回一个 operation。 使用操作中的操作 ID 进行轮询(使用重试逻辑),确定原始方法的状态。

public String wait_for_operation(Operation op) throws Exception {
    System.out.println ("Waiting for operation to finish...");
    Boolean waiting = true;
    String result = "";
    while (true == waiting) {
        var op_ = ops_client.getDetails(op.operationId());
        var state = op_.operationState();
        if (OperationStateType.FAILED == state) {
            throw new Exception("Operation failed.");
        }
        if (OperationStateType.SUCCEEDED == state) {
            waiting = false;
            // Remove "/knowledgebases/" from the resource location.
            result = op_.resourceLocation().replace("/knowledgebases/", "");
        }
        if (true == waiting) {
            System.out.println("Waiting 10 seconds for operation to complete...");
            Thread.sleep(10000);
        }
    }
    return result;
}

运行此应用程序

下面是应用程序的 main 方法。

    public static void main(String[] args) {
        try {
            Quickstart quickstart = new Quickstart();
            String kb_id = quickstart.create_kb();
//			quickstart.list_kbs();
            quickstart.update_kb(kb_id);
            quickstart.publish_kb(kb_id);
            quickstart.download_kb(kb_id);
            quickstart.query_kb(kb_id);
            quickstart.delete_kb(kb_id);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }

按如下所示运行应用程序。 这会假设类名为 Quickstart,并且依赖项位于当前文件夹下名为 lib 的子文件夹中。

javac Quickstart.java -cp .;lib\*
java -cp .;lib\* Quickstart

可以在 GitHub 上找到此示例的源代码。

清理资源

如果想要清理并移除 Azure AI 服务订阅,可以删除资源或资源组。 删除资源组同时也会删除与之相关联的任何其他资源。

后续步骤