.NET 用 Azure OpenAI クライアント ライブラリ - バージョン 1.0.0-beta.9
.NET 用 Azure OpenAI クライアント ライブラリは、慣用的なインターフェイスと Azure SDK エコシステムの残りの部分との豊富な統合を提供する OpenAI の REST API の適応です。 Azure OpenAI リソース または 非 Azure OpenAI 推論エンドポイントに接続できるため、Azure OpenAI 以外の開発にも最適です。
Azure OpenAI 用のクライアント ライブラリを使用して、次の手順を実行します。
Azure OpenAI は、開発者が Azure リソース上の OpenAI モデルからコンテンツをデプロイ、調整、生成できるようにするマネージド サービスです。
ソースコード | パッケージ (NuGet) | API リファレンス ドキュメント | 製品ドキュメント | サンプル
作業の開始
前提条件
Azure OpenAI リソースを使用する場合は、 Azure サブスクリプション と Azure OpenAI アクセス権が必要です。 これにより、Azure OpenAI リソースを作成し、接続 URL と API キーの両方を取得できます。 詳細については、「 クイック スタート: Azure OpenAI Service を使用してテキストの生成を開始する」を参照してください。
Azure OpenAI .NET クライアント ライブラリを使用して Azure 以外の OpenAI に接続する場合は、 の開発者アカウント https://platform.openai.com/から API キーが必要です。
パッケージをインストールする
NuGet を使用して .NET 用のクライアント ライブラリをインストールします。
dotnet add package Azure.AI.OpenAI --prerelease
クライアントを認証する
Azure OpenAI または OpenAI と対話するには、 OpenAIClient クラスのインスタンスを作成する必要があります。 Azure OpenAI で使用するようにクライアントを構成するには、Azure OpenAI リソースに対して有効なエンドポイント URI と、Azure OpenAI リソースの使用が許可されている対応するキー資格情報、トークン資格情報、または Azure ID 資格情報を指定します。 代わりに、OpenAI のサービスに接続するようにクライアントを構成するには、OpenAI の開発者ポータルから API キーを指定します。
OpenAIClient client = useAzureOpenAI
? new OpenAIClient(
new Uri("https://your-azure-openai-resource.com/"),
new AzureKeyCredential("your-azure-openai-resource-api-key"))
: new OpenAIClient("your-api-key-from-platform.openai.com");
Azure Active Directory 資格情報を使用して OpenAIClient を作成する
クライアント サブスクリプション キー認証は、この入門ガイドのほとんどの例で使用されますが、Azure Id ライブラリを使用して Azure Active Directory で認証することもできます。 次に示す DefaultAzureCredential プロバイダー、または Azure SDK で提供されているその他の資格情報プロバイダーを使用するには、Azure.Identity パッケージをインストールしてください。
dotnet add package Azure.Identity
string endpoint = "https://myaccount.openai.azure.com/";
var client = new OpenAIClient(new Uri(endpoint), new DefaultAzureCredential());
主要な概念
理解メイン概念は Completions です。 簡単に説明すると、入力候補はテキスト プロンプトの形式で機能を提供します。この機能は、特定の モデルを使用してコンテキストとパターンの照合を試み、出力テキストを提供します。 次のコード スニペットでは、大まかな概要を示します (詳細については、サンプル コードを GenerateChatbotResponsesWithToken
参照してください)。
OpenAIClient client = useAzureOpenAI
? new OpenAIClient(
new Uri("https://your-azure-openai-resource.com/"),
new AzureKeyCredential("your-azure-openai-resource-api-key"))
: new OpenAIClient("your-api-key-from-platform.openai.com");
Response<Completions> response = await client.GetCompletionsAsync(new CompletionsOptions()
{
DeploymentName = "text-davinci-003", // assumes a matching model deployment or model name
Prompts = { "Hello, world!" },
});
foreach (Choice choice in response.Value.Choices)
{
Console.WriteLine(choice.Text);
}
スレッド セーフ
すべてのクライアント インスタンス メソッドがスレッド セーフであり、相互に独立していることを保証します (ガイドライン)。 これにより、クライアント インスタンスの再利用に関する推奨事項は、スレッド間でも常に安全になります。
その他の概念
クライアント オプション | 応答 | へのアクセス実行時間の長い操作 | エラーの | 処理診断 | あざける | クライアントの有効期間
例
サンプルを使用すると、さまざまな API について理解できます。
チャットボットの応答を生成する
メソッドは GenerateChatbotResponse
DefaultAzureCredential を使用して認証を行い、入力プロンプトに対するテキスト応答を生成します。
string endpoint = "https://myaccount.openai.azure.com/";
var client = new OpenAIClient(new Uri(endpoint), new DefaultAzureCredential());
CompletionsOptions completionsOptions = new()
{
DeploymentName = "text-davinci-003",
Prompts = { "What is Azure OpenAI?" },
};
Response<Completions> completionsResponse = client.GetCompletions(completionsOptions);
string completion = completionsResponse.Value.Choices[0].Text;
Console.WriteLine($"Chatbot: {completion}");
サブスクリプション キーを使用して複数のチャットボット応答を生成する
メソッドは GenerateMultipleChatbotResponsesWithSubscriptionKey
、Azure サブスクリプション キーを使用して入力プロンプトにテキスト応答を生成する例を示します
// Replace with your Azure OpenAI key
string key = "YOUR_AZURE_OPENAI_KEY";
string endpoint = "https://myaccount.openai.azure.com/";
var client = new OpenAIClient(new Uri(endpoint), new AzureKeyCredential(key));
CompletionsOptions completionsOptions = new()
{
DeploymentName = "text-davinci-003",
Prompts =
{
"How are you today?",
"What is Azure OpenAI?",
"Why do children love dinosaurs?",
"Generate a proof of Euler's identity",
"Describe in single words only the good things that come into your mind about your mother."
},
};
Response<Completions> completionsResponse = client.GetCompletions(completionsOptions);
foreach (Choice choice in completionsResponse.Value.Choices)
{
Console.WriteLine($"Response for prompt {choice.Index}: {choice.Text}");
}
入力候補を含むテキストを集計する
メソッドは SummarizeText
、指定された入力プロンプトの概要を生成します。
string endpoint = "https://myaccount.openai.azure.com/";
var client = new OpenAIClient(new Uri(endpoint), new DefaultAzureCredential());
string textToSummarize = @"
Two independent experiments reported their results this morning at CERN, Europe's high-energy physics laboratory near Geneva in Switzerland. Both show convincing evidence of a new boson particle weighing around 125 gigaelectronvolts, which so far fits predictions of the Higgs previously made by theoretical physicists.
""As a layman I would say: 'I think we have it'. Would you agree?"" Rolf-Dieter Heuer, CERN's director-general, asked the packed auditorium. The physicists assembled there burst into applause.
:";
string summarizationPrompt = @$"
Summarize the following text.
Text:
""""""
{textToSummarize}
""""""
Summary:
";
Console.Write($"Input: {summarizationPrompt}");
var completionsOptions = new CompletionsOptions()
{
DeploymentName = "text-davinci-003",
Prompts = { summarizationPrompt },
};
Response<Completions> completionsResponse = client.GetCompletions(completionsOptions);
string completion = completionsResponse.Value.Choices[0].Text;
Console.WriteLine($"Summarization: {completion}");
Azure 以外の OpenAI を使用してチャット メッセージをストリーミングする
string nonAzureOpenAIApiKey = "your-api-key-from-platform.openai.com";
var client = new OpenAIClient(nonAzureOpenAIApiKey, new OpenAIClientOptions());
var chatCompletionsOptions = new ChatCompletionsOptions()
{
DeploymentName = "gpt-3.5-turbo", // Use DeploymentName for "model" with non-Azure clients
Messages =
{
new ChatMessage(ChatRole.System, "You are a helpful assistant. You will talk like a pirate."),
new ChatMessage(ChatRole.User, "Can you help me?"),
new ChatMessage(ChatRole.Assistant, "Arrrr! Of course, me hearty! What can I do for ye?"),
new ChatMessage(ChatRole.User, "What's the best way to train a parrot?"),
}
};
await foreach (StreamingChatCompletionsUpdate chatUpdate in client.GetChatCompletionsStreaming(chatCompletionsOptions))
{
if (chatUpdate.Role.HasValue)
{
Console.Write($"{chatUpdate.Role.Value.ToString().ToUpperInvariant()}: ");
}
if (!string.IsNullOrEmpty(chatUpdate.ContentUpdate))
{
Console.Write(chatUpdate.ContentUpdate);
}
}
ストリーミング中に複数をChoice
明示的に要求する場合は、 の プロパティStreamingChatCompletionsUpdate
をChoiceIndex
使用して、各更新プログラムが対応する対象Choice
を決定します。
// A ChoiceCount > 1 will feature multiple, parallel, independent text generations arriving on the
// same response. This may be useful when choosing between multiple candidates for a single request.
var chatCompletionsOptions = new ChatCompletionsOptions()
{
Messages = { new ChatMessage(ChatRole.User, "Write a limerick about bananas.") },
ChoiceCount = 4
};
await foreach (StreamingChatCompletionsUpdate chatUpdate
in client.GetChatCompletionsStreaming(chatCompletionsOptions))
{
// Choice-specific information like Role and ContentUpdate will also provide a ChoiceIndex that allows
// StreamingChatCompletionsUpdate data for independent choices to be appropriately separated.
if (chatUpdate.ChoiceIndex.HasValue)
{
int choiceIndex = chatUpdate.ChoiceIndex.Value;
if (chatUpdate.Role.HasValue)
{
textBoxes[choiceIndex].Text += $"{chatUpdate.Role.Value.ToString().ToUpperInvariant()}: ";
}
if (!string.IsNullOrEmpty(chatUpdate.ContentUpdate))
{
textBoxes[choiceIndex].Text += chatUpdate.ContentUpdate;
}
}
}
チャット機能を使用する
チャット関数を使用すると、チャット完了の呼び出し元は、モデルが機能を外部ツールとデータ ソースに拡張するために使用できる機能を定義できます。
チャット関数の詳細については、OpenAI のブログを参照してください。 https://openai.com/blog/function-calling-and-other-api-updates
注: チャット関数には、gpt-4 および gpt-3.5-turbo のラベルで始まるモデル バージョンが -0613
必要です。 古いバージョンのモデルでは使用できません。
メモ: 1 つの要求でのチャット関数と Azure チャット拡張機能 の同時使用はまだサポートされていません。 両方を指定すると、チャット関数の情報は無視され、操作は Azure チャット拡張機能のみが提供されたかのように動作します。 この制限に対処するには、ソリューション設計の複数の要求間でチャット関数と Azure チャット拡張機能の評価を分離することを検討してください。
チャット関数を使用するには、まず、必要に応じてモデルで使用できるようにする関数を定義します。 上記のリンクされたブログ投稿の例を使用します。
var getWeatherFuntionDefinition = new FunctionDefinition()
{
Name = "get_current_weather",
Description = "Get the current weather in a given location",
Parameters = BinaryData.FromObjectAsJson(
new
{
Type = "object",
Properties = new
{
Location = new
{
Type = "string",
Description = "The city and state, e.g. San Francisco, CA",
},
Unit = new
{
Type = "string",
Enum = new[] { "celsius", "fahrenheit" },
}
},
Required = new[] { "location" },
},
new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }),
};
関数を定義すると、そのオプションを使用してチャット完了要求で使用できます。 関数データは、後続のステートレス要求のデータを構築する複数の呼び出しで処理されるため、チャット メッセージの一覧は会話履歴の形式として保持されます。
var conversationMessages = new List<ChatMessage>()
{
new(ChatRole.User, "What is the weather like in Boston?"),
};
var chatCompletionsOptions = new ChatCompletionsOptions()
{
DeploymentName = "gpt-35-turbo-0613",
};
foreach (ChatMessage chatMessage in conversationMessages)
{
chatCompletionsOptions.Messages.Add(chatMessage);
}
chatCompletionsOptions.Functions.Add(getWeatherFuntionDefinition);
Response<ChatCompletions> response = await client.GetChatCompletionsAsync(chatCompletionsOptions);
モデルがチャット関数を呼び出す必要があると判断した場合は、選択肢に "FunctionCall" の終了理由が設定され、応答メッセージの FunctionCall
プロパティに詳細が表示されます。 通常、関数呼び出しの名前は指定された名前になり、引数は、使用されるに含まれる FunctionDefinition
スキーマと一致する設定された JSON ドキュメントになります。ただし、このデータが有効であるか、正しく書式設定されていることは 保証されません 。そのため、検証とエラー チェックは常に関数呼び出しの処理に伴う必要があります。
関数呼び出しを解決し、ユーザーが操作を続行するには、必要に応じて引数ペイロードを処理し、 を使用して適切な応答データを新しいメッセージ ChatRole.Function
にシリアル化します。 次に、これまでのすべてのメッセージ (最初 User
のメッセージ、最初の応答の FunctionCall
メッセージ、関数呼び出しへの応答で生成された解決メッセージ) を使用して新しい要求を Function
行い、モデルでデータを使用してチャット完了応答をより適切に作成できるようにします。
指定した関数呼び出し応答は、最初の呼び出しで指定されたスキーマに従う必要はありません。 モデルは、名前とフィールドの推定コンテキストに基づいて応答データの使用状況を推論します。
ChatChoice responseChoice = response.Value.Choices[0];
if (responseChoice.FinishReason == CompletionsFinishReason.FunctionCall)
{
// Include the FunctionCall message in the conversation history
conversationMessages.Add(responseChoice.Message);
if (responseChoice.Message.FunctionCall.Name == "get_current_weather")
{
// Validate and process the JSON arguments for the function call
string unvalidatedArguments = responseChoice.Message.FunctionCall.Arguments;
var functionResultData = (object)null; // GetYourFunctionResultData(unvalidatedArguments);
// Here, replacing with an example as if returned from GetYourFunctionResultData
functionResultData = new
{
Temperature = 31,
Unit = "celsius",
};
// Serialize the result data from the function into a new chat message with the 'Function' role,
// then add it to the messages after the first User message and initial response FunctionCall
var functionResponseMessage = new ChatMessage(
ChatRole.Function,
JsonSerializer.Serialize(
functionResultData,
new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }))
{
Name = responseChoice.Message.FunctionCall.Name
};
conversationMessages.Add(functionResponseMessage);
// Now make a new request using all three messages in conversationMessages
}
}
ストリーミングを使用する場合は、ストリーミング応答コンポーネントが到着したときにキャプチャし、コンテンツのストリーミングに使用されるのと同じ方法でストリーミング関数の引数を蓄積します。 次に、ストリーミング以外の応答から を ChatMessage
使用する代わりに、ストリーミングされた情報から作成された履歴の新しい ChatMessage
インスタンスを追加します。
string functionName = null;
StringBuilder contentBuilder = new();
StringBuilder functionArgumentsBuilder = new();
ChatRole streamedRole = default;
CompletionsFinishReason finishReason = default;
await foreach (StreamingChatCompletionsUpdate update
in client.GetChatCompletionsStreaming(chatCompletionsOptions))
{
contentBuilder.Append(update.ContentUpdate);
functionName ??= update.FunctionName;
functionArgumentsBuilder.Append(update.FunctionArgumentsUpdate);
streamedRole = update.Role ?? default;
finishReason = update.FinishReason ?? default;
}
if (finishReason == CompletionsFinishReason.FunctionCall)
{
string lastContent = contentBuilder.ToString();
string unvalidatedArguments = functionArgumentsBuilder.ToString();
ChatMessage chatMessageForHistory = new(streamedRole, lastContent)
{
FunctionCall = new(functionName, unvalidatedArguments),
};
conversationMessages.Add(chatMessageForHistory);
// Handle from here just like the non-streaming case
}
注: ストリーミングされた関数情報 (名前、引数) は到着時に評価される場合があります。ただし、 が受信されるまでFinishReason
FunctionCall
は、完全と見なしたり、確認したりしないでください。 関数名や、累積された部分的な JSON 引数に表示される特定のキー/値に基づいて、"ウォームアップ" またはその他の投機的な準備をベスト エフォートで試みるのが適切な場合がありますが、引数が完全に使用可能 FinishReason
になるまで、有効性、順序、またはその他の詳細に関する強い仮定は評価する必要はありません。
Azure OpenAI で独自のデータを使用する
独自のデータの使用機能は Azure OpenAI に固有であり、Azure 以外のサービスを使用するように構成されたクライアントでは機能しません。 概念的な背景と詳細なセットアップ手順については、 独自のデータを使用した Azure OpenAI のクイックスタート を参照してください。
メモ: 1 つの要求での チャット関数 と Azure チャット拡張機能の同時使用はまだサポートされていません。 両方を指定すると、チャット関数の情報は無視され、操作は Azure チャット拡張機能のみが提供されたかのように動作します。 この制限に対処するには、ソリューション設計の複数の要求間でチャット関数と Azure チャット拡張機能の評価を分離することを検討してください。
AzureCognitiveSearchChatExtensionConfiguration contosoExtensionConfig = new()
{
SearchEndpoint = new Uri("https://your-contoso-search-resource.search.windows.net"),
IndexName = "contoso-products-index",
};
contosoExtensionConfig.SetSearchKey("<your Cognitive Search resource API key>");
ChatCompletionsOptions chatCompletionsOptions = new()
{
DeploymentName = "gpt-35-turbo-0613",
Messages =
{
new ChatMessage(
ChatRole.System,
"You are a helpful assistant that answers questions about the Contoso product database."),
new ChatMessage(ChatRole.User, "What are the best-selling Contoso products this month?")
},
// The addition of AzureChatExtensionsOptions enables the use of Azure OpenAI capabilities that add to
// the behavior of Chat Completions, here the "using your own data" feature to supplement the context
// with information from an Azure Cognitive Search resource with documents that have been indexed.
AzureExtensionsOptions = new AzureChatExtensionsOptions()
{
Extensions = { contosoExtensionConfig }
}
};
Response<ChatCompletions> response = await client.GetChatCompletionsAsync(chatCompletionsOptions);
ChatMessage message = response.Value.Choices[0].Message;
// The final, data-informed response still appears in the ChatMessages as usual
Console.WriteLine($"{message.Role}: {message.Content}");
// Responses that used extensions will also have Context information that includes special Tool messages
// to explain extension activity and provide supplemental information like citations.
Console.WriteLine($"Citations and other information:");
foreach (ChatMessage contextMessage in message.AzureExtensionsContext.Messages)
{
// Note: citations and other extension payloads from the "tool" role are often encoded JSON documents
// and need to be parsed as such; that step is omitted here for brevity.
Console.WriteLine($"{contextMessage.Role}: {contextMessage.Content}");
}
埋め込みの生成
EmbeddingsOptions embeddingsOptions = new()
{
DeploymentName = "text-embedding-ada-002",
Input = { "Your text string goes here" },
};
Response<Embeddings> response = await client.GetEmbeddingsAsync(embeddingsOptions);
// The response includes the generated embedding.
EmbeddingItem item = response.Value.Data[0];
ReadOnlyMemory<float> embedding = item.Embedding;
DALL-E イメージ生成モデルを使用してイメージを生成する
Response<ImageGenerations> imageGenerations = await client.GetImageGenerationsAsync(
new ImageGenerationOptions()
{
Prompt = "a happy monkey eating a banana, in watercolor",
Size = ImageSize.Size256x256,
});
// Image Generations responses provide URLs you can use to retrieve requested images
Uri imageUri = imageGenerations.Value.Data[0].Url;
ささやき音声モデルを使用してオーディオ データを文字起こしする
using Stream audioStreamFromFile = File.OpenRead("myAudioFile.mp3");
var transcriptionOptions = new AudioTranscriptionOptions()
{
DeploymentName = "my-whisper-deployment", // whisper-1 as model name for non-Azure OpenAI
AudioData = BinaryData.FromStream(audioStreamFromFile),
ResponseFormat = AudioTranscriptionFormat.Verbose,
};
Response<AudioTranscription> transcriptionResponse
= await client.GetAudioTranscriptionAsync(transcriptionOptions);
AudioTranscription transcription = transcriptionResponse.Value;
// When using Simple, SRT, or VTT formats, only transcription.Text will be populated
Console.WriteLine($"Transcription ({transcription.Duration.Value.TotalSeconds}s):");
Console.WriteLine(transcription.Text);
ささやき音声モデルを使用して音声データを英語に翻訳する
using Stream audioStreamFromFile = File.OpenRead("mySpanishAudioFile.mp3");
var translationOptions = new AudioTranslationOptions()
{
DeploymentName = "my-whisper-deployment", // whisper-1 as model name for non-Azure OpenAI
AudioData = BinaryData.FromStream(audioStreamFromFile),
ResponseFormat = AudioTranslationFormat.Verbose,
};
Response<AudioTranslation> translationResponse = await client.GetAudioTranslationAsync(translationOptions);
AudioTranslation translation = translationResponse.Value;
// When using Simple, SRT, or VTT formats, only translation.Text will be populated
Console.WriteLine($"Translation ({translation.Duration.Value.TotalSeconds}s):");
// .Text will be translated to English (ISO-639-1 "en")
Console.WriteLine(translation.Text);
トラブルシューティング
.NET SDK を使用して Azure OpenAI と対話すると、サービスによって返されるエラーは、 REST API 要求に対して返されるのと同じ HTTP 状態コードに対応します。
たとえば、Azure OpenAI リソース エンドポイントと一致しないエンドポイントを使用してクライアントを作成しようとすると、 404
を示す Resource Not Found
エラーが返されます。
次のステップ
- パッケージ
/samples
のディレクトリ内の README と一緒に配置されているコード例へのリンクを提供します。 - 必要に応じて、役に立つ可能性のある他のパッケージをユーザーにポイントします。
- 開発者がパッケージを誤って見つけ出す可能性が高いと思われる場合 (特定の機能を検索していて、パッケージがその機能を提供していると誤って考えているため)、探している可能性のあるパッケージを指定します。
共同作成
このライブラリの構築、テスト、および投稿の詳細については、 OpenAI CONTRIBUTING.md を参照してください。
このプロジェクトでは、共同作成と提案を歓迎しています。 ほとんどの共同作成では、共同作成者使用許諾契約書 (CLA) にご同意いただき、ご自身の共同作成内容を使用する権利を Microsoft に供与する権利をお持ちであり、かつ実際に供与することを宣言していただく必要があります。 詳細については、「 cla.microsoft.com」を参照してください。
pull request を送信すると、CLA を提供して PR (ラベル、コメントなど) を適宜装飾する必要があるかどうかを CLA ボットが自動的に決定します。 ボットによって提供される手順にそのまま従ってください。 この操作は、Microsoft の CLA を使用するすべてのリポジトリについて、1 回だけ行う必要があります。
このプロジェクトでは、Microsoft オープン ソースの倫理規定を採用しています。 詳しくは、「Code of Conduct FAQ (倫理規定についてよくある質問)」を参照するか、opencode@microsoft.com 宛てに質問またはコメントをお送りください。