Comment créer un tool calling agentique avec Gemma 4 ?

Un tool calling agentique donne au modèle des outils pour lire, calculer et agir dans un environnement contrôlé. L’enjeu n’est pas seulement de connecter une API, mais de sécuriser chaque action locale. Voici l’architecture, les garde-fous et les pièges à éviter.

Qu’est-ce qu’un agent vraiment agentique ?

Un agent devient vraiment agentique lorsqu’il peut observer l’état d’un environnement, décider d’une action, l’exécuter via un outil, puis réévaluer la situation à partir du résultat obtenu.

Un chatbot conversationnel reste principalement dans le langage. Il répond, reformule, résume, explique, mais il ne touche pas vraiment à votre environnement. Si vous lui demandez quoi faire avec un fichier CSV, il peut proposer une méthode, mais il ne lit pas forcément le fichier, ne vérifie pas les colonnes et ne lance aucun calcul.

Un modèle qui appelle une API distante va plus loin, mais son action reste souvent limitée à une requête externe. Demander la météo via une API, par exemple, consiste à envoyer une ville et recevoir une température. C’est utile, mais cela ne modifie pas l’état de votre machine. Le modèle consomme une information, il n’agit pas vraiment sur votre contexte local.

Un agent local avec outils change la nature du problème. Il peut lister un dossier, lire un fichier, lancer un script Python, calculer une statistique, puis décider quoi faire ensuite selon le résultat. À ce moment-là, le modèle doit raisonner sur un état concret : quels fichiers existent, quelles données sont valides, quelles erreurs apparaissent, quelle action corriger.

Le tool calling désigne ce mécanisme précis : le modèle ne fait pas directement l’action. Il demande l’exécution d’une fonction structurée, avec des paramètres explicites, puis reçoit le résultat. Cette séparation est essentielle, car l’application garde le contrôle : elle valide les paramètres, limite les permissions, journalise les appels et bloque les actions dangereuses.

Le terme agentique désigne simplement cette capacité à enchaîner observation, décision, action et correction. Elle augmente la valeur business, parce qu’un agent peut automatiser des tâches plus complètes qu’une simple réponse texte. Mais elle augmente aussi le risque opérationnel si les outils sont mal encadrés : suppression de fichiers, fuite de données, appels coûteux ou boucles d’exécution inutiles.

Capacité Exemple Risque principal
Chatbot simple Répondre à une question ou expliquer une méthode. Réponse fausse ou approximative.
Assistant avec API Consulter la météo ou récupérer un prix via un service distant. Dépendance à une API, coût, donnée externe incorrecte.
Agent local avec outils Lister un dossier, lire un fichier, lancer un calcul Python. Action non maîtrisée sur l’environnement local.

La différence tient donc moins au modèle qu’à la boucle d’exécution autour de lui. Sans outils contrôlés, Gemma 4 ou un autre modèle reste un moteur de langage. Avec des outils bien définis, des permissions claires et une logique de réévaluation, il peut devenir un agent utile sans devenir incontrôlable.

Comment fonctionne la boucle de tool calling ?

La boucle de tool calling consiste à exposer des fonctions au modèle, détecter ses appels d’outils, exécuter ces fonctions côté application, puis renvoyer les résultats au modèle pour qu’il poursuive son raisonnement.

Avec un modèle local servi via Ollama, le flux reste assez simple. Ollama documente ce mécanisme dans sa page “Tool calling” pour les modèles qui le prennent en charge : le modèle ne lance pas directement une fonction Python, il produit une intention d’appel structurée, généralement dans un champ tool_calls. Le programme lit cette intention, décide si elle est autorisée, exécute ou refuse, puis ajoute le résultat comme message d’outil avant de relancer le modèle avec ce nouveau contexte.

  • Définir Des fonctions Python normales, par exemple une fonction météo, recherche ou lecture contrôlée de fichier.
  • Décrire Chaque outil avec un schéma JSON : nom, description, paramètres, types et champs obligatoires.
  • Transmettre Le registre d’outils au modèle dans la requête envoyée à Ollama.
  • Intercepter Les tool_calls retournés par le modèle.
  • Valider Les arguments, puis exécuter la fonction correspondante côté application.
  • Ajouter Le résultat comme message d’outil, puis rappeler le modèle pour obtenir la réponse finale.

