watch·ia
AccueilActusTutosGlossaireCette semaineTendancesSources
/
ACTUS
4 sept.Crusoe lève 3 milliards de dollars pour une valorisation de 30 milliards·3 sept.Accel en pourparlers pour diriger une levée de 1 milliard chez Thinking Machines·3 sept.Abliteration.ai propose des modèles IA sans restrictions via une plateforme commerciale·3 sept.Meta propose des réductions pour partager les données d’usage de Muse Spark·3 sept.OpenAI présente GPT-6 Astra, son modèle le plus avancé à ce jour·3 sept.Ollie lance un assistant IA familial conforme SOC 2 pour préserver la confidentialité·3 sept.Nvidia propose PAIR, un outil gratuit pour agréger des PC locaux en cluster d'inférence IA·3 sept.Google ajoute des modes vocaux en temps réel pour Gmail, Docs et Keep·3 sept.Panne simultanée de ChatGPT, Grok et Claude : trois assistants IA majeurs inaccessibles·3 sept.Google améliore son modèle météo IA WeatherNext 3 avec une résolution cinq fois supérieure·4 sept.Crusoe lève 3 milliards de dollars pour une valorisation de 30 milliards·3 sept.Accel en pourparlers pour diriger une levée de 1 milliard chez Thinking Machines·3 sept.Abliteration.ai propose des modèles IA sans restrictions via une plateforme commerciale·3 sept.Meta propose des réductions pour partager les données d’usage de Muse Spark·3 sept.OpenAI présente GPT-6 Astra, son modèle le plus avancé à ce jour·3 sept.Ollie lance un assistant IA familial conforme SOC 2 pour préserver la confidentialité·3 sept.Nvidia propose PAIR, un outil gratuit pour agréger des PC locaux en cluster d'inférence IA·3 sept.Google ajoute des modes vocaux en temps réel pour Gmail, Docs et Keep·3 sept.Panne simultanée de ChatGPT, Grok et Claude : trois assistants IA majeurs inaccessibles·3 sept.Google améliore son modèle météo IA WeatherNext 3 avec une résolution cinq fois supérieure·4 sept.Crusoe lève 3 milliards de dollars pour une valorisation de 30 milliards·3 sept.Accel en pourparlers pour diriger une levée de 1 milliard chez Thinking Machines·3 sept.Abliteration.ai propose des modèles IA sans restrictions via une plateforme commerciale·3 sept.Meta propose des réductions pour partager les données d’usage de Muse Spark·3 sept.OpenAI présente GPT-6 Astra, son modèle le plus avancé à ce jour·3 sept.Ollie lance un assistant IA familial conforme SOC 2 pour préserver la confidentialité·3 sept.Nvidia propose PAIR, un outil gratuit pour agréger des PC locaux en cluster d'inférence IA·3 sept.Google ajoute des modes vocaux en temps réel pour Gmail, Docs et Keep·3 sept.Panne simultanée de ChatGPT, Grok et Claude : trois assistants IA majeurs inaccessibles·3 sept.Google améliore son modèle météo IA WeatherNext 3 avec une résolution cinq fois supérieure·4 sept.Crusoe lève 3 milliards de dollars pour une valorisation de 30 milliards·3 sept.Accel en pourparlers pour diriger une levée de 1 milliard chez Thinking Machines·3 sept.Abliteration.ai propose des modèles IA sans restrictions via une plateforme commerciale·3 sept.Meta propose des réductions pour partager les données d’usage de Muse Spark·3 sept.OpenAI présente GPT-6 Astra, son modèle le plus avancé à ce jour·3 sept.Ollie lance un assistant IA familial conforme SOC 2 pour préserver la confidentialité·3 sept.Nvidia propose PAIR, un outil gratuit pour agréger des PC locaux en cluster d'inférence IA·3 sept.Google ajoute des modes vocaux en temps réel pour Gmail, Docs et Keep·3 sept.Panne simultanée de ChatGPT, Grok et Claude : trois assistants IA majeurs inaccessibles·3 sept.Google améliore son modèle météo IA WeatherNext 3 avec une résolution cinq fois supérieure·

