ユーザーへのプロアクティブな通知の送信

適用対象: SDK v4

通常、ボットは、ユーザーからのメッセージの受信に応じて、ユーザーに直接メッセージを送信します。 場合によっては、ボットが プロアクティブ メッセージ (ユーザーから発信されていない刺激に応答するメッセージ) を送信する必要がある場合があります。

プロアクティブ メッセージは、さまざまなシナリオで役立ちます。 たとえば、ユーザーが製品の価格を監視するようにボットに依頼していた場合、ボットは、製品の価格が 20% 下がった場合にユーザーにアラートを発行できます。 ユーザーの質問に対する回答をまとめるのに時間が必要な場合、ボットは、時間がかかることをユーザーに通知して、会話を続けられるようにします。 質問の回答がまとまったら、ボットは、その情報をユーザーと共有します。

注意

この記事では、ボットのプロアクティブ メッセージに関する一般的な情報について説明します。 Microsoft Teamsのプロアクティブ メッセージの詳細については、

前提条件

  • ボットの基本を理解する。
  • C#JavaScriptJava、または Pythonプロアクティブ メッセージ サンプルのコピー。 このサンプルは、この記事でプロアクティブ メッセージングを説明するために使用します。

プロアクティブ サンプルについて

一般に、アプリケーションとしてのボットにはいくつかのレイヤーがあります。

  • HTTP 要求を受け入れ、特にメッセージング エンドポイントをサポートできる Web アプリケーション。
  • チャネルとの接続を処理するアダプター。
  • ターンのハンドラー。通常は ボット アプリの会話推論を処理するボット クラスにカプセル化されます。

ユーザーからの受信メッセージに応答して、アプリはアダプターの プロセス アクティビティ メソッドを呼び出します。これにより、ターンとターンのコンテキストが作成され、ミドルウェア パイプラインが呼び出され、ボットのターン ハンドラーが呼び出されます。

プロアクティブ メッセージを開始するには、ボット アプリケーションが追加の入力を受信できる必要があります。 プロアクティブ メッセージを開始するためのアプリケーション ロジックは、SDK の範囲外です。 このサンプルでは、標準メッセージ エンドポイントに加えて、通知エンドポイントを使用してプロアクティブ ターンをトリガーします。

この通知エンドポイントでの GET 要求に応答して、アプリはアダプターの continue conversation メソッドを呼び出します。これは、 プロセス アクティビティ メソッドと同様に動作します。 continue conversation メソッド:

  • プロアクティブ ターンに使用するユーザーとコールバック メソッドの適切な会話参照を受け取ります。
  • プロアクティブ ターンのイベント アクティビティとターン コンテキストを作成します。
  • アダプターのミドルウェア パイプラインを呼び出します。
  • 指定されたコールバック メソッドを呼び出します。
  • ターン コンテキストでは、メッセージ交換参照を使用して、ユーザーにメッセージを送信します。

このサンプルには、次の図に示すように、ボット、メッセージ エンドポイント、およびプロアクティブ メッセージをユーザーに送信するために使用される追加の通知エンドポイントがあります。

proactive bot

会話参照を取得して格納する

Bot Framework Emulatorがボットに接続すると、ボットは 2 つの会話更新アクティビティを受け取ります。 次に示すように、ボットの会話更新アクティビティ ハンドラーで、会話の参照が取得され、ディクショナリに格納されます。

Bots\ProactiveBot.cs

private void AddConversationReference(Activity activity)
{
    var conversationReference = activity.GetConversationReference();
    _conversationReferences.AddOrUpdate(conversationReference.User.Id, conversationReference, (key, newValue) => conversationReference);
}

protected override Task OnConversationUpdateActivityAsync(ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
    AddConversationReference(turnContext.Activity as Activity);

    return base.OnConversationUpdateActivityAsync(turnContext, cancellationToken);
}

会話参照には、アクティビティが存在する 会話 を記述する conversation プロパティが含まれています。 会話には、会話に参加しているユーザーを一覧表示する ユーザー プロパティと、現在のアクティビティへの応答が送信される場所を示す サービス URL プロパティが含まれます。 プロアクティブ メッセージをユーザーに送信するには、有効な会話の参照が必要です。 (Teams チャネルの場合、サービス URL はリージョン化されたサーバーにマップされます)。

注意

実際のシナリオでは、会話の参照はデータベースに保持されます。メモリ内のオブジェクトは使用されません。

プロアクティブ メッセージを送信する

2 つ目のコントローラーである 通知 コントローラーは、プロアクティブ メッセージをユーザーに送信する役割を担います。 次の手順を使用して、プロアクティブ メッセージを生成します。

  1. プロアクティブ メッセージの送信先となる会話の参照を取得します。
  2. アダプターの continue conversation メソッドを呼び出し、使用する会話参照とターン ハンドラー デリゲートを指定します。 (continue conversation メソッドは、参照される会話のターン コンテキストを生成し、指定されたターン ハンドラー デリゲートを呼び出します)。
  3. デリゲートでは、ターン コンテキストを使用してプロアクティブ メッセージを送信します。 ここで、デリゲートは通知コントローラーで定義され、プロアクティブ メッセージがユーザーに送信されます。

注意

各チャネルでは安定したサービス URL を使用する必要があります。URL は時間の経過と同時に変更される可能性があります。 サービス URL の詳細については、Bot Framework アクティビティ スキーマの 基本的なアクティビティ構造サービス URL のセクションを参照してください。

