🐛
Microsoft 365 Agents SDK (Microsoft Bot Framework) でダイアログのステップが進まない
はじめに
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
メソッドで ConversationState
や UserState
の保存を基底クラスの 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