For AI agents: the complete documentation index is available at https://docs.ovhcloud.com/fr/llms.txt, the full documentation bundle is available at https://docs.ovhcloud.com/fr/llms-full.txt, and this page is available as Markdown at https://docs.ovhcloud.com/fr/guides/public-cloud/ai-machine-learning/ai-endpoints-function-calling.md.

AI Endpoints - Appel de fonctions

Voir en Markdown

Découvrez comment utiliser l'appel de fonctions avec OVHcloud AI Endpoints

Info

AI Endpoints est couvert par les Conditions particulières OVHcloud Public Cloud (voir l’Annexe 10 – « Conditions spécifiques – AI Endpoints »).

Introduction

AI Endpoints est une plateforme serverless proposée par OVHcloud qui offre un accès simplifié à une sélection de modèles d'IA pré-entraînés, mondialement reconnus. La plateforme est conçue pour être simple, sécurisée et intuitive, ce qui en fait une solution idéale pour les développeurs souhaitant enrichir leurs applications avec des capacités d'IA sans expertise poussée en IA ni préoccupations sur la confidentialité des données.

L'appel de fonctions (Function Calling), aussi appelé tool calling, est une fonctionnalité qui permet à un grand modèle de langage (LLM) de déclencher des fonctions définies par l'utilisateur (aussi appelées outils/tools). Ces outils sont définis par le développeur et implémentent des comportements spécifiques tels qu'appeler une API, récupérer des données ou effectuer des calculs, ce qui étend les capacités du LLM.

Le LLM identifie quel(s) outil(s) appeler et les arguments à utiliser. Cette fonctionnalité peut par exemple être utilisée pour développer des assistants ou des agents.

Objectif

Cette documentation présente un aperçu de l'utilisation de l'appel de fonctions avec les modèles d'IA proposés sur AI Endpoints. Les exemples fournis dans ce guide utilisent le modèle Mistral-Nemo-Instruct-2407.

Consultez notre Catalogue pour découvrir quels modèles sont compatibles avec l'appel de fonctions.

Prérequis

Nous utilisons Python pour les exemples fournis dans ce guide.

Assurez-vous d'avoir un environnement Python configuré, et installez le client openai.

pip install openai

Aperçu de l'appel de fonctions

Le fonctionnement de l'appel de fonctions est décrit ci-dessous :

  1. Définir les outils : indiquer au modèle quels outils il peut utiliser, avec un schéma JSON pour chaque outil.
  2. Appeler le modèle avec les outils : transmettre les outils avec vos messages système et utilisateur au modèle, qui générera éventuellement des appels d'outils.
  3. Traiter les appels d'outils : pour chaque appel d'outil renvoyé par le modèle, exécuter l'implémentation réelle de l'outil dans votre code.
  4. Appeler le modèle avec les réponses des outils : envoyer une nouvelle requête au modèle, avec la conversation mise à jour avec les résultats des appels d'outils.
  5. Réponse finale : traiter la réponse finale générée, qui prend en compte les résultats des outils.

Ce schéma illustre le fonctionnement :

Function calling workflow

Exemple : un assistant de suivi du temps

Pour illustrer l'utilisation de l'appel de fonctions et introduire progressivement les notions importantes liées à cette fonctionnalité, nous allons développer, étape par étape, un assistant de suivi du temps (time-tracking assistant).

L'assistant sera capable de :

  • enregistrer le temps passé sur une tâche
  • générer un rapport de temps

Chaque tâche possède un nom, une catégorie et une durée totale en minutes. Les catégories forment une liste fixe de chaînes de caractères, par exemple « Code » ou « Meetings ». Un rapport de temps peut être généré pour une catégorie de tâche donnée.

L'utilisateur pourra interagir avec l'assistant pour enregistrer du temps et obtenir des informations sur la répartition du temps passé.

Définir les outils