Le schéma JSON joue le rôle de contrat. Il indique au modèle ce qu’il peut demander et sous quelle forme. JSON Schema, documenté sur json-schema.org, permet notamment de décrire les types de données, comme “string”, “number”, “boolean” ou “array”, et les champs obligatoires avec “required”. Côté Python, la documentation officielle rappelle qu’une fonction est un bloc de code appelé avec des arguments, et que les modules standards comme json servent à encoder et décoder ces structures.

Le point important : le modèle propose, mais le programme dispose. Même si le modèle demande une action valide en apparence, votre code garde la décision finale d’exécution. C’est là que se joue la sécurité.

Outil API publique L’API distante applique ses propres limites, permissions, quotas et erreurs.
Outil local La fonction peut lire des fichiers, modifier des données ou exécuter du code. La responsabilité développeur augmente fortement.

Un appel à une API météo mal paramétré échoue souvent avec une erreur HTTP. Un outil local mal encadré peut supprimer un fichier, exposer une clé privée ou lancer une commande dangereuse. La boucle doit donc être pensée comme une interface d’exécution contrôlée, pas comme une délégation aveugle au modèle.

  • Registre D’outils clair et limité.
  • Validation Systématique des arguments reçus.
  • Journalisation Des appels, résultats et erreurs.
  • Erreurs Renvoyées proprement au modèle.
  • Refus Explicite des actions non prévues.

Comment sécuriser l’accès aux fichiers ?

L’accès aux fichiers doit être enfermé dans un répertoire autorisé, et chaque chemin demandé doit être résolu puis vérifié avant toute lecture ou exploration. Avec un agent Gemma 4 capable d’appeler des outils, cette règle évite qu’une simple demande utilisateur devienne une fuite de fichiers locaux.

L’outil list_directory_contents doit être traité comme un explorateur de système de fichiers sandboxé. Il permet au modèle de lister le contenu d’un dossier, mais uniquement dans une zone contrôlée définie au démarrage par SAFE_BASE_DIR. Une sandbox est un périmètre d’exécution limité : ici, le modèle peut regarder dans un dossier précis, pas dans toute la machine.

Les risques sont concrets. Un utilisateur peut fournir un chemin absolu comme /etc, une séquence ../ pour remonter dans l’arborescence, un raccourci ~ vers un dossier utilisateur, ou tenter d’atteindre un dossier parent contenant des fichiers sensibles. Cette attaque s’appelle une traversée de répertoire : elle consiste à sortir du dossier prévu en manipulant le chemin fourni.

La protection tient en trois étapes simples : construire le chemin avec os.path.join(SAFE_BASE_DIR, path), le résoudre avec os.path.abspath, puis refuser l’action si le chemin final n’est pas dans le répertoire de base autorisé. La méthode os.path.commonpath, documentée par Python, permet de comparer proprement des chemins normalisés.

import os

SAFE_BASE_DIR = os.path.abspath("./workspace")

def list_directory_contents(path="."):
    # Construire puis résoudre le chemin demandé.
    requested_path = os.path.abspath(os.path.join(SAFE_BASE_DIR, path))

    # Refuser toute sortie de la sandbox.
    try:
        if os.path.commonpath([SAFE_BASE_DIR, requested_path]) != SAFE_BASE_DIR:
            return {"error": "Accès refusé : chemin hors de la sandbox."}
    except ValueError:
        return {"error": "Accès refusé : chemin invalide."}

    # Vérifier l’existence et le type du chemin.
    if not os.path.exists(requested_path):
        return {"error": "Dossier introuvable."}

    if not os.path.isdir(requested_path):
        return {"error": "Le chemin demandé n’est pas un dossier."}

    try:
        return {"items": os.listdir(requested_path)}
    except PermissionError:
        return {"error": "Permissions insuffisantes pour lire ce dossier."}

Cette sandbox réduit fortement le risque, mais elle ne remplace pas les permissions système, les conteneurs, ni l’isolation d’exécution. Pour durcir un agent en production, je combine cette vérification avec un utilisateur système aux droits limités, un répertoire dédié et, si possible, une exécution en conteneur.

Sources : OWASP Path Traversal, https://owasp.org/www-community/attacks/Path_Traversal ; Documentation Python os.path, https://docs.python.org/3/library/os.path.html.

Comment encadrer un interpréteur Python ?

Un interpréteur Python donné à un agent doit être restreint, isolé et limité à des tâches précises, sinon il devient un point d’exécution de code arbitraire. Cela veut dire qu’un modèle peut produire du code qui sera réellement exécuté par votre système, avec les mêmes conséquences qu’un script lancé à la main.

