Comment créer un agent local avec Gemma 4 ?

Gemma 4 devient un agent local quand il peut inspecter un dossier sandboxé et lancer des calculs Python limités. L’enjeu n’est pas seulement technique : il faut orchestrer les outils, contrôler chaque action et empêcher l’accès aux fichiers ou commandes sensibles.

Pourquoi rendre Gemma 4 plus agentique ?

Gemma 4 devient plus agentique quand il ne se limite plus à discuter ou appeler des API, mais peut observer un environnement local, décider d’utiliser un outil, puis intégrer le résultat dans son raisonnement.

Un LLM, pour Large Language Model, est un grand modèle de langage entraîné à prédire et générer du texte à partir d’un contexte. Un chatbot classique utilise ce modèle pour répondre à vos messages. Il reste principalement dans la conversation : vous posez une question, il produit une réponse.

Un assistant avec appels d’API va plus loin. Le tool calling désigne la capacité du modèle à demander l’exécution d’une fonction externe, par exemple appeler une API météo, créer un ticket Jira ou interroger une base de données. Le modèle ne fait pas tout lui-même : il choisit un outil, reçoit un résultat, puis formule une réponse.

Un agent local ajoute une couche importante : il peut observer l’état de votre machine ou de votre projet. Par exemple, lire une arborescence de fichiers, analyser un fichier CSV, exécuter un script Python, vérifier des logs ou calculer localement un résultat. C’est là que le terme agentique prend son sens : capacité à enchaîner observation, décision et action, au lieu de répondre seulement à partir d’un prompt.

Le changement principal tient au contexte disponible. Un simple appel web donne une information externe ponctuelle. Un accès local donne au modèle une vision de votre environnement réel : fichiers présents, dépendances installées, erreurs dans un terminal, structure d’un dépôt Git. Pour du développement, de la data ou de l’automatisation, cette différence est majeure.

Cette puissance augmente aussi le risque. Plus l’agent peut lire, écrire ou exécuter localement, plus il faut limiter ses permissions. L’OWASP Top 10 for LLM Applications documente notamment les risques liés aux actions excessives, aux sorties non maîtrisées et à l’exposition de données sensibles. Le NIST AI Risk Management Framework 1.0 recommande une logique de gouvernance du risque : identifier, mesurer, gérer et surveiller les risques sur tout le cycle de vie du système.

Type Contexte disponible Capacité d’action Niveau de risque Garde-fous nécessaires
Chatbot Prompt et historique de conversation Réponse textuelle Faible à modéré Filtrage des données sensibles et validation humaine
Assistant avec API Conversation plus résultats d’API Appels de fonctions externes Modéré Permissions limitées, validation des paramètres, journalisation
Agent local Conversation, fichiers, scripts, logs et état machine Lecture, calcul, modification ou exécution locale Élevé Sandbox, liste blanche d’outils, droits minimaux, revue humaine

Comment fonctionne la boucle de tool calling ?

La boucle de tool calling repose sur 4 étapes simples : déclarer les outils, envoyer leurs schémas au modèle, intercepter les demandes d’outils, exécuter localement puis réinjecter le résultat dans la conversation.

Le modèle ne lance pas lui-même une fonction Python. Il propose un appel structuré. C’est une différence importante. Le code qui exécute vraiment l’action reste dans votre application, souvent appelée orchestrateur, c’est-à-dire la couche qui fait le lien entre le modèle, les outils et l’historique de conversation.

Le JSON Schema joue ici le rôle de contrat. Il décrit le nom de l’outil, ses paramètres attendus, leurs types et leurs contraintes. Par exemple : une chaîne de caractères pour un chemin de fichier, un nombre pour une limite, une valeur obligatoire ou optionnelle. Grâce à ce schéma, le modèle peut produire un appel propre, au lieu d’écrire une phrase vague comme “lis ce fichier”.

Le cycle complet ressemble à ceci :

  • Le développeur expose une fonction Python, par exemple lire un fichier, lancer un script ou interroger une base locale.
  • Le schéma de cette fonction est envoyé au modèle avec la conversation.
  • Le modèle répond soit avec du texte, soit avec un tool_call, c’est-à-dire une demande d’appel d’outil structurée.
  • L’orchestrateur intercepte cette demande, valide les arguments, puis exécute la fonction correspondante sur la machine.
  • Le résultat est ajouté aux messages, puis renvoyé au modèle pour qu’il puisse produire la réponse finale.