Notre assistant de suivi du temps utilisera deux outils :

  • log_work : enregistre le temps passé sur une tâche. Prend le nom de la tâche, la catégorie, la durée et l'unité (minutes ou heures). Par exemple, pour enregistrer 2 heures passées sur la rédaction de documentation, vous appelleriez log_work("User guide", "Documentation", 2, "hours")

  • time_report : récupère des données JSON sur toutes les tâches d'une catégorie donnée, et la durée totale dans une unité de temps donnée (minutes ou heures). Par exemple, pour obtenir la répartition du temps passé sur des tâches de code, en heures, vous appelleriez time_report("Code", "hours")

Pour que le modèle utilise ces outils, nous devons d'abord les déclarer à l'aide de schémas JSON, dans une liste tools que nous transmettrons à l'API Chat Completion.

Voici comment les outils peuvent être déclarés en Python :

# TOOLS DECLARATION (JSON SCHEMA)
# Possible Categories (we'll reuse this later)
CATEGORIES = ["Code", "Meetings", "Documentation", "Other"]

# Define the tool specification
TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "log_work",
            "description": "Logs a work session for a specific task by providing a start and end datetime.",
            "parameters": {
                "type": "object",
                "properties": {
                    "task_name": {
                        "type": "string",
                        "description": "The name of the task to log work for."
                    },
                    "task_category": {
                        "type": "string",
                        "enum": CATEGORIES,
                        "description": "The category of the task to log work for."
                    },
                    "duration": {
                        "type": "number",
                        "description": "The duration to log work for."
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["minutes", "hours"],
                        "description": "The time unit to log work in."
                    }
                },
                "required": ["task_name", "task_category", "duration", "unit"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "time_report",
            "description": "Output a JSON with the breakdown of time spent by each task of a given category, returned in a given time unit.",
            "parameters": {
                "type": "object",
                "properties": {
                    "category": {
                        "type": "string",
                        "description": "The name of the category to get the report for."
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["minutes", "hours"],
                        "description": "The time unit to return the result in."
                    }
                },
                "required": ["category", "unit"]
            }
        }
    }
]

Générer des appels d'outils

Nos outils étant prêts, nous pouvons maintenant essayer d'appeler le modèle et voir s'il comprend notre définition des outils. Nous utilisons le SDK Python OpenAI pour appeler la route ``/v1/chat/completionsde l'endpoint, en transmettant la définition des outils dans le paramètretools`.

Envoyons un simple message utilisateur : log 1 hour team meeting et voyons ce que répond le modèle.

Info

Pour obtenir une clé d'accès API pour un accès authentifié, suivez les instructions données dans le guide AI Endpoints - Premiers pas. Sinon, vous serez soumis à une limitation de débit (rate limiting).

import os
from openai import OpenAI

MODEL_NAME = "Mistral-Nemo-Instruct-2407"
API_KEY = os.environ.get("OVH_AI_ENDPOINTS_ACCESS_TOKEN")

# Initialize the OpenAI client
client = OpenAI(
    base_url="https://oai.endpoints.kepler.ai.cloud.ovh.net/v1",
    api_key=API_KEY
)

messages = [
    {"role": "user", "content": "log 1 hour team meeting"}
]

response = client.chat.completions.create(
    model=MODEL_NAME,
    messages=messages,
    tools=TOOLS,
    tool_choice="auto",
    temperature=0.15
)

# Add the assistant response to the conversation
assistant_response = response.choices[0].message
messages.append(assistant_response)

print(assistant_response.to_json())

Output:

{
  "role": "assistant",
  "tool_calls": [
    {
      "id": "wuvyeH6fR",
      "function": {
        "arguments": "{\"task_name\": \"team meeting\", \"task_category\": \"Meetings\", \"duration\": 1, \"unit\": \"hours\"}",
        "name": "log_work"
      },
      "type": "function"
    }
  ]
}

Nous constatons, en observant le message assistant généré, que le modèle a correctement identifié qu'il devait appeler l'outil log_work.

