Bibliothèque de client Azure OpenAI pour .NET - version 1.0.0-beta.9

La bibliothèque de client Azure OpenAI pour .NET est une adaptation des API REST d’OpenAI qui fournit une interface idiomatique et une intégration riche avec le reste de l’écosystème du SDK Azure. Il peut se connecter à des ressources Azure OpenAI ou au point de terminaison d’inférence OpenAI non-Azure, ce qui en fait un excellent choix pour le développement non-Azure OpenAI.

Utilisez la bibliothèque cliente pour Azure OpenAI pour :

Azure OpenAI est un service managé qui permet aux développeurs de déployer, d’ajuster et de générer du contenu à partir de modèles OpenAI sur des ressources Azure.

| Code sourcePackage (NuGet) | Documentation de référence sur les | API | Documentation produitÉchantillons

Prise en main

Prérequis

Si vous souhaitez utiliser une ressource Azure OpenAI, vous devez disposer d’un abonnement Azure et d’un accès Azure OpenAI. Cela vous permet de créer une ressource Azure OpenAI et d’obtenir à la fois une URL de connexion et des clés API. Pour plus d’informations, consultez Démarrage rapide : Prise en main de la génération de texte à l’aide du service Azure OpenAI.

Si vous souhaitez utiliser la bibliothèque cliente Azure OpenAI .NET pour vous connecter à des éléments non-Azure OpenAI, vous aurez besoin d’une clé API à partir d’un compte de développeur à l’adresse https://platform.openai.com/.

Installer le package

Installez la bibliothèque cliente pour .NET avec NuGet :

dotnet add package Azure.AI.OpenAI --prerelease

Authentifier le client

Pour interagir avec Azure OpenAI ou OpenAI, vous devez créer un instance de la classe OpenAIClient. Pour configurer un client à utiliser avec Azure OpenAI, fournissez un URI de point de terminaison valide à une ressource Azure OpenAI, ainsi qu’une clé d’identification, des informations d’identification de jeton ou des informations d’identification d’identité Azure autorisées à utiliser la ressource Azure OpenAI. Pour configurer le client pour qu’il se connecte au service OpenAI, fournissez une clé API à partir du portail des développeurs d’OpenAI.

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");

Créer OpenAIClient avec des informations d’identification Azure Active Directory

L’authentification par clé d’abonnement client est utilisée dans la plupart des exemples de ce guide de prise en main, mais vous pouvez également vous authentifier auprès d’Azure Active Directory à l’aide de la bibliothèque Azure Identity. Pour utiliser le fournisseur DefaultAzureCredential indiqué ci-dessous, ou d’autres fournisseurs d’informations d’identification fournis avec le Kit de développement logiciel (SDK) Azure, installez le package Azure.Identity :

dotnet add package Azure.Identity
string endpoint = "https://myaccount.openai.azure.com/";
var client = new OpenAIClient(new Uri(endpoint), new DefaultAzureCredential());

Concepts clés

Le concept main à comprendre est Complétion. Expliqué brièvement, les complétions fournissent leurs fonctionnalités sous la forme d’une invite de texte, qui, à l’aide d’un modèle spécifique, tente ensuite de faire correspondre le contexte et les modèles, en fournissant un texte de sortie. L’extrait de code suivant fournit une vue d’ensemble approximative (vous trouverez plus de détails dans l’exemple GenerateChatbotResponsesWithToken de code) :

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);
}

Sécurité des threads

Nous garantissons que toutes les méthodes de instance client sont thread-safe et indépendantes les unes des autres (instructions). Cela garantit que la recommandation de réutilisation des instances clientes est toujours sécurisée, même entre les threads.

Concepts supplémentaires

Options | du clientAccès à la réponse | Opérations | de longue duréeGestion des défaillances | Diagnostics | Moqueur | Durée de vie du client

Exemples

Vous pouvez vous familiariser avec différentes API à l’aide d’exemples.

Générer une réponse de chatbot

La GenerateChatbotResponse méthode s’authentifie à l’aide d’un DefaultAzureCredential, puis génère des réponses de texte aux invites d’entrée.

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}");

