Comment utiliser l'appel de fonctions avec Azure OpenAI dans les modèles Microsoft Foundry

Si une ou plusieurs fonctions sont incluses dans votre requête, le modèle détermine si l’une des fonctions doit être appelée en fonction du contexte de l’invite. Lorsque le modèle détermine thatodel une fonction doit être appelée, il répond avec un objet JSON, y compris les arguments de la fonction.

Les modèles formulent des appels d’API et des sorties de données de structure, toutes basées sur les fonctions que vous spécifiez. Il est important de noter que, bien que les modèles puissent générer ces appels, il vous incombe de les exécuter, en vous assurant de rester en contrôle.

À un niveau élevé, vous pouvez décomposer l’utilisation des fonctions en trois étapes :

  1. Appelez l’API de complétion de chat avec vos fonctions et l’entrée de l’utilisateur
  2. Utiliser la réponse du modèle pour appeler votre API ou fonction
  3. Appelez à nouveau l’API de complétions de chat, y compris la réponse de votre fonction pour obtenir une réponse définitive.

Conditions préalables

  • Un modèle OpenAI Azure déployé
  • Pour l’authentification Microsoft Entra ID :

Exemple d’appel d’outil/fonction unique

Tout d'abord, illustrez un appel de fonction jouet qui peut vérifier l'heure dans trois emplacements codés en dur avec une seule fonction définie. Nous avons ajouté des instructions d’impression pour faciliter l’exécution du code :

import os
import json
from openai import OpenAI
from datetime import datetime
from zoneinfo import ZoneInfo
from azure.identity import DefaultAzureCredential, get_bearer_token_provider

token_provider = get_bearer_token_provider(
    DefaultAzureCredential(), "https://ai.azure.com/.default"
)

client = OpenAI(  
  base_url = "https://YOUR-RESOURCE-NAME.openai.azure.com/openai/v1/",  
  api_key=token_provider,
)

# Define the deployment you want to use for your chat completions API calls

deployment_name = "<YOUR_DEPLOYMENT_NAME_HERE>"

# Simplified timezone data
TIMEZONE_DATA = {
    "tokyo": "Asia/Tokyo",
    "san francisco": "America/Los_Angeles",
    "paris": "Europe/Paris"
}

def get_current_time(location):
    """Get the current time for a given location"""
    print(f"get_current_time called with location: {location}")  
    location_lower = location.lower()
    
    for key, timezone in TIMEZONE_DATA.items():
        if key in location_lower:
            print(f"Timezone found for {key}")  
            current_time = datetime.now(ZoneInfo(timezone)).strftime("%I:%M %p")
            return json.dumps({
                "location": location,
                "current_time": current_time
            })
    
    print(f"No timezone data found for {location_lower}")  
    return json.dumps({"location": location, "current_time": "unknown"})

def run_conversation():
    # Initial user message
    messages = [{"role": "user", "content": "What's the current time in San Francisco"}] # Single function call
    #messages = [{"role": "user", "content": "What's the current time in San Francisco, Tokyo, and Paris?"}] # Parallel function call with a single tool/function defined

    # Define the function for the model
    tools = [
        {
            "type": "function",
            "function": {
                "name": "get_current_time",
                "description": "Get the current time in a given location",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "location": {
                            "type": "string",
                            "description": "The city name, e.g. San Francisco",
                        },
                    },
                    "required": ["location"],
                },
            }
        }
    ]

    # First API call: Ask the model to use the function
    response = client.chat.completions.create(
        model=deployment_name,
        messages=messages,
        tools=tools,
        tool_choice="auto",
    )

    # Process the model's response
    response_message = response.choices[0].message
    messages.append(response_message)

    print("Model's response:")  
    print(response_message)  

    # Handle function calls
    if response_message.tool_calls:
        for tool_call in response_message.tool_calls:
            if tool_call.function.name == "get_current_time":
                function_args = json.loads(tool_call.function.arguments)
                print(f"Function arguments: {function_args}")  
                time_response = get_current_time(
                    location=function_args.get("location")
                )
                messages.append({
                    "tool_call_id": tool_call.id,
                    "role": "tool",
                    "name": "get_current_time",
                    "content": time_response,
                })
    else:
        print("No tool calls were made by the model.")  

    # Second API call: Get the final response from the model
    final_response = client.chat.completions.create(
        model=deployment_name,
        messages=messages,
    )

    return final_response.choices[0].message.content

# Run the conversation and print the result
print(run_conversation())

Sortie:

