Azure.AI.OpenAI (.NET)
Biblioteca cliente para el servicio Azure OpenAI que proporciona acceso a modelos de OpenAI, incluyendo GPT-4, GPT-4o, embeddings, DALL-E y Whisper.
Instalación
dotnet add package Azure.AI.OpenAI
dotnet add package OpenAI
Versión actual: 2.1.0 (estable)
Variables de entorno
AZURE_OPENAI_ENDPOINT=https://<recurso>.openai.azure.com
AZURE_OPENAI_API_KEY=<clave-api>
AZURE_OPENAI_DEPLOYMENT_NAME=gpt-4o-mini
AZURE_TOKEN_CREDENTIALS=prod
Jerarquía de clientes
AzureOpenAIClient (nivel superior)
├── GetChatClient(nombreDespliegue) → ChatClient
├── GetEmbeddingClient(nombreDespliegue) → EmbeddingClient
├── GetImageClient(nombreDespliegue) → ImageClient
├── GetAudioClient(nombreDespliegue) → AudioClient
└── GetAssistantClient() → AssistantClient
Autenticación
Autenticación con clave de API
using Azure;
using Azure.AI.OpenAI;
AzureOpenAIClient cliente = new(
new Uri(Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")!),
new AzureKeyCredential(Environment.GetEnvironmentVariable("AZURE_OPENAI_API_KEY")!));
Credencial de token Microsoft Entra
using Azure.Identity;
using Azure.AI.OpenAI;
var credential = new DefaultAzureCredential(
DefaultAzureCredential.DefaultEnvironmentVariableName
);
AzureOpenAIClient cliente = new(
new Uri(Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")!),
credential);
Usar el SDK de OpenAI directamente con Azure
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 cliente = new(
model: "gpt-4o-mini",
authenticationPolicy: tokenPolicy,
options: new OpenAIClientOptions()
{
Endpoint = new Uri("https://TU-RECURSO.openai.azure.com/openai/v1")
});
Finalizaciones de chat
Chat básico
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("Eres un asistente útil."),
new UserChatMessage("¿Qué es Azure OpenAI?")
]);
Console.WriteLine(completion.Content[0].Text);
Chat asíncrono
ChatCompletion completion = await chatClient.CompleteChatAsync(
[
new SystemChatMessage("Eres un asistente útil."),
new UserChatMessage("Explica la computación en la nube en términos simples.")
]);
Console.WriteLine($"Respuesta: {completion.Content[0].Text}");
Console.WriteLine($"Tokens usados: {completion.Usage.TotalTokenCount}");
Chat en streaming
await foreach (StreamingChatCompletionUpdate update
in chatClient.CompleteChatStreamingAsync(messages))
{
if (update.ContentUpdate.Count > 0)
{
Console.Write(update.ContentUpdate[0].Text);
}
}
Chat con opciones
ChatCompletionOptions options = new()
{
MaxOutputTokenCount = 1000,
Temperature = 0.7f,
TopP = 0.95f,
FrequencyPenalty = 0,
PresencePenalty = 0
};
ChatCompletion completion = await chatClient.CompleteChatAsync(messages, options);
Conversación multi-turno
List<ChatMessage> messages = new()
{
new SystemChatMessage("Eres un asistente útil."),
new UserChatMessage("Hola, ¿puedes ayudarme?"),
new AssistantChatMessage("¡Por supuesto! ¿Con qué necesitas ayuda?"),
new UserChatMessage("¿Cuál es la capital de Francia?")
};
ChatCompletion completion = await chatClient.CompleteChatAsync(messages);
messages.Add(new AssistantChatMessage(completion.Content[0].Text));
Salidas estructuradas (esquema JSON)
using System.Text.Json;
ChatCompletionOptions options = new()
{
ResponseFormat = ChatResponseFormat.CreateJsonSchemaFormat(
jsonSchemaFormatName: "razonamiento_matematico",
jsonSchema: BinaryData.FromBytes("""
{
"type": "object",
"properties": {
"pasos": {
"type": "array",
"items": {
"type": "object",
"properties": {
"explicacion": { "type": "string" },
"resultado": { "type": "string" }
},
"required": ["explicacion", "resultado"],
"additionalProperties": false
}
},
"respuesta_final": { "type": "string" }
},
"required": ["pasos", "respuesta_final"],
"additionalProperties": false
}
"""u8.ToArray()),
jsonSchemaIsStrict: true)
};
ChatCompletion completion = await chatClient.CompleteChatAsync(
[new UserChatMessage("¿Cómo resuelvo 8x + 7 = -23?")],
options);
using JsonDocument json = JsonDocument.Parse(completion.Content[0].Text);
Console.WriteLine($"Respuesta: {json.RootElement.GetProperty("respuesta_final")}");
Modelos de razonamiento (o1, o4-mini)
ChatCompletionOptions options = new()
{
ReasoningEffortLevel = ChatReasoningEffortLevel.Low,
MaxOutputTokenCount = 100000
};
ChatCompletion completion = await chatClient.CompleteChatAsync(
[
new DeveloperChatMessage("Eres un asistente útil"),
new UserChatMessage("Explica la teoría de la relatividad")
], options);
Integración con 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("¿Qué planes de salud están disponibles?")],
options);
ChatMessageContext context = completion.GetMessageContext();
if (context?.Intent is not null)
{
Console.WriteLine($"Intención: {context.Intent}");
}
foreach (ChatCitation citation in context?.Citations ?? [])
{
Console.WriteLine($"Cita: {citation.Content}");
}
Embeddings
using OpenAI.Embeddings;
EmbeddingClient embeddingClient = azureClient.GetEmbeddingClient("text-embedding-ada-002");
OpenAIEmbedding embedding = await embeddingClient.GenerateEmbeddingAsync("¡Hola, mundo!");
ReadOnlyMemory<float> vector = embedding.ToFloats();
Console.WriteLine($"Dimensiones del embedding: {vector.Length}");
Embeddings por lotes
List<string> inputs = new()
{
"Texto del primer documento",
"Texto del segundo documento",
"Texto del tercer documento"
};
OpenAIEmbeddingCollection embeddings = await embeddingClient.GenerateEmbeddingsAsync(inputs);
foreach (OpenAIEmbedding emb in embeddings)
{
Console.WriteLine($"Índice {emb.Index}: {emb.ToFloats().Length} dimensiones");
}
Generación de imágenes (DALL-E)
using OpenAI.Images;
ImageClient imageClient = azureClient.GetImageClient("dall-e-3");
GeneratedImage image = await imageClient.GenerateImageAsync(
"Un horizonte urbano futurista al atardecer",
new ImageGenerationOptions
{
Size = GeneratedImageSize.W1024xH1024,
Quality = GeneratedImageQuality.High,
Style = GeneratedImageStyle.Vivid
});
Console.WriteLine($"URL de la imagen: {image.ImageUri}");
Audio (Whisper)
Transcripción
using OpenAI.Audio;
AudioClient audioClient = azureClient.GetAudioClient("whisper");
AudioTranscription transcription = await audioClient.TranscribeAudioAsync(
"audio.mp3",
new AudioTranscriptionOptions
{
ResponseFormat = AudioTranscriptionFormat.Verbose,
Language = "es"
});
Console.WriteLine(transcription.Text);
Texto a voz
BinaryData speech = await audioClient.GenerateSpeechAsync(
"Hola, ¡bienvenido a Azure OpenAI!",
GeneratedSpeechVoice.Alloy,
new SpeechGenerationOptions
{
SpeedRatio = 1.0f,
ResponseFormat = GeneratedSpeechFormat.Mp3
});
await File.WriteAllBytesAsync("output.mp3", speech.ToArray());
Llamada a funciones (Tools)
ChatTool getCurrentWeatherTool = ChatTool.CreateFunctionTool(
functionName: "obtener_clima_actual",
functionDescription: "Obtiene el clima actual en una ubicación dada",
functionParameters: BinaryData.FromString("""
{
"type": "object",
"properties": {
"ubicacion": {
"type": "string",
"description": "La ciudad y estado, ej. Ciudad de México, CDMX"
},
"unidad": {
"type": "string",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["ubicacion"]
}
"""));
ChatCompletionOptions options = new()
{
Tools = { getCurrentWeatherTool }
};
ChatCompletion completion = await chatClient.CompleteChatAsync(
[new UserChatMessage("¿Qué clima hace en Seattle?")],
options);
if (completion.FinishReason == ChatFinishReason.ToolCalls)
{
foreach (ChatToolCall toolCall in completion.ToolCalls)
{
Console.WriteLine($"Función: {toolCall.FunctionName}");
Console.WriteLine($"Argumentos: {toolCall.FunctionArguments}");
}
}
Referencia de tipos clave
| Tipo | Propósito |
|---|
AzureOpenAIClient | Cliente de nivel superior para Azure OpenAI |
ChatClient | Finalizaciones de chat |
EmbeddingClient | Embeddings de texto |
ImageClient | Generación de imágenes (DALL-E) |
AudioClient | Transcripción de audio/TTS |
ChatCompletion | Respuesta de chat |
ChatCompletionOptions | Configuración de solicitudes |
StreamingChatCompletionUpdate | Fragmento de respuesta en streaming |
ChatMessage | Tipo base de mensaje |
SystemChatMessage | Prompt del sistema |
UserChatMessage | Entrada del usuario |
AssistantChatMessage | Respuesta del asistente |
DeveloperChatMessage | Mensaje de desarrollador (modelos de razonamiento) |
ChatTool | Definición de función/herramienta |
ChatToolCall | Solicitud de invocación de herramienta |
Buenas prácticas
- Usar Entra ID en producción — Evitar claves de API; usar
DefaultAzureCredential
- Reutilizar instancias de cliente — Crear una vez, compartir entre solicitudes
- Manejar límites de tasa — Implementar retroceso exponencial para errores 429
- Transmitir respuestas largas — Usar
CompleteChatStreamingAsync para mejor experiencia de usuario
- Establecer tiempos de espera adecuados — Finalizaciones largas pueden necesitar tiempos de espera extendidos
- Usar salidas estructuradas — El esquema JSON garantiza un formato de respuesta consistente
- Monitorear uso de tokens — Seguir
completion.Usage para la gestión de costos
- Validar llamadas a herramientas — Siempre validar los argumentos de las funciones antes de ejecutarlas
Manejo de errores
using Azure;
try
{
ChatCompletion completion = await chatClient.CompleteChatAsync(messages);
}
catch (RequestFailedException ex) when (ex.Status == 429)
{
Console.WriteLine("Límite de tasa alcanzado. Reintentar tras una pausa.");
await Task.Delay(TimeSpan.FromSeconds(10));
}
catch (RequestFailedException ex) when (ex.Status == 400)
{
Console.WriteLine($"Solicitud incorrecta: {ex.Message}");
}
catch (RequestFailedException ex)
{
Console.WriteLine($"Error de Azure OpenAI: {ex.Status} - {ex.Message}");
}
SDKs relacionados
| SDK | Propósito | Instalación |
|---|
Azure.AI.OpenAI | Cliente de Azure OpenAI (este SDK) | dotnet add package Azure.AI.OpenAI |
OpenAI | Compatibilidad con OpenAI | dotnet add package OpenAI |
Azure.Identity | Autenticación | dotnet add package Azure.Identity |
Azure.Search.Documents | AI Search para RAG | dotnet add package Azure.Search.Documents |
Enlaces de referencia