Реализация навыка

ОБЛАСТЬ ПРИМЕНЕНИЯ: ПАКЕТ SDK версии 4

Вы можете использовать навыки для расширения функциональности другого бота. Навыком здесь называется бот, который может выполнять ряд задач для другого бота.

  • Интерфейс навыка описывается манифестом. Разработчики, у которых нет доступа к исходному коду навыка, могут использовать информацию из этого манифеста для разработки потребителя навыка.
  • Навык может использовать проверку утверждений для управления доступом от других ботов и пользователей.

В этой статье демонстрируется реализация навыка, который выводит на экран вводимые пользователем данные.

Некоторые типы потребителей навыков не могут использовать некоторые типы ботов навыков. В следующей таблице описывается, какие сочетания поддерживаются.

  Навыки с несколькими клиентами Навык однотенантного клиента Навык управляемого удостоверения, назначаемого пользователем
Потребитель с несколькими клиентами Поддерживается Не поддерживается Не поддерживается
Потребитель с одним клиентом Не поддерживается Поддерживается, если оба приложения принадлежат к одному клиенту Поддерживается, если оба приложения принадлежат к одному клиенту
Потребитель управляемого удостоверения, назначаемого пользователем Не поддерживается Поддерживается, если оба приложения принадлежат к одному клиенту Поддерживается, если оба приложения принадлежат к одному клиенту

Примечание.

Пакеты SDK для JavaScript, C# и Python для Bot Framework по-прежнему будут поддерживаться, однако пакет SDK java отменяется с окончательной долгосрочной поддержкой, заканчивающейся в ноябре 2023 года. В этом репозитории будут выполняться только критически важные исправления безопасности и ошибок.

Существующие боты, созданные с помощью пакета SDK для Java, будут продолжать функционировать.

Для создания нового бота рекомендуется использовать Power Virtual Agent и ознакомиться с выбором подходящего решения чат-бота.

Дополнительные сведения см. в статье "Будущее создания бота".

Необходимые компоненты

Примечание.

Начиная с версии 4.11, вам не нужен идентификатор приложения и пароль для локального тестирования навыка в эмуляторе Bot Framework. Подписка Azure по-прежнему необходима для развертывания навыка в Azure.

Об этом примере

В пример простого навыка для ботов включены проекты двух ботов:

  • бот эхо-навыка, который реализует этот навык;
  • простой корневой бот, который реализует бот для использования этого навыка.

Эта статья посвящена навыку, в том числе логике поддержки в боте и адаптере.

Сведения о простом корневом боте см. в статье о реализации потребителя навыка.

Ресурсы

Для развернутых ботов проверка подлинности "бот — бот" требует, чтобы каждый участвующий бот имеет допустимые сведения об удостоверениях. Однако вы можете протестировать многотенантные навыки и потребители навыков локально с помощью эмулятора без идентификатора приложения и пароля.

Чтобы сделать навык доступным для пользователей ботов, зарегистрируйте навык в Azure. Дополнительные сведения см. в статье о регистрации бота с помощью Azure AI Служба Bot.

Конфигурация приложений

При необходимости добавьте в файл конфигурации сведения о удостоверении навыка. Если пользователь навыка или навыка предоставляет сведения о удостоверении, оба должны.

Массив allowed callers позволяет ограничить круг потребителей, имеющих доступ к этому навыку. Добавьте элемент "*", чтобы принимать вызовы от любого потребителя навыка.

Примечание.

Если вы тестируете навык локально без сведений об удостоверениях бота, ни навык, ни потребитель навыка не запускают код для проверки утверждений.

EchoSkillBot\appsettings.json

При необходимости добавьте сведения об удостоверениях навыка в файл appsettings.json.

{
  "MicrosoftAppType": "",
  "MicrosoftAppId": "",
  "MicrosoftAppPassword": "",
  "MicrosoftAppTenantId": "",

  // This is a comma separate list with the App IDs that will have access to the skill.
  // This setting is used in AllowedCallersClaimsValidator.
  // Examples: 
  //    [ "*" ] allows all callers.
  //    [ "AppId1", "AppId2" ] only allows access to parent bots with "AppId1" and "AppId2".
  "AllowedCallers": [ "*" ]
}

Логика обработчика действий

Прием входных параметров

Потребитель навыка может отправить информацию в этот навык. Один из способов принять такую информацию — через свойство value входящего сообщения. Другой способ — обработка действий события и вызова.

Навык в этом примере не принимает входные параметры.

Продолжение или завершение беседы

Когда навык отправляет действие, потребитель навыка должен перенаправить это действие пользователю.

Но при завершении работы навыка необходимо отправить действие endOfConversation, иначе потребитель навыка будет и далее пересылать действия пользователя в навык. Можно также поместить возвращаемое значение в свойство value, а причину завершения навыка — в свойство code обрабатываемого действия.