La liste tool_calls contient les appels d'outils générés par le modèle en réponse à notre message utilisateur. Les champs name et arguments précisent quel outil appeler et quels paramètres transmettre à la fonction. L'id est un identifiant unique pour cet appel d'outil, dont nous aurons besoin plus tard.

Cette liste peut contenir plusieurs appels d'outils.

En interne, le modèle a reconnu que l'intention de l'utilisateur était liée à l'ensemble des outils fournis, et a généré une séquence de tokens spécifiques qui ont été post-traités pour créer un objet d'appel d'outil.

Nous ajoutons ce message à la conversation afin que le modèle ait connaissance de cet appel d'outil lors des tours suivants de notre conversation multi-tours.

Traiter les appels d'outils

Maintenant que nous avons vu que le modèle est capable de générer des appels d'outils, nous devons coder l'implémentation Python des outils, afin de pouvoir traiter les appels d'outils générés par le LLM et commencer à enregistrer le temps !

Chaque tâche est stockée dans un dictionnaire, avec le nom comme clé, et les catégories forment une liste fixe.

Nous définissons les deux fonctions, log_work et time_report, dans le code Python ci-dessous :

# TOOLS IMPLEMENTATION

import json
from dataclasses import dataclass

# We store tasks by their names
TASKS_BY_NAME = {}

# A task has a name, category, and total duration in minutes
# When we log a new work entry for a task, we add to this total duration
@dataclass
class Task:
    name: str
    category: str
    duration_minutes: float = 0.0

    def add_entry(self, duration:float, unit:str):
        self.duration_minutes += to_minutes(duration, unit)

    def __str__(self):
        return json.dumps({"name": self.name, "category": self.category, "total_duration": self.duration_minutes})


# TOOL 1 : log a work entry (task name, category, duration and unit = minutes or hours)
def log_work(task_name: str, task_category: str, duration: float, unit: str):
    # we create a new task if the name doesn't exist yet
    if task_name in TASKS_BY_NAME:
        status = "updated"
    else:
        status = "created"
        TASKS_BY_NAME[task_name] = Task(task_name, task_category)

    task = TASKS_BY_NAME.get(task_name)
    task.add_entry(duration=duration, unit=unit)

    # the tool returns the data for the created or updated task, so that the model can use this information if needed
    return {"task": task.name, "task_category": task.category, "total_duration": convert(task.duration_minutes, unit), "status": status}

# TOOL 2 : get JSON data about a tasks in a given category, and total duration (category, unit = minutes or hours)
def time_report(category: str, unit: str):
    data = [{"name":t.name, "total_duration":convert(t.duration_minutes, unit)} for t in TASKS_BY_NAME.values() if t.category == category]
    data.append({"total_duration_for_category": sum([x["total_duration"] for x in data])})
    return data

# Utilities function: convert to and from minutes and hours
def convert(duration_min: float, unit: str) -> float:
    if unit == "minutes":
        return duration_min
    elif unit == "hours":
        return duration_min / 60
    else:
        raise ValueError("Invalid unit. Must be 'minutes', or 'hours'.")

def to_minutes(duration: float, unit: str) -> float:
    if unit == "minutes":
        return duration
    elif unit == "hours":
        return duration * 60
    else:
        raise ValueError("Invalid unit. Must be 'minutes', or 'hours'.")

Voyons maintenant comment nous pouvons traiter les appels d'outils générés par le modèle :

# this map allows us to know which Python function for a given tool
FUNCTION_MAP = {
    "log_work": log_work,
    "time_report": time_report
}

# if there are tool calls in the assistant-generated response
if assistant_response.tool_calls:
    print(f"<\t{len(assistant_response.tool_calls)} tool(s) to call")
    # we can have several tool calls
    for tool_call in assistant_response.tool_calls:
        # The tool name should be associated with a Python function
        if tool_call.function.name in FUNCTION_MAP.keys():
            # the arguments provided by the model should be a valid JSON (in production code, this should be checked)
            function_args = json.loads(tool_call.function.arguments)
            print(f">\t\tExecute tool {tool_call.function.name} with arguments {function_args}")

            # execute the tool
            function_response = FUNCTION_MAP[tool_call.function.name](**function_args)

            print(function_response)

