スキル コンシューマーを実装するImplement a skill consumer

適用対象: SDK v4APPLIES TO: SDK v4

スキルを使用して別のボットを拡張することができます。You can use skills to extend another bot. "スキル" は別のボットに対して一連のタスクを実行できるボットであり、マニフェストを使用してそのインターフェイスが記述されます。A skill is a bot that can perform a set of tasks for another bot and uses a manifest to describe its interface. "ルート ボット" は、1 つ以上のスキルを呼び出すことができるユーザー向けのボットです。A root bot is a user-facing bot that can invoke one or more skills. ルート ボットは "スキル コンシューマー" の一種です。A root bot is a type of skill consumer.

  • スキル コンシューマーは、要求検証を使用して、アクセスできるスキルを管理する必要があります。A skill consumer must use claims validation to manage which skills can access it.
  • スキル コンシューマーは複数のスキルを使用できます。A skill consumer can use multiple skills.
  • スキルのソース コードにアクセスできない開発者は、スキル マニフェストの情報を使用してスキル コンシューマーを設計できます。Developers who don't have access to the skill's source code can use the information in the skill's manifest to design their skill consumer.

この記事では、エコー スキルを使用してユーザーの入力をエコーするスキル コンシューマーを実装する方法について説明します。This article demonstrates how to implement a skill consumer that uses the echo skill to echo the user's input. スキル マニフェストのサンプルおよびエコー スキルの実装に関する情報については、「スキルを実装する」を参照してください。For a sample skill manifest and information about implementing the echo skill, see how to implement a skill.

スキル ダイアログを使用してスキルを利用する方法については、ダイアログを使用してスキルを利用する方法を参照してください。For information about using a skill dialog to consume a skill, see how to use a dialog to consume a skill.

前提条件Prerequisites

注意

バージョン 4.11 から、アプリ ID とパスワードを使用して、スキル コンシューマーをローカルでテストする必要Emulator。Starting with version 4.11, you do not need an app ID and password to test a skill consumer locally in the Emulator. コンシューマーを Azure にデプロイしたり、デプロイされたスキルを使用したりするには、引き続き Azure サブスクリプションが必要です。An Azure subscription is still required to deploy your consumer to Azure or to consume a deployed skill.

このサンプルについてAbout this sample

skills simple bot-to-bot サンプルには、次の 2 つのボットのプロジェクトが含まれています。The skills simple bot-to-bot sample includes projects for two bots:

  • スキルを実装する "エコー スキル ボット"。The echo skill bot, which implements the skill.
  • スキルを使用するルート ボットを実装する "単純なルート ボット"。The simple root bot, which implements a root bot that consumes the skill.

この記事で取り上げるルート ボットには、ボット オブジェクトとアダプター オブジェクトにサポート ロジックが組み込まれ、かつアクティビティをスキルとやり取りするためのオブジェクトが含まれています。This article focuses on the root bot, which includes support logic in its bot and adapter objects and includes objects used to exchange activities with a skill. これには以下が含まれます。These include:

  • スキル クライアント。スキルにアクティビティを送信するために使用されます。A skill client, used to send activities to a skill.
  • スキル ハンドラー。スキルからアクティビティを受信するために使用されます。A skill handler, used to receive activities from a skill.
  • スキル会話 ID ファクトリ。ユーザー/ルート間の会話リファレンスの参照とルート/スキル間の会話リファレンスの間で変換を行うために、スキル クライアントとスキル ハンドラーで使用されます。A skill conversation ID factory, used by the skill client and handler to translate between the user-root conversation reference and the root-skill conversation reference.

エコー スキル ボットについては、「スキルを実装する」を参照してください。For information about the echo skill bot, see how to Implement a skill.

リソースResources

デプロイされたボットの場合、ボットからボットへの認証では、参加している各ボットに有効なアプリ ID とパスワードが必要です。For deployed bots, bot-to-bot authentication requires that each participating bot has a valid app ID and password. ただし、アプリ ID とパスワードを使用せずに、ローカルでEmulatorスキルとスキル コンシューマーをテストできます。However, you can test skills and skill consumers locally with the Emulator without an app ID and password.