Dans un agent Gemma 4, Python rend l’agent beaucoup plus utile. Il peut calculer un ratio, transformer un fichier CSV, inspecter une structure JSON, vérifier une hypothèse ou produire un graphique. Mais ce gain pratique a un coût. Un code généré par un modèle peut contenir une erreur, lancer une boucle infinie, consommer trop de mémoire ou tenter d’accéder à des fichiers, variables d’environnement ou services réseau non autorisés.

La restriction consiste à réduire ce que le code a le droit de faire. Par exemple, autoriser uniquement certains modules comme math, statistics ou json, bloquer les imports dangereux comme os, subprocess ou socket, et refuser les appels réseau si l’agent n’en a pas besoin. L’isolation consiste à exécuter ce code dans un environnement séparé, par exemple un processus dédié ou un conteneur, pour limiter l’impact si quelque chose se passe mal.

Les garde-fous minimums sont simples à poser, et je les considère non négociables :

  • Limiter explicitement les modules disponibles.
  • Bloquer les imports et fonctions dangereuses, notamment exec, eval, open non contrôlé, subprocess et socket.
  • Fixer un timeout court pour interrompre une exécution trop longue.
  • Limiter la mémoire et le CPU disponibles.
  • Exécuter le code dans un processus séparé ou un conteneur.
  • Supprimer l’accès aux secrets, clés API et variables d’environnement sensibles.
Risque Exemple Garde-fou recommandé
Boucle infinie while True sans condition d’arrêt Timeout strict et arrêt forcé du processus
Import dangereux Import de os, subprocess ou socket Liste blanche de modules autorisés
Accès fichier Lecture de /etc/passwd ou d’un fichier interne Répertoire de travail isolé et permissions minimales
Fuite de secret Lecture d’une clé API dans les variables d’environnement Environnement nettoyé sans secrets exposés
Consommation CPU ou mémoire Création d’une liste géante ou calcul intensif Limites CPU, mémoire et conteneurisation

La documentation Python avertit clairement sur les risques de eval et exec, qui exécutent du code dynamique. OWASP recommande de traiter toute entrée non fiable avec validation stricte et principe du moindre privilège. Les pratiques de conteneurisation, documentées notamment par Docker, complètent ce cadre quand l’exécution doit être séparée du système hôte.

Quels garde-fous faut-il prévoir en production ?

En production, je traite chaque appel d’outil comme une action sensible. Un tool calling agentique ne “discute” pas seulement avec Gemma 4 : il déclenche du code, lit des fichiers, exécute parfois Python et manipule des données réelles. Il faut donc prévoir validation, permissions minimales, logs, limites d’exécution et possibilité de refus.

La boucle de tool calling donne la mécanique. La sandbox fichiers donne un premier périmètre. L’interpréteur Python apporte de la puissance. Mais l’ensemble doit être gouverné comme un système applicatif critique, pas comme une simple démo IA.

Les garde-fous opérationnels doivent être explicites :

  • Liste blanche d’outils : Le modèle ne peut appeler que des fonctions déclarées et autorisées côté application.
  • Validation stricte des arguments JSON : Chaque champ doit être typé, obligatoire si nécessaire, borné et refusé s’il contient une valeur inattendue.
  • Contrôle d’accès : Un utilisateur, un rôle ou un contexte métier ne doit accéder qu’aux outils prévus pour lui.
  • Environnement séparé : Les tests, les fichiers temporaires et les données de production doivent être isolés.
  • Journalisation : Chaque tool_call doit conserver l’utilisateur, l’outil, les arguments, l’heure, le résultat et l’erreur éventuelle.
  • Erreurs sobres : Un message d’erreur ne doit pas exposer de chemin système, de secret, de stack trace ou de donnée sensible.
  • Limites d’exécution : Il faut définir des timeouts, des quotas, des limites de fréquence et des alertes en cas d’usage anormal.

Le principe du moindre privilège est central. Un outil ne doit avoir que les droits nécessaires à sa tâche, rien de plus. Un outil qui liste des fichiers n’a pas besoin de supprimer, modifier ou écrire dans le système de fichiers. Cette séparation réduit l’impact d’un prompt malveillant, d’une erreur du modèle ou d’un bug applicatif.

