Microsoft Bot Framework で ChatGPT を使えるようにする
はじめに
世間では ChatGPT の話題で持ちきりですが、Azure にはボットを作成するための Azure Bot Service および Microsoft Bot Framework があります。Microsoft Bot Framework では、キーワードの抽出は、手動または LUIS (現在は Azure Cognitive Service for Language) を使用していました。ここを ChatGPT (OpenAI) に置き換えることで、より自然な対話ができるようになります。
Teams のカスタム ボット、メッセージ拡張、会議アプリなどの機能も Azure Bot Service が利用されています。この点においても ChatGPT (OpenAI) の活用が期待できます。すでに Microsoft 365 Copilot の拡張としてプラグインが開発できるとアナウンスされており、Teams AI ライブラリがプレビュー公開されています。
とはいえ、いきなり Teams AI ライブラリを使って開発するのは難易度が高いです。まずはコアの部分である Microsoft Bot Framework で ChatGPT をどのように利用するかを紹介します。
サンプル コード
実行手順 (基本)
プロジェクトの作成
今回は EchoBot のテンプレートをベースに作成します。
まずは EchoBot のテンプレートをダウンロードします。
dotnet new -i Microsoft.Bot.Framework.CSharp.EchoBot
プロジェクトを作成します。なお、現時点では .NET 7 SDK がインストールされている場合は動作しないため、.NET 6 SDK を使用してください。
dotnet new echobot -n Karamem0.SampleApplication
パッケージの追加
OpenAI クライアント ライブラリを追加します。
dotnet add package Azure.AI.OpenAI --prerelease
コードの修正
appsettings.json
OpenAI のサイトから API キーを取得して設定します。
{
"MicrosoftAppType": "",
"MicrosoftAppId": "",
"MicrosoftAppPassword": "",
"MicrosoftAppTenantId": "",
+ "OpenAIApiKey": "{{openai-api-key}}"
}
EchoBot.cs
コンストラクタを追加して OpenAIClient のインスタンスを作成します。API キーは appsettings.json で設定したものを使用します。
private readonly OpenAIClient chatClient;
public EchoBot(IConfiguration configuration)
{
this.chatClient = new OpenAIClient(configuration.GetValue<string>("OpenAIApiKey"));
}
OnMessageActivityAsync メソッドを修正します。
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
var chatCompletionsOptions = new ChatCompletionsOptions();
chatCompletionsOptions.Messages.Add(new ChatMessage(
ChatRole.System,
"あなたは Microsoft Bot Framework から呼び出されるアシスタントです。ユーザーからの質問に回答してください。"
));
chatCompletionsOptions.Messages.Add(new ChatMessage(
ChatRole.User,
turnContext.Activity.Text
));
var chatCompletion = await this.chatClient.GetChatCompletionsAsync(
"gpt-3.5-turbo",
chatCompletionsOptions,
cancellationToken
);
var replyText = chatCompletion.Value.Choices[0].Message.Content;
await turnContext.SendActivityAsync(MessageFactory.Text(replyText, replyText), cancellationToken);
}
エミュレータでの確認
Bot Framework Emulator を使って動作を確認します。正しく回答できていることが確認できます。
実行手順 (応用)
この状態では 1 問 1 答となるため、ChatGPT の特長である文脈の理解ができません。そこで会話履歴を保持するようにします。Microsoft Bot Framework にはユーザーごとの状態管理機能があるため、これを使用します。状態はインメモリでも管理できますが、今回は Azure Blob Storage に格納します。
Azurite のインストール
Azurite は Azure Storage Account のエミュレーターです。これまでの Azure Storage Emulator は非推奨となっているため、Azurite を使用してください。
パッケージの追加
Azure Blob Storage を扱うためのパッケージを追加します。
dotnet add package Microsoft.Bot.Builder.Azure.Blobs
コードの修正
appsettings.json
Azure Blob Storage (Azurite) への接続情報を追加します。
{
"MicrosoftAppType": "",
"MicrosoftAppId": "",
"MicrosoftAppPassword": "",
"MicrosoftAppTenantId": "",
"OpenAIApiKey": "{{openai-api-key}}",
+ "AzureBlobStorageConnectionString": "UseDevelopmentStorage=true",
+ "AzureBlobStorageContainerName": "bot-states"
}
Startup.cs
状態管理のための構成情報を追加します。
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient().AddControllers().AddNewtonsoftJson(options =>
{
options.SerializerSettings.MaxDepth = HttpHelper.BotMessageSerializerSettings.MaxDepth;
});
services.AddSingleton<BotFrameworkAuthentication, ConfigurationBotFrameworkAuthentication>();
services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();
services.AddTransient<IBot, Bots.EchoBot>();
+ services.AddSingleton<IStorage>(new BlobsStorage(
+ this.Configuration.GetValue<string>("AzureBlobStorageConnectionString"),
+ this.Configuration.GetValue<string>("AzureBlobStorageContainerName")));
+ services.AddSingleton<ConversationState>();
}
EchoBot.cs
コンストラクタで ConversationState を受け取るようにします。
private readonly OpenAIClient chatClient;
+ private readonly ConversationState conversationState;
public EchoBot(IConfiguration configuration, ConversationState conversationState)
{
this.chatClient = new OpenAIClient(configuration.GetValue<string>("OpenAIApiKey"));
+ this.conversationState = conversationState;
}
OnMessageActivityAsync メソッドを書き換えます。過去の会話は ConversationState を使って保持し、OpenAI を呼び出す際に追加します。トークン長の制限があるため、古い会話は切り捨てます。
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
var accessor = this.conversationState.CreateProperty<List<ChatMessage>>(nameof(ChatMessage));
var messages = await accessor.GetAsync(turnContext, () => new(), cancellationToken);
while (messages.Count > 8)
{
messages.RemoveAt(0);
}
var chatCompletionsOptions = new ChatCompletionsOptions();
chatCompletionsOptions.Messages.Add(new ChatMessage(
ChatRole.System,
"あなたは Microsoft Bot Framework から呼び出されるアシスタントです。ユーザーからの質問に回答してください。"
));
foreach (var message in messages)
{
chatCompletionsOptions.Messages.Add(message);
}
chatCompletionsOptions.Messages.Add(new ChatMessage(ChatRole.User, turnContext.Activity.Text));
var chatCompletion = await this.chatClient.GetChatCompletionsAsync(
"gpt-3.5-turbo",
chatCompletionsOptions,
cancellationToken
);
var replyText = chatCompletion.Value.Choices[0].Message.Content;
await turnContext.SendActivityAsync(MessageFactory.Text(replyText, replyText), cancellationToken);
messages.Add(new ChatMessage(ChatRole.User, turnContext.Activity.Text));
messages.Add(new ChatMessage(ChatRole.Assistant, replyText));
await accessor.SetAsync(turnContext, messages, cancellationToken);
await this.conversationState.SaveChangesAsync(turnContext, cancellationToken: cancellationToken);
}
エミュレータでの確認
Bot Framework Emulator で確認します。前の会話の内容を理解して回答できていることが確認できます。
おわりに
ここまでの手順で、Azure Bot Service を利用して Microsoft Teams、Slack、LINE などのさまざまな外部サービスと連携できるようになります。今回は OpenAI の API を利用しましたが、Azure OpenAI Service を使う場合も OpenAIClient の初期化方法を一部変更するだけで対応可能です。
このサンプルは ChatGPT との対話を実現するシンプルなものです。プロンプトを工夫することで、ユーザーの入力内容に応じたロジックの推論や、返却する内容の生成など、より高度な活用も可能です。ぜひ本記事を参考に、さまざまなシナリオで Bot Framework と ChatGPT の連携を試してみてください。
Discussion