アプリケーションの構成Application configuration

  1. 必要に応じて、ルート ボットのアプリ ID とパスワードを構成ファイルに追加します。Optionally, add the root bot's app ID and password to the config file.
  2. スキル コンシューマーに応答するスキル ホスト エンドポイント (サービスまたはコールバック URL) を追加します。Add the skill host endpoint (the service or callback URL) to which the skills should reply to the skill consumer.
  3. スキル コンシューマーが使用するスキルごとにエントリを追加します。Add an entry for each skill the skill consumer will use. 各エントリには次のものが含まれます。Each entry includes:
    • スキル コンシューマーが各スキルを識別するために使用する ID。An ID the skill consumer will use to identify each skill.
    • 必要に応じて、スキルのアプリ ID。Optionally, the skill's app ID.
    • スキルのメッセージング エンドポイント。The skill's messaging endpoint.

注意

スキルまたはスキル コンシューマーがアプリ ID とパスワードを使用する場合は、両方とも必要です。If either the skill or skill consumer uses an app ID and password, both must.

SimpleRootBot\appsettings.jsonSimpleRootBot\appsettings.json

必要に応じて、ルート ボットのアプリ ID とパスワードを追加し、エコー スキル ボットのアプリ ID を配列に追加 BotFrameworkSkills します。Optionally, add the root bot's app ID and password and add the app ID for the echo skill bot to the BotFrameworkSkills array.

{
  "MicrosoftAppId": "",
  "MicrosoftAppPassword": "",
  "SkillHostEndpoint": "http://localhost:3978/api/skills/",
  "BotFrameworkSkills": [
    {
      "Id": "EchoSkillBot",
      "AppId": "",
      "SkillEndpoint": "http://localhost:39783/api/messages"
    }
  ]
}

スキルの構成Skills configuration

このサンプルでは、構成ファイル内の各スキルの情報を、"スキル" オブジェクトのコレクションに読み込みます。This sample reads information for each skill in the configuration file into a collection of skill objects.

SimpleRootBot\SkillsConfiguration.csSimpleRootBot\SkillsConfiguration.cs

public class SkillsConfiguration
{
    public SkillsConfiguration(IConfiguration configuration)
    {
        var section = configuration?.GetSection("BotFrameworkSkills");
        var skills = section?.Get<BotFrameworkSkill[]>();
        if (skills != null)
        {
            foreach (var skill in skills)
            {
                Skills.Add(skill.Id, skill);
            }
        }

        var skillHostEndpoint = configuration?.GetValue<string>(nameof(SkillHostEndpoint));
        if (!string.IsNullOrWhiteSpace(skillHostEndpoint))
        {
            SkillHostEndpoint = new Uri(skillHostEndpoint);
        }
    }

    public Uri SkillHostEndpoint { get; }

    public Dictionary<string, BotFrameworkSkill> Skills { get; } = new Dictionary<string, BotFrameworkSkill>();
}

会話 ID ファクトリConversation ID factory

会話 ID ファクトリは、スキルで使用する会話 ID を作成し、スキルの会話 ID から元のユーザー会話 ID を復旧できるようにします。This creates the conversation ID for use with the skill and can recover the original user conversation ID from the skill conversation ID.

このサンプルの会話 ID ファクトリは、次に示す単純なシナリオをサポートしています。The conversation ID factory for this sample supports a simple scenario where:

  • 1 つの特定のスキルを使用するようにルート ボットが設計されている。The root bot is designed to consume one specific skill.
  • ルート ボットとスキルの間で一度にアクティブになる会話は 1 つだけである。The root bot has only one active conversation with a skill at a time.

SimpleRootBot\SkillConversationIdFactory.csSimpleRootBot\SkillConversationIdFactory.cs

public class SkillConversationIdFactory : SkillConversationIdFactoryBase
{
    private readonly ConcurrentDictionary<string, string> _conversationRefs = new ConcurrentDictionary<string, string>();