Générer plusieurs réponses de chatbot avec la clé d’abonnement

La GenerateMultipleChatbotResponsesWithSubscriptionKey méthode fournit un exemple de génération de réponses de texte aux invites d’entrée à l’aide d’une clé d’abonnement 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}");
}

Résumer le texte avec la saisie semi-automatique

La SummarizeText méthode génère un résumé de l’invite d’entrée donnée.

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}");

Diffuser en continu des messages de conversation avec non-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);
    }
}

Lorsque vous en demandez explicitement plusieurs Choice lors de la diffusion en continu, utilisez la ChoiceIndex propriété on StreamingChatCompletionsUpdate pour déterminer à laquelle Choice correspond chaque mise à jour.

// 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;
        }
    }
}

Utiliser des fonctions de conversation

Les fonctions de conversation permettent à un appelant d’achèvements de conversation de définir des fonctionnalités que le modèle peut utiliser pour étendre ses fonctionnalités à des outils externes et des sources de données.

Vous pouvez en savoir plus sur les fonctions de conversation sur le blog d’OpenAI : https://openai.com/blog/function-calling-and-other-api-updates

REMARQUE : Les fonctions de conversation nécessitent des versions de modèle commençant par les étiquettes gpt-4 et gpt-3.5-turbo -0613 . Ils ne sont pas disponibles avec les versions antérieures des modèles.

NOTE: L’utilisation simultanée des fonctions de conversation et des extensions de conversation Azure sur une seule requête n’est pas encore prise en charge. Si vous fournissez les deux, les informations des fonctions de conversation sont ignorées et l’opération se comporte comme si seules les extensions de conversation Azure étaient fournies. Pour résoudre cette limitation, envisagez de séparer l’évaluation des fonctions de conversation et des extensions de conversation Azure entre plusieurs demandes dans votre conception de solution.

Pour utiliser les fonctions de conversation, vous définissez d’abord la fonction que vous souhaitez que le modèle puisse utiliser le cas échéant. En utilisant l’exemple du billet de blog lié, ci-dessus :

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 }),
};

Une fois la fonction définie, elle peut ensuite être utilisée dans une demande d’achèvement de conversation via ses options. Les données de fonction sont gérées sur plusieurs appels qui créent des données pour les demandes sans état suivantes. Nous conservons donc une liste de messages de conversation sous forme d’historique des conversations.

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);

Si le modèle détermine qu’il doit appeler une fonction de conversation, une raison de fin de « FunctionCall » est renseignée sur le choix et les détails sont présents dans la propriété du message de FunctionCall réponse. En règle générale, le nom de l’appel de fonction est celui qui a été fourni et les arguments sont un document JSON rempli correspondant au schéma inclus dans le FunctionDefinition utilisé ; il n’est pas garanti que ces données sont valides ou même correctement mises en forme. Toutefois, la validation et la vérification des erreurs doivent toujours accompagner le traitement des appels de fonction.

Pour résoudre l’appel de fonction et poursuivre l’interaction avec l’utilisateur, traitez la charge utile de l’argument en fonction des besoins, puis sérialisez les données de réponse appropriées dans un nouveau message avec ChatRole.Function. Ensuite, effectuez une nouvelle demande avec tous les messages jusqu’à présent (le message initial User , le message de FunctionCall la première réponse et le message de résolution Function généré en réponse à l’appel de fonction) afin que le modèle puisse utiliser les données pour mieux formuler une réponse de fin de conversation.

Notez que la réponse d’appel de fonction que vous fournissez n’a pas besoin de suivre un schéma fourni dans l’appel initial. Le modèle déduit l’utilisation des données de réponse en fonction du contexte déduit des noms et des champs.

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
    }
}

Lors de l’utilisation de la diffusion en continu, capturez les composants de réponse de streaming à mesure qu’ils arrivent et accumulent les arguments de fonction de diffusion en continu de la même manière que pour la diffusion en continu de contenu. Ensuite, au lieu d’utiliser à partir de la réponse de non-diffusion en continu, ajoutez à la ChatMessage place une nouvelle ChatMessage instance pour l’historique, créée à partir des informations diffusées en continu.

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
}