L’évaluation doit couvrir autre chose que les cas nominaux. Il faut tester des prompts malveillants, des chemins suspects comme ../secrets, des paramètres manquants, des fichiers volumineux, des boucles, des appels répétés et des réponses ambiguës du modèle. Un agent local doit être testé comme une surface d’attaque, pas seulement comme une fonctionnalité IA.

Ces pratiques s’alignent avec OWASP ASVS et OWASP Top 10 pour la validation d’entrées et la gestion des risques applicatifs, avec le NIST AI Risk Management Framework pour la gouvernance du risque IA, avec la documentation Python pour l’exécution contrôlée de code et avec la documentation Ollama pour l’usage de l’API locale.

Checklist avant mise en production :

  • Outils autorisés : Chaque outil est déclaré dans une liste blanche.
  • Arguments validés : Les schémas JSON refusent les champs inconnus et les valeurs hors limites.
  • Droits réduits : Chaque outil applique le moindre privilège.
  • Sandbox vérifiée : Les chemins, fichiers temporaires et accès système sont confinés.
  • Logs activés : Les tool_calls et leurs résultats sont traçables.
  • Timeouts configurés : Les appels longs ou bloqués sont interrompus.
  • Quotas définis : Les fréquences d’appel sont limitées par utilisateur ou session.
  • Erreurs maîtrisées : Les messages ne divulguent aucune information sensible.
  • Tests offensifs réalisés : Les prompts malveillants, entrées invalides et boucles ont été testés.
  • Refus possible : L’agent peut répondre qu’il ne peut pas exécuter une action.

Et maintenant, quel outil faut-il donner à votre agent ?

Le tool calling agentique avec Gemma 4 devient intéressant quand le modèle ne se contente plus de répondre, mais peut observer un environnement, choisir une action et exploiter le résultat. La boucle reste simple : des outils décrits en JSON, une orchestration Python, des appels interceptés puis validés côté application. La vraie difficulté se trouve dans les permissions. Un explorateur de fichiers doit rester dans sa sandbox. Un interpréteur Python doit être restreint et isolé. En avançant par outils limités, testés et traçables, vous gagnez en automatisation sans abandonner le contrôle.

FAQ

  • Qu’est-ce que le tool calling en IA ?
    Le tool calling permet à un modèle d’IA de demander l’exécution d’une fonction externe avec des paramètres structurés. Le modèle ne fait pas directement l’action : l’application reçoit l’appel, vérifie les arguments, exécute ou refuse l’outil, puis renvoie le résultat au modèle.
  • Quelle est la différence entre tool calling et agent IA ?
    Le tool calling est une capacité technique. Un agent IA utilise cette capacité dans une boucle plus large : observer, décider, appeler un outil, lire le résultat, corriger son raisonnement et poursuivre. L’agent devient plus utile, mais aussi plus sensible à sécuriser.
  • Pourquoi sandboxer l’accès au système de fichiers ?
    Une sandbox limite l’agent à un répertoire autorisé. Sans cette protection, un chemin manipulé avec ../, un chemin absolu ou un raccourci système peut conduire à des fichiers sensibles. La résolution et la vérification des chemins sont donc indispensables.
  • Peut-on laisser un agent exécuter du Python librement ?
    Il vaut mieux éviter. L’exécution libre de Python peut ouvrir la porte à du code arbitraire, des boucles infinies, des imports dangereux ou des fuites de secrets. Un interpréteur doit être restreint, isolé, limité en temps et privé d’accès aux ressources inutiles.
  • Quels sont les garde-fous minimum pour un agent local ?
    Les garde-fous minimum sont une liste blanche d’outils, une validation stricte des paramètres, le principe du moindre privilège, des timeouts, des logs détaillés, une sandbox pour les fichiers, une isolation pour le code et des tests avec des entrées malveillantes.

 

 

A propos de l’auteur

Je suis Franck Scandolera, responsable de l’agence webAnalyste et de l’organisme Formations Analytics. J’accompagne les entreprises sur le tracking avancé server-side, l’Analytics Engineering, l’automatisation No/Low Code avec n8n, l’intégration de l’IA dans les process business et le SEO/GEO. J’ai travaillé pour des références comme Logis Hôtel, Yelloh Village, BazarChic, la Fédération Française de Football ou Texdecor. Si vous voulez cadrer des agents IA utiles, mesurables et sécurisés dans votre entreprise, contactez-moi.

Retour en haut
MetricsMag