    public override Task<string> CreateSkillConversationIdAsync(SkillConversationIdFactoryOptions options, CancellationToken cancellationToken)
    {
        var skillConversationReference = new SkillConversationReference
        {
            ConversationReference = options.Activity.GetConversationReference(),
            OAuthScope = options.FromBotOAuthScope
        };
        var key = $"{options.FromBotId}-{options.BotFrameworkSkill.AppId}-{skillConversationReference.ConversationReference.Conversation.Id}-{skillConversationReference.ConversationReference.ChannelId}-skillconvo";
        _conversationRefs.GetOrAdd(key, JsonConvert.SerializeObject(skillConversationReference));
        return Task.FromResult(key);
    }

    public override Task<SkillConversationReference> GetSkillConversationReferenceAsync(string skillConversationId, CancellationToken cancellationToken)
    {
        var conversationReference = JsonConvert.DeserializeObject<SkillConversationReference>(_conversationRefs[skillConversationId]);
        return Task.FromResult(conversationReference);
    }

    public override Task DeleteConversationReferenceAsync(string skillConversationId, CancellationToken cancellationToken)
    {
        _conversationRefs.TryRemove(skillConversationId, out _);
        return Task.CompletedTask;
    }
}

より複雑なシナリオをサポートするには、次のように会話 ID ファクトリを設計します。To support more complex scenarios, design your conversation ID factory so that:

  • create skill conversation ID メソッドで、適切なスキル会話 ID を取得または生成します。The create skill conversation ID method gets or generates the appropriate skill conversation ID.
  • get conversation reference メソッドで、正しいユーザー会話を取得します。The get conversation reference method gets the correct user conversation.

スキル クライアントとスキル ハンドラーSkill client and skill handler

スキル コンシューマーは、スキル クライアントを使用してアクティビティをスキルに転送します。The skill consumer uses a skill client to forward activities to the skill. クライアントは、このためにスキルの構成情報と会話 ID ファクトリを使用します。The client uses the skills configuration information and conversation ID factory to do so.

スキル コンシューマーは、スキル ハンドラーを使用してスキルからアクティビティを受信します。The skill consumer uses a skill handler to receive activities from a skill. ハンドラーは、このために会話 ID ファクトリ、認証構成、および資格情報プロバイダーを使用するほか、ルート ボットのアダプターとアクティビティ ハンドラーへの依存関係を持ちます。The handler uses the conversation ID factory, the authentication configuration, and a credential provider to do so, and also has dependencies on the root bot's adapter and activity handler

SimpleRootBot\Startup.csSimpleRootBot\Startup.cs

// Register the skills client and skills request handler.
services.AddSingleton<SkillConversationIdFactoryBase, SkillConversationIdFactory>();
services.AddHttpClient<SkillHttpClient>();
services.AddSingleton<ChannelServiceHandler, SkillHandler>();

スキルからの HTTP トラフィックは、スキル コンシューマーがスキルにアドバタイズするサービス URL エンドポイントに入されます。HTTP traffic from the skill will come into the service URL endpoint that the skill consumer advertises to the skill. トラフィックをスキル ハンドラーに転送するには、言語固有のエンドポイント ハンドラーを使用します。Use a language-specific endpoint handler to forward traffic to the skill handler.

既定のスキル ハンドラーは次のことを行います。The default skill handler:

  • アプリ ID とパスワードが存在する場合は、認証構成オブジェクトを使用してボット間認証と要求検証の両方を実行します。If an app ID and password are present, uses an authentication configuration object to perform both bot-to-bot authentication and claims validation.
  • 会話 ID ファクトリを使用して、コンシューマー/スキル間の会話を、元のルート/ユーザー間の会話に変換します。Uses the conversation ID factory to translate from the consumer-skill conversation back to the root-user conversation.
  • プロアクティブ メッセージを生成して、スキル コンシューマーがルート/ユーザー間のターン コンテキストを再確立し、アクティビティをユーザーに転送できるようにします。Generates a proactive message so that the skill consumer can reestablish a root-user turn context and forward activities to the user.

アクティビティ ハンドラーのロジックActivity handler logic