Remarque : bien que les informations de fonction en continu (nom, arguments) puissent être évaluées à mesure qu’elles arrivent, elles ne doivent pas être considérées comme complètes ou confirmées tant que le FinishReason de FunctionCall n’est pas reçu. Il peut être approprié de faire des tentatives de « préchauffage » ou d’autres préparations spéculatives basées sur un nom de fonction ou une clé/valeur particulière apparaissant dans les arguments JSON partiels accumulés, mais aucune hypothèse forte sur la validité, l’ordre ou d’autres détails ne doit être évalué jusqu’à ce que les arguments soient entièrement disponibles et confirmés via FinishReason.

Utiliser vos propres données avec Azure OpenAI

La fonctionnalité Utiliser vos propres données est propre à Azure OpenAI et ne fonctionne pas avec un client configuré pour utiliser le service non-Azure. Consultez le guide de démarrage rapide Azure OpenAI using your own data (Utilisation de vos propres données ) pour obtenir des instructions de configuration détaillées et un arrière-plan conceptuel.

NOTE: L’utilisation simultanée des fonctions de conversation et des extensions de conversation Azure sur une seule requête n’est pas encore prise en charge. Si vous fournissez les deux, les informations des fonctions de conversation sont ignorées et l’opération se comporte comme si seules les extensions de conversation Azure étaient fournies. Pour résoudre cette limitation, envisagez de séparer l’évaluation des fonctions de conversation et des extensions de conversation Azure entre plusieurs demandes dans votre conception de solution.

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}");
}

Générer des incorporations

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;

Générer des images avec des modèles de génération d’images 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;

Transcrire des données audio avec des modèles vocaux Whisper

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);

Traduire des données audio en anglais avec des modèles de voix Whisper

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);

Dépannage

Lorsque vous interagissez avec Azure OpenAI à l’aide du Kit de développement logiciel (SDK) .NET, les erreurs retournées par le service correspondent aux mêmes codes de status HTTP retournés pour les demandes d’API REST.

Par exemple, si vous essayez de créer un client à l’aide d’un point de terminaison qui ne correspond pas à votre point de terminaison de ressource Azure OpenAI, une 404 erreur est retournée, indiquant Resource Not Found.

Étapes suivantes

  • Fournissez un lien vers des exemples de code supplémentaires, idéalement vers ceux qui se trouve à côté du FICHIER LISEZ-MOI dans le répertoire du /samples package.
  • Le cas échéant, pointez les utilisateurs vers d’autres packages qui peuvent être utiles.
  • Si vous pensez qu’il y a de bonnes chances que les développeurs trébuchent sur votre package par erreur (parce qu’ils recherchent des fonctionnalités spécifiques et pensent à tort que le package fournit cette fonctionnalité), pointez-les vers les packages qu’ils recherchent peut-être.

Contribution

Consultez la CONTRIBUTING.md OpenAI pour plus d’informations sur la création, le test et la contribution à cette bibliothèque.

Ce projet accepte les contributions et les suggestions. La plupart des contributions vous demandent d’accepter un contrat de licence de contribution (CLA) déclarant que vous avez le droit de nous accorder, et que vous nous accordez réellement, les droits d’utilisation de votre contribution. Pour plus d’informations, visitez cla.microsoft.com.

Quand vous envoyez une demande de tirage (pull request), un bot CLA détermine automatiquement si vous devez fournir un contrat CLA et agrémenter la demande de tirage de façon appropriée (par exemple, avec une étiquette ou un commentaire). Suivez simplement les instructions fournies par le bot. Vous ne devez effectuer cette opération qu’une seule fois sur tous les dépôts utilisant notre contrat CLA.

Ce projet a adopté le Code de conduite Open Source de Microsoft. Pour plus d’informations, consultez les Questions fréquentes (FAQ) sur le code de conduite ou envoyez vos questions ou vos commentaires à opencode@microsoft.com.

Impressions