Les LLM ne pénètrent pas dans votre code – ils vous transmettent une requête, et c'est vous qui exécutez la fonction. Ce simple fait déconstruit le mythe selon lequel « le modèle appelle magiquement ma routine Python » et oblige les développeurs à repenser le débogage et la sécurité.
La boucle de dispatch, étape par étape
Lorsqu'un modèle de langage (LLM) a besoin d'un outil, il suit une séquence déterministe :
- Planification – le modèle décide qu'une action est nécessaire (ex. : « rembourser un paiement »).
- Génération d'une requête – il produit un texte structuré — généralement du JSON — qui nomme l'outil et fournit les arguments.
- Analyse (Parsing) – votre application ou un framework de support lit ce texte.
- Correspondance (Matching) – le framework recherche le nom dans le registre des fonctions réelles que vous avez exposées.
- Validation – il vérifie que les arguments correspondent au schéma de la fonction et que l'appelant est autorisé.
- Exécution – la fonction correspondante s'exécute dans votre environnement, effectuant le travail.
- Retour – le résultat est emballé et renvoyé au modèle pour la suite du raisonnement.
Considérez le LLM comme un planificateur, le framework comme un répartiteur (dispatcher) et la fonction comme l'ouvrier qui déplace réellement les données ou l'argent.
Pourquoi le mythe de la « magie » persiste
La plupart des développeurs voient une seule ligne de sortie du modèle qui ressemble à un appel de fonction et supposent que le modèle a effectué l'opération lui-même. Le terme « tool calling » dans la documentation des fournisseurs laisse entendre que le modèle invoque directement le code.
En réalité, le modèle ne fait que produire du texte qui décrit un appel. Votre processus fait le gros du travail : recherche, vérification des types, application des permissions et gestion des erreurs.
Les frameworks qui masquent la tuyauterie
Des bibliothèques telles que PydanticAI et LangChain font abstraction de la boucle pour vous permettre de vous concentrer sur la logique métier. Elles automatisent :
- La validation des arguments par rapport à un schéma (ex. : un modèle Pydantic).
- L'application des permissions, garantissant que l'utilisateur est autorisé à déclencher l'outil.
- La tentative de réexécution en cas d'échec, en revenant au modèle lorsqu'un outil renvoie une erreur.
- La protection contre les boucles infinies, en limitant le nombre d'appels d'outils consécutifs.
- Le maintien de l'état de la conversation, en intégrant les résultats des outils au dialogue.
Même avec ces assistants, le schéma reste le même : le modèle n'exécute jamais de code.
Le support natif du tool-calling par les fournisseurs
Certains fournisseurs proposent une interface de « tool-calling » native qui standardise les définitions d'outils et les formats de requête. Cela facilite l'intégration, mais ne supprime pas l'étape de dispatch. Vous devez toujours écrire (ou importer) le code qui exécute réellement l'opération demandée.
Le débogage devient plus facile quand on renomme le problème
Au lieu de blâmer un « agent confus », dites que le problème est que « la réponse du modèle ne contenait aucun appel d'outil ». La distinction est importante :
- Aucun appel d'outil – le modèle a répondu directement ou n'a pas réussi à générer une requête correctement formatée.
- Requête malformée – le JSON est syntaxiquement incorrect ou il manque des champs obligatoires, le dispatcher le rejette donc.
- Échec de validation – les arguments ne correspondent pas au schéma, déclenchant une erreur avant l'exécution.
Catégoriser les échecs vous permet de journaliser chaque étape de la boucle et de localiser précisément là où les choses ont déraillé.
Conseils pratiques pour un pipeline fiable
- Traitez la sortie du modèle comme une entrée non fiable. Passez chaque requête par une validation déterministe avant d'invoquer tout code ayant des effets de bord.
- Journalisez la requête brute et le résultat de chaque étape de validation. Cela crée une trace rejouable en cas de problème.
- Définissez des limites explicites sur les appels d'outils consécutifs ; une boucle infinie peut épuiser les ressources ou atteindre les limites de débit (rate limits).
- Enveloppez chaque fonction dans un bloc try/except qui renvoie un objet d'erreur structuré compréhensible par le modèle, incitant à une nouvelle tentative ou à une solution de repli (fallback) élégante.
- Séparez les vérifications de permissions de la logique métier. Vérifiez les droits de l'appelant avant l'exécution de la fonction, en particulier pour les actions privilégiées comme « supprimer l'utilisateur ».
- Utilisez des définitions basées sur des schémas (ex. : modèles Pydantic) afin que le framework puisse générer automatiquement le schéma JSON que le modèle doit suivre.
À surveiller ensuite
À mesure que les fournisseurs affinent les API de tool-calling natives, attendez-vous à des contrats plus stricts concernant les formats de requête et des codes d'erreur plus riches. Ces changements faciliteront la validation et permettront aux développeurs de construire des barrières de sécurité plus strictes. Gardez un œil sur les mises à jour des bibliothèques — beaucoup ajoutent un support intégré pour les dernières fonctionnalités des fournisseurs.
À retenir
Le LLM est un générateur de texte sophistiqué, pas un exécutant. Votre code demeure la seule autorité qui effectue les actions, et le dispatcher que vous construisez (ou importez) est le gardien qui valide, autorise et exécute ces actions. Repenser le workflow élimine le mythe de la « magie », rend le débogage plus précis et impose la discipline de sécurité dont tout système de production a besoin.