注目すべき点として、スキル コンシューマーのロジックでは次の処理を行う必要があります。Of note, the skill consumer logic should:

  • アクティブなスキルの有無を記憶し、必要に応じてそれらのスキルにアクティビティに転送します。Remember whether there are any active skills and forward activities to them as appropriate.
  • スキルへの転送が必要な要求をユーザーが行ったことを確認し、スキルを開始します。Notice when a user makes a request that should be forwarded to a skill, and start the skill.
  • アクティブなスキルからの endOfConversation アクティビティを探し、その完了を確認します。Look for an endOfConversation activity from any active skill, to notice when it completes.
  • 必要に応じて、未完了のスキルをユーザーまたはスキル コンシューマーがキャンセルできるようにするロジックを追加します。If appropriate, add logic to let the user or skill consumer cancel a skill that has not completed yet.
  • 応答がスキル コンシューマーの別のインスタンスに返される可能性があるため、スキルを呼び出す前に状態を保存します。Save state before making the call to a skill, as any response may come back to a different instance of the skill consumer.

SimpleRootBot\Bots\RootBot.csSimpleRootBot\Bots\RootBot.cs

ルート ボットには、会話状態、スキル情報、スキル クライアント、および全般的な構成への依存関係があります。The root bot has dependencies on conversation state, the skills information, the skill client, and the general configuration. これらのオブジェクトは、ASP.NET から依存関係の挿入を通じて提供されます。ASP.NET provides these objects through dependency injection. またルート ボットでは、アクティブなスキルを追跡するための会話状態プロパティ アクセサーが定義されます。The root bot also defines a conversation state property accessor to track which skill is active.

public static readonly string ActiveSkillPropertyName = $"{typeof(RootBot).FullName}.ActiveSkillProperty";
private readonly IStatePropertyAccessor<BotFrameworkSkill> _activeSkillProperty;
private readonly string _botId;
private readonly ConversationState _conversationState;
private readonly SkillHttpClient _skillClient;
private readonly SkillsConfiguration _skillsConfig;
private readonly BotFrameworkSkill _targetSkill;

public RootBot(ConversationState conversationState, SkillsConfiguration skillsConfig, SkillHttpClient skillClient, IConfiguration configuration)
{
    _conversationState = conversationState ?? throw new ArgumentNullException(nameof(conversationState));
    _skillsConfig = skillsConfig ?? throw new ArgumentNullException(nameof(skillsConfig));
    _skillClient = skillClient ?? throw new ArgumentNullException(nameof(skillsConfig));
    if (configuration == null)
    {
        throw new ArgumentNullException(nameof(configuration));
    }

    _botId = configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppIdKey)?.Value;

    // We use a single skill in this example.
    var targetSkillId = "EchoSkillBot";
    _skillsConfig.Skills.TryGetValue(targetSkillId, out _targetSkill);

    // Create state property to track the active skill
    _activeSkillProperty = conversationState.CreateProperty<BotFrameworkSkill>(ActiveSkillPropertyName);
}

次のサンプルでは、アクティビティをスキルに転送するためのヘルパー メソッドが使用されています。This sample has a helper method for forwarding activities to a skill. このメソッドは、スキルを呼び出す前に会話状態を保存し、HTTP 要求が成功したかどうかを確認します。It saves conversation state before invoking the skill, and it checks whether the HTTP request was successful.

private async Task SendToSkill(ITurnContext turnContext, BotFrameworkSkill targetSkill, CancellationToken cancellationToken)
{
    // NOTE: Always SaveChanges() before calling a skill so that any activity generated by the skill
    // will have access to current accurate state.
    await _conversationState.SaveChangesAsync(turnContext, force: true, cancellationToken: cancellationToken);

    // route the activity to the skill
    var response = await _skillClient.PostActivityAsync(_botId, targetSkill, _skillsConfig.SkillHostEndpoint, turnContext.Activity, cancellationToken);

    // Check response status
    if (!(response.Status >= 200 && response.Status <= 299))
    {
        throw new HttpRequestException($"Error invoking the skill id: \"{targetSkill.Id}\" at \"{targetSkill.SkillEndpoint}\" (status is {response.Status}). \r\n {response.Body}");
    }
}