Output:

<	1 tool(s) to call
>		Execute tool log_work with arguments {'task_name': 'team meeting', 'task_category': 'Meetings', 'duration': 1, 'unit': 'hours'}
{'task': 'team meeting', 'task_category': 'Meetings', 'total_duration': 1.0}

Nous constatons que nous avons créé avec succès une tâche appelée « team meeting », dans la catégorie « Meetings », avec une durée totale de 1 heure.

Envoyer les résultats des appels d'outils et obtenir la réponse finale

Maintenant que nous avons exécuté nos appels d'outils, nous devons renvoyer le résultat au modèle afin qu'il puisse générer une nouvelle réponse en tenant compte de cette nouvelle information, par exemple pour informer l'utilisateur que la tâche a bien été créée ou pour fournir le rapport horaire.

Il ne nous reste plus qu'à ajouter les résultats des outils sous forme de nouveaux messages tool dans la conversation ; nous allons donc mettre à jour notre code :

if assistant_response.tool_calls:
    print(f"<\t{len(assistant_response.tool_calls)} tool(s) to call")
    # we can have several tool calls
    for tool_call in assistant_response.tool_calls:
        # The tool name should be associated with a Python function
        if tool_call.function.name in FUNCTION_MAP.keys():
            # the arguments provided by the model should be a valid JSON (in production code, this should be checked)
            function_args = json.loads(tool_call.function.arguments)
            print(f">\t\tExecute tool {tool_call.function.name} with arguments {function_args}")

            # execute the tool
            function_response = FUNCTION_MAP[tool_call.function.name](**function_args)

            # Add tool call result to the conversation
            tool_call_result = {
                "role": "tool",
                "name": tool_call.function.name,
                "content": json.dumps(function_response),
                "tool_call_id": tool_call.id
            }
            messages.append(tool_call_result)

            print(f">\t\tAdd tool call result to conversation:\n{tool_call_result}")

Nous appelons ensuite le modèle avec la conversation mise à jour :

print(f">\tCall assistant with tool results")

response = client.chat.completions.create(
    model=MODEL_NAME,
    messages=messages,
)

print(f"<\t\tAssistant final answer:\n{response.choices[0].message.content}")

Output:

<	1 tool(s) to call
>		Execute tool log_work with arguments {'task_name': 'team meeting', 'task_category': 'Meetings', 'duration': 1, 'unit': 'hours'}
>		Add tool call result to conversation:
{'role': 'tool', 'name': 'log_work', 'content': '{"task": "team meeting", "task_category": "Meetings", "total_duration": 1.0, "status": "created"}', 'tool_call_id': 'v1X1sJP9b'}
>	Call assistant with tool results
<		Assistant final answer:
Following is the details of 1 hour team meeting:

- Task: Team Meeting
- Duration: 1.0 hours
- Status: Created

L'assistant a généré une réponse confirmant la création de la tâche.

Ajouter un system prompt

Pour rendre notre assistant plus robuste et plus performant, il peut être utile d'ajouter un system prompt qui :

  • explique ce qui est attendu du modèle.
  • fournit au modèle des informations utiles, comme les tâches et catégories actuellement existantes.
SYSTEM_PROMPT = \
"""
You are a helpful and precise time-tracking assistant.
You use tools to log work and generate time reports.

# Possible categories: {{categories}}

# Existing tasks: {{tasks}}

"""

def format_system_prompt():
    return SYSTEM_PROMPT \
        .replace("{{tasks}}", json.dumps([str(t) for t in TASKS_BY_NAME.values()])) \
        .replace("{{categories}}", json.dumps(CATEGORIES))

messages = [
    {"role": "system", "content": format_system_prompt()},
    {"role": "user", "content": "log 1 hour team meeting"}
]