Model's response:
ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_pOsKdUlqvdyttYB67MOj434b', function=Function(arguments='{"location":"San Francisco"}', name='get_current_time'), type='function')])
Function arguments: {'location': 'San Francisco'}
get_current_time called with location: San Francisco
Timezone found for san francisco
The current time in San Francisco is 09:24 AM.

Si nous utilisons un déploiement de modèle qui prend en charge les appels de fonction parallèles, nous pourrions convertir cela en exemple d’appel de fonction parallèle en modifiant le tableau de messages pour demander le temps dans plusieurs emplacements au lieu d’un.

Pour ce faire, échangez les commentaires dans ces deux lignes :

    messages = [{"role": "user", "content": "What's the current time in San Francisco"}] # Single function call
    #messages = [{"role": "user", "content": "What's the current time in San Francisco, Tokyo, and Paris?"}] # Parallel function call with a single tool/function defined

Pour que le résultat ressemble à ceci, puis exécutez de nouveau le code :

    #messages = [{"role": "user", "content": "What's the current time in San Francisco"}] # Single function call
    messages = [{"role": "user", "content": "What's the current time in San Francisco, Tokyo, and Paris?"}] # Parallel function call with a single tool/function defined

Cela génère la sortie suivante :

Sortie:

Model's response:
ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_IjcAVz9JOv5BXwUx1jd076C1', function=Function(arguments='{"location": "San Francisco"}', name='get_current_time'), type='function'), ChatCompletionMessageToolCall(id='call_XIPQYTCtKIaNCCPTdvwjkaSN', function=Function(arguments='{"location": "Tokyo"}', name='get_current_time'), type='function'), ChatCompletionMessageToolCall(id='call_OHIB5aJzO8HGqanmsdzfytvp', function=Function(arguments='{"location": "Paris"}', name='get_current_time'), type='function')])
Function arguments: {'location': 'San Francisco'}
get_current_time called with location: San Francisco
Timezone found for san francisco
Function arguments: {'location': 'Tokyo'}
get_current_time called with location: Tokyo
Timezone found for tokyo
Function arguments: {'location': 'Paris'}
get_current_time called with location: Paris
Timezone found for paris
As of now, the current times are:

- **San Francisco:** 11:15 AM
- **Tokyo:** 03:15 AM (next day)
- **Paris:** 08:15 PM

Les appels de fonction parallèle vous permettent d’effectuer plusieurs appels de fonction ensemble, ce qui permet l’exécution parallèle et la récupération des résultats. Cela réduit le nombre d’appels à l’API qui doivent être effectués et peut améliorer les performances globales.

Par exemple, dans notre application de temps simple, nous avons récupéré plusieurs fois en même temps. Cela a entraîné un message d'achèvement de chat avec trois appels de fonction dans le tableau tool_calls, chacun avec un identifiant unique id. Si vous souhaitiez répondre à ces appels de fonction, vous ajouteriez trois nouveaux messages à la conversation, chacun contenant le résultat d’un appel de fonction, avec une référence au tool_call_id de id.

Pour forcer le modèle à appeler une fonction spécifique, définissez tool_choice sur un objet d’outil nommé, par exemple : tool_choice={"type": "function", "function": {"name": "get_current_time"}}. Pour forcer un message accessible à l’utilisateur, définissez tool_choice="none".

Note

Le comportement par défaut (tool_choice: "auto") est que le modèle décide par lui-même s’il doit appeler une fonction et, si tel est le cas, quelle fonction appeler.

Appel de fonction parallèle avec plusieurs fonctions

Maintenant, nous montrons un autre exemple d’appel de fonction jouet, cette fois avec différents outils/fonctions définis.

import os
import json
from openai import OpenAI
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
from azure.identity import DefaultAzureCredential, get_bearer_token_provider

token_provider = get_bearer_token_provider(
    DefaultAzureCredential(), "https://ai.azure.com/.default"
)

client = OpenAI(  
  base_url = "https://YOUR-RESOURCE-NAME.openai.azure.com/openai/v1/",  
  api_key=token_provider,
)

# Provide the model deployment name you want to use for this example

deployment_name = "YOUR_DEPLOYMENT_NAME_HERE" 

# Simplified weather data
WEATHER_DATA = {
    "tokyo": {"temperature": "10", "unit": "celsius"},
    "san francisco": {"temperature": "72", "unit": "fahrenheit"},
    "paris": {"temperature": "22", "unit": "celsius"}
}

# Simplified timezone data
TIMEZONE_DATA = {
    "tokyo": "Asia/Tokyo",
    "san francisco": "America/Los_Angeles",
    "paris": "Europe/Paris"
}