Le function calling : laisser une IA déclencher des actions

mercredi 17 juin 202607:128 min de lecture
L'essentiel — 3 points
  • 01Le function calling laisse l'IA demander l'exécution d'une fonction — mais c'est TON code qui l'exécute, toujours.
  • 02Le cycle tient en 4 temps : tu décris l'outil, l'IA demande l'appel, tu exécutes, tu renvoies le résultat.
  • 03À la fin tu as un script Python complet, compatible OpenAI/Mistral/Ollama, que tu adaptes à tes propres fonctions.
AGENTS

À la fin de ce tuto, tu auras un assistant en ligne de commande qui répond à « Où en est ma commande 4521 ? » en appelant réellement une fonction get_order_status() dans ton code, puis en formulant la réponse en français. Tu comprendras chaque étape du mécanisme, et tu pourras y brancher tes propres fonctions (base de données, API interne, envoi de mail…).

Durée : 20–30 min. Prérequis : Python 3.10+, savoir lancer un script, une clé API (OpenAI ou Mistral — le code est identique, on verra la nuance).

Le modèle mental (lis ça avant de coder)

Le malentendu numéro un : l'IA n'exécute jamais ton code. Elle ne fait que demander « j'aimerais appeler get_order_status avec order_id="4521" ». C'est ton programme qui lance la vraie fonction et lui renvoie le résultat. Tu gardes le contrôle total.

Le cycle complet tient en quatre temps :

1. TU décris les outils disponibles  ──►  envoyés au modèle avec la question
2. L'IA décide                        ──►  "appelle get_order_status(order_id='4521')"
3. TON code exécute la fonction       ──►  {"statut": "expédiée", ...}
4. TU renvoies le résultat à l'IA     ──►  "Votre commande 4521 a été expédiée, livraison le 25/06."

Garde ce schéma en tête : tout le reste n'est que la mise en œuvre de ces quatre flèches.

Étape 0 — Installation

pip install openai

Et ta clé dans l'environnement :

export OPENAI_API_KEY="sk-..."     # macOS / Linux
# setx OPENAI_API_KEY "sk-..."     # Windows (puis rouvrir le terminal)

Tu préfères Mistral ? Même code, tu changes juste le client : OpenAI(base_url="https://api.mistral.ai/v1", api_key="...") et le modèle (mistral-small-latest). Avec Ollama en local : base_url="http://localhost:11434/v1".

Étape 1 — Un appel simple, pour voir le problème

Avant les outils, regardons ce qui se passe sans. Crée assistant.py :

from openai import OpenAI

client = OpenAI()  # lit OPENAI_API_KEY automatiquement

resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Où en est ma commande 4521 ?"}],
)
print(resp.choices[0].message.content)

Lance-le :

python assistant.py

Résultat typique :

Je n'ai pas accès à votre système de commandes. Pour connaître le statut
de la commande 4521, contactez le service client...

Logique : le modèle ne connaît pas tes commandes. C'est exactement ce trou que le function calling va combler.

Étape 2 — Décrire l'outil que l'IA pourra demander

On déclare l'outil dans un format précis (du JSON Schema). Ajoute ceci dans assistant.py :

tools = [{
    "type": "function",
    "function": {
        "name": "get_order_status",
        "description": "Récupère le statut et la date de livraison d'une commande à partir de son numéro.",
        "parameters": {
            "type": "object",
            "properties": {
                "order_id": {
                    "type": "string",
                    "description": "Le numéro de commande, ex. '4521'."
                }
            },
            "required": ["order_id"],
        },
    },
}]

Décortiquons, car chaque champ a un rôle :

  • name : l'identifiant que l'IA renverra quand elle voudra l'appeler.
  • description : le champ le plus important. C'est uniquement là-dessus que l'IA décide quand utiliser l'outil. Vague = elle l'appelle au mauvais moment ou jamais. Sois explicite sur ce que fait l'outil.
  • parameters : les arguments attendus, en JSON Schema. Ici un seul, order_id, de type string.
  • required : les arguments obligatoires.