Avec ce system prompt, le modèle pourra utiliser les données sur les tâches et catégories existantes pour générer ses réponses.

Assembler le tout

Nous pouvons maintenant combiner toutes les notions vues jusqu'ici pour créer une méthode query qui va :

  • appeler le modèle avec le system prompt formaté et le message utilisateur
  • traiter les appels d'outils
  • appeler le modèle une seconde fois avec les résultats des outils
  • produire la réponse finale
def query(user_prompt: str):
    print(f"> Querying assistant with user prompt: {user_prompt}")

    messages = [
        {"role": "system", "content": format_system_prompt()},
        {"role": "user", "content": user_prompt}
    ]

    response = client.chat.completions.create(
        model=MODEL_NAME,
        messages=messages,
        tools=TOOLS,
        tool_choice="auto",
        temperature=0.15
    )

    # Add the assistant response to the conversation
    assistant_response = response.choices[0].message
    messages.append(assistant_response)

    # Process the tool calls
    if assistant_response.tool_calls:
        print(f"<\t{len(assistant_response.tool_calls)} tool(s) to call")
        for tool_call in assistant_response.tool_calls:

            # Execute the function
            if tool_call.function.name in FUNCTION_MAP.keys():
                function_args = json.loads(tool_call.function.arguments)
                print(f">\t\tExecute tool {tool_call.function.name} with arguments {function_args}")
                function_response = FUNCTION_MAP[tool_call.function.name](**function_args)

                # Add results to the conversation
                tool_call_result = {
                    "role": "tool",
                    "name": tool_call.function.name,
                    "content": json.dumps(function_response),
                    "tool_call_id": tool_call.id
                }
                messages.append(tool_call_result)

                print(f">\t\tAdd tool call result to conversation:\n{tool_call_result}")
    else:
        print("<\tNO TOOL CALLS")

    print(f">\tCall assistant with tool results")

    response = client.chat.completions.create(
        model=MODEL_NAME,
        messages=messages,
    )

    print(f"<\t\tAssistant final answer:\n{response.choices[0].message.content}")
    print("\n---\n")

Essayons notre assistant sur quelques exemples !

query("Spent 2 hours coding on Feature A")
query("Feature B: 3h")
query("Team meeting 1h")
# this query is more complex
# as it requires the model to generate 2 tool calls (one log_work for each feature),
# and to reuse the task "Feature B" instead of creating a new one
query("log 2 hours on feat B and 3 hours on feature C")
query("time spent in meetings?")
query("total time on coding")
query("on which task did I spent most hours coding?")

Output:

> Querying assistant with user prompt: Spent 2 hours coding on Feature A
<	1 tool(s) to call
>		Execute tool log_work with arguments {'duration': 2, 'task_category': 'Code', 'task_name': 'Feature A', 'unit': 'hours'}
>		Add tool call result to conversation:
{'role': 'tool', 'name': 'log_work', 'content': '{"task": "Feature A", "task_category": "Code", "total_duration": 2.0, "status": "created"}', 'tool_call_id': 'iGcC6qbte'}
>	Call assistant with tool results
<		Assistant final answer:
Logged time for Code
  Feature A 2 hours, 0 minutes
  ============================

---

> Querying assistant with user prompt: Feature B: 3h
<	1 tool(s) to call
>		Execute tool log_work with arguments {'task_name': 'Feature B', 'task_category': 'Code', 'duration': 3, 'unit': 'hours'}
>		Add tool call result to conversation:
{'role': 'tool', 'name': 'log_work', 'content': '{"task": "Feature B", "task_category": "Code", "total_duration": 3.0, "status": "created"}', 'tool_call_id': 'd30xAKNT1'}
>	Call assistant with tool results
<		Assistant final answer:
- Your work log has been created. Here are the details:
  - Task: Feature B
  - Category: Code
  - Duration: 3 hours
  - Status: Created

---