注目すべき点として、ルート ボットには、アクティビティのスキルへの転送、ユーザーの要求でのスキルの開始、およびスキルが完了したときのスキルの停止を行うためのロジックが含まれています。Of note, the root bot includes logic for forwarding activities to the skill, starting the skill at the user's request, and stopping the skill when the skill completes.

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    if (turnContext.Activity.Text.Contains("skill"))
    {
        await turnContext.SendActivityAsync(MessageFactory.Text("Got it, connecting you to the skill..."), cancellationToken);

        // Save active skill in state
        await _activeSkillProperty.SetAsync(turnContext, _targetSkill, cancellationToken);

        // Send the activity to the skill
        await SendToSkill(turnContext, _targetSkill, cancellationToken);
        return;
    }

    // just respond
    await turnContext.SendActivityAsync(MessageFactory.Text("Me no nothin'. Say \"skill\" and I'll patch you through"), cancellationToken);

    // Save conversation state
    await _conversationState.SaveChangesAsync(turnContext, force: true, cancellationToken: cancellationToken);
}

protected override async Task OnEndOfConversationActivityAsync(ITurnContext<IEndOfConversationActivity> turnContext, CancellationToken cancellationToken)
{
    // forget skill invocation
    await _activeSkillProperty.DeleteAsync(turnContext, cancellationToken);

    // Show status message, text and value returned by the skill
    var eocActivityMessage = $"Received {ActivityTypes.EndOfConversation}.\n\nCode: {turnContext.Activity.Code}";
    if (!string.IsNullOrWhiteSpace(turnContext.Activity.Text))
    {
        eocActivityMessage += $"\n\nText: {turnContext.Activity.Text}";
    }

    if ((turnContext.Activity as Activity)?.Value != null)
    {
        eocActivityMessage += $"\n\nValue: {JsonConvert.SerializeObject((turnContext.Activity as Activity)?.Value)}";
    }

    await turnContext.SendActivityAsync(MessageFactory.Text(eocActivityMessage), cancellationToken);

    // We are back at the root
    await turnContext.SendActivityAsync(MessageFactory.Text("Back in the root bot. Say \"skill\" and I'll patch you through"), cancellationToken);

    // Save conversation state
    await _conversationState.SaveChangesAsync(turnContext, cancellationToken: cancellationToken);
}

オン ターン エラー ハンドラーOn turn error handler

エラーが発生すると、アダプターは会話状態をクリアしてユーザーとの会話をリセットし、エラー状態を解消します。When an error occurs, the adapter clears conversation state to reset the conversation with the user and avoid persisting an error state.

スキル コンシューマーの会話状態をクリアする前に、アクティブなスキルに会話の終了アクティビティを送信する方法をお試しください。It's a good practice to send an end of conversation activity to any active skill before clearing conversation state in the skill consumer. これにより、スキル コンシューマーが会話を解放する前に、コンシューマ/スキル間の会話に関連するリソースをスキルが解放できるようになります。This lets the skill release any resources associated with the consumer-skill conversation before the skill consumer releases the conversation.

SimpleRootBot\AdapterWithErrorHandler.csSimpleRootBot\AdapterWithErrorHandler.cs

このサンプルでは、ターン エラー ロジックがいくつかのヘルパー メソッドに分割されています。In this sample, the turn error logic is split up among a few helper methods.

private async Task HandleTurnError(ITurnContext turnContext, Exception exception)
{
    // Log any leaked exception from the application.
    // NOTE: In production environment, you should consider logging this to
    // Azure Application Insights. Visit https://aka.ms/bottelemetry to see how
    // to add telemetry capture to your bot.
    _logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}");

    await SendErrorMessageAsync(turnContext, exception);
    await EndSkillConversationAsync(turnContext);
    await ClearConversationStateAsync(turnContext);
}

private async Task SendErrorMessageAsync(ITurnContext turnContext, Exception exception)
{
    try
    {
        // Send a message to the user
        var errorMessageText = "The bot 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
        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 EndSkillConversationAsync(ITurnContext turnContext)
{
    if (_skillClient == null || _skillsConfig == null)
    {
        return;
    }

    try
    {
        // Inform the active skill that the conversation is ended so that it has
        // a chance to clean up.
        // Note: ActiveSkillPropertyName is set by the RooBot while messages are being
        // forwarded to a Skill.
        var activeSkill = await _conversationState.CreateProperty<BotFrameworkSkill>(RootBot.ActiveSkillPropertyName).GetAsync(turnContext, () => null);
        if (activeSkill != null)
        {
            var botId = _configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppIdKey)?.Value;

            var endOfConversation = Activity.CreateEndOfConversationActivity();
            endOfConversation.Code = "RootSkillError";
            endOfConversation.ApplyConversationReference(turnContext.Activity.GetConversationReference(), true);

            await _conversationState.SaveChangesAsync(turnContext, true);
            await _skillClient.PostActivityAsync(botId, activeSkill, _skillsConfig.SkillHostEndpoint, (Activity)endOfConversation, CancellationToken.None);
        }
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, $"Exception caught on attempting to send EndOfConversation : {ex}");
    }
}