def get_current_weather(location, unit=None):
    """Get the current weather for a given location"""
    location_lower = location.lower()
    print(f"get_current_weather called with location: {location}, unit: {unit}")  
    
    for key in WEATHER_DATA:
        if key in location_lower:
            print(f"Weather data found for {key}")  
            weather = WEATHER_DATA[key]
            return json.dumps({
                "location": location,
                "temperature": weather["temperature"],
                "unit": unit if unit else weather["unit"]
            })
    
    print(f"No weather data found for {location_lower}")  
    return json.dumps({"location": location, "temperature": "unknown"})

def get_current_time(location):
    """Get the current time for a given location"""
    print(f"get_current_time called with location: {location}")  
    location_lower = location.lower()
    
    for key, timezone in TIMEZONE_DATA.items():
        if key in location_lower:
            print(f"Timezone found for {key}")  
            current_time = datetime.now(ZoneInfo(timezone)).strftime("%I:%M %p")
            return json.dumps({
                "location": location,
                "current_time": current_time
            })
    
    print(f"No timezone data found for {location_lower}")  
    return json.dumps({"location": location, "current_time": "unknown"})

def run_conversation():
    # Initial user message
    messages = [{"role": "user", "content": "What's the weather and current time in San Francisco, Tokyo, and Paris?"}]

    # Define the functions for the model
    tools = [
        {
            "type": "function",
            "function": {
                "name": "get_current_weather",
                "description": "Get the current weather in a given location",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "location": {
                            "type": "string",
                            "description": "The city name, e.g. San Francisco",
                        },
                        "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
                    },
                    "required": ["location"],
                },
            }
        },
        {
            "type": "function",
            "function": {
                "name": "get_current_time",
                "description": "Get the current time in a given location",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "location": {
                            "type": "string",
                            "description": "The city name, e.g. San Francisco",
                        },
                    },
                    "required": ["location"],
                },
            }
        }
    ]

    # First API call: Ask the model to use the functions
    response = client.chat.completions.create(
        model=deployment_name,
        messages=messages,
        tools=tools,
        tool_choice="auto",
    )

    # Process the model's response
    response_message = response.choices[0].message
    messages.append(response_message)

    print("Model's response:")  
    print(response_message)  

    # Handle function calls
    if response_message.tool_calls:
        for tool_call in response_message.tool_calls:
            function_name = tool_call.function.name
            function_args = json.loads(tool_call.function.arguments)
            print(f"Function call: {function_name}")  
            print(f"Function arguments: {function_args}")  
            
            if function_name == "get_current_weather":
                function_response = get_current_weather(
                    location=function_args.get("location"),
                    unit=function_args.get("unit")
                )
            elif function_name == "get_current_time":
                function_response = get_current_time(
                    location=function_args.get("location")
                )
            else:
                function_response = json.dumps({"error": "Unknown function"})
            
            messages.append({
                "tool_call_id": tool_call.id,
                "role": "tool",
                "name": function_name,
                "content": function_response,
            })
    else:
        print("No tool calls were made by the model.")  

    # Second API call: Get the final response from the model
    final_response = client.chat.completions.create(
        model=deployment_name,
        messages=messages,
    )

    return final_response.choices[0].message.content

# Run the conversation and print the result
print(run_conversation())

Sortie

Model's response:
ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_djHAeQP0DFEVZ2qptrO0CYC4', function=Function(arguments='{"location": "San Francisco", "unit": "celsius"}', name='get_current_weather'), type='function'), ChatCompletionMessageToolCall(id='call_q2f1HPKKUUj81yUa3ITLOZFs', function=Function(arguments='{"location": "Tokyo", "unit": "celsius"}', name='get_current_weather'), type='function'), ChatCompletionMessageToolCall(id='call_6TEY5Imtr17PaB4UhWDaPxiX', function=Function(arguments='{"location": "Paris", "unit": "celsius"}', name='get_current_weather'), type='function'), ChatCompletionMessageToolCall(id='call_vpzJ3jElpKZXA9abdbVMoauu', function=Function(arguments='{"location": "San Francisco"}', name='get_current_time'), type='function'), ChatCompletionMessageToolCall(id='call_1ag0MCIsEjlwbpAqIXJbZcQj', function=Function(arguments='{"location": "Tokyo"}', name='get_current_time'), type='function'), ChatCompletionMessageToolCall(id='call_ukOu3kfYOZR8lpxGRpdkhhdD', function=Function(arguments='{"location": "Paris"}', name='get_current_time'), type='function')])
Function call: get_current_weather
Function arguments: {'location': 'San Francisco', 'unit': 'celsius'}
get_current_weather called with location: San Francisco, unit: celsius
Weather data found for san francisco
Function call: get_current_weather
Function arguments: {'location': 'Tokyo', 'unit': 'celsius'}
get_current_weather called with location: Tokyo, unit: celsius
Weather data found for tokyo
Function call: get_current_weather
Function arguments: {'location': 'Paris', 'unit': 'celsius'}
get_current_weather called with location: Paris, unit: celsius
Weather data found for paris
Function call: get_current_time
Function arguments: {'location': 'San Francisco'}
get_current_time called with location: San Francisco
Timezone found for san francisco
Function call: get_current_time
Function arguments: {'location': 'Tokyo'}
get_current_time called with location: Tokyo
Timezone found for tokyo
Function call: get_current_time
Function arguments: {'location': 'Paris'}
get_current_time called with location: Paris
Timezone found for paris
Here's the current information for the three cities:

