Поделиться через


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

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

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

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

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

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

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

Примечание.

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

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

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

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

Предварительные условия

Примечание.

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

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

Пример навыков простого взаимодействия "бот-бот" включает проекты для двух ботов:

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

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

Для получения сведений о простом корневом боте см. как реализовать потребителя навыка.

Ресурсы

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

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

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

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

Массив 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. Чтобы сигнализировать о завершении навыка из-за ошибки, используйте свойство кода действия.

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

Пример расшифровки с завершением диалога.

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

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

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

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

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