关于 azure-ai-openai-dotnet
面向 .NET 开发者的客户端库 Skill,介绍如何通过 Azure.AI.OpenAI 和 OpenAI SDK 使用 Azure OpenAI Service,涵盖聊天、嵌入、图像与音频 API、身份验证及请求模式。
主要功能
- 01聊天补全与流式响应
- 02结构化 JSON Schema 输出
- 03文本嵌入
- 04图像生成与音频 API
- 05API 密钥和 Entra ID 身份验证
- 06函数调用
适用场景
- 01构建 .NET 聊天应用
- 02为文本生成嵌入
- 03开发图像或音频功能
- 04配置结构化模型响应
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ sickn33/ agentic-awesome-skills --skill azure-ai-openai-dotnet安装后在 Claude Code 中输入/azure-ai-openai-dotnet确认已加载。
详细介绍
Azure.AI.OpenAI(.NET)
Azure OpenAI Service 的客户端库,可访问 GPT-4、GPT-4o、嵌入、DALL-E 和 Whisper 等 OpenAI 模型。
安装
dotnet add package Azure.AI.OpenAI
# For OpenAI (non-Azure) compatibility
dotnet add package OpenAI
历史示例基线:2.1.0;请验证并固定兼容的 Azure.AI.OpenAI/OpenAI 版本。以下较新的 v1 API 示例可能需要更新的软件包。
环境变量
AZURE_OPENAI_ENDPOINT=https://<resource-name>.openai.azure.com
AZURE_OPENAI_API_KEY=<api-key> # For key-based auth
AZURE_OPENAI_DEPLOYMENT_NAME=<deployment-name> # Azure deployment, not necessarily the model ID
客户端层级
AzureOpenAIClient (top-level)
├── 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 ID(生产环境推荐)
using Azure.Identity;
using Azure.AI.OpenAI;
AzureOpenAIClient client = new(
new Uri(Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")!),
new DefaultAzureCredential());
直接通过 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("You are a helpful assistant."),
new UserChatMessage("What is Azure OpenAI?")
]);
Console.WriteLine(completion.Content[0].Text);
异步聊天
ChatCompletion completion = await chatClient.CompleteChatAsync(
[
new SystemChatMessage("You are a helpful assistant."),
new UserChatMessage("Explain cloud computing in simple terms.")
]);
Console.WriteLine($"Response: {completion.Content[0].Text}");
Console.WriteLine($"Tokens used: {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("You are a helpful assistant."),
new UserChatMessage("Hi, can you help me?"),
new AssistantChatMessage("Of course! What do you need help with?"),
new UserChatMessage("What's the capital of France?")
};
ChatCompletion completion = await chatClient.CompleteChatAsync(messages);
messages.Add(new AssistantChatMessage(completion.Content[0].Text));
结构化输出(JSON Schema)
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("How can I solve 8x + 7 = -23?")],
options);
using JsonDocument json = JsonDocument.Parse(completion.Content[0].Text);
Console.WriteLine($"Answer: {json.RootElement.GetProperty("final_answer")}");
推理模型(o1、o4-mini)
ChatCompletionOptions options = new()
{
ReasoningEffortLevel = ChatReasoningEffortLevel.Low,
MaxOutputTokenCount = 100000
};
ChatCompletion completion = await chatClient.CompleteChatAsync(
[
new DeveloperChatMessage("You are a helpful assistant"),
new UserChatMessage("Explain the theory of relativity")
], 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("What health plans are available?")],
options);
ChatMessageContext context = completion.GetMessageContext();
if (context?.Intent is not null)
{
Console.WriteLine($"Intent: {context.Intent}");
}
foreach (ChatCitation citation in context?.Citations ?? [])
{
Console.WriteLine($"Citation: {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($"Embedding dimensions: {vector.Length}");
批量嵌入
List<string> inputs = new()
{
"First document text",
"Second document text",
"Third document text"
};
OpenAIEmbeddingCollection embeddings = await embeddingClient.GenerateEmbeddingsAsync(inputs);
foreach (OpenAIEmbedding emb in embeddings)
{
Console.WriteLine($"Index {emb.Index}: {emb.ToFloats().Length} dimensions");
}
图像生成(DALL-E)
using OpenAI.Images;
ImageClient imageClient = azureClient.GetImageClient("dall-e-3");
GeneratedImage image = await imageClient.GenerateImageAsync(
"A futuristic city skyline at sunset",
new ImageGenerationOptions
{
Size = GeneratedImageSize.W1024xH1024,
Quality = GeneratedImageQuality.High,
Style = GeneratedImageStyle.Vivid
});
Console.WriteLine($"Image 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(
"Hello, welcome to 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: "Get the current weather in a given location",
functionParameters: BinaryData.FromString("""
{
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["location"]
}
"""));
ChatCompletionOptions options = new()
{
Tools = { getCurrentWeatherTool }
};
ChatCompletion completion = await chatClient.CompleteChatAsync(
[new UserChatMessage("What's the weather in Seattle?")],
options);
if (completion.FinishReason == ChatFinishReason.ToolCalls)
{
foreach (ChatToolCall toolCall in completion.ToolCalls)
{
Console.WriteLine($"Function: {toolCall.FunctionName}");
Console.WriteLine($"Arguments: {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 错误实现指数退避
- 对较长的响应使用流式处理 — 使用
CompleteChatStreamingAsync改善用户体验 - 设置适当的超时时间 — 较长的补全可能需要延长超时时间
- 使用结构化输出 — JSON schema 可确保响应格式一致
- 监控令牌用量 — 跟踪
completion.Usage以管理成本 - 验证工具调用 — 执行前始终验证函数参数
错误处理
using System.ClientModel;
try
{
ChatCompletion completion = await chatClient.CompleteChatAsync(messages);
}
catch (System.ClientModel.ClientResultException ex) when (ex.Status == 429)
{
Console.WriteLine("Rate limited. Retry after delay.");
await Task.Delay(TimeSpan.FromSeconds(10));
}
catch (System.ClientModel.ClientResultException ex) when (ex.Status == 400)
{
Console.WriteLine($"Bad request: {ex.Message}");
}
catch (System.ClientModel.ClientResultException ex)
{
Console.WriteLine($"Azure OpenAI error: {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 |
参考链接
适用场景
此技能适用于执行概述中描述的工作流或操作。
限制
- 仅当任务明确符合上述范围时,才使用此技能。
- 不要将输出视为可替代特定环境的验证、测试或专家审核。
- 如果缺少必需的输入、权限、安全边界或成功标准,请停下并寻求澄清。
示例是相互独立的片段,并非可编译的应用;请添加所需的导入、变量和特定模型的部署名称。聊天、音频、图像功能和选项因部署/API 版本而异:Whisper 转录和语音生成通常需要不同的部署。在建立索引前检查拒绝情况、结束原因和内容数量;结构化输出并不保证响应成功且未被拒绝。将检索到的文本/工具参数视为不可信内容,并独立授权副作用。限制重试次数并遵循重试提示;只休眠一次不算重试循环。不要记录包含敏感数据的提示词、引用或原始服务错误。此处的模型名称、软件包版本和预览版 API 仅为历史示例,并不代表当前可用性。
评论
支持 Markdown