private async Task ClearConversationStateAsync(ITurnContext turnContext)
{
    try
    {
        // Delete the conversationState for the current conversation to prevent the
        // bot from getting stuck in a error-loop caused by being in a bad state.
        // ConversationState should be thought of as similar to "cookie-state" in a Web pages.
        await _conversationState.DeleteAsync(turnContext);
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, $"Exception caught on attempting to Delete ConversationState : {ex}");
    }
}

スキル エンドポイントSkills endpoint

ボットでは、受信したスキル アクティビティをルート ボットのスキル ハンドラーに転送するエンドポイントが定義されます。The bot defines an endpoint that forwards incoming skill activities to the root bot's skill handler.

SimpleRootBot\Controllers\SkillController.csSimpleRootBot\Controllers\SkillController.cs

[ApiController]
[Route("api/skills")]
public class SkillController : ChannelServiceController
{
    public SkillController(ChannelServiceHandler handler)
        : base(handler)
    {
    }
}

サービス登録Service registration

要求検証を含む認証構成オブジェクトを、すべての追加オブジェクトと共に組み込みます。Include an authentication configuration object with any claims validation, plus all the additional objects. このサンプルでは、ユーザーとスキルの両方のアクティビティを検証するために、同じ認証構成ロジックを使用します。This sample uses the same authentication configuration logic for validating activities from both users and skills.

SimpleRootBot\Startup.csSimpleRootBot\Startup.cs

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers().AddNewtonsoftJson();

    // Configure credentials
    services.AddSingleton<ICredentialProvider, ConfigurationCredentialProvider>();

    // Register the skills configuration class
    services.AddSingleton<SkillsConfiguration>();

    // Register AuthConfiguration to enable custom claim validation.
    services.AddSingleton(sp => new AuthenticationConfiguration { ClaimsValidator = new Microsoft.BotBuilderSamples.SimpleRootBot.Authentication.AllowedSkillsClaimsValidator(sp.GetService<SkillsConfiguration>()) });

    // Register the Bot Framework Adapter with error handling enabled.
    // Note: some classes use the base BotAdapter so we add an extra registration that pulls the same instance.
    services.AddSingleton<BotFrameworkHttpAdapter, AdapterWithErrorHandler>();
    services.AddSingleton<BotAdapter>(sp => sp.GetService<BotFrameworkHttpAdapter>());

    // Register the skills client and skills request handler.
    services.AddSingleton<SkillConversationIdFactoryBase, SkillConversationIdFactory>();
    services.AddHttpClient<SkillHttpClient>();
    services.AddSingleton<ChannelServiceHandler, SkillHandler>();

    // Register the storage we'll be using for User and Conversation state. (Memory is great for testing purposes.)
    services.AddSingleton<IStorage, MemoryStorage>();

    // Register Conversation state (used by the Dialog system itself).
    services.AddSingleton<ConversationState>();

    // Register the bot as a transient. In this case the ASP Controller is expecting an IBot.
    services.AddTransient<IBot, RootBot>();
}

ルート ボットのテストTest the root bot

スキル コンシューマーは通常のボットと同様にエミュレーターでテストできますが、スキルとスキル コンシューマーの両方のボットを同時に実行する必要があります。You can test the skill consumer in the Emulator as if it were a normal bot; however, you need to run both the skill and skill consumer bots at the same time. スキルを構成する方法については、「スキルを実装する」を参照してください。See how to implement a skill for information on how to configure the skill.