La nouveauté ne vient pas forcément de la boucle elle-même. OpenAI documente le function calling depuis 2023, Anthropic documente aussi le tool use dans Claude. Ce qui change avec un agent local, c’est la nature des outils : on ne parle plus seulement de clients API distants, mais de fonctions capables de lire le système de fichiers, d’exécuter du code ou d’automatiser une machine locale. Avec un modèle ouvert comme Gemma, documenté par Google AI, cette logique devient intéressante pour construire des agents plus privés et plus proches de votre environnement de travail.

tools = {
    "read_file": {
        "schema": {
            "name": "read_file",
            "parameters": {
                "path": {"type": "string"}
            },
            "required": ["path"]
        },
        "function": read_file
    }
}

messages = [{"role": "user", "content": "Résume le fichier notes.txt"}]

while True:
    response = call_model(messages, tools=tools)

    if not response.get("tool_calls"):
        print(response["content"])
        break

    for call in response["tool_calls"]:
        name = call["name"]
        args = call["arguments"]

        result = tools[name]["function"](**args)

        messages.append({
            "role": "tool",
            "name": name,
            "content": result
        })

Les références utiles pour approfondir sont la documentation OpenAI sur le function calling et le tool calling, la documentation Anthropic sur le tool use, et la documentation Google AI consacrée aux modèles Gemma.

Comment sécuriser l’exploration de fichiers ?

Il faut enfermer l’explorateur de fichiers dans un répertoire de base autorisé, résoudre chaque chemin en chemin absolu, puis refuser toute requête qui sort de ce périmètre.

L’outil list_directory_contents sert à lister le contenu d’un répertoire local pour que Gemma 4 comprenne l’état du projet sans recevoir tout le système en contexte. C’est utile, mais dangereux si le modèle peut demander n’importe quel chemin.

Le risque principal s’appelle path traversal. C’est une technique qui consiste à manipuler un chemin pour sortir du dossier prévu. Une chaîne comme ../../etc, / ou ~ peut tenter de remonter vers des fichiers sensibles. Cette vulnérabilité est documentée par CWE-22 Improper Limitation of a Pathname to a Restricted Directory : https://cwe.mitre.org/data/definitions/22.html. OWASP la référence aussi dans ses ressources sur le path traversal : https://owasp.org/www-community/attacks/Path_Traversal.

La règle importante : la vérification ne doit jamais faire confiance à la chaîne fournie par le modèle. Il faut vérifier le chemin réellement résolu par le système.

from pathlib import Path
import logging

SAFE_BASE_DIR = Path("/home/app/sandbox").resolve(strict=True)
MAX_ITEMS = 100

def list_directory_contents(requested_path: str = ".") -> list[str]:
    # Journaliser la demande brute pour audit.
    logging.info("Demande de listing: %s", requested_path)

    # Construire puis résoudre le chemin réel.
    candidate = (SAFE_BASE_DIR / requested_path).resolve()

    # Refuser tout chemin qui sort de la sandbox.
    try:
        candidate.relative_to(SAFE_BASE_DIR)
    except ValueError:
        logging.warning("Chemin refusé hors sandbox: %s", candidate)
        raise PermissionError("Accès refusé")

    # Vérifier que la cible existe et reste un dossier.
    if not candidate.exists():
        raise FileNotFoundError("Répertoire introuvable")

    if not candidate.is_dir():
        raise NotADirectoryError("La cible n'est pas un dossier")

    # Retourner un volume limité, uniquement les noms.
    return sorted(item.name for item in candidate.iterdir())[:MAX_ITEMS]

Les garde-fous à appliquer sont simples, mais non négociables :

  • Utiliser un répertoire sandbox dédié, séparé du système, du dossier utilisateur et du dépôt complet si possible.
  • Préférer une liste blanche, par exemple un seul dossier autorisé, plutôt qu’une liste noire de chemins interdits.
  • Exclure les secrets : clés API, fichiers .env, tokens, certificats et exports de base de données.
  • Limiter le volume retourné pour éviter d’inonder le contexte du modèle et de divulguer trop d’informations.
  • Conserver des logs d’audit des chemins demandés, acceptés et refusés.
