Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Cet article explique comment utiliser des modèles modals Azure OpenAI pour générer des réponses aux messages utilisateur et charger des images dans une application de conversation. Cet exemple d’application de conversation inclut également toute l’infrastructure et la configuration nécessaires pour approvisionner des ressources Azure OpenAI et déployer l’application sur Azure Container Apps à l’aide de l’interface DE ligne de commande du développeur Azure.
En suivant les instructions de cet article, vous allez :
- Déployez une application de conversation Azure Container qui utilise l’identité managée pour l’authentification.
- Chargez des images à utiliser dans le flux de conversation.
- Discutez avec un modèle de langage large (LLM) modal Azure OpenAI à l’aide de la bibliothèque OpenAI.
Une fois cet article terminé, vous pouvez commencer à modifier le nouveau projet avec votre code personnalisé.
Remarque
Cet article utilise un ou plusieurs modèles d’application IA comme base pour les exemples et les conseils qu’il contient. Les modèles d’application IA vous fournissent des implémentations de référence bien gérées et faciles à déployer, qui constituent un point de départ de qualité pour vos applications IA.
Vue d’ensemble de l’architecture
Une architecture simple de l’application de conversation est illustrée dans le diagramme suivant :
L’application de conversation s’exécute en tant qu’application conteneur Azure. L’application utilise une identité managée via l’ID Microsoft Entra pour s’authentifier auprès d’Azure OpenAI en production, au lieu d’une clé API. Pendant le développement, l’application prend en charge plusieurs méthodes d’authentification, notamment les informations d’identification de l’interface CLI pour développeurs Azure, les clés API et les modèles GitHub pour les tests sans ressources Azure.
L’architecture d’application s’appuie sur les services et composants suivants :
- Azure OpenAI représente le fournisseur d'IA auquel nous envoyons les requêtes de l'utilisateur.
- Azure Container Apps est l'environnement de conteneurs dans lequel l'application est hébergée.
- Managed Identity nous aide à garantir une sécurité optimale et élimine la nécessité pour vous en tant que développeur de gérer en toute sécurité un secret.
- Fichiers Bicep pour l’approvisionnement de ressources Azure, notamment Azure OpenAI, Azure Container Apps, Azure Container Registry, Azure Log Analytics et les rôles de contrôle d’accès en fonction du rôle (RBAC).
- Microsoft AI Chat Protocol fournit des contrats d’API standardisés pour les solutions et les langages d’IA. L’application de conversation est conforme au protocole Microsoft AI Chat.
- Quart Python qui utilise le
openaipackage pour générer des réponses aux messages utilisateur avec des fichiers image chargés. - Frontend HTML/JavaScript de base qui diffuse des réponses du back-end à l’aide de lignes JSON sur un readableStream.
Cost
Dans une tentative de maintenir la tarification aussi faible que possible dans cet exemple, la plupart des ressources utilisent un niveau tarifaire de base ou de consommation. Modifiez votre niveau selon vos besoins en fonction de votre utilisation prévue. Pour arrêter les frais, supprimez les ressources lorsque vous avez terminé avec l’article.
En savoir plus sur les coûts dans l’exemple de dépôt.
Prérequis
Un environnement de conteneur de développement est disponible avec toutes les dépendances requises pour terminer cet article. Vous pouvez exécuter le conteneur de développement dans GitHub Codespaces (dans un navigateur) ou localement à l’aide de Visual Studio Code.
Pour utiliser cet article, vous devez remplir les conditions préalables suivantes :
Un abonnement Azure - En créer un gratuitement
Autorisations de compte Azure : votre compte Azure doit disposer
Microsoft.Authorization/roleAssignments/writed’autorisations, telles que l’administrateur de l’accès utilisateur ou le propriétaire.GitHub
Environnement de développement ouvert
Utilisez les instructions suivantes pour déployer un environnement de développement préconfiguré contenant toutes les dépendances requises pour terminer cet article.
GitHub Codespaces exécute un conteneur de développement géré par GitHub avec Visual Studio Code pour le web comme interface utilisateur. Pour un environnement de développement le plus simple, utilisez GitHub Codespaces pour disposer des outils de développement et des dépendances appropriés préinstallés pour terminer cet article.
Important
Tous les comptes GitHub peuvent utiliser Des espaces de code pour jusqu’à 60 heures gratuites chaque mois avec deux instances principales. Pour plus d’informations, consultez Le stockage mensuel inclus et les heures de cœur GitHub Codespaces.
Procédez comme suit pour créer un espace de code GitHub sur la main branche du Azure-Samples/openai-chat-vision-quickstart dépôt GitHub.
Cliquez avec le bouton droit sur le bouton suivant, puis sélectionnez Ouvrir le lien dans la nouvelle fenêtre. Cette action vous permet d’avoir l’environnement de développement et la documentation disponible pour révision.
Dans la page Créer un espace de code, passez en revue, puis sélectionnez Créer un espace de code
Attendez que le codespace démarre. Ce processus de démarrage peut prendre quelques minutes.
Connectez-vous à Azure avec Azure Developer CLI dans le terminal en bas de l’écran.
azd auth loginCopiez le code à partir du terminal, puis collez-le dans un navigateur. Suivez les instructions pour vous authentifier avec votre compte Azure.
Les tâches restantes de cet article s’effectuent dans ce conteneur de développement.
Déployer et exécuter
L’exemple de référentiel contient tous les fichiers de code et de configuration du déploiement Azure de l’application de conversation. Les étapes suivantes vous guident dans l’exemple de processus de déploiement Azure de l’application de conversation.
Déployer une application de conversation sur Azure
Important
Pour réduire les coûts, cet exemple utilise des niveaux tarifaires de base ou de consommation pour la plupart des ressources. Ajustez le niveau en fonction des besoins, puis supprimez les ressources une fois terminé pour éviter des frais.
Exécutez la commande AZURE Developer CLI suivante pour le provisionnement de ressources Azure et le déploiement de code source :
azd upUtilisez le tableau suivant pour répondre aux invites :
Prompt Réponse Nom de l’environnement Gardez-le court et en minuscules. Ajoutez votre nom ou votre pseudo. Par exemple : chat-vision. Il est utilisé comme partie du nom du groupe de ressources.Abonnement Sélectionnez l’abonnement pour créer les ressources. Emplacement (pour l’hébergement) Sélectionnez un emplacement près de chez vous dans la liste. Emplacement du modèle Azure OpenAI Sélectionnez un emplacement près de chez vous dans la liste. Si le premier emplacement choisi est également disponible, sélectionnez-le. Attendez que l’application soit déployée. Le déploiement prend généralement entre 5 et 10 minutes.
Utiliser l’application de conversation pour poser des questions au modèle de langage volumineux
Le terminal affiche une URL après le déploiement réussi de l’application.
Sélectionnez cette URL étiquetée
Deploying service webpour ouvrir l’application de conversation dans un navigateur.Dans le navigateur, chargez une image en cliquant sur Choisir un fichier et en sélectionnant une image.
Posez une question sur l’image chargée, telle que « Qu’est-ce que l’image à propos ? ».
La réponse provient d’Azure OpenAI et le résultat s’affiche.
Exploration de l’exemple de code
Bien qu’OpenAI et Azure OpenAI Service s’appuient sur une bibliothèque de client Python commune, de petites modifications de code sont nécessaires lors de l’utilisation de points de terminaison Azure OpenAI. Cet exemple utilise un modèle modal Azure OpenAI pour générer des réponses aux messages utilisateur et charger des images.
Encodage base64 de l’image chargée dans le front-end
L’image chargée doit être encodée en Base64 afin qu’elle puisse être utilisée directement en tant qu’URI de données dans le cadre du message.
Dans l’exemple, l’extrait de code front-end suivant dans la scriptbalise du src/quartapp/templates/index.html fichier gère cette fonctionnalité. La toBase64 fonction de flèche utilise la readAsDataURL méthode de lectureFileReader asynchrone dans le fichier image chargé en tant que chaîne encodée en base64.
const toBase64 = file => new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
});
La toBase64 fonction est appelée par un écouteur sur l’événement du submit formulaire.
L'écouteur d'événement submit gère le flux complet d'interaction de chat. Lorsque l’utilisateur envoie un message, le flux suivant se produit :
- Masque l’élément « no-messages-heading » pour afficher la conversation démarrée
- Obtient et encode base64 le fichier image chargé (le cas échéant)
- Crée et affiche le message de l’utilisateur dans la conversation, y compris l’image chargée
- Préprare un conteneur de messages d’assistant avec un indicateur « saisie… »
- Ajoute le message de l’utilisateur au tableau d’historique des messages
- Appelle la méthode du
getStreamedCompletion()client ai Chat Protocol avec l’historique et le contexte des messages (y compris l’image et le nom de fichier encodés en Base64) - Traite les blocs de réponse diffusés et convertit Markdown en HTML à l’aide de Showdown.js
- Gère les erreurs lors de la diffusion en continu
- Ajoute un bouton de sortie vocale après avoir reçu la réponse complète afin que les utilisateurs puissent entendre la réponse
- Efface le champ d’entrée et retourne le focus pour le message suivant
form.addEventListener("submit", async function(e) {
e.preventDefault();
// Hide the no-messages-heading when a message is added
document.getElementById("no-messages-heading").style.display = "none";
const file = document.getElementById("file").files[0];
const fileData = file ? await toBase64(file) : null;
const message = messageInput.value;
const userTemplateClone = userTemplate.content.cloneNode(true);
userTemplateClone.querySelector(".message-content").innerText = message;
if (file) {
const img = document.createElement("img");
img.src = fileData;
userTemplateClone.querySelector(".message-file").appendChild(img);
}
targetContainer.appendChild(userTemplateClone);
const assistantTemplateClone = assistantTemplate.content.cloneNode(true);
let messageDiv = assistantTemplateClone.querySelector(".message-content");
targetContainer.appendChild(assistantTemplateClone);
messages.push({
"role": "user",
"content": message
});
try {
messageDiv.scrollIntoView();
const result = await client.getStreamedCompletion(messages, {
context: {
file: fileData,
file_name: file ? file.name : null
}
});
let answer = "";
for await (const response of result) {
if (!response.delta) {
continue;
}
if (response.delta.content) {
// Clear out the DIV if its the first answer chunk we've received
if (answer == "") {
messageDiv.innerHTML = "";
}
answer += response.delta.content;
messageDiv.innerHTML = converter.makeHtml(answer);
messageDiv.scrollIntoView();
}
if (response.error) {
messageDiv.innerHTML = "Error: " + response.error;
}
}
messages.push({
"role": "assistant",
"content": answer
});
messageInput.value = "";
const speechOutput = document.createElement("speech-output-button");
speechOutput.setAttribute("text", answer);
messageDiv.appendChild(speechOutput);
messageInput.focus();
} catch (error) {
messageDiv.innerHTML = "Error: " + error;
}
});
Gestion de l’image avec le back-end
Dans le fichier, le code principal pour la src\quartapp\chat.py gestion des images démarre après la configuration de l’authentification sans clé.
Remarque
Pour plus d’informations sur l’utilisation de connexions sans clé pour l’authentification et l’autorisation auprès d’Azure OpenAI, consultez l’article Prise en main du bloc de construction de sécurité Azure OpenAI microsoft Learn.
Configuration de l'authentification
La configure_openai() fonction configure le client OpenAI avant que l’application commence à traiter les requêtes. Il utilise le décorateur @bp.before_app_serving de Quart pour configurer l’authentification basée sur des variables d’environnement. Ce système flexible permet aux développeurs de travailler dans différents contextes sans modifier le code.
Modes d’authentification expliqués
-
Développement local (
OPENAI_HOST=local) : se connecte à un service d’API compatible OpenAI local (tel que Ollama ou LocalAI) sans authentification. Utilisez ce mode pour les tests sans coût Internet ou API. -
Modèles GitHub (
OPENAI_HOST=github) : utilise la Place de marché des modèles IA de GitHub avec uneGITHUB_TOKENauthentification. Lors de l’utilisation de modèles GitHub, préfixez le nomopenai/du modèle par (par exemple).openai/gpt-4oCe mode permet aux développeurs d’essayer des modèles avant de provisionner des ressources Azure. -
Azure OpenAI avec clé API (
AZURE_OPENAI_KEY_FOR_CHATVISIONvariable d’environnement) : utilise une clé API pour l’authentification. Évitez ce mode en production, car les clés API nécessitent une rotation manuelle et présentent des risques de sécurité en cas d’exposition. Utilisez-le pour les tests locaux à l’intérieur d’un conteneur Docker sans informations d’identification Azure CLI. -
Production avec identité managée (
RUNNING_IN_PRODUCTION=true) : utiliseManagedIdentityCredentialpour s’authentifier auprès d’Azure OpenAI via l’identité managée de l’application conteneur. Cette méthode est recommandée pour la production, car elle supprime la nécessité de gérer les secrets. Azure Container Apps fournit automatiquement l’identité managée et accorde des autorisations pendant le déploiement via Bicep. -
Développement avec Azure CLI (mode par défaut) : utilise
AzureDeveloperCliCredentialpour s’authentifier auprès d’Azure OpenAI à l’aide des informations d’identification Azure CLI connectées localement. Ce mode simplifie le développement local sans gérer les clés API.
Détails de l’implémentation clé
- La fonction
get_bearer_token_provider()actualise les identifiants Azure et les utilise comme jetons d'accès. - Le chemin du point de terminaison Azure OpenAI inclut
/openai/v1/pour répondre aux exigences de la bibliothèque cliente OpenAI. - La journalisation indique le mode d’authentification actif.
- La fonction est asynchrone pour prendre en charge les opérations liées aux identifiants Azure.
Voici le code complet de configuration de l’authentification à partir de chat.py:
@bp.before_app_serving
async def configure_openai():
bp.model_name = os.getenv("OPENAI_MODEL", "gpt-4o")
openai_host = os.getenv("OPENAI_HOST", "github")
if openai_host == "local":
bp.openai_client = AsyncOpenAI(api_key="no-key-required", base_url=os.getenv("LOCAL_OPENAI_ENDPOINT"))
current_app.logger.info("Using local OpenAI-compatible API service with no key")
elif openai_host == "github":
bp.model_name = f"openai/{bp.model_name}"
bp.openai_client = AsyncOpenAI(
api_key=os.environ["GITHUB_TOKEN"],
base_url="https://models.github.ai/inference",
)
current_app.logger.info("Using GitHub models with GITHUB_TOKEN as key")
elif os.getenv("AZURE_OPENAI_KEY_FOR_CHATVISION"):
bp.openai_client = AsyncOpenAI(
base_url=os.environ["AZURE_OPENAI_ENDPOINT"],
api_key=os.getenv("AZURE_OPENAI_KEY_FOR_CHATVISION"),
)
current_app.logger.info("Using Azure OpenAI with key")
elif os.getenv("RUNNING_IN_PRODUCTION"):
client_id = os.environ["AZURE_CLIENT_ID"]
azure_credential = ManagedIdentityCredential(client_id=client_id)
token_provider = get_bearer_token_provider(azure_credential, "https://cognitiveservices.azure.com/.default")
bp.openai_client = AsyncOpenAI(
base_url=os.environ["AZURE_OPENAI_ENDPOINT"] + "/openai/v1/",
api_key=token_provider,
)
current_app.logger.info("Using Azure OpenAI with managed identity credential for client ID %s", client_id)
else:
tenant_id = os.environ["AZURE_TENANT_ID"]
azure_credential = AzureDeveloperCliCredential(tenant_id=tenant_id)
token_provider = get_bearer_token_provider(azure_credential, "https://cognitiveservices.azure.com/.default")
bp.openai_client = AsyncOpenAI(
base_url=os.environ["AZURE_OPENAI_ENDPOINT"] + "/openai/v1/",
api_key=token_provider,
)
current_app.logger.info("Using Azure OpenAI with az CLI credential for tenant ID: %s", tenant_id)
Fonction de gestionnaire de conversation
La fonction chat_handler() traite les requêtes de chat envoyées au point de terminaison /chat/stream. Il reçoit une requête POST avec une charge utile JSON qui suit le protocole Microsoft AI Chat.
La charge utile JSON comprend :
-
messages : liste de l’historique des conversations. Chaque message a un
role(« utilisateur » ou « Assistant ») etcontent(le texte du message). -
contexte : Données supplémentaires pour le traitement, notamment :
-
fichier : données d’image encodées en base64 (par exemple,
data:image/png;base64,...). - file_name : nom de fichier d’origine de l’image chargée (utile pour la journalisation ou l’identification du type d’image).
-
fichier : données d’image encodées en base64 (par exemple,
- température (facultatif) : float qui contrôle l’aléatoire de la réponse (la valeur par défaut est 0,5).
Le gestionnaire extrait l’historique des messages et les données d’image. Si aucune image n’est chargée, la valeur de l’image est nullet le code gère ce cas.
@bp.post("/chat/stream")
async def chat_handler():
request_json = await request.get_json()
request_messages = request_json["messages"]
# Get the base64 encoded image from the request context
# This will be None if no image was uploaded
image = request_json["context"]["file"]
# The context also includes the filename for reference
# file_name = request_json["context"]["file_name"]
Création du tableau de messages pour les demandes de vision
La response_stream() fonction prépare le tableau de messages qui est envoyé à l’API Azure OpenAI. Le @stream_with_context décorateur conserve le contexte de la requête lors de la diffusion en continu de la réponse.
Logique de préparation des messages
-
Commencer par l’historique des conversations : la fonction commence par
all_messages, qui inclut un message système et tous les messages précédents, à l’exception de la dernière (request_messages[0:-1]). -
Gérez le message utilisateur actuel en fonction de la présence d’image :
-
Avec l’image : Mettez en forme le message de l’utilisateur en tant que tableau de contenu en plusieurs parties avec du texte et des objets image_url. L’objet
image_urlcontient les données d’image encodées en Base64 et undetailparamètre. - Sans image : ajoutez le message de l’utilisateur en texte brut.
-
Avec l’image : Mettez en forme le message de l’utilisateur en tant que tableau de contenu en plusieurs parties avec du texte et des objets image_url. L’objet
-
Paramètre
detail: défini sur « auto » pour permettre au modèle de choisir entre les détails « bas » et « élevé » en fonction de la taille de l’image. Les détails faibles sont plus rapides et moins chers, tandis que les détails élevés fournissent une analyse plus précise pour les images complexes.
@stream_with_context
async def response_stream():
# This sends all messages, so API request may exceed token limits
all_messages = [
{"role": "system", "content": "You are a helpful assistant."},
] + request_messages[0:-1]
all_messages = request_messages[0:-1]
if image:
user_content = []
user_content.append({"text": request_messages[-1]["content"], "type": "text"})
user_content.append({"image_url": {"url": image, "detail": "auto"}, "type": "image_url"})
all_messages.append({"role": "user", "content": user_content})
else:
all_messages.append(request_messages[-1])
Remarque
Pour plus d’informations sur le paramètre d’image detail et les paramètres associés, consultez la section Paramètres de détail de l’article « Utiliser des modèles de conversation compatibles avec vision » Dans l’article Microsoft Learn.
Ensuite, bp.openai_client.chat.completions obtient les achèvements de conversation via un appel d’API Azure OpenAI et diffuse la réponse.
chat_coroutine = bp.openai_client.chat.completions.create(
# Azure OpenAI takes the deployment name as the model name
model=bp.model_name,
messages=all_messages,
stream=True,
temperature=request_json.get("temperature", 0.5),
)
Enfin, la réponse est redirigée vers le client, avec une gestion des erreurs pour toutes les exceptions.
try:
async for event in await chat_coroutine:
event_dict = event.model_dump()
if event_dict["choices"]:
yield json.dumps(event_dict["choices"][0], ensure_ascii=False) + "\n"
except Exception as e:
current_app.logger.error(e)
yield json.dumps({"error": str(e)}, ensure_ascii=False) + "\n"
return Response(response_stream())
Bibliothèques et fonctionnalités front-end
Le serveur frontal utilise des API et des bibliothèques de navigateur modernes pour créer une expérience de conversation interactive. Les développeurs peuvent personnaliser l’interface ou ajouter des fonctionnalités en comprenant ces composants :
Entrée/sortie vocale : les composants web personnalisés utilisent les API Speech du navigateur :
<speech-input-button>: convertit la voix en texte à l’aide deSpeechRecognitionl’API Web Speech. Il fournit un bouton de microphone qui écoute l’entrée vocale et émet unspeech-input-resultévénement avec le texte transcrit.<speech-output-button>: lit le texte à haute voix à l’aide de l’APISpeechSynthesis. Il apparaît après chaque réponse de l’Assistant avec une icône de haut-parleur, ce qui permet aux utilisateurs d’entendre la réponse.
Pourquoi utiliser des API de navigateur au lieu d’Azure Speech Services ?
- Aucun coût - s’exécute entièrement dans le navigateur
- Réponse instantanée : aucune latence réseau
- Confidentialité : les données vocales restent sur l’appareil de l’utilisateur
- Aucune ressource Azure supplémentaire n’est nécessaire
Ces composants sont dans
src/quartapp/static/speech-input.jsetspeech-output.js.Aperçu de l’image : affiche l’image chargée dans la conversation avant l’envoi de l’analyse pour confirmation. La préversion est mise à jour automatiquement lorsqu’un fichier est sélectionné.
fileInput.addEventListener("change", async function() { const file = fileInput.files[0]; if (file) { const fileData = await toBase64(file); imagePreview.src = fileData; imagePreview.style.display = "block"; } });Bootstrap 5 et Bootstrap Icons : fournit des composants d'interface utilisateur et des icônes réactifs. L’application utilise le thème Cosmo de Bootswatch pour une apparence moderne.
Rendu de message basé sur un modèle : utilise des éléments HTML
<template>pour les dispositions de messages réutilisables, ce qui garantit un style et une structure cohérents.
Autres exemples de ressources à explorer
En plus de l’exemple d’application de conversation, il existe d’autres ressources dans le référentiel pour explorer davantage d’apprentissage. Consultez les blocs-notes suivants dans le notebooks répertoire :
| Notebook | Description |
|---|---|
| chat_pdf_images.ipynb | Ce bloc-notes montre comment convertir des pages PDF en images et les envoyer à un modèle de vision pour l’inférence. |
| chat_vision.ipynb | Ce notebook est fourni pour l’expérimentation manuelle avec le modèle de vision utilisé dans l’application. |
Contenu localisé : les versions espagnoles des blocs-notes se trouvent dans le notebooks/Spanish/ répertoire, offrant la même formation pratique pour les développeurs espagnols. Les blocs-notes anglais et espagnols montrent :
- Comment appeler des modèles de vision directement pour l’expérimentation
- Comment convertir des pages PDF en images à des fins d’analyse
- Comment ajuster les paramètres et les invites de test
Nettoyer les ressources
Nettoyage des ressources Azure
Les ressources Azure créées dans cet article sont facturées dans votre abonnement Azure. Si vous pensez ne plus avoir besoin de ces ressources, supprimez-les pour éviter des frais supplémentaires.
Pour supprimer les ressources Azure et supprimer le code source, exécutez la commande CLI Azure Developer suivante :
azd down --purge
Nettoyer GitHub Codespaces
La suppression de l’environnement GitHub Codespaces vous permet d’optimiser le nombre d’heures gratuites par cœur que vous obtenez pour votre compte.
Important
Pour plus d’informations sur les droits de votre compte GitHub, consultez GitHub Codespaces mensuel inclus stockage et heures principales.
Connectez-vous au tableau de bord GitHub Codespaces.
Localisez vos codespaces en cours d’exécution provenant du référentiel GitHub
Azure-Samples//openai-chat-vision-quickstart.Ouvrez le menu contextuel du codespace et sélectionnez Supprimer.
Obtenir de l’aide
Consignez votre problème dans les problèmes du référentiel.