Presque tous les frameworks d'agents IA dont vous avez entendu parler fonctionnent de la même manière : le modèle émet un bloc JSON décrivant l'outil à appeler et ses arguments, un runtime l'analyse, exécute la fonction et renvoie le résultat. LangGraph, CrewAI, l'OpenAI Agents SDK, Pydantic AI — tous parlent le langage des appels d'outils en JSON.
La bibliothèque smolagents de Hugging Face fait un pari différent. Au lieu de demander au modèle de remplir un formulaire JSON, elle lui demande d'écrire un extrait de code Python, puis exécute ce code dans une sandbox. Ce motif s'appelle CodeAct, et une fois que vous le voyez à l'œuvre, l'approche JSON commence à ressembler à un contournement.
Ce guide explique pourquoi les agents qui écrivent du code comptent, comment smolagents les implémente, et comment faire tourner l'ensemble sur votre propre infrastructure — une vraie préoccupation pour les équipes des marchés réglementés de la région MENA.
Pourquoi les agents qui écrivent du code battent les appels JSON
Prenons une tâche : « Trouve les trois modèles les plus téléchargés pour la classification de texte, puis calcule la moyenne de leurs téléchargements. »
Un agent à appels d'outils JSON doit le faire en plusieurs allers-retours. Appeler l'outil de recherche. Recevoir les résultats. Rappeler l'outil de recherche. Recevoir les résultats. Puis additionner et diviser d'une manière ou d'une autre — sauf que les appels JSON ne savent pas faire d'arithmétique, il faut donc encore un autre outil ou un autre tour de modèle.
Un agent de code, lui, écrit un seul bloc :
models = search_models("text-classification", limit=3)
counts = [m.downloads for m in models]
average = sum(counts) / len(counts)
final_answer(average)C'est tout l'intérêt. Le code est une couche de composition universelle. Les boucles, les conditions, les variables, l'imbrication de fonctions et l'arithmétique sont gratuites — elles font déjà partie du langage. Un modèle qui exprime ses actions sous forme de code peut combiner des outils comme le ferait un programmeur, au lieu d'être contraint à un appel JSON rigide par étape.
Hugging Face indique que cela conduit à nettement moins d'étapes et moins d'appels au modèle pour les tâches multi-étapes, car le modèle regroupe les opérations liées en une seule action exécutable. Moins d'allers-retours signifie moins de latence et un coût en jetons réduit.
Installer smolagents
La bibliothèque centrale est réputée minuscule — environ mille lignes de Python que vous pouvez lire en un après-midi. Cela la rend auditable et modifiable, ce qui compte quand un agent exécute du code en votre nom.
pip install smolagents
# Pour la boîte à outils par défaut (recherche web, etc.)
pip install 'smolagents[toolkit]'Votre premier CodeAgent
Un CodeAgent a besoin de deux choses : un modèle et une liste d'outils. Voici un agent minimal alimenté par un modèle de l'API d'inférence de Hugging Face.
from smolagents import CodeAgent, InferenceClientModel
model = InferenceClientModel(model_id="meta-llama/Llama-3.3-70B-Instruct")
agent = CodeAgent(tools=[], model=model, add_base_tools=True)
agent.run("Could you give me the 118th number in the Fibonacci sequence?")add_base_tools=True charge un petit ensemble d'outils intégrés. L'agent raisonne, écrit du Python, le runtime l'exécute, et la boucle continue jusqu'à ce que le modèle appelle final_answer().
smolagents fournit deux classes d'agents, héritant toutes deux de MultiStepAgent :
CodeAgent— par défaut ; écrit ses actions sous forme de code Python.ToolCallingAgent— écrit ses actions en JSON, pour les cas où vous voulez précisément le motif classique ou lorsque votre modèle est faible en code.
Définir vos propres outils
Un outil n'est qu'une fonction que l'agent est autorisé à appeler depuis son code. La façon la plus simple d'en créer un est le décorateur @tool. Donnez-lui un nom clair, des annotations de type et une docstring avec une section Args: — le modèle lit tout cela pour décider quand et comment utiliser l'outil.
from smolagents import tool
@tool
def get_exchange_rate(base: str, quote: str) -> float:
"""
Returns the current exchange rate between two currencies.
Args:
base: The base currency code, e.g. "USD".
quote: The quote currency code, e.g. "TND".
"""
rates = fetch_rates(base)
return rates[quote]Quand vous avez besoin de plus de contrôle — attributs lourds chargés une seule fois, clients externes maintenus ouverts — dérivez plutôt la classe Tool :
from smolagents import Tool
class ExchangeRateTool(Tool):
name = "get_exchange_rate"
description = "Returns the current exchange rate between two currencies."
inputs = {
"base": {"type": "string", "description": "Base currency code, e.g. USD."},
"quote": {"type": "string", "description": "Quote currency code, e.g. TND."},
}
output_type = "number"
def forward(self, base: str, quote: str) -> float:
return fetch_rates(base)[quote]L'outil intégré WebSearchTool est un bon exemple d'outil prêt à l'emploi que vous pouvez glisser directement dans la liste des outils.
from smolagents import CodeAgent, WebSearchTool
agent = CodeAgent(tools=[WebSearchTool()], model=model)
agent.run("What changed in the latest Python release?")La sandbox : la règle à ne pas sauter
Voici la vérité inconfortable sur les agents de code : un modèle qui écrit et exécute du Python sur votre machine est un risque de sécurité si ce code tourne sans sandbox. Un agent capable de import os et de toucher au système de fichiers n'est qu'à une mauvaise génération de causer des dégâts.
smolagents gère cela via l'argument executor_type. Elle prend en charge Docker, E2B, Modal et Blaxel d'emblée, et l'agent fonctionne comme gestionnaire de contexte, de sorte que la sandbox est nettoyée automatiquement.
from smolagents import CodeAgent, InferenceClientModel
with CodeAgent(model=InferenceClientModel(), tools=[], executor_type="docker") as agent:
agent.run("Can you give me the 100th Fibonacci number?")Remplacez "docker" par "e2b", "modal" ou "blaxel" selon que vous voulez une isolation locale ou une sandbox cloud gérée. Pour l'exécution locale, vous contrôlez aussi les imports autorisés via additional_authorized_imports, afin que l'agent n'atteigne que les bibliothèques auxquelles vous faites explicitement confiance :
agent = CodeAgent(
tools=[WebSearchTool()],
model=model,
additional_authorized_imports=["pandas", "numpy"],
max_steps=10,
)Traitez la sandbox comme obligatoire, pas optionnelle. L'exécuteur Docker est le chemin le plus simple pour faire tourner des agents de code sur vos propres serveurs sans exposer l'hôte.
Faites-le tourner sur votre propre infrastructure
C'est là que smolagents devient intéressante pour les équipes MENA soumises aux règles de résidence des données de l'INPDP et de la PDPL. Le framework est agnostique au modèle : rien ne vous oblige à envoyer vos prompts vers un cloud américain.
Via LiteLLMModel, vous pouvez pointer l'agent vers un serveur Ollama local :
from smolagents import CodeAgent, LiteLLMModel
model = LiteLLMModel(
model_id="ollama_chat/llama3.2",
api_base="http://localhost:11434",
num_ctx=8192,
)
agent = CodeAgent(tools=[], model=model, add_base_tools=True)
agent.run("Could you give me the 118th number in the Fibonacci sequence?")Ou ciblez n'importe quel point de terminaison compatible OpenAI — un serveur vLLM auto-hébergé, par exemple — avec OpenAIModel :
from smolagents import OpenAIModel
model = OpenAIModel(
model_id="Qwen/Qwen2.5-Coder-32B-Instruct",
api_base="http://your-vllm-host:8000/v1",
api_key="not-needed-for-local",
)Un agent de code exécutant des poids ouverts sur une machine vLLM, à l'intérieur d'une sandbox Docker sur le même réseau, n'envoie jamais les données client hors site. C'est une histoire d'auto-hébergement propre pour les déploiements soucieux de souveraineté.
Équipes multi-agents
Pour des charges plus importantes, vous pouvez construire une hiérarchie : un agent manager qui délègue à des agents ouvriers spécialisés. Tout agent que vous voulez faire gérer doit avoir un name et une description pour que le manager sache ce qu'il fait et quand l'appeler.
from smolagents import CodeAgent, ToolCallingAgent, WebSearchTool, InferenceClientModel
model = InferenceClientModel()
web_agent = ToolCallingAgent(
tools=[WebSearchTool()],
model=model,
name="web_search_agent",
description="Searches the web and returns relevant findings for a query.",
)
manager = CodeAgent(
tools=[],
model=model,
managed_agents=[web_agent],
)
manager.run("Research recent open-source agent frameworks and summarise the trade-offs.")Le manager appelle l'agent web exactement comme s'il s'agissait d'une fonction, en passant une description de tâche. Cela garde le contexte de recherche web hors du raisonnement propre du manager et permet à chaque agent de se spécialiser.
Quand choisir smolagents
smolagents est le bon outil lorsque vos tâches sont réellement computationnelles — manipulation de données, recherche multi-étapes, tout ce où le modèle gagne à composer des opérations plutôt qu'à lancer des appels d'outils isolés. Sa base de code minuscule et sa conception agnostique au modèle la rendent idéale pour les déploiements auto-hébergés, sensibles au coût ou contraints par la conformité.
Elle convient moins aux workflows rigides et audités où vous voulez contraindre chaque action à un schéma fixe — là, un framework à appels JSON ou un ToolCallingAgent vous donne un contrôle plus serré.
Le glissement plus large mérite d'être intégré : les agents les plus performants commencent à traiter le code lui-même comme l'espace d'action. Les appels JSON étaient un pont. Laisser les modèles écrire et exécuter du vrai code, sandboxé en sécurité, est la direction que prend une grande partie de l'écosystème des agents — et smolagents est l'endroit le plus propre pour commencer à apprendre ce motif aujourd'hui.
Si vous comparez ceci aux stacks JSON-first, notre comparatif LangGraph, CrewAI et OpenAI Agents SDK est un compagnon utile, tout comme notre guide d'auto-hébergement de LLM avec Ollama.