> Querying assistant with user prompt: Team meeting 1h
<	1 tool(s) to call
>		Execute tool log_work with arguments {'task_name': 'Team meeting', 'task_category': 'Meetings', 'duration': 60, 'unit': 'minutes'}
>		Add tool call result to conversation:
{'role': 'tool', 'name': 'log_work', 'content': '{"task": "Team meeting", "task_category": "Meetings", "total_duration": 60.0, "status": "created"}', 'tool_call_id': 'EV3D7LdPE'}
>	Call assistant with tool results
<		Assistant final answer:
The task "Team meeting" has been created successfully.

---

> Querying assistant with user prompt: log 2 hours on feat B and 3 hours on feature C
<	2 tool(s) to call
>		Execute tool log_work with arguments {'task_name': 'Feature B', 'task_category': 'Code', 'duration': 2, 'unit': 'hours'}
>		Add tool call result to conversation:
{'role': 'tool', 'name': 'log_work', 'content': '{"task": "Feature B", "task_category": "Code", "total_duration": 5.0, "status": "updated"}', 'tool_call_id': 'frrThsgJ5'}
>		Execute tool log_work with arguments {'task_name': 'Feature C', 'task_category': 'Code', 'duration': 3, 'unit': 'hours'}
>		Add tool call result to conversation:
{'role': 'tool', 'name': 'log_work', 'content': '{"task": "Feature C", "task_category": "Code", "total_duration": 3.0, "status": "created"}', 'tool_call_id': 'K4aTPhdBp'}
>	Call assistant with tool results
<		Assistant final answer:
Great! Feature B's total working hours have been updated to 5 hours. Feature C's working time has been recorded as 3 hours.

---

> Querying assistant with user prompt: time spent in meetings?
<	1 tool(s) to call
>		Execute tool time_report with arguments {'category': 'Meetings', 'unit': 'minutes'}
>		Add tool call result to conversation:
{'role': 'tool', 'name': 'time_report', 'content': '[{"name": "Team meeting", "total_duration": 60.0}, {"total_duration_for_category": 60.0}]', 'tool_call_id': '1G8uk1bPH'}
>	Call assistant with tool results
<		Assistant final answer:
Here's the time spent in meetings:

- **Team meeting**: 60 minutes

---

> Querying assistant with user prompt: total time on coding
<	1 tool(s) to call
>		Execute tool time_report with arguments {'category': 'Code', 'unit': 'hours'}
>		Add tool call result to conversation:
{'role': 'tool', 'name': 'time_report', 'content': '[{"name": "Feature A", "total_duration": 2.0}, {"name": "Feature B", "total_duration": 5.0}, {"name": "Feature C", "total_duration": 3.0}, {"total_duration_for_category": 10.0}]', 'tool_call_id': '50bmrsPII'}
>	Call assistant with tool results
<		Assistant final answer:
Here's the breakdown of your coding time:

- Feature A: 2 hours
- Feature B: 5 hours
- Feature C: 3 hours
- **Total**: 10 hours

---

> Querying assistant with user prompt: on which task did I spent most hours coding?
<	1 tool(s) to call
>		Execute tool time_report with arguments {'category': 'Code', 'unit': 'hours'}
>		Add tool call result to conversation:
{'role': 'tool', 'name': 'time_report', 'content': '[{"name": "Feature A", "total_duration": 2.0}, {"name": "Feature B", "total_duration": 5.0}, {"name": "Feature C", "total_duration": 3.0}, {"total_duration_for_category": 10.0}]', 'tool_call_id': 'uFDF7rS0H'}
>	Call assistant with tool results
<		Assistant final answer:
Based on the tracking data, the task on which you spent the most hours coding is:

- **Feature B**: 5 hours
- The total coding time across all tasks is 10 hours.

Mission accomplie !

Astuces et bonnes pratiques

Cette section contient des astuces supplémentaires qui peuvent améliorer la performance des requêtes d'appel de fonctions.

Choix de l'outil

Vous avez remarqué que nous avons utilisé le mode auto dans notre tutoriel.

