Azure OpenAI Service On Your Data は、Microsoft Build 2023 でパブリックプレビューが開始された機能です。今回は .NET エンジニアの視点で On Your Data を使ってみました。
Azure OpenAI Service On Your Dataとは
Azure OpenAI On Your Data では、インターネットには公開できない独自のドキュメントに基づいて LLM に回答させること(グラウンディング)ができます。しかも、Azure の PaaS として簡単にできるところが嬉しいです。
zenn.dev
シナリオ
社内の就業規則をもとにユーザーからの質問に回答する総務担当アシスタントを作成します。
事前準備として、就業規則のドキュメントを Blob Storage にアップロードします。
Azure OpenAI Sutido の ChatGPT プレイグラウンドで試します。モデルは、先日東日本リージョンで使えるようになった gpt-4 を使います。プレイグラウンドの「add your data」から、Cognitive Search にインデックスを作成します。
Cognitive Search に作成されたインデックスは、いい感じにドキュメントを分割して作られています。インデクサーは作成されないので、インデックスの更新は別途対応が必要です。
システムメッセージを設定して質問すると、就業規則をもとに回答してくれます。
REST API を呼び出してみる
今回のシナリオを .NET アプリケーションに組み込むためには、Azure OpenAI の Completions extensions API を呼び出す必要があります。
ドキュメントに記載されている仕様通りに、Postman で REST API を実行してみます。
まずは Azure OpenAI への認証として、ヘッダーに api-key をセットします。
リクエストの Body に dataSources と messages を JSON で渡すと、プレイグラウンドと同様の結果を取得できます。
.NET の API Client を自動生成する
HttpClient を使って HTTP リクエストを組み立てるのは面倒なので、NSwag を使って Swagger.json から .NET の API Client を自動生成します。
NSwag のコード生成機能にはいくつかのオプションがありますが、今回はシンプルに Windows デスクトップ アプリを使います。
NSwagStudio をインストールして、前述の Swagger.json を貼り付けます。
- Runtime で .NET70 を指定
- Namespace で MyApiClient を変更
- Interface を使うように指定(好みの問題なのでオプションです)
Generate Outputs ボタンを押すと、C# のコードが自動生成されます。
コンソールアプリケーションから API Client を呼び出してみる
先ほどの自動生成した API Client を使って実装してみます。.NET 7 のコンソールアプリを作り、NuGet パッケージをインストールします。
Install-Package Newtonsoft.Json -Version 13.0.3 Install-Package Microsoft.Extensions.Configuration.Binder -Version 7.0.4 Install-Package Microsoft.Extensions.Configuration.UserSecrets -Version 7.0.0
Microsoft.Extensions.Configuration 関連の NuGet パッケージは、Azure OpenAI に接続する資格情報を管理するためにインストールしました。
{ "AzureOpenAISettings": { "CognitiveSearchEndpoint": "https://xxx.search.windows.net", "CognitiveSearchKey": "xxx", "CognitiveSearchIndexName": "azureblob-index", "Endpoint": "https://xxx.openai.azure.com/openai", "ApiVersion": "2023-06-01-preview", "ApiKey": "xxx", "DeploymentId": "gpt-4" } }
secret.json に各プロパティを定義したら、バインドするクラスを作ります。
internal class AzureOpenAISettings { public required string CognitiveSearchEndpoint { get; set; } public required string CognitiveSearchKey { get; set; } public required string CognitiveSearchIndexName { get; set; } public required string Endpoint { get; set; } public required string ApiVersion { get; set; } public required string ApiKey { get; set; } public required string DeploymentId { get; set; } }
ConfigurationBuilder
を使って、secret.json を読み込んで AzureOpenAISettings
クラスにバインドします。
var settings = new ConfigurationBuilder() .AddUserSecrets<Program>() .Build() .GetSection(nameof(AzureOpenAISettings)).Get<AzureOpenAISettings>() ?? throw new NullReferenceException();
リクエストの Body は、ExtensionsChatCompletionsRequest
クラスが自動生成されています。DataSource
には Cognitive Search の情報を設定し、Messages
にはシステムロールにアシスタントのコンテキスト、ユーザーロールには質問を設定します。
Console.WriteLine("アシスタントのセットアップ中・・・"); var body = new ExtensionsChatCompletionsRequest { DataSources = new[] { new DataSource { Type = "AzureCognitiveSearch", Parameters = new { endpoint = settings.CognitiveSearchEndpoint, key = settings.CognitiveSearchKey, indexName = settings.CognitiveSearchIndexName } } }, Messages = new[] { new Message { Role = MessageRole.System, Content = """ あなたは社内の総務担当です。就業規則をもとにして、ユーザーからの質問に回答してください。 回答の際には出典を出力してください。 回答が分からない場合は、「分かりません」と回答してください。 """ }, new Message { Role = MessageRole.User, Content = "社員が結婚するときの特別休暇は何日ですか?" } }, Max_tokens = 800, Temperature = 0d, Frequency_penalty = 0d, Presence_penalty = 0d, }; Console.WriteLine("チャットを開始する"); foreach (var message in body.Messages) { Console.WriteLine($"{message.Role}: {message.Content}"); }
Completions extensions API の呼び出しは、ExtensionsChatCompletionsClient
クラスが自動生成されています。Azure OpenAI の api-key をセットした HttpClient
のインスタンスを渡して、REST API を呼び出します。
using (var httpClient = new HttpClient()) { httpClient.DefaultRequestHeaders.Add("api-key", settings.ApiKey); var client = new ExtensionsChatCompletionsClient(httpClient); client.BaseUrl = settings.Endpoint; Console.WriteLine("就業規則を確認中・・・"); var result = await client.CreateAsync(settings.DeploymentId, settings.ApiVersion, body); foreach (var choice in result.Choices) { foreach (var message in choice.Messages) { if (message.Role == MessageRole.Assistant) { Console.WriteLine($"{message.Role}: {message.Content}"); } } } }
コンソールアプリを実行すると、プレイグラウンドと同様の結果を取得できます。
まとめ
Azure OpenAI Service On Your Data を .NET アプリケーションから使ってみました。Retrieval Augmented Generation(RAG)と呼ばれるデザインパターンを素早く構築できる待望の機能です。Azure の PaaS として簡単にできるとはいえ、回答精度を継続的に改善しつつ維持していくためには、Cognitive Search のインデックスや検索対象ドキュメントの保守は必須となります。
今回のサンプルアプリは、こちらで公開しています。
github.com