Faut-il utiliser les schémas Pydantic ?
Sans schéma Pydantic = moins de vérifications explicites
Quand on n’utilise pas de classe Pydantic, on relie l’outil via un schéma JSON brut (dans la description de l’outil). Dans ce cas :
• Le LLM ne fait pas de validation stricte côté Python.
• Il fait confiance au schéma JSON pour comprendre les types attendus.
• Il génère les inputs en se basant sur la description, mais sans vérification automatique des types ou des valeurs.
Résultat :
✅ Exécution plus rapide
✅ Moins de friction
⚠️ Moins de sécurité sur les entrées (si l’agent hallucine ou malformate les données)
Avec Pydantic = validation rigoureuse
Si on utilise une classe Pydantic (déclaré dans le paramètre fn_schema du FunctionTool) pour définir les paramètres :
• Le LLM doit conformer les inputs à la structure attendue.
• Chaque champ est validé (type, présence, valeur).
• Tu obtiens des erreurs explicites si l’input est mal formé.
Résultat :
✅ Robustesse
✅ Clarté des erreurs
⚠️ Temps de traitement plus long
⚠️ Risque de blocage si le LLM ne formate pas parfaitement.
Gestion des retours de fonction
C’est un point souvent négligé dans les workflows ReAct : la gestion des retours de fonction.
Comment ReAct gère les retours de fonction
Dans LlamaIndex ReAct, l’agent ne lit pas directement le code Python de la fonction. Il se base sur :
1. La docstring de la fonction (si elle est fournie)
2. Le nom de la fonction
3. Le contexte de la requête utilisateur
4. L’observation du résultat après appel de la fonction
Autrement dit, il ne sait pas à l’avance ce que la fonction retourne, sauf cela lui est expliqué.
Bonnes pratiques pour que ReAct comprenne le retour
Voici comment on peut l’aider à bien interpréter le résultat :
1. Docstring explicite dans la fonction :
- def extract_values_by_key(data_list, key):
- """
- Retourne une liste contenant les valeurs associées à une clé donnée
- dans chaque dictionnaire de la liste.
- """
- return [item[key] for item in data_list if key in item]
2. Description claire dans le schéma JSON :
"description": "Retourne une liste des valeurs correspondant à une clé spécifique dans une liste de dictionnaires."
3. Nom de fonction évocateur
Un nom comme ’extract_values_by_key’ est déjà très parlant. Éviter les noms trop génériques comme ’process_data’.
4. Observation du résultat
Après appel de la fonction, l’agent voit le retour (par exemple [’Alice’,’Bob’,’Charlie’]) et peut l’utiliser dans sa chaîne de raisonnement suivante.
L’annotation de type de retour () dans la signature Python est utile pour le développeur, mais elle n’a aucun impact direct sur le comportement de l’agent ReAct :
LlamaIndex ReAct ne lit pas le code source de la fonction. Il ne fait pas d’analyse statique comme un IDE ou un linter. Ce qu’il utilise pour comprendre le comportement d’un outil, c’est :
• Le nom de la fonction,
• La description (dans le schéma JSON ou la docstring),
• Les paramètres définis dans le schéma,
• Le résultat observé après exécution.
Pour aller plus loin…
On peut aussi encapsuler le retour dans un dictionnaire pour le rendre plus lisible :
- def extract_values_by_key(data_list, key):
- return {"values": [item[key] for item in data_list if key in item]}
Cela permet à l’agent de mieux comprendre la structure du résultat, surtout si tu veux enchaîner avec d’autres outils.