Voici les valeurs disponibles pour ce paramètre et leur impact sur la sortie.

Valeur tool_choiceEffet
autoMode par défaut lorsque des outils sont définis, le modèle génère de 0 à N appels d'outils.
requiredForce le modèle à générer au moins 1 appel d'outil, en utilisant des sorties structurées (structured outputs).
fonction nomméeForce le modèle à générer au moins 1 appel d'outil vers la fonction donnée.
Par exemple, pour forcer le modèle à appeler l'outil log_work :
tool_choice = {"type": "function", "function": {"name": "log_work"}}
noneAucun appel d'outil généré.

Streaming

Vous pouvez utiliser l'appel de fonctions en mode streaming en réglant stream sur true dans votre requête.

Voici deux exemples cURL montrant comment effectuer une telle requête, avec le modèle LLaMa 3.3 70B :

  • L'un utilisant un accès anonyme, soumis à des limitations de débit.
  • L'autre utilisant l'authentification par token AI Endpoints, qui évite la limitation de débit.
Info

Pour obtenir un token d'accès API pour un accès authentifié, suivez les instructions données dans le guide AI Endpoints - Premiers pas.

Mode anonyme (limité en débit)
Mode authentifié (sans limite de débit)
curl -X 'POST' \
  'https://oai.endpoints.kepler.ai.cloud.ovh.net/v1/chat/completions' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "max_tokens": 100,
    "messages": [
      {
        "content": "What is the current weather in Paris?",
        "role": "user"
      }
    ],
    "model": "Meta-Llama-3_3-70B-Instruct",
    "seed": null,
    "stream": true,
    "temperature": 0.1,
    "tool_choice": "auto",
    "tools": [
      {
        "function": {
          "description": "Get the current weather in a given location",
          "name": "get_current_weather",
          "parameters": {
            "properties": {
              "country": {
                "description": "The two-letter country code",
                "type": "string"
              },
              "location": {
                "description": "The city",
                "type": "string"
              },
              "unit": {
                "enum": [
                  "celsius",
                  "fahrenheit"
                ],
                "type": "string"
              }
            },
            "required": [
              "location",
              "country"
            ],
            "type": "object"
          }
        },
        "type": "function"
      }
    ],
    "top_p": 1
  }'

Vous obtiendrez des deltas d'appels d'outils dans les chunks d'événements côté serveur, au format suivant :

data: {...,"choices":[{"index":0,"delta":{"role":"assistant","content":""}}],...,"object":"chat.completion.chunk"}
data: {...,"choices":[{"index":0,"delta":{"role":"assistant","tool_calls":[{"index":0,"id":"chatcmpl-tool-e41bfee4ae1346bbbb4336061037e2b5","type":"function","function":{"name":"get_current_weather","arguments":""}}]}}],...,"object":"chat.completion.chunk"}
data: {...,"choices":[{"index":0,"delta":{"role":"assistant","tool_calls":[{"index":0,"function":{"arguments":"{\"country\": \""}}]}}],...,"object":"chat.completion.chunk"}
data: {...,"choices":[{"index":0,"delta":{"role":"assistant","tool_calls":[{"index":0,"function":{"arguments":"FR\""}}]}}],...,"object":"chat.completion.chunk"}
data: {...,"choices":[{"index":0,"delta":{"role":"assistant","tool_calls":[{"index":0,"function":{"arguments":", \"location\": \""}}]}}],...,"object":"chat.completion.chunk"}
data: {...,"choices":[{"index":0,"delta":{"role":"assistant","tool_calls":[{"index":0,"function":{"arguments":"Paris\""}}]}}],...,"object":"chat.completion.chunk"}
data: {...,"choices":[{"index":0,"delta":{"role":"assistant","tool_calls":[{"index":0,"function":{"arguments":", \"unit\": \""}}]}}],...,"object":"chat.completion.chunk"}
data: {...,"choices":[{"index":0,"delta":{"role":"assistant","tool_calls":[{"index":0,"function":{"arguments":"c"}}]}}],...,"object":"chat.completion.chunk"}
data: {...,"choices":[{"index":0,"delta":{"role":"assistant","tool_calls":[{"index":0,"function":{"arguments":"elsius\"}"}}]}}],...,"object":"chat.completion.chunk"}
data: {...,"choices":[{"index":0,"delta":{"role":"assistant","tool_calls":[{"index":0,"function":{"arguments":""}}]},"finish_reason":"tool_calls"}],...,"object":"chat.completion.chunk"}
data: [DONE]

