[ChatGPT]C#でもストリーミングなレスポンスを受け取りたい
2023-06-28
azblob://2023/06/28/eyecatch/2023-6-28-get-gpt-stream-message-000.png

こんにちは!

久しぶりにブログを書く気になった曽我部です。

早速ですが今回はAzure OpenAIでGPTをいい感じに出力させたいと思い頑張った、ストリーミングなレスポンスの受け取り方に関して書こうと思います。

1. はじめに

今回はC#でもストリーミングなレスポンスを受けってぬるぬるなGPTの回答を見たいと思ったが、どのように出力させるのか全く分からない人に向けてます。

こんなこと常識だよっていうことも書いているかもしれませんがご了承ください。

では、まず簡単にAzure OpenAIについて説明します。

2. Azure OpenAI Serviceとは

GPTを使うときに使うにはMicrosoft社が提供するAzure OpenAI ServiceとOpenAI社が提供するAPIの2種類があります。

簡単な違いを説明するとAzure OpenAI ServiceはAzureの一部として提供されるため、より広範な機能と統合があり、セキュリティや可用性の面でも優れていますが、最新のモデルの提供にはやや遅れが生じる可能性があります。

一方、OpenAIのAPIは最新の機能を最速で利用できますが、Azureの特定の機能や統合にはアクセスできません。

今回の場合、OpenAI社のAPIでStreamを受け取るためにはAPIにのけって送るパラメータの中にあるStreamをtrueに設定すれば実現できます。(Defaultはfalse)

しかし、Azure OpenAI Serviceを使う場合は少し勝手が違うので説明していきます。

3. C#とAzure OpenAI Serviceの連携方法

Azure OpenAI ServiceをC#で呼び出したいが、その方法が分からないという場合はものすごくわかりやすくまとめてくださっているブログがあるためこちらブログを参考にしてください。

この方法ではぬるぬる出てくるのではなく一括で表示されます。これを改善する方法を知りたい場合はこのまま読み進めてください。

4. ストリーミングな出力を受け取る方法

それでは本題のストリーミングなレスポンスで表示させる方法を解説していきます。

まず、GPTにパラメータやメッセージを与えるためのオプションを設定していきます。

これは一括で表示させるときと同じものを使えば大丈夫です。

C#var option = new ChatCompletionsOptions
{
	Messages =
	{
		new ChatMessage(ChatRole.System, @""),
        new ChatMessage(ChatRole.User, input)
    },
    // 温度パラメータ
    Temperature = (float)0.01,
    // 最大トークン数パラメータ
    MaxTokens = 50,
    // 上位Pパラメータ
    NucleusSamplingFactor = (float)0.95,
    FrequencyPenalty = 0,
    PresencePenalty = 0,
};

必要なoptionを設定したら実行に移ります。実行するためのコードを次に示します。

C#var aiClient = new OpenAIClient(
            new Uri("URI"),
            new AzureKeyCredential("Key")
           );
           
var response = await aiClient.GetChatCompletionsStreamingAsync("モデル名", option);
await foreach (StreamingChatChoice item in response.Value.GetChoicesStreaming())
{
    await foreach (ChatMessage message in item.GetMessageStreaming())
    {
        Console.Write(message.Content);
    }
}

以上のようなコードを書くことでストリーミングなレスポンスを受け取り、コマンドプロンプトにGPTの回答を表示することができます。

これを書いてみて本当にできているか?と感じるときはConsole.WriteLineにして確認してみてください。また、大量の文章が返ってくるときはわかりやすいので試してみて下さい。

6. 応用例

ここからは、私が最初出来なかったことを書いていきます。

今まで非同期的関数にあまり触れてこなかった私には、ストリーミングなレスポンスを受けとってそれを関数から逐次的に戻り値を返す方法が全く分かりませんでしたので、受け取り方と送り方の分かるコードを書いておきます。

まず、先ほど書いたコードを関数化していきます。

C#public async IAsyncEnumerable<string> StreamMessageAsync(string input)
{

	// オプションを設定
    var option = new ChatCompletionsOptions
    {
        Messages =
        {
            new ChatMessage(ChatRole.System, @""),
            new ChatMessage(ChatRole.User, input)
        },
        // 温度パラメータ
        Temperature = (float)0.01,
        // 最大トークン数パラメータ
        MaxTokens = 50,
        // 上位Pパラメータ
        NucleusSamplingFactor = (float)0.95,
        FrequencyPenalty = 0,
        PresencePenalty = 0,
    };
    
    var aiClient = new OpenAIClient(
            new Uri("URI"),
            new AzureKeyCredential("Key")
           );
           
    // 必要なストリーミングなレスポンスの取得
    var response = await aiClient.GetChatCompletionsStreamingAsync("モデル名", option);
    await foreach (StreamingChatChoice item in response.Value.GetChoicesStreaming())
    {
        await foreach (ChatMessage message in item.GetMessageStreaming())
        {
            yield return message.Content;
        }
    }
}

以上のようなコードを書くことで関数化には成功しました。また、例外処理などで関数を終わらせたい場合はyield breakを使ってください。

次にこの関数の呼び出し方を示します。

C#await foreach (var message in StreamMessageAsync("<ここにユーザーの入力を入れる>"))
{
    Console.Write(message);
}

このように行うことで、ストリーミングなレスポンスを返してくれるGPTの汎用性が上がり、SSE(Server Sent Events)でAPI通信をすれば、本家さながらのチャットボットを作れるかもしれません。

7. まとめ

今回のブログでは、Azure OpenAIを使用してC#でストリーミングなレスポンスを受け取る方法を解説しました。まず、Azure OpenAIとは何かを説明しました。

その後、Streamを使っての出力を受け取る方法や関数化・呼び出し方について詳しく解説しました。

これにより、ストリーミングなレスポンスを返すGPTの汎用性が向上し、よりスムーズなアプリケーションやプロジェクトの開発が可能になります。

今回の知識を活用して、ぜひ自分だけの素晴らしいプロジェクトを作成してください!

今後も技術的な進歩や最新情報について取り上げていきますので、お楽しみに!