Un agent local avec Gemma 4 se construit en branchant le modèle à des outils contrôlés. Fichiers, Python, orchestration, sécurité : l’enjeu n’est pas de tout autoriser, mais de donner juste assez d’autonomie pour produire un résultat utile sans exposer votre machine.
Qu’est-ce qui rend Gemma 4 agentique ?
Gemma 4 devient agentique quand il ne se limite plus à générer du texte, mais peut choisir et appeler des outils pour observer ou modifier un environnement contrôlé.
Un modèle de langage prédit du texte à partir d’un contexte. Un agent, lui, ajoute une boucle d’action : il analyse une demande, décide d’utiliser ou non un outil, lit le résultat, puis continue. Le tool calling, ou appel d’outil, désigne ce mécanisme où le modèle demande à une couche externe d’exécuter une fonction précise.
| Chatbot classique | Répond avec ce qu’il sait ou ce qu’on lui donne dans le prompt. Il ne vérifie pas l’état réel de votre machine. |
| Modèle avec API web | Appelle un service distant, souvent de façon stateless, c’est-à-dire sans mémoire locale persistante entre deux appels. Le fournisseur encadre les permissions. |
| Agent local | Utilise des outils sur votre machine. Il peut lire un dossier, écrire un fichier, lancer du code ou interroger une base locale. |
Un environnement local correspond ici à votre poste, serveur ou conteneur. L’état local, c’est ce qui existe réellement dedans : fichiers, variables, logs, bases SQLite, scripts, résultats intermédiaires. Cette différence change tout. Sans outil, le modèle devine. Avec outil, il observe.
Par exemple, si vous demandez : “Trouve le fichier CSV dans mon dossier de travail et calcule la moyenne de la colonne revenue”, un modèle seul peut seulement proposer une méthode générique. Un agent local peut d’abord lister le dossier, identifier le bon fichier, puis proposer ou exécuter un script Python.
from pathlib import Path
import pandas as pd
# Cherche les fichiers CSV dans le dossier courant.
csv_files = list(Path(".").glob("*.csv"))
if not csv_files:
raise FileNotFoundError("Aucun fichier CSV trouvé.")
df = pd.read_csv(csv_files[0])
# Calcule une statistique simple.
print(df["revenue"].mean())
L’intérêt avec Gemma 4 en exécution locale, dans l’esprit des familles de modèles ouverts Gemma documentées par Google via leurs model cards, est de garder les données et les traitements près de la machine. La contrepartie est claire : la sécurité devient votre responsabilité. Un outil local mal limité peut supprimer des fichiers, exposer des secrets ou exécuter du code dangereux.
Le point important : Gemma ne devient pas agentique “tout seul”. Les modèles ouverts comme Gemma sont conçus pour être exécutés dans différents environnements selon le runtime utilisé, par exemple Ollama, llama.cpp ou une API compatible. Le tool calling dépend surtout de la couche d’orchestration autour du modèle, comme le décrivent la documentation Gemma de Google et les documentations de runtimes prenant en charge les appels d’outils. La suite logique consiste donc à définir cette architecture d’orchestration.
Quelle boucle d’orchestration faut-il garder ?
La même boucle d’orchestration reste valable, même quand les outils deviennent locaux. Je garde le même principe : le modèle raisonne, le programme hôte exécute, et aucune action sensible ne part directement du modèle vers la machine.
Le flux logique tient en quelques étapes simples. D’abord, vous définissez les fonctions disponibles, par exemple lire un fichier, chercher dans une base locale ou lancer un calcul. Ensuite, vous exposez leur signature au modèle avec un schéma JSON, c’est-à-dire un format texte structuré qui décrit le nom de la fonction, ses paramètres et leurs types. Puis, vous envoyez la demande utilisateur au modèle.
Si le modèle estime qu’un outil est nécessaire, il ne l’exécute pas lui-même. Il renvoie un tool_call, autrement dit une demande d’appel d’outil. Le programme hôte intercepte cette demande, vérifie que la fonction est autorisée, exécute le code localement, ajoute le résultat dans l’historique, puis rappelle le modèle pour qu’il formule la réponse finale.
Historique = [MessageUtilisateur]
Réponse = AppelerModèle(Historique, OutilsDisponibles)
Si Réponse.ContientToolCalls:
Pour Chaque Appel Dans Réponse.ToolCalls:
Si Appel.Nom Est Dans FonctionsAutorisées:
Résultat = ExécuterFonctionLocale(Appel.Nom, Appel.Arguments)
Historique.Ajouter(RésultatOutil(Appel.Id, Résultat))
Sinon:
Historique.Ajouter(ErreurOutil(Appel.Id, "Outil non autorisé"))
RéponseFinale = AppelerModèle(Historique, OutilsDisponibles)
Afficher(RéponseFinale.Texte)
Cette architecture est réutilisable parce qu’elle sépare deux responsabilités différentes. Le modèle propose une action en fonction du contexte. Le programme hôte décide si cette action est acceptable, comment elle est exécutée, avec quels droits, sur quelles données, et avec quelles limites.
| Étape | Rôle | Risque principal |
| Déclaration d’outil | Lister les fonctions que le modèle peut demander. | Exposer trop de capacités dès le départ. |
| Schéma JSON | Décrire les paramètres attendus de manière stricte. | Accepter des arguments trop libres ou ambigus. |
| Exécution locale | Lancer la fonction sur la machine ou le réseau local. | Donner accès à des ressources sensibles. |
| Retour au modèle | Fournir le résultat pour produire une réponse utile. | Réinjecter une sortie non contrôlée dans le contexte. |
Dès qu’un outil accède au système de fichiers, cette séparation ne suffit plus à elle seule. La sécurité devient centrale, car lire, modifier ou supprimer un fichier local n’a pas le même niveau de risque qu’un simple calcul en mémoire.
Comment explorer les fichiers sans danger ?
Il faut sandboxer l’exploration de fichiers dans un répertoire de base strictement autorisé. Concrètement, l’agent ne doit jamais pouvoir lister librement le disque : il reçoit un périmètre, par exemple SAFE_BASE_DIR, et tout chemin demandé doit rester à l’intérieur.
L’outil list_directory_contents sert à donner au modèle une capacité simple : lister les fichiers d’un dossier. C’est utile, parce que le modèle peut découvrir les fichiers réellement disponibles au lieu d’inventer des noms comme config.json, data.csv ou notes.txt. Mais cette capacité doit être strictement encadrée.
Le risque principal s’appelle path traversal. C’est une technique qui consiste à manipuler un chemin de fichier pour sortir du répertoire prévu, souvent avec ../. Il faut aussi bloquer les chemins absolus comme /, les raccourcis comme ~, et faire attention aux liens symboliques si votre système les suit. Sans garde-fou, un agent peut accéder involontairement à des secrets, des clés API, des fichiers de configuration ou des données personnelles.
import os
SAFE_BASE_DIR = os.path.abspath("./agent_workspace")
def list_directory_contents(relative_path="."):
# Construit un chemin depuis un chemin relatif fourni par le modèle.
requested_path = os.path.join(SAFE_BASE_DIR, relative_path)
# Normalise le chemin pour supprimer les ambiguïtés comme "../".
final_path = os.path.abspath(requested_path)
# Vérifie que le chemin final reste dans le répertoire autorisé.
if os.path.commonpath([SAFE_BASE_DIR, final_path]) != SAFE_BASE_DIR:
return {"error": "Chemin non autorisé."}
if not os.path.isdir(final_path):
return {"error": "Dossier introuvable ou inaccessible."}
return {
"path": os.path.relpath(final_path, SAFE_BASE_DIR),
"items": os.listdir(final_path)
}
La vérification importante repose sur os.path.commonpath, pas sur un simple startswith. Une comparaison naïve peut être fragile avec certains chemins proches, normalisations différentes ou préfixes trompeurs. La documentation Python précise que os.path.abspath retourne une version normalisée et absolue du chemin, tandis que os.path.commonpath calcule un chemin commun valide entre plusieurs chemins.
Cette approche suit les recommandations de sécurité documentées par OWASP Path Traversal et par la faiblesse CWE-22 Improper Limitation of a Pathname to a Restricted Directory, qui décrit précisément les erreurs de limitation d’accès à un répertoire contrôlé.
Avant de brancher cet outil à Gemma 4, je garde cette checklist minimale :
- Définir un répertoire de base unique, comme SAFE_BASE_DIR.
- Normaliser chaque chemin avec os.path.abspath.
- Refuser tout accès hors périmètre avec os.path.commonpath.
- Journaliser les refus, sans exposer de chemins sensibles au modèle.
- Exécuter l’agent avec des droits système minimaux, jamais avec un compte administrateur.
Comment brancher Python sans tout ouvrir ?
Il faut exposer un interpréteur Python restreint, limité dans le temps, les modules, les entrées-sorties et les ressources. Pas un accès libre à Python. Un agent local doit pouvoir exécuter du code utile, mais dans une zone contrôlée.
Python est très pratique pour un agent local. Il permet de faire des calculs, lire et analyser des fichiers, transformer des données, vérifier rapidement une hypothèse ou lancer un petit test. Pour un assistant connecté à vos documents ou à vos scripts, c’est souvent l’outil le plus simple.
Le problème, c’est que Python peut aussi exécuter presque n’importe quoi. Il peut supprimer des fichiers, lire des secrets, envoyer des données sur le réseau, importer des modules sensibles comme os ou subprocess, tourner en boucle infinie ou consommer toute la mémoire disponible.
Les garde-fous minimums sont donc clairs :
- Exécuter le code dans un processus isolé.
- Fixer un timeout strict, par exemple 3 ou 5 secondes.
- Utiliser un répertoire de travail sandboxé, dédié à l’agent.
- Couper l’accès réseau si l’outil n’en a pas besoin.
- Autoriser seulement certains modules avec une allowlist, c’est-à-dire une liste explicite de modules permis.
- Limiter les fichiers accessibles au strict nécessaire.
- Capturer stdout et stderr, c’est-à-dire la sortie normale et la sortie d’erreur du programme.
- Limiter la taille maximale de sortie.
- Lancer le processus avec un utilisateur système aux droits réduits.
import ast
import subprocess
import tempfile
from pathlib import Path
SAFE_BASE_DIR = Path("/tmp/local-agent-python").resolve()
SAFE_BASE_DIR.mkdir(parents=True, exist_ok=True)
ALLOWED_MODULES = {"math", "statistics", "json", "csv", "datetime"}
def check_imports(code: str) -> None:
tree = ast.parse(code)
for node in ast.walk(tree):
if isinstance(node, ast.Import):
for alias in node.names:
if alias.name.split(".")[0] not in ALLOWED_MODULES:
raise ValueError(f"Module interdit: {alias.name}")
if isinstance(node, ast.ImportFrom):
module = (node.module or "").split(".")[0]
if module not in ALLOWED_MODULES:
raise ValueError(f"Module interdit: {module}")
def run_python_code(code: str, timeout: int = 3) -> dict:
check_imports(code)
with tempfile.NamedTemporaryFile(
mode="w",
suffix=".py",
dir=SAFE_BASE_DIR,
delete=False,
encoding="utf-8"
) as f:
f.write(code)
script_path = Path(f.name)
result = subprocess.run(
["python3", str(script_path)],
cwd=SAFE_BASE_DIR,
timeout=timeout,
capture_output=True,
text=True
)
return {
"stdout": result.stdout[:10_000],
"stderr": result.stderr[:10_000],
"returncode": result.returncode
}
Ce code n’est pas une sandbox complète. C’est une base pédagogique. La documentation Python de subprocess rappelle que l’exécution de commandes doit être traitée avec prudence, surtout avec des entrées non fiables. Les recommandations OWASP vont dans le même sens : éviter l’exécution arbitraire, valider les entrées et appliquer le principe du moindre privilège.
| Outil | Utilité | Risque | Garde-fou obligatoire |
| Fichier | Lire, écrire, chercher dans des documents | Accès à des données sensibles | Limiter le répertoire accessible |
| Python | Calculer, transformer, tester, analyser | Exécution arbitraire et fuite de données | Processus isolé, timeout, allowlist et droits réduits |
Quels garde-fous mettre en production ?
En production, il faut considérer chaque tool_call comme une action potentiellement risquée et l’encadrer par des règles vérifiables. Un agent local avec Gemma 4 peut lire, écrire, exécuter du code ou appeler un service externe : ce n’est plus seulement du texte, c’est un système qui agit.
Le premier garde-fou est le principe du moindre privilège. Cela veut dire donner à l’agent uniquement les droits nécessaires pour accomplir sa tâche, rien de plus. Si l’agent doit résumer des fichiers dans un dossier précis, il n’a pas besoin d’accéder à tout le disque. Si l’agent doit générer un rapport, il n’a pas besoin de supprimer des fichiers sources.
La stratégie de base tient en quelques règles simples :
- Permissions minimales : Limiter les dossiers, commandes, API et bases de données accessibles.
- Validation des entrées : Contrôler les chemins de fichiers, formats, tailles, paramètres et extensions avant chaque action.
- Sandboxing : Exécuter l’agent dans un environnement isolé, par exemple un conteneur Docker sans accès libre au système hôte.
- Journalisation : Enregistrer chaque tool_call avec l’entrée, la sortie, l’heure, l’utilisateur et la décision prise.
- Supervision : Définir des alertes sur les volumes anormaux, les erreurs répétées ou les appels coûteux.
- Tests adversariaux : Tester l’agent avec des prompts malveillants, ambigus ou contradictoires pour mesurer ses limites.
- Séparation des environnements : Ne jamais donner les mêmes droits en développement, test et production.
- Validation humaine : Bloquer les actions sensibles jusqu’à confirmation explicite.
| Niveau de risque | Exemple | Contrôle minimal |
| Lecture sandboxée | Lire un fichier local autorisé | Liste blanche de dossiers et extensions |
| Écriture sandboxée | Créer un rapport dans un dossier temporaire | Interdiction d’écraser sans versionnement |
| Exécution Python | Lancer un script d’analyse | Timeout, limite mémoire, dépendances contrôlées |
| Accès réseau | Appeler une API externe | Domaines autorisés, quotas, logs complets |
| Action business | Modifier une commande ou envoyer un email client | Validation humaine obligatoire |
Une validation humaine devient nécessaire dès qu’une action peut être difficile à annuler ou avoir un impact métier : suppression de fichiers, écriture dans un dossier partagé, accès à des données personnelles, exécution de code long ou coûteux, appel à un CRM, ERP ou système de paiement. Si des données personnelles sont traitées, le RGPD impose notamment de penser minimisation, traçabilité, base légale et durée de conservation. Ce n’est pas un conseil juridique, mais c’est un signal clair : l’agent doit manipuler le minimum de données nécessaire.
L’objectif n’est pas de bloquer Gemma 4. L’objectif est de rendre son autonomie auditable, limitée et réversible. Gemma 4 peut devenir réellement utile en local si l’architecture garde le contrôle.
Alors, faut-il donner des outils locaux à Gemma 4 ?
Donner des outils locaux à Gemma 4 a du sens si l’orchestration reste maître du jeu. Le modèle peut explorer un dossier, comprendre les fichiers disponibles, lancer un calcul Python et produire une réponse mieux ancrée dans votre environnement. Mais chaque outil élargit aussi la surface de risque. La bonne approche consiste à sandboxer, limiter les droits, valider les entrées, tracer les actions et réserver les opérations sensibles à une validation humaine. Vous obtenez ainsi un agent plus utile qu’un simple chatbot, sans lui confier les clés de votre système.
FAQ
- Qu’est-ce que le tool calling avec Gemma 4 ?
Le tool calling consiste à donner au modèle une liste d’outils qu’il peut demander à utiliser pendant une conversation. Le modèle ne lance pas directement l’action : il produit une demande structurée, souvent en JSON, puis votre application exécute ou refuse cette demande. - Pourquoi utiliser des outils locaux plutôt que des API web ?
Les outils locaux permettent à l’agent de travailler sur vos fichiers, vos scripts et votre environnement réel. C’est utile pour analyser un dossier, tester du code ou traiter des données internes. En contrepartie, les risques sont plus élevés qu’avec une API distante limitée. - Qu’est-ce qu’un système de fichiers sandboxé ?
C’est un espace limité dans lequel l’agent a le droit de lire ou écrire. Même si le modèle demande un chemin comme ../ ou /, l’application doit vérifier le chemin final et refuser tout accès en dehors du répertoire autorisé. - Peut-on laisser un agent exécuter librement du Python ?
Ce n’est pas recommandé. Python peut lire des fichiers, lancer des processus, consommer des ressources ou exfiltrer des données si l’environnement est mal contrôlé. Il faut limiter le temps d’exécution, les modules, les accès fichiers, les sorties et les droits système. - Quels sont les garde-fous prioritaires pour un agent local ?
Les priorités sont le principe du moindre privilège, la validation des chemins, le sandboxing, les timeouts, la journalisation des tool_calls et la validation humaine pour les actions sensibles. L’objectif est de rendre l’autonomie de l’agent utile, mais contrôlable.
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 server-side, l’Analytics Engineering, l’automatisation no/low code avec n8n, l’intégration de l’IA, le SEO et le 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, automatiser vos workflows ou sécuriser vos données de tracking, vous pouvez me contacter.
⭐ Analytics engineer, Data Analyst et Automatisation IA indépendant ⭐
- Ref clients : Logis Hôtel, Yelloh Village, BazarChic, Fédération Football Français, Texdecor…
Mon terrain de jeu :
- Data Analyst & Analytics engineering : tracking avancé (GTM server, e-commerce, CAPI, RGPD), entrepôt de données (BigQuery, Snowflake, PostgreSQL, ClickHouse), modèles (Airflow, dbt, Dataform), dashboards décisionnels (Looker, Power BI, Metabase, SQL, Python).
- Automatisation IA des taches Data, Marketing, RH, compta etc : conception de workflows intelligents robustes (n8n, App Script, scraping) connectés aux API de vos outils et LLM (OpenAI, Mistral, Claude…).
- Engineering IA pour créer des applications et agent IA sur mesure : intégration de LLM (OpenAI, Mistral…), RAG, assistants métier, génération de documents complexes, APIs, backends Node.js/Python.