Le premier delta d'appel d'outil contient l'id unique de l'appel d'outil, ainsi qu'un delta de fonction avec le name de la fonction à appeler.

Les deltas de fonction suivants contiennent une partie des arguments à utiliser.

Pour parser ces chunks avec le SDK Python OpenAI, vous pouvez utiliser cet extrait de code :

final_tool_calls_dict = {}

for chunk in completion:
    if len(chunk.choices) > 0:
        for tool_call in chunk.choices[0].delta.tool_calls or []:
            index = tool_call.index

            if index not in final_tool_calls_dict:
                final_tool_calls_dict[index] = tool_call

            final_tool_calls_dict[index].function.arguments += tool_call.function.arguments

final_tool_calls = [v for (k, v) in sorted(final_tool_calls_dict.items())]

Appels d'outils en parallèle

Certains modèles sont capables de générer plusieurs appels d'outils en un seul tour (voir le tutoriel de suivi du temps ci-dessus pour un exemple). Pour contrôler ce comportement, la spécification OpenAI permet de transmettre un paramètre booléen parallel_tool_calls.

Si false, le modèle ne peut générer qu'un seul appel d'outil au maximum. Ce cas n'est actuellement pas pris en charge par AI Endpoints.

Si vous avez besoin que votre système ne traite qu'un seul appel d'outil à la fois, ou si le modèle que vous utilisez ne prend pas en charge plusieurs appels d'outils, nous vous suggérons de sélectionner le premier, de le traiter, puis de rappeler le modèle.

Notez que les modèles LLaMa ne prennent pas en charge plusieurs appels d'outils entre les messages utilisateur et assistant.

Prompting et paramètres additionnels

Quelques considérations supplémentaires concernant les prompts et les paramètres du modèle :

  • La plupart des modèles ont tendance à mieux fonctionner avec une température plus basse pour l'appel de fonctions.
  • L'utilisation d'un system prompt est recommandée, afin d'orienter le modèle vers l'utilisation des outils à sa disposition. Qu'un system prompt soit défini ou non, une description des outils sera généralement incluse dans les tokens envoyés au modèle (voir le chat template du modèle pour plus de détails).
  • Si vous savez à l'avance que votre modèle doit appeler des outils, utilisez le paramètre tool_choice=required pour vous assurer qu'il génère au moins un appel d'outil.
  • Certains fournisseurs de modèles peuvent recommander des system prompts et paramètres spécifiques pour les sorties structurées et l'appel de fonctions. N'hésitez pas à consulter les pages des modèles pour approfondir leurs spécificités (exemple pour Llama 3.3 sur HuggingFace).

Conclusion

Dans ce guide, nous avons expliqué comment utiliser l'appel de fonctions avec les modèles AI Endpoints. Nous avons fourni un aperçu complet de cette fonctionnalité qui peut vous aider à parfaire l'intégration du LLM dans votre propre application.

Aller plus loin

Parcourez la documentation AI Endpoints complète pour mieux comprendre les concepts principaux et démarrer.

Pour une formation ou une assistance technique sur la mise en œuvre de nos solutions, contactez votre commercial ou consultez la page Professional Services pour obtenir un devis et faire analyser votre projet par nos experts.

Votre avis nous intéresse !

N’hésitez pas à nous faire part de vos questions, retours et suggestions pour améliorer le service :

Cette page vous a-t-elle aidé ?