Azure.AI.OpenAI (.NET)
Azure OpenAI サービス用のクライアントライブラリ。GPT-4、GPT-4o、埋め込み、DALL-E、Whisper などの OpenAI モデルにアクセスできます。
インストール
dotnet add package Azure.AI.OpenAI
# OpenAI (非Azure) との互換性のために
# dotnet add package OpenAI
現在のバージョン: 2.1.0 (安定版)
環境変数
AZURE_OPENAI_ENDPOINT=https://<リソース名>.openai.azure.com # 必須: Azure OpenAI エンドポイント
AZURE_OPENAI_API_KEY=<api-key> # AzureKeyCredential 認証の場合のみ必須
AZURE_OPENAI_DEPLOYMENT_NAME=gpt-4o-mini # 必須: モデルデプロイ名
AZURE_TOKEN_CREDENTIALS=prod # 本番環境で DefaultAzureCredential を使用する場合のみ必須
クライアント階層
AzureOpenAIClient (トップレベル)
├── GetChatClient(deploymentName) → ChatClient
├── GetEmbeddingClient(deploymentName) → EmbeddingClient
├── GetImageClient(deploymentName) → ImageClient
├── GetAudioClient(deploymentName) → AudioClient
└── GetAssistantClient() → AssistantClient
認証
API キー認証
using Azure;
using Azure.AI.OpenAI;
AzureOpenAIClient client = new(
new Uri(Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")!),
new AzureKeyCredential(Environment.GetEnvironmentVariable("AZURE_OPENAI_API_KEY")!));
Microsoft Entra トークン資格情報
using Azure.Identity;
using Azure.AI.OpenAI;
// ローカル開発: DefaultAzureCredential。本番環境: AZURE_TOKEN_CREDENTIALS=prod または AZURE_TOKEN_CREDENTIALS=<特定の資格情報>
var credential = new DefaultAzureCredential(
DefaultAzureCredential.DefaultEnvironmentVariableName
);
// または本番環境で特定の資格情報を直接使用:
// https://learn.microsoft.com/dotnet/api/overview/azure/identity-readme?view=azure-dotnet#credential-classes
// var credential = new ManagedIdentityCredential();
AzureOpenAIClient client = new(
new Uri(Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")!),
credential);
Azure で OpenAI SDK を直接使用
using Azure.Identity;
using OpenAI;
using OpenAI.Chat;
using System.ClientModel.Primitives;
#pragma warning disable OPENAI001
BearerTokenPolicy tokenPolicy = new(
new DefaultAzureCredential(),
"https://cognitiveservices.azure.com/.default");
ChatClient client = new(
model: "gpt-4o-mini",
authenticationPolicy: tokenPolicy,
options: new OpenAIClientOptions()
{
Endpoint = new Uri("https://YOUR-RESOURCE.openai.azure.com/openai/v1")
});
チャット補完
基本チャット
using Azure.AI.OpenAI;
using OpenAI.Chat;
AzureOpenAIClient azureClient = new(
new Uri(endpoint),
new DefaultAzureCredential());
ChatClient chatClient = azureClient.GetChatClient("gpt-4o-mini");
ChatCompletion completion = chatClient.CompleteChat(
[
new SystemChatMessage("あなたは親切なアシスタントです。"),
new UserChatMessage("Azure OpenAI とは何ですか?")
]);
Console.WriteLine(completion.Content[0].Text);
非同期チャット
ChatCompletion completion = await chatClient.CompleteChatAsync(
[
new SystemChatMessage("あなたは親切なアシスタントです。"),
new UserChatMessage("クラウドコンピューティングを簡単な言葉で説明してください。")
]);
Console.WriteLine($"応答: {completion.Content[0].Text}");
Console.WriteLine($"使用トークン数: {completion.Usage.TotalTokenCount}");
ストリーミングチャット
await foreach (StreamingChatCompletionUpdate update
in chatClient.CompleteChatStreamingAsync(messages))
{
if (update.ContentUpdate.Count > 0)
{
Console.Write(update.ContentUpdate[0].Text);
}
}
オプション付きチャット
ChatCompletionOptions options = new()
{
MaxOutputTokenCount = 1000,
Temperature = 0.7f,
TopP = 0.95f,
FrequencyPenalty = 0,
PresencePenalty = 0
};
ChatCompletion completion = await chatClient.CompleteChatAsync(messages, options);
マルチターン会話
List<ChatMessage> messages = new()
{
new SystemChatMessage("あなたは親切なアシスタントです。"),
new UserChatMessage("こんにちは、手伝ってくれますか?"),
new AssistantChatMessage("もちろんです!何をお手伝いしましょうか?"),
new UserChatMessage("フランスの首都はどこですか?")
};
ChatCompletion completion = await chatClient.CompleteChatAsync(messages);
messages.Add(new AssistantChatMessage(completion.Content[0].Text));
構造化出力 (JSON スキーマ)
using System.Text.Json;
ChatCompletionOptions options = new()
{
ResponseFormat = ChatResponseFormat.CreateJsonSchemaFormat(
jsonSchemaFormatName: "math_reasoning",
jsonSchema: BinaryData.FromBytes("""
{
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"explanation": { "type": "string" },
"output": { "type": "string" }
},
"required": ["explanation", "output"],
"additionalProperties": false
}
},
"final_answer": { "type": "string" }
},
"required": ["steps", "final_answer"],
"additionalProperties": false
}
"""u8.ToArray()),
jsonSchemaIsStrict: true)
};
ChatCompletion completion = await chatClient.CompleteChatAsync(
[new UserChatMessage("8x + 7 = -23 をどうやって解きますか?")],
options);
using JsonDocument json = JsonDocument.Parse(completion.Content[0].Text);
Console.WriteLine($"答え: {json.RootElement.GetProperty("final_answer")}");
推論モデル (o1, o4-mini)
ChatCompletionOptions options = new()
{
ReasoningEffortLevel = ChatReasoningEffortLevel.Low,
MaxOutputTokenCount = 100000
};
ChatCompletion completion = await chatClient.CompleteChatAsync(
[
new DeveloperChatMessage("あなたは親切なアシスタントです"),
new UserChatMessage("相対性理論について説明してください")
], options);
Azure AI Search 統合 (RAG)
using Azure.AI.OpenAI.Chat;
#pragma warning disable AOAI001
ChatCompletionOptions options = new();
options.AddDataSource(new AzureSearchChatDataSource()
{
Endpoint = new Uri(searchEndpoint),
IndexName = searchIndex,
Authentication = DataSourceAuthentication.FromApiKey(searchKey)
});
ChatCompletion completion = await chatClient.CompleteChatAsync(
[new UserChatMessage("利用可能な健康保険プランは何ですか?")],
options);
ChatMessageContext context = completion.GetMessageContext();
if (context?.Intent is not null)
{
Console.WriteLine($"意図: {context.Intent}");
}
foreach (ChatCitation citation in context?.Citations ?? [])
{
Console.WriteLine($"引用: {citation.Content}");
}
埋め込み
using OpenAI.Embeddings;
EmbeddingClient embeddingClient = azureClient.GetEmbeddingClient("text-embedding-ada-002");
OpenAIEmbedding embedding = await embeddingClient.GenerateEmbeddingAsync("Hello, world!");
ReadOnlyMemory<float> vector = embedding.ToFloats();
Console.WriteLine($"埋め込み次元数: {vector.Length}");
バッチ埋め込み
List<string> inputs = new()
{
"最初のドキュメントテキスト",
"2番目のドキュメントテキスト",
"3番目のドキュメントテキスト"
};
OpenAIEmbeddingCollection embeddings = await embeddingClient.GenerateEmbeddingsAsync(inputs);
foreach (OpenAIEmbedding emb in embeddings)
{
Console.WriteLine($"インデックス {emb.Index}: {emb.ToFloats().Length} 次元");
}
画像生成 (DALL-E)
using OpenAI.Images;
ImageClient imageClient = azureClient.GetImageClient("dall-e-3");
GeneratedImage image = await imageClient.GenerateImageAsync(
"夕暮れの未来的な都市のスカイライン",
new ImageGenerationOptions
{
Size = GeneratedImageSize.W1024xH1024,
Quality = GeneratedImageQuality.High,
Style = GeneratedImageStyle.Vivid
});
Console.WriteLine($"画像 URL: {image.ImageUri}");
音声 (Whisper)
文字起こし
using OpenAI.Audio;
AudioClient audioClient = azureClient.GetAudioClient("whisper");
AudioTranscription transcription = await audioClient.TranscribeAudioAsync(
"audio.mp3",
new AudioTranscriptionOptions
{
ResponseFormat = AudioTranscriptionFormat.Verbose,
Language = "en"
});
Console.WriteLine(transcription.Text);
テキスト読み上げ
BinaryData speech = await audioClient.GenerateSpeechAsync(
"Azure OpenAI へようこそ!",
GeneratedSpeechVoice.Alloy,
new SpeechGenerationOptions
{
SpeedRatio = 1.0f,
ResponseFormat = GeneratedSpeechFormat.Mp3
});
await File.WriteAllBytesAsync("output.mp3", speech.ToArray());
関数呼び出し (ツール)
ChatTool getCurrentWeatherTool = ChatTool.CreateFunctionTool(
functionName: "get_current_weather",
functionDescription: "指定された場所の現在の天気を取得します",
functionParameters: BinaryData.FromString("""
{
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "市町村と州、例: サンフランシスコ、CA"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["location"]
}
"""));
ChatCompletionOptions options = new()
{
Tools = { getCurrentWeatherTool }
};
ChatCompletion completion = await chatClient.CompleteChatAsync(
[new UserChatMessage("シアトルの天気はどうですか?")],
options);
if (completion.FinishReason == ChatFinishReason.ToolCalls)
{
foreach (ChatToolCall toolCall in completion.ToolCalls)
{
Console.WriteLine($"関数: {toolCall.FunctionName}");
Console.WriteLine($"引数: {toolCall.FunctionArguments}");
}
}
主要な型リファレンス
| 型 | 目的 |
|---|---|
AzureOpenAIClient | Azure OpenAI のトップレベルクライアント |
ChatClient | チャット補完 |
EmbeddingClient | テキスト埋め込み |
ImageClient | 画像生成 (DALL-E) |
AudioClient | 音声文字起こし/TTS |
ChatCompletion | チャット応答 |
ChatCompletionOptions | リクエスト設定 |
StreamingChatCompletionUpdate | ストリーミング応答チャンク |
ChatMessage | ベースメッセージ型 |
SystemChatMessage | システムプロンプト |
UserChatMessage | ユーザー入力 |
AssistantChatMessage | アシスタント応答 |
DeveloperChatMessage | 開発者メッセージ (推論モデル) |
ChatTool | 関数/ツールの定義 |
ChatToolCall | ツール呼び出し要求 |
ベストプラクティス
- 本番環境では Entra ID を使用 — API キーを避け、
DefaultAzureCredentialを使用する - クライアントインスタンスを再利用 — 一度作成し、リクエスト間で共有する
- レート制限に対処 — 429 エラーに指数バックオフを実装する
- 長い応答にはストリーミング — より良い UX のために
CompleteChatStreamingAsyncを使用する - 適切なタイムアウトを設定 — 長い補完には拡張タイムアウトが必要な場合がある
- 構造化出力を使用 — JSON スキーマで応答形式を一貫させる
- トークン使用量を監視 —
completion.Usageを追跡してコスト管理を行う - ツール呼び出しを検証 — 関数の引数を実行前に必ず検証する
エラー処理
using Azure;
try
{
ChatCompletion completion = await chatClient.CompleteChatAsync(messages);
}
catch (RequestFailedException ex) when (ex.Status == 429)
{
Console.WriteLine("レート制限に達しました。遅延後に再試行します。");
await Task.Delay(TimeSpan.FromSeconds(10));
}
catch (RequestFailedException ex) when (ex.Status == 400)
{
Console.WriteLine($"無効なリクエスト: {ex.Message}");
}
catch (RequestFailedException ex)
{
Console.WriteLine($"Azure OpenAI エラー: {ex.Status} - {ex.Message}");
}
関連 SDK
| SDK | 目的 | インストール |
|---|---|---|
Azure.AI.OpenAI | Azure OpenAI クライアント (このSDK) | dotnet add package Azure.AI.OpenAI |
OpenAI | OpenAI 互換性 | dotnet add package OpenAI |
Azure.Identity | 認証 | dotnet add package Azure.Identity |
Azure.Search.Documents | RAG 用 AI Search | dotnet add package Azure.Search.Documents |