Difficile, dans le monde des frameworks d'agents IA, de s'y retrouver : LangChain et son orchestrateur LangGraph, CrewAI, AutoGen, etc. Mais dans ce guide, nous parlerons de PydanticAI, d'autant plus que la version 2 vient de sortir en juin 2026.
C'est quoi PydanticAI ?
Il s'agit donc d'un framework open-source pour construire des agents IA en Python. Pour faire simple, un agent est un LLM auquel on donne des instructions, des outils qu'il peut appeler et dont on encadre les réponses. Pydantic est utilisé par les librairies d'OpenAI, d'Anthropic, de Google, etc. D'ailleurs, le framework FastAPI repose sur Pydantic, et nous avons un article dessus.
Comme l'équipe Pydantic l'explique elle-même (voir citation ci-dessous), en créant PydanticAI, l'objectif est de retrouver, pour le développement d'agents et d'applications d'IA, cette sensation qui a fait le succès de FastAPI.
We built Pydantic AI with one simple aim: to bring that FastAPI feeling to GenAI app and agent development.
À ce jour, le dépôt GitHub dépasse les 18 500 étoiles. De plus, il s'agit d'un framework agnostique aux modèles.
Comme dans la suite de ce guide nous allons parler typage, n'hésitez pas à aller lire notre article sur le typage en Python.
Votre premier agent
Créez un dossier pour votre nouveau projet avec un environnement virtuel, puis installez le framework. Comme nous allons utiliser Mistral, nous précisons le fournisseur correspondant entre crochets, afin d'embarquer les dépendances nécessaires :
pip install "pydantic-ai-slim[mistral]"
À noter
Le package pydantic-ai complet embarque déjà OpenAI, Anthropic et Google, mais pas Mistral : d'où l'extra [mistral] que nous ajoutons ici. Chaque fournisseur dispose ainsi de son propre groupe optionnel, et la version slim permet de n'installer que le strict nécessaire. Je vous invite à consulter la page d'installation officielle qui détaille les combinaisons possibles.
Pour ce guide, nous utiliserons l'API de Mistral, mais vous pouvez très bien utiliser un autre modèle. Récupérez une clé sur la console Mistral. Pour ma part, j'ai l'habitude de créer un fichier .env à la racine de mon projet pour y stocker mes clés.
Je charge le fichier .env avec la bibliothèque python-dotenv :
pip install python-dotenv
Créons maintenant notre premier agent IA dans un fichier agent.py :
from dotenv import load_dotenv from pydantic_ai import Agent # Charge le contenu du .env dans les variables d'environnement load_dotenv() # On indique le fournisseur et le modèle dans une simple chaîne agent = Agent( "mistral:mistral-small-latest", instructions="Tu es un assistant concis, réponds en une seule phrase.", ) # run_sync exécute l'agent de manière synchrone resultat = agent.run_sync("Explique-moi ce qu'est un agent IA.") print(resultat.output)
J'obtiens ce résultat :
Un agent IA est un programme autonome capable d'agir dans un environnement pour atteindre des objectifs en utilisant des techniques d'intelligence artificielle.
-
Agent(...)crée l'agent avec le modèle qu'on lui passe -
instructionsdéfinit le comportement de l'agent -
run_sync()lance la conversation et renvoie le résultat via l'attributoutput
Les sorties structurées avec PydanticAI
Nous y voilà !
Par défaut, un agent renvoie du texte libre. Mais cela peut vite devenir embêtant lorsque vous avez besoin d'un format cohérent, par exemple si ce qui est renvoyé par votre agent sert à alimenter un autre système.
PydanticAI règle ce problème avec le paramètre output_type : vous fournissez un modèle Pydantic, et l'agent renvoie une instance validée de ce modèle.
from typing import Literal from dotenv import load_dotenv from pydantic import BaseModel, Field from pydantic_ai import Agent load_dotenv() class TicketSupport(BaseModel): titre: str = Field(min_length=5, max_length=100) priorite: Literal["basse", "normale", "haute"] categorie: Literal["bug", "acces", "materiel"] urgence: int = Field(ge=1, le=5) # Un score entre 1 et 5 inclus agent = Agent( "mistral:mistral-small-latest", instructions="Transforme le message de l'utilisateur en ticket de support.", output_type=TicketSupport, ) message_patrick = ( "Bonjour, c'est encore moi. Mon écran affiche des lignes violettes " "depuis ce matin et j'ai une démo client à 14h. C'est la panique !" ) resultat = agent.run_sync(message_patrick) # resultat.output est une instance de TicketSupport, déjà validée ticket = resultat.output print(ticket) # titre='Écran affiche des lignes violettes - Urgence démo client' priorite='haute' categorie='materiel' urgence=5 print(ticket.priorite) # 'haute', garanti parmi nos trois valeurs Literal
-
output_type=TicketSupporttransmet notre modèle à l'agent, PydanticAI génère le schéma JSON du modèle et l'impose au LLM -
La réponse est validée par Pydantic, en prenant en compte les contraintes
-
Si la réponse du LLM échoue à la validation, l'agent lui renvoie automatiquement l'erreur et lui demande une correction
Attention
Le schéma garantit la forme de la réponse, pas son contenu. Le modèle peut toujours évaluer l'urgence à 3 là où vous auriez dit 5. Et gardez en tête que chaque essai de validation est un appel API supplémentaire.
Donner des outils à son agent
Ce qui fait d'un agent... un agent, c'est sa capacité à agir en appelant des fonctions pour récupérer des informations ou déclencher des actions. PydanticAI le permet via le décorateur @agent.tool_plain.
Partons directement sur un exemple avec nos amis Patrick et Sébastien :
from dotenv import load_dotenv from pydantic_ai import Agent load_dotenv() agent = Agent( "mistral:mistral-small-latest", instructions=( "Tu es l'assistant du support technique. " "Utilise les outils à ta disposition pour répondre." ), ) @agent.tool_plain def chercher_collaborateur(nom: str) -> dict[str, str]: """Renvoie le service et le site d'un collaborateur à partir de son nom.""" # Faux annuaire interne pour l'exemple annuaire = { "Patrick": {"service": "Comptabilité", "site": "Lyon"}, "Sébastien": {"service": "Direction", "site": "Paris"}, } return annuaire.get(nom, {"service": "inconnu", "site": "inconnu"}) resultat = agent.run_sync("Dans quel service travaille Patrick, et sur quel site ?") print(resultat.output) # Ce que j'ai obtenu : Patrick travaille dans le service **Comptabilité** sur le site de **Lyon**.
Le décorateur enregistre la fonction comme un outil de l'agent. Le type des paramètres est extrait de la signature et transmis au LLM, tout comme la docstring. Par exemple, le modèle sait qu'il doit passer une chaîne de caractères à nom, et la docstring lui donne des précisions. Ensuite, le modèle récupère le dictionnaire envoyé et formule sa réponse.
Ce n'est qu'un exemple, mais vous imaginez qu'il est possible de créer des outils complets, comme brancher une vraie base de données à la place de notre dictionnaire.
PydanticAI V2
La version 2 est sortie le 23 juin 2026 et introduit le concept de capability.
Jusqu'ici, on configurait un agent bout de code par bout de code, avec des instructions, des outils, etc.
Une capability regroupe tout cela en une seule unité composable : instructions, outils, hooks, paramètres.
Sachez que l'équipe a profité de ce lancement pour sortir Pydantic AI Harness, un paquet séparé de capabilities prêtes à l'emploi.
Voici un exemple qui illustre bien les capabilities, tiré de l'annonce officielle de la V2 :
from pydantic_ai import Agent from pydantic_ai.capabilities import Capability, Thinking, ToolSearch, WebSearch from pydantic_ai.mcp import MCPToolset from pydantic_ai_harness import CodeMode agent = Agent( 'anthropic:claude-opus-4-7', instructions='Research thoroughly and cite your sources.', capabilities=[ Thinking(effort='high'), CodeMode(), WebSearch(), ToolSearch(), Capability( id='github', description='Look up GitHub issues, pull requests, and code.', instructions='Use the GitHub tools when a question is about a repository.', toolset=MCPToolset('https://mcp.example.com/github'), defer_loading=True, ), ], )
-
Thinking(effort='high')active le raisonnement étendu. La syntaxe est la même quel que soit le fournisseur 😎 -
CodeMode()permet à l'agent d'écrire du code exécuté dans un environnement isolé, plutôt que d'appeler différents outils et d'attendre les résultats. Il s'agit d'une capability duHarness -
WebSearch()parle de lui-même, l'agent a accès à la recherche web -
ToolSearch()permet à l'agent d'aller chercher des outils au moment où il en a besoin, plutôt que de lui en donner une liste -
La
Capabilityfinale est un bloc sur mesure, avec une description, des instructions et un serveur MCP.defer_loading=Truepermet de la laisser en dehors du prompt tant que le modèle n'en a pas besoin
Cette présentation de PydanticAI me tenait à cœur, car c'est encore jeune et il n'y a pas encore beaucoup de ressources francophones à l'heure où j'écris ces lignes. Si vous avez l'occasion de tester PydanticAI, n'hésitez pas à nous donner vos retours sur notre serveur Discord.