最新の Bot Framework Emulator をダウンロードしてインストールしますDownload and install the latest Bot Framework Emulator

  1. エコー スキル ボットと単純なルート ボットをお使いのマシンでローカルに実行します。Run the echo skill bot and simple root bot locally on your machine. 手順が必要な場合は README 、C# 、JavaScript、Java、またはPython のサンプルのファイルを参照してください。If you need instructions, refer to the README file for the C#, JavaScript, Java, or Python sample.
  2. 次に示すように、エミュレーターを使用してボットをテストします。Use the Emulator to test the bot as shown below. または メッセージをスキルに送信すると、スキルは応答メッセージに加えてアクティビティをルート ボット end stop endOfConversation に送信します。When you send an end or stop message to the skill, the skill sends to the root bot an endOfConversation activity, in addition to the reply message. endOfConversation アクティビティの code プロパティにより、スキルが正常に完了したことが示されます。The endOfConversation activity's code property indicates that the skill completed successfully.

スキル コンシューマーのテスト

関連情報Additional information

より複雑なルート ボットを実装する場合に検討すべき事項を次に示します。Here are some things to consider when implementing a more complex root bot.

ユーザーが複数ステップのスキルをキャンセルできるようにするTo allow the user to cancel a multi-step skill

ルート ボットでは、ユーザーのメッセージをアクティブなスキルに転送する前に確認する必要があります。The root bot should check the user's message before forwarding it to the active skill. ユーザーが現在のプロセスのキャンセルを求めた場合、ルート ボットはメッセージを転送する代わりに endOfConversation アクティビティをスキルに送信できます。If the user wants to cancel the current process, the root bot can send an endOfConversation activity to the skill, instead of forwarding the message.

ルート ボットとスキル ボットの間でデータをやり取りするTo exchange data between the root and skill bots

スキル コンシューマーでは、スキルにパラメーターを送信するために、スキルに送信するメッセージに value プロパティを設定できます。To send parameters to the skill, the skill consumer can set the value property on messages it sends to the skill. スキルから戻り値を受信するために、スキル コンシューマーでは、スキルから endOfConversation アクティビティが送信されたときに value プロパティを確認する必要があります。To receive return values from the skill, the skill consumer should check the value property when the skill sends an endOfConversation activity.

複数のスキルを使用するTo use multiple skills

  • アクティブなスキルがある場合、ルート ボットはそのスキルを特定し、ユーザーのメッセージを適切なスキルに転送する必要があります。If a skill is active, the root bot needs to determine which skill is active and forward the user's message to the correct skill.
  • アクティブなスキルがない場合、ルート ボットは、ボットの状態とユーザーの入力を基に、開始するスキル (存在する場合) を特定する必要があります。If no skill is active, the root bot needs to determine which skill to start, if any, based on bot state and the user's input.
  • ユーザーが複数の同時スキル間を切り替えられるようにする場合は、ルート ボットで、ユーザーのメッセージを転送する前にユーザーが対話しようとしているアクティブなスキルを特定する必要があります。If you want to allow the user to switch between multiple concurrent skills, the root bot needs to determine which of the active skills the user is intending to interact with before forwarding the user's message.

期待される応答の配信モードを使用するにはTo use a delivery mode of expect replies

応答 配信モードを使用するには、次のようにします。To use the expect replies delivery mode:

  • ターンコンテキストからアクティビティを複製します。Clone the activity from the turn context.
  • ルート bot からスキルにアクティビティを送信する前に、新しいアクティビティの [ 配信モード ] プロパティを "ExpectReplies" に設定します。Set the delivery mode property of the new activity to "ExpectReplies" before sending the activity from root bot to skill.
  • 要求応答から返された 呼び出し応答 本文から、予想される 応答を読み取ります。Read expected replies from the invoke response body returned from the request response.
  • ルート bot 内で、または元の要求を開始したチャネルに送信することによって、各アクティビティを処理します。Process each activity, either within the root bot or by sending it on to the channel that initiated the original request.

期待される応答は、アクティビティに応答する bot が、アクティビティを受け取った bot の同じインスタンスである必要がある場合に役立ちます。Expect replies can be useful in situations in which the bot that replies to an activity needs to be the same instance of the bot that received the activity.