### San Francisco
- **Time:** 09:13 AM
- **Weather:** 72°C (quite warm!)

### Tokyo
- **Time:** 01:13 AM (next day)
- **Weather:** 10°C

### Paris
- **Time:** 06:13 PM
- **Weather:** 22°C

Is there anything else you need?

Important

La réponse JSON peut ne pas toujours être valide. Vous devez donc ajouter une logique supplémentaire à votre code pour pouvoir gérer les erreurs. Pour certains cas d’usage, vous devrez peut-être utiliser l'ajustement fin afin d'améliorer les performances des appels de fonction.

Optimisation des instructions avec des fonctions

Lorsque vous définissez une fonction dans le cadre de votre demande, les détails sont injectés dans le message système à l’aide d’une syntaxe spécifique sur laquelle le modèle a été formé. Cela signifie que les fonctions consomment des jetons dans votre invite et que vous pouvez appliquer des techniques d'optimisation des invites pour optimiser la performance de vos appels de fonction. Le modèle utilise le contexte complet de l’invite pour déterminer si une fonction doit être appelée, y compris la définition de fonction, le message système et les messages utilisateur.

Amélioration de la qualité et de la fiabilité

Si le modèle n’appelle pas votre fonction quand ou comment vous vous attendez, vous pouvez essayer d’améliorer la qualité.

Fournissez plus de détails dans votre définition de fonction

Il est important que vous fournissiez un élément significatif description de la fonction et fournissez des descriptions pour tout paramètre qui n’est peut-être pas évident pour le modèle. Par exemple, dans la description du location paramètre, vous pouvez inclure des détails et des exemples supplémentaires sur le format de l’emplacement.

"location": {
    "type": "string",
    "description": "The location of the hotel. The location should include the city and the state's abbreviation (i.e. Seattle, WA or Miami, FL)"
},
Fournir davantage de contexte dans le message système

Le message système peut également être utilisé pour fournir davantage de contexte au modèle. Par exemple, si vous avez une fonction appelée search_hotels , vous pouvez inclure un message système comme le suivant pour indiquer au modèle d’appeler la fonction lorsqu’un utilisateur demande de l’aide pour trouver un hôtel.

{"role": "system", "content": "You're an AI assistant designed to help users search for hotels. When a user asks for help finding a hotel, you should call the search_hotels function."}
Demander au modèle de poser des questions de clarification

Dans certains cas, vous souhaitez demander au modèle de poser des questions de clarification afin d’éviter d’effectuer des hypothèses sur les valeurs à utiliser avec les fonctions. Par exemple, avec search_hotels vous souhaitez que le modèle demande des précisions si la demande de l’utilisateur n’a pas inclus de détails sur location. Pour demander au modèle de poser une question de clarification, vous pouvez inclure du contenu comme dans l’exemple suivant dans votre message système.

{"role": "system", "content": "Don't make assumptions about what values to use with functions. Ask for clarification if a user request is ambiguous."}

Réduction des erreurs

Un autre domaine où l'ingénierie des prompts peut être utile est de réduire les erreurs dans les appels de fonction. Les modèles sont entraînés pour générer des appels de fonction correspondant au schéma que vous définissez, mais les modèles produisent un appel de fonction qui ne correspond pas au schéma que vous avez défini ou essayez d’appeler une fonction que vous n’avez pas inclus.

Si vous trouvez que le modèle génère des appels de fonction qui n’ont pas été fournis, essayez d’inclure une phrase dans le message système qui indique "Only use the functions you have been provided with.".

L'utilisation responsable des appels de fonctions