Étape 3 — Premier aller-retour : l'IA demande l'appel

Maintenant on renvoie la question avec les outils, et on observe ce que l'IA répond :

messages = [{"role": "user", "content": "Où en est ma commande 4521 ?"}]

resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=messages,
    tools=tools,
)

msg = resp.choices[0].message
print(msg.tool_calls)

Cette fois, msg.content est vide, mais msg.tool_calls contient :

[ChatCompletionMessageToolCall(
    id='call_abc123',
    function=Function(
        name='get_order_status',
        arguments='{"order_id":"4521"}'   # ⚠️ une CHAÎNE, pas un dict
    ),
    type='function'
)]

L'IA n'a rien exécuté : elle te dit « voilà la fonction que je veux, avec ces arguments ». Note que arguments est une chaîne JSON — on devra la parser. Le champ id servira à relier le résultat à cette demande précise.

Étape 4 — Exécuter la fonction dans ton code

C'est ici que tu prends la main. La vraie fonction (remplace plus tard par ta base de données) :

import json

ORDERS = {
    "4521": {"statut": "expédiée", "livraison_estimée": "2026-06-25"},
    "4522": {"statut": "en préparation", "livraison_estimée": "2026-06-27"},
}

def get_order_status(order_id: str) -> dict:
    return ORDERS.get(order_id, {"erreur": "commande introuvable"})

Et on exécute ce que l'IA a demandé :

tool_call = msg.tool_calls[0]
args = json.loads(tool_call.function.arguments)   # '{"order_id":"4521"}' -> dict
result = get_order_status(**args)                 # {'statut': 'expédiée', ...}

Étape 5 — Renvoyer le résultat à l'IA pour la réponse finale

L'IA doit maintenant transformer ce dict en phrase. On lui renvoie deux messages : sa propre demande d'appel (pour garder le fil), puis le résultat, relié par tool_call_id :

messages.append(msg)  # la demande d'appel de l'IA
messages.append({
    "role": "tool",
    "tool_call_id": tool_call.id,            # relie le résultat à la bonne demande
    "content": json.dumps(result, ensure_ascii=False),
})

final = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=messages,
    tools=tools,
)
print(final.choices[0].message.content)

Résultat :

Votre commande 4521 a bien été expédiée. La livraison est estimée au 25 juin 2026.

Tu viens de boucler les quatre flèches du schéma de départ.

Étape 6 — Le script complet et réutilisable

En pratique, on ne sait pas à l'avance combien d'appels l'IA voudra faire (parfois plusieurs d'affilée). On enveloppe donc tout dans une boucle, avec un garde-fou. Voici le script final, prêt à copier :

import json, os
from openai import OpenAI

client = OpenAI()

# --- 1. Tes vraies fonctions ---
ORDERS = {
    "4521": {"statut": "expédiée", "livraison_estimée": "2026-06-25"},
    "4522": {"statut": "en préparation", "livraison_estimée": "2026-06-27"},
}
def get_order_status(order_id: str) -> dict:
    return ORDERS.get(order_id, {"erreur": "commande introuvable"})

# --- 2. Le registre : nom vu par l'IA -> fonction réelle ---
dispatch = {"get_order_status": get_order_status}

# --- 3. La description vue par l'IA ---
tools = [{
    "type": "function",
    "function": {
        "name": "get_order_status",
        "description": "Récupère le statut et la date de livraison d'une commande à partir de son numéro.",
        "parameters": {
            "type": "object",
            "properties": {
                "order_id": {"type": "string", "description": "Le numéro de commande, ex. '4521'."}
            },
            "required": ["order_id"],
        },
    },
}]