Risque Exemple Protection recommandée
Sortie du dossier autorisé ../../etc Résoudre le chemin absolu et vérifier relative_to(SAFE_BASE_DIR)
Accès à la racine système / Refuser tout chemin résolu hors sandbox
Lecture de secrets .env ou id_rsa Ne jamais placer de secrets dans le répertoire accessible
Contexte trop volumineux Dossier avec 20 000 fichiers Limiter le nombre d’éléments retournés
Attaque invisible Demandes répétées refusées Journaliser les chemins demandés et refusés

Comment encadrer l’exécution Python ?

L’exécution Python doit être restreinte par défaut, isolée, limitée dans le temps et privée d’accès aux ressources sensibles. Un interpréteur Python donne une vraie capacité agentique à Gemma 4 : il peut calculer, transformer des données, valider une hypothèse, tester une logique ou analyser un fichier autorisé. C’est utile, mais ce n’est jamais neutre.

Le danger arrive vite. Du code généré ou demandé par un modèle peut lire des fichiers locaux, lancer des commandes système, consommer toute la mémoire, boucler indéfiniment ou exfiltrer des données si l’environnement n’est pas contrôlé. La documentation Python le rappelle notamment pour subprocess, qui permet de démarrer des processus externes et demande une attention particulière sur la sécurité, surtout avec les commandes construites dynamiquement. Le module ast, lui, permet d’analyser du code Python sous forme d’arbre syntaxique, mais il ne transforme pas à lui seul une exécution en environnement sûr.

Les garde-fous doivent être explicites et cumulés :

  • Sandbox : Exécuter le code dans un espace isolé, idéalement jetable.
  • Timeout court : Couper l’exécution après quelques secondes.
  • Mémoire limitée : Empêcher un script de saturer la machine.
  • Réseau désactivé : Interdire Internet si la tâche ne l’exige pas.
  • Répertoire isolé : Ne monter que les fichiers nécessaires.
  • Variables d’environnement filtrées : Ne jamais exposer de secrets, clés API ou tokens.
  • Imports restreints : Bloquer les modules dangereux comme os, subprocess ou socket si inutiles.
  • Journalisation : Garder la demande, le code, la durée, stdout et stderr.
import subprocess
import sys
import tempfile
from pathlib import Path

MAX_OUTPUT = 4000

def run_restricted_python(code: str, timeout: int = 3) -> dict:
    # Exemple conceptuel, insuffisant comme sandbox de production.
    with tempfile.TemporaryDirectory() as tmp:
        script_path = Path(tmp) / "agent_code.py"
        script_path.write_text(code, encoding="utf-8")

        result = subprocess.run(
            [sys.executable, "-I", str(script_path)],
            cwd=tmp,
            env={},
            text=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            timeout=timeout,
            shell=False
        )

        return {
            "exit_code": result.returncode,
            "stdout": result.stdout[:MAX_OUTPUT],
            "stderr": result.stderr[:MAX_OUTPUT],
        }

Pour un usage sérieux, il faut préférer une isolation système : conteneur sans réseau, machine virtuelle, microVM ou environnement jetable avec quotas CPU et mémoire. L’OWASP Top 10 for LLM Applications classe justement les actions excessives et l’exposition de données sensibles parmi les risques majeurs des applications LLM.

Le même principe que pour les fichiers s’applique au code : le modèle demande, l’orchestrateur décide, l’environnement exécute sous contraintes. Le modèle ne doit jamais obtenir directement les pleins pouvoirs sur votre machine.

Comment tester avant de passer en production ?

Il faut tester l’agent comme un système à privilèges, pas comme une simple interface de chat. Un agent local avec Gemma 4 peut appeler des outils, lire des fichiers, lancer du Python ou manipuler des données : chaque capacité devient une surface d’attaque.

La validation doit suivre une démarche simple, reproductible et documentée.

  • Définir les actions autorisées : répertoires lisibles, commandes disponibles, formats acceptés, taille maximale des sorties.
  • Écrire des tests de refus : l’agent doit refuser clairement ce qui sort de son périmètre.
  • Simuler des chemins malveillants : une attaque de type path traversal consiste à remonter dans l’arborescence avec ../ pour lire des fichiers non prévus.
  • Tester les timeouts Python : un timeout coupe une exécution trop longue pour éviter qu’une boucle infinie bloque la machine.
  • Vérifier les logs : les décisions, erreurs et appels d’outils doivent être compréhensibles après coup.
  • Faire une revue de sécurité avant ouverture à des utilisateurs réels, surtout si l’agent peut écrire, supprimer, exécuter ou envoyer des données.

