Maîtriser l'Appel d'Outils (Tool Calling) avec Ollama et Python
L'appel d'outil (tool calling) transforme un modèle qui se contente de générer du texte en un agent capable de déclencher du vrai code : appeler une API météo, interroger une base, lancer un calcul. Ce guide montre comment maîtriser l'appel d'outil Ollama en Python de bout en bout — format JSON des outils, boucle d'exécution, streaming des tool calls (série 0.17) et structured outputs contraints par un JSON Schema appliqué directement au décodage. Tout tourne en local sur http://localhost:11434, sans clé API ni fuite de données.
#Pourquoi l'appel d'outil (tool calling) ?
Un LLM seul ne sait rien du monde réel après son entraînement : il ne connaît ni la météo d'aujourd'hui, ni le solde d'un compte, ni le contenu de votre base de données. L'appel d'outil comble ce vide. Vous décrivez au modèle une liste de fonctions disponibles, il décide lesquelles appeler et avec quels arguments, votre code les exécute, puis renvoie le résultat au modèle pour qu'il rédige une réponse informée.
Le point crucial à comprendre : le modèle n'exécute jamais rien lui-même. Il se contente de produire une demande structurée — « appelle get_meteo avec ville='Lyon' ». C'est votre programme Python qui exécute la fonction et garde le contrôle total. Cette séparation est ce qui rend le tool calling sûr et prévisible.
- Données fraîches
- Le modèle interroge une API en temps réel plutôt que de deviner à partir de ses souvenirs d'entraînement.
- Actions concrètes
- Créer un ticket, envoyer un e-mail, écrire dans une base — le LLM orchestre, votre code agit.
- Fiabilité
- Les calculs et les recherches exactes sont délégués à du code déterministe, pas hallucinés par le modèle.
- 100 % local
- Avec Ollama, toute la chaîne reste sur votre machine : ni clé API, ni requête sortante, ni facture au token.
#Comment fonctionne l'appel d'outil Ollama
Le cycle complet tient en cinq temps. Bien le visualiser évite la confusion la plus fréquente : croire qu'un seul appel suffit. Il en faut au moins deux — un pour obtenir la demande d'outil, un pour obtenir la réponse finale.
- 01Vous envoyez la question + les outilsLa requête chat contient le message de l'utilisateur et la liste des outils disponibles (paramètre tools).
- 02Le modèle renvoie une demande d'outilAu lieu de répondre en texte, il retourne un ou plusieurs tool_calls avec le nom de la fonction et les arguments.
- 03Votre code exécute la fonctionVous récupérez name et arguments, appelez la vraie fonction Python correspondante, obtenez un résultat.
- 04Vous renvoyez le résultatLe résultat est ajouté à l'historique sous forme d'un message de rôle « tool », puis vous relancez chat.
- 05Le modèle rédige la réponse finaleFort du résultat, il produit cette fois une réponse en langage naturel pour l'utilisateur.
#Prérequis
Trois briques : le daemon Ollama qui tourne, un modèle qui supporte réellement les outils, et la librairie Python officielle. Attention au deuxième point — tous les modèles ne savent pas faire du tool calling. Visez les familles récentes conçues pour ça.
- Ollama à jour
- Série 0.17 ou plus récente pour profiter du streaming des tool calls. Le daemon écoute sur http://localhost:11434.
- Un modèle compatible outils
- Qwen 3, Llama 3.1 / 3.3, Mistral, Firefunction, Command-R. Les modèles marqués « tools » sur ollama.com/library.
- Assez de VRAM
- Un 7B (Q4_K_M ≈ 5 Go) suffit pour tester ; un 14B (≈ 9 Go) suit mieux les consignes multi-outils. RTX 3060 12 Go comme entrée de gamme.
- La librairie ollama
- pip install -U ollama. Elle sait construire le schéma d'un outil directement depuis une fonction Python typée.
#Le format JSON des outils
Un outil se décrit avec un schéma JSON strictement aligné sur celui d'OpenAI : un objet type: "function" contenant un nom, une description et un objet parameters au format JSON Schema. La description compte énormément — c'est elle que le modèle lit pour décider quand et comment appeler l'outil. Soyez explicite.
#Premier appel d'outil en Python
Commençons par le cas le plus simple : une fonction, une question, et on observe ce que le modèle décide. Les annotations de type et la docstring servent à générer le schéma envoyé au modèle.
À ce stade, message.content est généralement vide : le modèle a renvoyé sa demande dans message.tool_calls. Chaque tool_call expose function.name (une chaîne) et function.arguments (déjà désérialisé en dictionnaire Python par la librairie). Il ne reste plus qu'à exécuter et à renvoyer.
#La boucle d'exécution complète
Voici le squelette réutilisable d'un agent tool calling : un dictionnaire qui associe chaque nom d'outil à sa fonction, l'exécution des appels demandés, l'ajout des résultats à l'historique, puis un second appel pour la réponse finale. On enveloppe le tout dans une boucle pour gérer le cas où le modèle enchaîne plusieurs outils.
Le message de résultat porte le rôle tool et un champ tool_name qui indique à quel appel il répond. Le content doit être une chaîne : sérialisez vos objets (json.dumps) avant de les renvoyer. Le modèle relit ce contenu comme s'il s'agissait d'une observation du monde.
#Parité OpenAI : le même code avec le client openai
Ollama expose un endpoint compatible OpenAI sur /v1. Si votre code utilise déjà le client openai, vous n'avez presque rien à changer : pointez base_url vers Ollama et mettez une clé API factice. Le format des outils et des tool_calls est identique — c'est la « parité OpenAI » qui rend la migration triviale.
#Streaming des tool calls (série 0.17)
Historiquement, activer le streaming désactivait le tool calling : il fallait choisir. Depuis la série 0.17, Ollama sait streamer les appels d'outils au fil de la génération. Concrètement, vous recevez les tool_calls dans les morceaux (chunks) du flux, en même temps que le texte éventuel, ce qui permet d'afficher une réponse fluide tout en déclenchant des outils.
#Structured outputs : forcer un JSON Schema
Le tool calling sert à agir ; les structured outputs servent à garantir la forme de la réponse. Avec le paramètre format, vous passez un JSON Schema qu'Ollama applique au décodage : le modèle est contraint, token par token, à ne produire qu'une sortie valide au regard du schéma. Fini le parsing fragile de JSON approximatif — la structure est garantie par construction.
Le plus pratique en Python est de décrire la structure avec un modèle Pydantic, puis d'en tirer le schéma via model_json_schema(). Vous récupérez ensuite un objet typé et validé.
#Gestion des erreurs et pièges courants
Le tool calling échoue rarement bruyamment : le plus souvent, le modèle « déraille » silencieusement. Voici les pannes fréquentes et comment les traiter.
- Aucun tool_call renvoyé
- Le modèle a répondu en texte alors qu'un outil s'imposait. Améliorez la description de l'outil, ou changez de modèle : les petits modèles ratent souvent la décision d'appeler.
- Arguments manquants ou faux
- function.arguments peut omettre un champ required ou mal le typer. Validez avec Pydantic ou un try/except avant d'appeler la vraie fonction, et renvoyez l'erreur au modèle comme résultat d'outil.
- Outil halluciné
- Le modèle invente un nom de fonction inexistant. D'où le OUTILS.get(name) qui renvoie un message d'erreur au lieu de planter — le modèle peut alors se corriger au tour suivant.
- Boucle infinie d'outils
- Un modèle peut redemander sans fin le même outil. Ajoutez un compteur d'itérations maximal (ex : 5) pour couper la boucle et éviter de tourner à vide.
- Contexte tronqué
- Ollama limite parfois le contexte à 2048 tokens par défaut, ce qui écrase l'historique des outils sur les longues sessions. Augmentez num_ctx via les options du modèle.
- Résultat non sérialisé
- Renvoyer un objet Python brut comme content casse la requête. Sérialisez toujours en chaîne (json.dumps ou str) avant de l'ajouter aux messages.
L'idée clé : ne jamais laisser une erreur d'outil faire crasher l'agent. Renvoyez le message d'erreur au modèle comme s'il s'agissait d'un résultat. Un bon modèle lit « outil inconnu » ou « argument manquant » et ajuste son prochain appel de lui-même.
#Pour aller plus loin
Vous savez désormais faire du tool calling Ollama en Python : format JSON des outils, boucle d'exécution, parité OpenAI, streaming et structured outputs contraints par schéma. Ces guides prolongent naturellement le sujet.
- L'API REST d'Ollama
- « Intégrer Ollama dans une application Python via l'API REST » — les bases de l'endpoint :11434, du streaming et du JSON mode, socle de tout ce guide.
- Agents avec LangChain
- « Créer un agent IA local en Python avec LangChain et Ollama » — orchestrer plusieurs outils et de la mémoire au-dessus du tool calling brut.
- Choisir sa quantification
- « Choisir sa quantification (Q4, Q5, Q8, FP16) » — pour équilibrer VRAM et qualité du modèle qui pilotera vos outils.
Un retour, une erreur, une précision ? Faites-nous signe, ça améliore le guide pour tout le monde.