def run(question: str) -> str:
    messages = [
        {"role": "system", "content": "Tu es l'assistant SAV. Utilise les outils pour répondre précisément."},
        {"role": "user", "content": question},
    ]
    for _ in range(5):  # garde-fou : 5 tours maximum
        resp = client.chat.completions.create(
            model="gpt-4o-mini", messages=messages, tools=tools,
        )
        msg = resp.choices[0].message
        if not msg.tool_calls:
            return msg.content            # plus d'outil à appeler : c'est la réponse finale
        messages.append(msg)              # on garde la demande dans l'historique
        for tc in msg.tool_calls:         # l'IA peut demander plusieurs appels d'un coup
            args = json.loads(tc.function.arguments)
            result = dispatch[tc.function.name](**args)
            messages.append({
                "role": "tool",
                "tool_call_id": tc.id,
                "content": json.dumps(result, ensure_ascii=False),
            })
    return "Trop d'étapes, j'arrête."

if __name__ == "__main__":
    print(run("Où en est ma commande 4521 ?"))
    print(run("Et la 9999 ?"))

Teste les deux cas : une commande qui existe, une qui n'existe pas. L'IA s'adapte au résultat (erreur: commande introuvable) et le formule poliment.

Ajouter un deuxième outil

Le pattern passe à l'échelle sans effort. Tu écris la fonction, tu l'ajoutes au dispatch et à tools :

def cancel_order(order_id: str) -> dict:
    if order_id in ORDERS:
        ORDERS[order_id]["statut"] = "annulée"
        return {"ok": True, "order_id": order_id}
    return {"erreur": "commande introuvable"}

dispatch["cancel_order"] = cancel_order
# + ajoute le bloc correspondant dans `tools`

L'IA choisira seule le bon outil selon la question (« annule la 4521 » → cancel_order). C'est ce mécanisme, mis en boucle, qui fait un agent (sujet des tutos avancés).

Sécurité : la partie non négociable

Comme c'est l'IA qui choisit les arguments, ne lui donne jamais un accès aveugle à des actions sensibles.

  • Valide les arguments avant d'exécuter. Un order_id doit ressembler à un numéro, pas à "; DROP TABLE…. Ne fais jamais confiance au contenu tel quel.
  • Moindre privilège. Un outil de lecture ne doit pas pouvoir écrire. Limite chaque fonction au strict nécessaire.
  • Confirme l'irréversible. Pour une annulation, un paiement, une suppression : mets une barrière que le modèle ne contrôle pas.
def cancel_order(order_id: str, confirm: bool = False) -> dict:
    if not confirm:
        return {"action": "confirmation_requise",
                "message": f"Confirmer l'annulation de {order_id} ?"}
    # ... annulation réelle seulement si confirm=True

Erreurs fréquentes (et comment les régler)

  • L'IA invente un argument → ta description est trop floue, ou il manque une contrainte. Précise, et pour un choix fermé utilise "enum": ["urgent", "normal"] dans le schéma.
  • json.loads plante → un petit modèle a renvoyé du JSON malformé. Entoure d'un try/except et redemande, ou choisis un modèle plus fiable pour cette tâche.
  • Boucle qui ne s'arrête pas → garde toujours la limite d'itérations (range(5) ici).
  • L'outil n'est jamais appelé → améliore la description, ou force avec tool_choice="required".
  • Tu utilises Claude (API Anthropic) ? Le principe est identique mais le format diffère : les outils se déclarent dans le paramètre tools avec input_schema, et la réponse contient des blocs tool_use / tool_result. La logique des quatre temps, elle, ne change pas.

L'adapter à tes besoins

Pour brancher ton propre cas, trois choses à changer seulement :

  1. Écris ta fonction (get_stock, creer_facture, chercher_client…) — du Python normal qui retourne un dict.
  2. Ajoute-la au dispatch et décris-la dans tools (soigne la description).
  3. Garde le reste tel quel : la boucle run() fonctionne quel que soit le nombre d'outils.

À retenir

Le function calling laisse l'IA demander l'exécution d'une fonction, mais c'est toujours ton code qui agit. Le cycle tient en quatre temps : tu décris l'outil, l'IA renvoie un tool_call (nom + arguments en chaîne JSON), tu exécutes, tu renvoies le résultat via un message tool relié par tool_call_id. Enveloppe le tout dans une boucle avec garde-fou, soigne tes descriptions, valide les arguments et confirme l'irréversible. Tu tiens là la brique de base de tous les agents.

Réagir :
Partager —XLinkedIn