EchoSkillBot\Bots\EchoBot.cs

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    if (turnContext.Activity.Text.Contains("end") || turnContext.Activity.Text.Contains("stop"))
    {
        // Send End of conversation at the end.
        var messageText = $"ending conversation from the skill...";
        await turnContext.SendActivityAsync(MessageFactory.Text(messageText, messageText, InputHints.IgnoringInput), cancellationToken);
        var endOfConversation = Activity.CreateEndOfConversationActivity();
        endOfConversation.Code = EndOfConversationCodes.CompletedSuccessfully;
        await turnContext.SendActivityAsync(endOfConversation, cancellationToken);
    }
    else
    {
        var messageText = $"Echo: {turnContext.Activity.Text}";
        await turnContext.SendActivityAsync(MessageFactory.Text(messageText, messageText, InputHints.IgnoringInput), cancellationToken);
        messageText = "Say \"end\" or \"stop\" and I'll end the conversation and back to the parent.";
        await turnContext.SendActivityAsync(MessageFactory.Text(messageText, messageText, InputHints.ExpectingInput), cancellationToken);
    }
}

Отмена выполнения навыка

В навыках с несколькими репликами необходимо также принимать от потребителя навыков действия endOfConversation, которые позволят потребителю отменить текущую беседу.

Логика этого навыка не изменяется с поворота. Если реализуемый вами навык выделяет ресурсы для беседы, добавьте в обработчик завершения беседы код для очистки этих ресурсов.

EchoSkillBot\Bots\EchoBot.cs

protected override Task OnEndOfConversationActivityAsync(ITurnContext<IEndOfConversationActivity> turnContext, CancellationToken cancellationToken)
{
    // This will be called if the root bot is ending the conversation.  Sending additional messages should be
    // avoided as the conversation may have been deleted.
    // Perform cleanup of resources if needed.
    return Task.CompletedTask;
}

Средство проверки утверждений

В нашем примере для проверки утверждений используется список разрешенных вызывающих объектов. Этот список определен в файле конфигурации навыка и считывается в объект средства проверки при его создании.

Необходимо добавить проверяющий элемент утверждений в конфигурацию проверки подлинности. Утверждения оцениваются после заголовка проверки подлинности. Код средства проверки должен создавать исключение или ошибку, чтобы отклонить запрос. Отклонение запроса, уже прошедшего проверку подлинности, может потребоваться по разным причинам. Например:

  • навык предоставляется как часть платной службы; У пользователя нет доступа к базе данных.
  • доступ к навыку ограничен правообладателем; вызвать навык могут только определенные потребители.

Важно!

Если вы не предоставляете проверяющий средство утверждений, бот создаст ошибку или исключение при получении действия от потребителя навыка.

Пакет SDK предоставляет класс, который добавляет AllowedCallersClaimsValidator авторизацию на уровне приложения на основе простого списка идентификаторов приложений, которые могут вызывать навык. Если список содержит звездочку (*), все вызывающие абоненты разрешены. Проверяющий элемент утверждений настроен в Startup.cs.

Адаптер навыка

При возникновении ошибки адаптер навыка должен очистить состояние беседы для этого навыка и отправить потребителю действие endOfConversation. Используйте свойство code в этом действии, чтобы сообщить о завершении навыка из-за ошибки.

EchoSkillBot\SkillAdapterWithErrorHandler.cs

private async Task HandleTurnError(ITurnContext turnContext, Exception exception)
{
    // Log any leaked exception from the application.
    _logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}");

    await SendErrorMessageAsync(turnContext, exception);
    await SendEoCToParentAsync(turnContext, exception);
}

private async Task SendErrorMessageAsync(ITurnContext turnContext, Exception exception)
{
    try
    {
        // Send a message to the user.
        var errorMessageText = "The skill encountered an error or bug.";
        var errorMessage = MessageFactory.Text(errorMessageText, errorMessageText, InputHints.IgnoringInput);
        await turnContext.SendActivityAsync(errorMessage);

        errorMessageText = "To continue to run this bot, please fix the bot source code.";
        errorMessage = MessageFactory.Text(errorMessageText, errorMessageText, InputHints.ExpectingInput);
        await turnContext.SendActivityAsync(errorMessage);

        // Send a trace activity, which will be displayed in the Bot Framework Emulator.
        // Note: we return the entire exception in the value property to help the developer;
        // this should not be done in production.
        await turnContext.TraceActivityAsync("OnTurnError Trace", exception.ToString(), "https://www.botframework.com/schemas/error", "TurnError");
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, $"Exception caught in SendErrorMessageAsync : {ex}");
    }
}

private async Task SendEoCToParentAsync(ITurnContext turnContext, Exception exception)
{
    try
    {
        // Send an EndOfConversation activity to the skill caller with the error to end the conversation,
        // and let the caller decide what to do.
        var endOfConversation = Activity.CreateEndOfConversationActivity();
        endOfConversation.Code = "SkillError";
        endOfConversation.Text = exception.Message;
        await turnContext.SendActivityAsync(endOfConversation);
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, $"Exception caught in SendEoCToParentAsync : {ex}");
    }
}

Регистрация службы

