ROMANCE DAWN for the new world

Microsoft Azure を中心とした技術情報を書いています。

.NET エンジニアが Azure OpenAI Service を使ってみた

Azure OpenAI Service は、2023 年 1 月に一般提供(GA)された Microsoft の OpenAI です。今回は .NET エンジニアの視点で Azure OpenAI を使ってみました。

Azure OpenAI Service とは

Azure OpenAI の概要は、こちらの記事が分かりやすいです。利用申請には企業ドメインのメールアドレスが必要(Gmail などは使えない)ですが、現在は申請すると数時間でアクティブになるようです。
zenn.dev

シナリオ

Azure OpenAI Sutido の ChatGPT プレイグラウンドを使って、ONEPIECE のチョッパーと会話してみます。モデルは、先日公開されたばかりの gpt-35-turbo-16k を使います。

アシスタントに雑なキャラ付けをセットアップするだけで、少し違和感ありますが、チョッパーと会話できました。

Azure OpenAI Client Library を使ってみる

先ほどのシナリオを Azure OpenAI Client Library を使って実装してみます。.NET 7 のコンソールアプリを作り、NuGet パッケージをインストールします。

Install-Package Azure.AI.OpenAI -Version 1.0.0-beta.5
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 に接続する資格情報を管理するためにインストールしました。Managed ID を使ってもいいですが、環境によって認証が通らないケースもあるので、シンプルに .NET の UserSecrets を使います。誤って GitHub にプッシュするリスクがあるのでハードコーディングはやめましょう。

{
  "AzureOpenAISettings": {
    "Endpoint": "https://xxx.openai.azure.com/",
    "ApiKey": "xxx",
    "DeploymentName": "gpt-35-turbo-16k"
  }
}

secret.json にエンドポイント、キー、モデル名を定義したら、バインドするクラスを作ります。

internal class AzureOpenAISettings
{
    public required string Endpoint { get; set; }
    public required string ApiKey { get; set; }
    public required string DeploymentName { get; set; }
}

ConfigurationBuilder を使って、secret.json を読み込んで AzureOpenAISettings クラスにバインドします。

var settings = new ConfigurationBuilder()
    .AddUserSecrets<Program>()
    .Build()
    .GetSection(nameof(AzureOpenAISettings)).Get<AzureOpenAISettings>() ?? throw new NullReferenceException();

システムロールにアシスタントの性格と応答する際のコンテキストを定義します。

var chatCompletionsOptions = new ChatCompletionsOptions
{
    MaxTokens = 200,
    Messages =
        {
            new ChatMessage(ChatRole.System, """
                おれの名前は、トニートニー・チョッパー。
                動物系悪魔の実「ヒトヒトの実」の能力者で、人の言葉を話せるトナカイ。
                海賊「麦わらの一味」の船医。
                夢は、何でも治せる医者になること。
                わたあめ大好き。
                一人称は、おれ。
                口調はフレンドリーで可愛い。
            """)
        }
};

ユーザーロールには、こちらからの送信メッセージを定義します。本来はチャットなのでインタラクティブなやり取りですが、サンプルアプリなのでメッセージを決め打ちにしました。

var userMessages = new String[] {
    "こんにちは。",
    "トナカイなのに人の言葉を話せるの?",
    "好きな食べ物は?",
};

Azure OpenAI の API はステートレスなので、API を呼び出す都度システムロールとユーザーロールの履歴を含めて送信します。

Console.WriteLine("アシスタントのセットアップ中・・・");
var client = new OpenAIClient(new Uri(settings.Endpoint), new AzureKeyCredential(settings.ApiKey));
await client.GetChatCompletionsAsync(settings.DeploymentName, chatCompletionsOptions);

Console.WriteLine("チャットを開始する");
foreach (var userMessage in userMessages)
{
    Console.WriteLine($"{ChatRole.User}: {userMessage}");
    chatCompletionsOptions.Messages.Add(new ChatMessage(ChatRole.User, userMessage));
    var result = await client.GetChatCompletionsAsync(settings.DeploymentName, chatCompletionsOptions);

    foreach (var choice in result.Value.Choices)
    {
        Console.WriteLine($"{choice.Message.Role}: {choice.Message.Content}");
        chatCompletionsOptions.Messages.Add(new ChatMessage(choice.Message.Role, choice.Message.Content));
    }
}

プレイグラウンドと同様の結果を取得できたことが分かります。


まとめ

Azure OpenAI Client Library を使って、Azure OpenAI で遊んでみました。
アシスタントのセットアップでシステムロールに、

  • 動作に関する指示や応答の生成時に参照する必要があるコンテキスト
  • 何に答えるべきで何に答えてはいけないか
  • 応答の書式

などをどのように伝えるのかのメタプロンプトが重要となります。
また、業務向けに作りこむとなると、複数のプロンプトを部品化して順番に呼び出すオーケストレーション的な設計が必要となり、Semantic Kernel のような LLM と C# を統合して扱える SDK が使いたくなります。
次回は、Semantic Kernel についての記事を書きたいと思います。
gooner.hateblo.jp
今回のサンプルアプリは、こちらで公開しています。
github.com