Comme n’importe quel système IA, l’utilisation d’appels de fonction pour intégrer des modèles linguistiques à d’autres outils et systèmes présente des risques potentiels. Il est important de comprendre les risques que les appels de fonction peuvent présenter et prendre des mesures pour vous assurer que vous utilisez les fonctionnalités de manière responsable.

Voici quelques conseils pour vous aider à utiliser des fonctions en toute sécurité et en toute sécurité :

  • Valider les appels de fonction : vérifiez toujours les appels de fonction générés par le modèle. Cela inclut la vérification des paramètres, la fonction appelée et la vérification que l’appel s’aligne sur l’action prévue.
  • Utilisez des données et des outils approuvés : utilisez uniquement les données provenant de sources approuvées et vérifiées. Les données non approuvées dans la sortie d’une fonction peuvent être utilisées pour indiquer au modèle d’écrire des appels de fonction d’une manière autre que prévu.
  • Suivez le principe du privilège minimum : accordez uniquement l’accès minimal nécessaire à la fonction pour effectuer son travail. Cela réduit l’impact potentiel si une fonction est mal utilisée ou exploitée. Par exemple, si vous utilisez des appels de fonction pour interroger une base de données, vous devez uniquement accorder à votre application un accès en lecture seule à la base de données. Vous ne devez pas non plus vous fier uniquement à la limitation des capacités dans la définition de fonction en tant que mesure de sécurité.
  • Considérez Real-World Impact : tenez compte de l’impact réel des appels de fonction que vous envisagez d’exécuter, en particulier ceux qui déclenchent des actions telles que l’exécution de code, la mise à jour des bases de données ou l’envoi de notifications.
  • Implémenter les étapes de confirmation de l’utilisateur : en particulier pour les fonctions qui prennent des actions, nous vous recommandons d’inclure une étape où l’utilisateur confirme l’action avant l’exécution.

Pour en savoir plus sur nos recommandations sur l’utilisation Azure modèles OpenAI de manière responsable, consultez la Overview des pratiques d’IA responsable pour Azure modèles OpenAI.

Important

Les paramètres functions et function_call ont été déconseillés avec la publication de la version 2023-12-01-preview de l’API. Le remplacement de functions est le paramètre tools. Le remplacement de function_call est le paramètre tool_choice.

Prise en charge des appels de fonction

Appel de fonction parallèle

  • gpt-4 (2024-04-09)
  • gpt-4o (2024-05-13)
  • gpt-4o (2024-08-06)
  • gpt-4o (2024-11-20)
  • gpt-4o-mini (2024-07-18)
  • gpt-4.1 (2025-04-14)
  • gpt-4.1-mini (2025-04-14)
  • gpt-5 (2025-08-07)
  • gpt-5-mini (2025-08-07)
  • gpt-5-nano (2025-08-07)
  • gpt-5-codex (2025-09-11)
  • gpt-5.1 (2025-11-13)
  • gpt-5.1-chat (2025-11-13)
  • gpt-5.1-codex (2025-11-13)
  • gpt-5.1-codex-mini (2025-11-13)
  • gpt-5.1-codex-max (2025-12-04)
  • gpt-5.2 (2025-12-11)
  • gpt-5.2-chat (2025-12-11)
  • gpt-5.2-codex (2026-01-14)
  • gpt-5.2-chat (2026-02-10)
  • gpt-5.3-codex (2026-02-24)
  • gpt-5.3-chat (2026-03-03)
  • gpt-5.4 (2026-03-05)
  • gpt-5.4 (2026-03-05)
  • gpt-5.4-mini (2026-03-17)
  • gpt-5.4-nano (2026-03-17)
  • gpt-5.5 (2026-04-24)

La prise en charge de la fonction parallèle a été ajoutée pour la première fois dans la version de l’API 2023-12-01-preview

Appel de fonctions de base avec outils

  • Tous les modèles qui prennent en charge l’appel de fonction parallèle
  • gpt-5.4-pro (2026-03-05)
  • gpt-5-pro (2025-10-06)
  • codex-mini (2025-05-16)
  • o3-pro (2025-06-10)
  • o4-mini (2025-04-16)
  • o3 (2025-04-16)
  • gpt-4.1-nano (2025-04-14)
  • o3-mini (2025-01-31)
  • o1 (2024-12-17)

Note

Le tool_choice paramètre est désormais pris en charge avec o3-mini et o1. Pour plus d’informations, consultez le guide des modèles de raisonnement.

Important

Les descriptions des outils/fonctions sont actuellement limitées à 1 024 caractères avec Azure OpenAI. Nous allons mettre à jour cet article si cette limite est modifiée.

Étapes suivantes