Адаптер Bot Framework использует объект конфигурации проверки подлинности, который настраивается при создании адаптера, для проверки заголовков проверки подлинности во входящих запросах.

В нашем примере в конфигурацию проверки подлинности добавляется проверка утверждений, а также применяется адаптер навыка с обработчиком ошибок, который описан в предыдущем разделе.

EchoSkillBot\Startup.cs

    options.SerializerSettings.MaxDepth = HttpHelper.BotMessageSerializerSettings.MaxDepth;
});

// Register AuthConfiguration to enable custom claim validation.
services.AddSingleton(sp =>
{
    var allowedCallers = new List<string>(sp.GetService<IConfiguration>().GetSection("AllowedCallers").Get<string[]>());

    var claimsValidator = new AllowedCallersClaimsValidator(allowedCallers);

    // If TenantId is specified in config, add the tenant as a valid JWT token issuer for Bot to Skill conversation.
    // The token issuer for MSI and single tenant scenarios will be the tenant where the bot is registered.
    var validTokenIssuers = new List<string>();
    var tenantId = sp.GetService<IConfiguration>().GetSection(MicrosoftAppCredentials.MicrosoftAppTenantIdKey)?.Value;

    if (!string.IsNullOrWhiteSpace(tenantId))
    {
        // For SingleTenant/MSI auth, the JWT tokens will be issued from the bot's home tenant.
        // Therefore, these issuers need to be added to the list of valid token issuers for authenticating activity requests.
        validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidTokenIssuerUrlTemplateV1, tenantId));
        validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidTokenIssuerUrlTemplateV2, tenantId));
        validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidGovernmentTokenIssuerUrlTemplateV1, tenantId));
        validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidGovernmentTokenIssuerUrlTemplateV2, tenantId));
    }

    return new AuthenticationConfiguration
    {
        ClaimsValidator = claimsValidator,
        ValidTokenIssuers = validTokenIssuers
    };
});

// Create the Bot Framework Authentication to be used with the Bot Adapter.
services.AddSingleton<BotFrameworkAuthentication, ConfigurationBotFrameworkAuthentication>();

Манифест навыка

Манифест навыка — это файл в формате JSON с описанием действий, которые может выполнять навык, его входных и выходных параметров, а также конечных точек навыка. Манифест содержит сведения, которые вам нужны для доступа к навыку из другого бота. Последняя версия схемы — версия 2.1.

EchoSkillBot\wwwroot\manifest\echoskillbot-manifest-1.0.json

{
  "$schema": "https://schemas.botframework.com/schemas/skills/skill-manifest-2.0.0.json",
  "$id": "EchoSkillBot",
  "name": "Echo Skill bot",
  "version": "1.0",
  "description": "This is a sample echo skill",
  "publisherName": "Microsoft",
  "privacyUrl": "https://echoskillbot.contoso.com/privacy.html",
  "copyright": "Copyright (c) Microsoft Corporation. All rights reserved.",
  "license": "",
  "iconUrl": "https://echoskillbot.contoso.com/icon.png",
  "tags": [
    "sample",
    "echo"
  ],
  "endpoints": [
    {
      "name": "default",
      "protocol": "BotFrameworkV3",
      "description": "Default endpoint for the skill",
      "endpointUrl": "http://echoskillbot.contoso.com/api/messages",
      "msAppId": "00000000-0000-0000-0000-000000000000"
    }
  ]
}

Схема манифеста навыка — это файл в формате JSON с описанием схемы манифеста навыков. Текущая версия схемы — 2.1.0.

Тестирование навыка

На этом этапе вы можете проверить работу навыка в эмуляторе, как для любого обычного бота. Но прежде, чем протестировать его как навык, необходимо реализовать потребитель навыка.

Скачайте и установите последнюю версию Bot Framework Emulator.

  1. Запустите бот с эхо-навыком на локальном компьютере. Если вам нужны инструкции, ознакомьтесь с файлом README для примера C#, JavaScript, JavaScript или Python.
  2. Примените эмулятор для тестирования бота, как показано ниже. При отправке сообщения "end" или "stop" навыку он отправляет endOfConversation действие в дополнение к ответу. Навык отправляет действие endOfConversation, чтобы обозначить завершение своей работы.

Example transcript showing the end-of-conversation activity.

Дополнительные сведения об отладке

Так как трафик между навыками и потребителями навыков проходит проверку подлинности, при отладке таких ботов выполняются дополнительные действия.

  • Потребитель навыка и все навыки, которые он потребляет, прямо или косвенно, должны работать.
  • Если боты работают локально и если у любого из ботов есть идентификатор приложения и пароль, все боты должны иметь действительные идентификаторы и пароли.
  • Если боты развернуты, узнайте, как отладить бота из любого канала с помощью ngrok.
  • Если некоторые боты выполняются локально, а некоторые развертываются, см. инструкции по отладке навыка или потребителя навыков.

В противном случае можно отладить потребителя навыка или навыка, как отладить другие боты. Дополнительные сведения см. в статье отладка бота и отладка с помощью эмулятора Bot Framework.

Следующие шаги