La note précédente montrait comment un modèle peut appeler une fonction au lieu de simplement en parler. Une question restait ouverte : quand plusieurs outils sont disponibles, comment décide-t-il lequel utiliser ?
Le problème
Un agent utile a rarement un seul outil. Sur une plateforme de service client, on en compte vite une dizaine : consulter une commande, chercher un client, créer un billet, envoyer un courriel, vérifier un stock.
Quand l'utilisateur écrit une phrase, personne ne dit au modèle quelle fonction appeler. Il n'y a ni règle, ni liste de mots-clés, ni aiguillage écrit à la main.
Ce que le modèle voit réellement
Voici le point le plus contre-intuitif : le modèle ne voit pas ton code. Il ignore ce que fait le corps de la fonction. Ce qui lui est transmis, pour chaque outil, tient en trois choses :
- le nom de l'outil ;
- sa description ;
- le schéma de ses paramètres.
En Python, ces trois éléments viennent de la signature et de la docstring.
@beta_tool def get_weather(city: str) -> str: """Retourne la météo actuelle d'une ville.""" return "24°C" @beta_tool def calculate(a: float, b: float) -> float: """Effectue un calcul mathématique.""" return a * b
Le return ne sera jamais lu par le modèle. La docstring, elle, est lue à chaque tour de conversation.
Le nom et la description ne sont pas de la documentation. Ce sont les données d'entrée de la décision.
La décision
Le modèle met en face l'intention de la demande et la description de chaque outil disponible, puis retient celle qui correspond.
Démonstration
Même agent, même modèle, deux questions.
Combien font 125 × 8 ?
↓
calculate(125, 8)
Est-ce qu'il va pleuvoir à Montréal ?
↓
get_weather("Montréal")
Rien n'a changé dans le code entre les deux appels. Seule la demande a changé, et la correspondance avec les descriptions a suffi.
Le modèle a aussi rempli les paramètres : il a extrait « Montréal » d'un côté, 125 et 8 de l'autre, en s'appuyant sur le schéma déclaré dans la signature.
Là où ça se dégrade
La sélection n'a rien de magique, et elle échoue de façons assez prévisibles.
Une description vague
Une docstring comme """Gère les données.""" ne dit rien au modèle. Il devra deviner à partir du nom, et il devinera mal.
Des outils trop proches
search_customer, find_client et get_user_info se ressemblent trop. Si toi tu hésites en lisant les trois descriptions, le modèle hésitera aussi. La solution n'est pas un meilleur prompt : c'est fusionner les outils ou séparer clairement leurs domaines.
Trop d'outils exposés en même temps
Plus la liste est longue, plus la décision est bruitée. Il vaut mieux n'exposer que les outils pertinents pour l'utilisateur et le moment en cours, plutôt que de tout déclarer et corriger après coup.
Quand un agent se trompe d'outil, le problème est presque toujours dans la description, rarement dans le modèle.
Écrire une description utile
Une bonne description dit trois choses : ce que l'outil fait, quand l'utiliser, et quand ne pas l'utiliser.
@beta_tool def search_customer(query: str) -> dict: """Recherche un client par courriel ou téléphone. À utiliser avant toute modification de dossier client. Ne pas utiliser pour retrouver une commande : voir get_order. """
C'est plus long qu'une ligne, et c'est normal. Sur un agent qui grossit, j'ai fini par passer plus de temps à écrire les descriptions qu'à écrire les fonctions elles-mêmes.
À retenir
Un agent ne choisit pas un outil au hasard, et il ne lit pas ton code. Il compare la demande à la description de chaque outil disponible.
La qualité de la sélection dépend donc surtout de ce que tu écris : des noms distincts, des descriptions précises, et pas trop d'outils exposés à la fois.