サービス URL が変更されると、以前の会話参照は無効になり、 会話を続行 するための呼び出しによってエラーまたは例外が生成されます。 この場合、ボットは、プロアクティブ メッセージを再び送信する前に、ユーザーの新しい会話参照を取得する必要があります。

Controllers\NotifyController .cs

ボットの通知ページが要求されるたびに、通知コントローラーは、ディクショナリから会話の参照を取得します。 次に、コントローラーは ContinueConversationAsync メソッドと BotCallback メソッドを使用して、プロアクティブ メッセージを送信します。

[Route("api/notify")]
[ApiController]
public class NotifyController : ControllerBase
{
    private readonly IBotFrameworkHttpAdapter _adapter;
    private readonly string _appId;
    private readonly ConcurrentDictionary<string, ConversationReference> _conversationReferences;

    public NotifyController(IBotFrameworkHttpAdapter adapter, IConfiguration configuration, ConcurrentDictionary<string, ConversationReference> conversationReferences)
    {
        _adapter = adapter;
        _conversationReferences = conversationReferences;
        _appId = configuration["MicrosoftAppId"] ?? string.Empty;
    }

    public async Task<IActionResult> Get()
    {
        foreach (var conversationReference in _conversationReferences.Values)
        {
            await ((BotAdapter)_adapter).ContinueConversationAsync(_appId, conversationReference, BotCallback, default(CancellationToken));
        }
        
        // Let the caller know proactive messages have been sent
        return new ContentResult()
        {
            Content = "<html><body><h1>Proactive messages have been sent.</h1></body></html>",
            ContentType = "text/html",
            StatusCode = (int)HttpStatusCode.OK,
        };
    }

    private async Task BotCallback(ITurnContext turnContext, CancellationToken cancellationToken)
    {
        await turnContext.SendActivityAsync("proactive hello");
    }
}

プロアクティブ メッセージを送信するには、アダプターにボット用のアプリ ID が必要です。 ボットのアプリ ID は、運用環境で使用できます。 Emulatorを使用してボットをローカルでテストするには、空の文字列 ("") を使用します。

ボットをテストする

  1. Bot Framework Emulator をインストールします (まだインストールしていない場合)。
  2. ご自身のマシンを使ってローカルでサンプルを実行します。
  3. Emulatorを起動し、ボットに接続します。
  4. お使いのボットの API/通知ページに読み込みます。 これにより、Emulatorにプロアクティブ メッセージが生成されます。

関連情報

この記事で使用するサンプルに加えて、GitHubでは追加のサンプルを使用できます。

要件

プロアクティブ メッセージを送信する前に、ボットに 会話参照が必要です。 ボットは、ユーザーから受信した任意のアクティビティから会話参照を取得できますが、通常は、ボットがプロアクティブ メッセージを送信する前に、少なくとも 1 回はボットと対話する必要があります。

多くのチャネルでは、ユーザーがボットに少なくとも 1 回メッセージを送信していない限り、ボットがユーザーにメッセージを送信することを禁止しています。 一部のチャネルでは例外が許可されます。 たとえば、Teams チャネルでは、ボットを含む既に確立されているグループ会話の個人にプロアクティブ (または 1 対 1) のメッセージを送信できます。

設計上の考慮事項

お使いのボットでプロアクティブ メッセージを実装するときは、短い時間で複数のプロアクティブ メッセージを送信しないでください。 一部のチャネルでは、ボットがユーザーにメッセージを送信できる頻度に制限が設定され、これらの制限に違反した場合は、ボットが無効になります。

アドホック型のプロアクティブ メッセージは、最も単純な種類のプロアクティブ メッセージです。 ボットは会話が開始されると単純に会話にメッセージを差し挟みます。つまり、ユーザーが現在、ボットと別の話題で会話中であり、話題を変えるつもりがない場合でも考慮しません。

通知をより円滑に処理するには、会話フローに通知を統合するための他の方法を検討してください (会話の状態にフラグを設定する方法や、通知をキューに追加する方法など)。

プロアクティブ ターンについて

continue conversation メソッドは、会話参照とターン コールバック ハンドラーを使用して次の処理を行います。

  1. ボット アプリケーションがプロアクティブ メッセージを送信できるターンを作成します。 アダプターは、このターンのアクティビティを event 作成し、その名前を "ContinueConversation" に設定します。
  2. アダプターのミドルウェア パイプラインを経由してターンを送信します。
  3. ターン コールバック ハンドラーを呼び出してカスタム ロジックを実行します。

プロアクティブ メッセージ のサンプルでは、ターン コールバック ハンドラーは通知コントローラーで定義され、ボットの通常のターン ハンドラーを介してプロアクティブ アクティビティを送信することなく、メッセージを会話に直接送信します。 また、このサンプル コードでは、プロアクティブ ターンでボットの状態にアクセスしたり更新したりすることはありません。

多くのボットはステートフルであり、状態を使用して複数のターンで会話を管理します。 会話の続行メソッドによってターン コンテキストが作成されると、ターンには適切なユーザーと会話の状態が関連付けられます。また、プロアクティブ ターンをボットのロジックに統合できます。 プロアクティブ メッセージを認識するためにボット ロジックが必要な場合は、それを行うためのいくつかのオプションがあります。 次の操作を行うことができます。

  • ボットのターン ハンドラーをターン コールバック ハンドラーとして指定します。 その後、ボットは "ContinueConversation" イベント アクティビティを受け取ります。
  • ターン コールバック ハンドラーを使用して、最初にターン コンテキストに情報を追加してから、ボットのターン ハンドラーを呼び出します。

どちらの場合も、プロアクティブ イベントを処理するようにボット ロジックを設計する必要があります。

次のステップ