Les tests concrets doivent être agressifs. Demandez à l’agent de lire /, ../../etc, ~/.ssh, puis de récupérer les variables d’environnement. Demandez-lui aussi de proposer un import os, de lancer une boucle infinie et de générer une sortie très longue. Le bon comportement n’est pas “répondre intelligemment”, mais refuser, limiter ou interrompre proprement.

Le point central reste le principe du moindre privilège. L’agent ne doit avoir accès qu’à ce qui est nécessaire à sa tâche, jamais à toute la machine par confort de développement. Si son rôle consiste à analyser des CSV dans un dossier précis, il n’a aucune raison d’accéder à ~/.ssh, aux variables d’environnement, au réseau ou au système complet.

Côté observabilité, je recommande de stocker les tool_calls, c’est-à-dire les appels d’outils demandés par le modèle, avec les paramètres reçus, les décisions de refus, la durée d’exécution, le volume de sortie et les erreurs. Les secrets ne doivent jamais être journalisés : clés API, tokens, mots de passe, contenus de fichiers sensibles.

Checklist avant production

  • Sandbox créée.
  • Secrets absents.
  • Tests de path traversal passés.
  • Timeouts actifs.
  • Réseau coupé si inutile.
  • Logs relus.
  • Politique de refus claire.
  • Validation humaine prévue pour les actions sensibles.

Prêt à donner plus d’autonomie à Gemma 4 sans perdre le contrôle ?

Créer un agent local avec Gemma 4 consiste à garder une boucle de tool calling simple, mais à traiter les nouveaux outils comme des capacités sensibles. L’exploration de fichiers doit rester enfermée dans un répertoire sandboxé. L’exécution Python doit être isolée, limitée et observable. Le modèle peut demander une action, mais l’orchestrateur garde la responsabilité de l’autoriser, de l’exécuter et d’en contrôler le résultat. C’est ce compromis qui rend l’agent utile sans le transformer en risque opérationnel. Vous gagnez un assistant capable de raisonner sur votre environnement local, tout en conservant une maîtrise claire de ses limites.

FAQ

  • Qu’est-ce que le tool calling avec Gemma 4 ? Le tool calling permet à Gemma 4 de demander l’exécution d’une fonction externe au lieu de répondre uniquement avec du texte. Le modèle choisit un outil, fournit des paramètres structurés, puis l’orchestrateur exécute l’action et renvoie le résultat au modèle.
  • Pourquoi un agent local est-il plus risqué qu’un chatbot ? Un chatbot produit surtout du texte. Un agent local peut lire des fichiers, lancer du code ou interagir avec un environnement réel. Ces capacités sont utiles, mais elles exigent des limites strictes pour éviter l’accès aux secrets, aux fichiers système ou aux ressources non prévues.
  • Comment empêcher Gemma 4 d’accéder à tout le système de fichiers ? Il faut définir un répertoire autorisé, résoudre chaque chemin en chemin absolu, puis refuser toute requête qui sort de ce répertoire. Cette protection limite les attaques de type path traversal comme ../../etc ou l’accès à des dossiers personnels.
  • Peut-on exécuter du Python généré par un LLM en sécurité ? On peut réduire le risque, mais pas le supprimer avec un simple filtre. L’exécution doit être isolée, limitée par timeout, privée de secrets, surveillée et idéalement lancée dans un conteneur, une machine virtuelle ou un environnement jetable.
  • Quels tests faire avant d’utiliser un agent Gemma 4 en production ? Il faut tester les refus d’accès aux chemins interdits, les boucles infinies, les sorties trop longues, les imports dangereux, l’absence de secrets dans l’environnement et la qualité des logs. L’objectif est de vérifier que l’orchestrateur garde le contrôle même si le modèle demande une action risquée.

 

 

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é avec des organisations comme Logis Hôtel, Yelloh Village, BazarChic, la Fédération Française de Football ou Texdecor. Si vous voulez cadrer un projet d’automatisation ou d’agent IA sans ouvrir de failles inutiles, contactez-moi.

Retour en haut
AIgenierie