🐛

Microsoft 365 Agents SDK (Microsoft Bot Framework) でダイアログのステップが進まない

2025/02/05に公開

はじめに

Microsoft 365 Agents SDK (Microsoft Bot Framework) でダイアログを使ったボットを作っているとき、次のステップに進まないことがあります。

問題点

サンプルとして 3 つのステップを持つダイアログを作成します。

public class MainDialog : ComponentDialog
{

    protected override Task OnInitializeAsync(DialogContext dialogContext)
    {
        _ = this.AddDialog(new WaterfallDialog(
            nameof(WaterfallDialog),
            [
                this.Step1Async,
                this.Step2Async,
                this.Step3Async
            ]));
        _ = this.AddDialog(new TextPrompt(nameof(TextPrompt)));
        this.InitialDialogId = nameof(WaterfallDialog);
        return base.OnInitializeAsync(dialogContext);
    }

    private async Task<DialogTurnResult> Step1Async(WaterfallStepContext stepContext, CancellationToken cancellationToken)
    {
        return await stepContext.PromptAsync(
            nameof(TextPrompt),
            new PromptOptions
            {
              Prompt = MessageFactory.Text("This is the 1st message")
            },
            cancellationToken
        );
    }

    private async Task<DialogTurnResult> Step2Async(WaterfallStepContext stepContext, CancellationToken cancellationToken)
    {
        return await stepContext.PromptAsync(
            nameof(TextPrompt),
            new PromptOptions
            {
              Prompt = MessageFactory.Text("This is the 2nd message")
            },
            cancellationToken
        );
    }

    private async Task<DialogTurnResult> Step3Async(WaterfallStepContext stepContext, CancellationToken cancellationToken)
    {
        return await stepContext.PromptAsync(
            nameof(TextPrompt),
            new PromptOptions
            {
              Prompt = MessageFactory.Text("This is the 3rd message")
            },
            cancellationToken
        );
    }

}

この場合、以下の順番でボットからのメッセージが表示されるはずです。

  • This is the 1st message
  • This is the 2nd message
  • This is the 3rd message

しかし実際は This is the 1st message が繰り返し表示されます。

原因

OnTurnAsync メソッドで ConversationStateUserState の保存を基底クラスの OnTurnAsync メソッドの呼び出しより前に実施するとこの事象は発生します。

public class DialogBot<T>(
    T dialog,
    ConversationState conversationState,
    UserState userState
) : ActivityHandler where T: Dialog
{

    private readonly Dialog dialog = dialog;
    private readonly ConversationState conversationState = conversationState;
    private readonly UserState userState = userState;

    public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
    {
        _ = this.conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
        _ = this.userState.SaveChangesAsync(turnContext, false, cancellationToken);
        await base.OnTurnAsync(turnContext, cancellationToken);
    }

}

解決方法

基底クラスの OnTurnAsync メソッドの呼び出しより後に実施するのが正しいです。

  public class DialogBot<T>(
      T dialog,
      ConversationState conversationState,
      UserState userState
  ) : ActivityHandler where T: Dialog
  {

      private readonly Dialog dialog = dialog;
      private readonly ConversationState conversationState = conversationState;
      private readonly UserState userState = userState;

      public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
      {
+         await base.OnTurnAsync(turnContext, cancellationToken);
          _ = this.conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
          _ = this.userState.SaveChangesAsync(turnContext, false, cancellationToken);
-         await base.OnTurnAsync(turnContext, cancellationToken);
      }

  }

OnTurnAsync メソッドは OnMessageActivityAsync メソッドをはじめとしたイベント ハンドラーの呼び出しを行なっています。そのため、保存を先に行なってしまうと、ダイアログの結果が正しく保存されないことになります。

修正するとステップは正しく進みます。

おわりに

慣習的に、基底クラスのメソッドの呼び出しは最後に書くことが多いため、原因に気づかないことが多いです。できるだけ間違えないようにしたいですね。

Discussion