Les boucles à agent unique sont géniales — jusqu'au jour où votre problème implique réellement plusieurs spécialistes. La recherche, la rédaction, la revue de code, l'analyse financière : ce sont des sports d'équipe, pas des numéros en solo. CrewAI prend cette intuition et la transforme en abstraction programmable : vous définissez un équipage d'agents basés sur des rôles, vous donnez à chacun un objectif et une histoire, vous les équipez d'outils, et vous les laissez collaborer séquentiellement ou hiérarchiquement vers un objectif partagé.
Contrairement aux frameworks à base de graphes comme LangGraph ou aux exécuteurs à agent unique comme OpenAI Agents SDK, CrewAI traite l'orchestration comme un organigramme d'entreprise. Dans ce tutoriel vous allez installer CrewAI à partir de zéro, construire une équipe d'étude de marché de quatre agents, y brancher des outils de navigation et d'écriture de fichiers, basculer entre processus séquentiel et hiérarchique, ajouter une mémoire longue durée, et instrumenter le tout pour la production.
Prérequis
Avant de commencer, assurez-vous d'avoir :
- Python 3.10 ou plus récent installé
- Une clé API OpenAI ou Anthropic (ou une installation locale d'Ollama)
- Une clé Serper.dev gratuite pour la recherche web (optionnelle mais recommandée)
- Une familiarité de base avec les classes Python, les décorateurs et
async/await - Un éditeur de code (VS Code avec l'extension Python recommandé)
Ce que vous allez construire
À la fin de ce tutoriel, vous aurez :
- Un projet CrewAI échafaudé avec
uvet la CLI officielle - Une équipe de quatre agents — Chercheur, Analyste, Rédacteur, Éditeur — qui produit une note de marché soignée
- Des outils de recherche web et d'écriture de fichiers branchés aux bons agents
- Un pipeline séquentiel et une variante hiérarchique pilotée par un manager
- Une mémoire court terme et long terme activée avec des embeddings
- Des callbacks personnalisés qui diffusent les pensées des agents et les appels d'outils en temps réel
- Un endpoint FastAPI qui déclenche l'équipe à la demande
- De l'observabilité via la télémétrie CrewAI Plus et des logs structurés
Étape 1 : Installer CrewAI
CrewAI est livré comme un seul paquet avec des extras optionnels pour les outils, les embeddings et les helpers de déploiement. Commencez par un environnement isolé — uv est l'option la plus rapide en 2026.
mkdir market-crew && cd market-crew
uv venv --python 3.11
source .venv/bin/activate
uv pip install "crewai[tools]" python-dotenv fastapi uvicornOu avec pip classique :
python -m venv .venv
source .venv/bin/activate
pip install "crewai[tools]" python-dotenv fastapi uvicornVérifiez l'installation :
crewai version
# CrewAI version: 0.86.xÉtape 2 : Échafauder le projet
CrewAI fournit une CLI qui génère la structure de dossiers attendue par le framework. Lancez le générateur depuis le dossier parent.
cd .. && crewai create crew market-crewQuand on vous le demande, choisissez openai comme fournisseur et gpt-4o-mini comme modèle. La CLI dépose cette structure :
market-crew/
├── src/
│ └── market_crew/
│ ├── config/
│ │ ├── agents.yaml
│ │ └── tasks.yaml
│ ├── crew.py
│ ├── main.py
│ └── tools/
├── .env
├── pyproject.toml
└── README.md
Les deux fichiers YAML sont l'endroit où la majeure partie de votre travail va vivre. agents.yaml définit les rôles et les objectifs ; tasks.yaml définit ce que chaque agent doit produire.
Ajoutez vos secrets à .env :
OPENAI_API_KEY=sk-...
SERPER_API_KEY=... # depuis serper.dev, optionnel
MODEL=gpt-4o-miniÉtape 3 : Définir les agents
Ouvrez src/market_crew/config/agents.yaml et remplacez le contenu placeholder par quatre rôles spécialisés.
researcher:
role: >
Chercheur de marché senior spécialisé dans {industry}
goal: >
Rassembler les faits, statistiques et citations les plus récents
et crédibles à propos de {topic}, issus de sources web publiques
publiées au cours des douze derniers mois.
backstory: >
Vous avez passé une décennie chez McKinsey à diriger des recherches
primaires et secondaires. Vous triangulez chaque affirmation entre
au moins deux sources indépendantes et vous étiquetez chaque
information avec sa date de publication et son URL.
verbose: true
allow_delegation: false
analyst:
role: >
Analyste stratégique pour {industry}
goal: >
Transformer les notes brutes du chercheur en SWOT, en matrice
concurrentielle et en trois recommandations actionnables pour
{target_audience}.
backstory: >
Vous écrivez ce genre de mémos de deux pages que les CEO lisent
réellement. Vous refusez d'inclure toute affirmation qui n'est pas
appuyée par une source citée des notes du chercheur.
verbose: true
writer:
role: >
Rédacteur éditorial senior
goal: >
Produire une note exécutive de 1200 mots sur {topic} qu'un
investisseur pourrait lire en moins de six minutes et transférer
à ses partenaires.
backstory: >
Vous avez écrit la newsletter hebdomadaire Stratechery. Vous
privilégiez les phrases courtes, les exemples concrets et
exactement une thèse forte par publication.
verbose: true
editor:
role: >
Rédacteur en chef
goal: >
Vérifier la note contre la liste de sources du chercheur, corriger
la prose faible et s'assurer que chaque affirmation cite sa source.
backstory: >
Vous avez dirigé le bureau des standards à The Economist pendant
huit ans. Vous ne laissez passer aucun chiffre non sourcé.
verbose: trueCrewAI interpole les placeholders {industry}, {topic} et {target_audience} au moment de l'exécution à partir des entrées que vous passez à l'équipe.
Étape 4 : Définir les tâches
Éditez src/market_crew/config/tasks.yaml :
research_task:
description: >
Collectez au moins 12 trouvailles de haute qualité sur {topic} dans
le secteur {industry}. Pour chaque trouvaille, capturez :
l'affirmation, l'URL de la source, la date de publication et un
résumé en une phrase.
expected_output: >
Une liste markdown d'au moins 12 puces. Chaque puce doit inclure
l'URL de la source et la date. Aucune paraphrase sans citation.
agent: researcher
analysis_task:
description: >
À partir des trouvailles du chercheur, produisez une analyse SWOT
pour {target_audience} entrant sur le marché de {topic}, une
matrice concurrentielle de 5 lignes, et exactement trois
recommandations classées par impact.
expected_output: >
Un document markdown en trois sections : SWOT, Matrice
concurrentielle, Recommandations. Toute affirmation chiffrée doit
citer une trouvaille par URL.
agent: analyst
context:
- research_task
writing_task:
description: >
Rédigez une note exécutive de 1200 mots sur {topic} destinée à
{target_audience}. Ouvrez avec une thèse en une seule phrase.
Utilisez le SWOT et les recommandations de l'analyste. Terminez
par une section "À surveiller" listant trois indicateurs avancés.
expected_output: >
Une note markdown soignée, entre 1100 et 1300 mots, avec des
titres H2 et des citations en ligne sous forme de liens markdown.
agent: writer
context:
- research_task
- analysis_task
editing_task:
description: >
Éditez la note pour la clarté et la précision. Toute affirmation
chiffrée doit citer une source de la liste du chercheur. Signalez
toute affirmation non soutenue en la remplaçant par un commentaire
TODO.
expected_output: >
La note finale markdown, enregistrée dans `output/brief.md`.
agent: editor
context:
- research_task
- analysis_task
- writing_task
output_file: output/brief.mdLe champ context est l'endroit où vit le modèle de collaboration de CrewAI. Chaque tâche reçoit les sorties de ses dépendances comme entrée — aucun assemblage manuel de prompts requis.
Étape 5 : Câbler l'équipe
Ouvrez src/market_crew/crew.py. La CLI a généré un squelette ; remplacez-le par la version ci-dessous.
from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from crewai_tools import SerperDevTool, FileWriterTool
@CrewBase
class MarketCrew:
"""Équipe de recherche de marché avec quatre spécialistes."""
agents_config = "config/agents.yaml"
tasks_config = "config/tasks.yaml"
@agent
def researcher(self) -> Agent:
return Agent(
config=self.agents_config["researcher"],
tools=[SerperDevTool()],
)
@agent
def analyst(self) -> Agent:
return Agent(config=self.agents_config["analyst"])
@agent
def writer(self) -> Agent:
return Agent(config=self.agents_config["writer"])
@agent
def editor(self) -> Agent:
return Agent(
config=self.agents_config["editor"],
tools=[FileWriterTool()],
)
@task
def research_task(self) -> Task:
return Task(config=self.tasks_config["research_task"])
@task
def analysis_task(self) -> Task:
return Task(config=self.tasks_config["analysis_task"])
@task
def writing_task(self) -> Task:
return Task(config=self.tasks_config["writing_task"])
@task
def editing_task(self) -> Task:
return Task(config=self.tasks_config["editing_task"])
@crew
def crew(self) -> Crew:
return Crew(
agents=self.agents,
tasks=self.tasks,
process=Process.sequential,
verbose=True,
)Quelques détails à noter :
- Le décorateur
@CrewBasecâble les fichiers YAML aux objets Python au moment de la construction. - Les décorateurs
@agentet@taskdécorent des méthodes fabriques ; l'ordre des décorateurs@taskdétermine l'ordre d'exécution en mode séquentiel. - Seul le chercheur reçoit la recherche web et seul l'éditeur reçoit l'écriture de fichier. Garder les surfaces d'outils étroites est le plus grand gain de fiabilité dans les systèmes multi-agents.
Étape 6 : Exécuter l'équipe
Éditez src/market_crew/main.py pour passer les entrées paramétrées.
from market_crew.crew import MarketCrew
def run():
inputs = {
"topic": "Agents IA de codage pour plateformes de développeurs en entreprise",
"industry": "outils pour développeurs",
"target_audience": "Responsables d'ingénierie en Series B",
}
MarketCrew().crew().kickoff(inputs=inputs)
if __name__ == "__main__":
run()Lancez-le :
crewai runVous verrez chaque agent annoncer son rôle, chercher sur le web, rédiger et passer le relais au suivant. La note finale arrive dans output/brief.md. Sur gpt-4o-mini l'exécution complète coûte environ dix centimes et prend environ quatre minutes.
Étape 7 : Passer à un processus hiérarchique
Le séquentiel convient à un pipeline fixe. Quand vous voulez qu'un manager décide qui travaille sur quoi, passez à Process.hierarchical. Remplacez la méthode crew :
from crewai import Agent
@crew
def crew(self) -> Crew:
manager = Agent(
role="Directeur éditorial",
goal="Décider de l'ordre des tâches et déléguer au bon spécialiste",
backstory="Ancien chef de bureau Bloomberg qui dirige des rédactions serrées.",
allow_delegation=True,
verbose=True,
)
return Crew(
agents=self.agents,
tasks=self.tasks,
process=Process.hierarchical,
manager_agent=manager,
verbose=True,
)En mode hiérarchique, le manager lit la description de chaque tâche, choisit un agent, évalue la sortie et peut reboucler. Cela coûte plus de tokens mais gère les workflows ambigus bien mieux qu'un pipeline fixe.
Étape 8 : Ajouter de la mémoire
Par défaut, chaque exécution d'équipe démarre à neuf. Pour accumuler de la connaissance entre les exécutions, activez la mémoire.
from crewai import Crew, Process
@crew
def crew(self) -> Crew:
return Crew(
agents=self.agents,
tasks=self.tasks,
process=Process.sequential,
memory=True,
embedder={
"provider": "openai",
"config": {"model": "text-embedding-3-small"},
},
verbose=True,
)CrewAI maintient désormais trois magasins de mémoire :
- Court terme : bloc-notes partagé pour l'exécution en cours
- Long terme : magasin vectoriel persistant entre les exécutions (SQLite + Chroma sur disque par défaut)
- Entité : entités extraites et leurs relations
Réinitialisez la mémoire avec crewai reset-memories. Pour des déploiements à l'échelle d'une équipe, remplacez l'embedder par bedrock ou vertex et pointez le magasin long terme vers une instance Postgres+pgvector managée.
Étape 9 : Diffuser les pensées des agents avec des callbacks
Pour l'intégration UI ou le débogage vous voulez généralement chaque étape en temps réel. CrewAI expose des callbacks par tâche et par étape.
from crewai.tasks.task_output import TaskOutput
def on_task_complete(output: TaskOutput) -> None:
print(f"[task:{output.task.description[:60]}] -> {len(output.raw)} chars")
def on_step(step: dict) -> None:
if step.get("tool"):
print(f" tool call: {step['tool']} args={step['tool_input']}")
@task
def research_task(self) -> Task:
return Task(
config=self.tasks_config["research_task"],
callback=on_task_complete,
)Pour le streaming au niveau de l'étape, passez step_callback=on_step lors de la construction de chaque Agent. Branchez ces callbacks à des Server-Sent Events et vous obtenez un flux d'agent en direct dans votre application.
Étape 10 : Exposer l'équipe comme une API
CrewAI se marie très bien avec FastAPI. Créez src/market_crew/api.py :
from fastapi import FastAPI
from pydantic import BaseModel
from market_crew.crew import MarketCrew
app = FastAPI()
class BriefRequest(BaseModel):
topic: str
industry: str
target_audience: str
@app.post("/brief")
def generate_brief(req: BriefRequest):
result = MarketCrew().crew().kickoff(inputs=req.model_dump())
return {"output": result.raw, "token_usage": result.token_usage}Lancez-le :
uv run uvicorn market_crew.api:app --reload --port 8000Testez avec curl :
curl -X POST http://localhost:8000/brief \
-H "content-type: application/json" \
-d '{"topic":"AI coding agents","industry":"developer tools","target_audience":"CTOs"}'En production, lancez l'API derrière Gunicorn avec une classe de worker Uvicorn, fixez un timeout de requête d'environ cinq minutes pour les exécutions de l'équipe, et déchargez les kickoffs vers une file Celery ou Hatchet si vous attendez du trafic concurrent.
Étape 11 : Ajouter l'observabilité
CrewAI livre une télémétrie de première classe via CrewAI Plus, mais vous pouvez aussi utiliser OpenTelemetry directement. La voie gratuite reste les logs structurés.
import logging, json, time
class CrewLogFormatter(logging.Formatter):
def format(self, record):
payload = {
"ts": int(time.time() * 1000),
"level": record.levelname,
"msg": record.getMessage(),
}
return json.dumps(payload)
handler = logging.StreamHandler()
handler.setFormatter(CrewLogFormatter())
logging.getLogger("crewai").addHandler(handler)
logging.getLogger("crewai").setLevel(logging.INFO)Envoyez stdout vers Loki, Datadog ou un ClickHouse auto-hébergé et vous pouvez répondre à "quel agent a brûlé le plus de tokens la semaine dernière" sans monter un second projet. Pour les traces au niveau des spans, installez crewai[telemetry] et pointez OTEL_EXPORTER_OTLP_ENDPOINT vers votre collecteur.
Étape 12 : Tester l'équipe de manière déterministe
Les exécutions multi-agents sont non déterministes par défaut. Pour la CI, remplacez le LLM par un faux.
from crewai.llm import LLM
from market_crew.crew import MarketCrew
class FakeLLM(LLM):
def __init__(self):
super().__init__(model="fake")
self.replies = iter([
"- finding 1 (https://example.com 2026-01-01)",
"## SWOT\n- strength: x",
"Brief draft...",
"Edited brief.",
])
def call(self, messages, **kwargs):
return next(self.replies)
def test_crew_smoke(monkeypatch):
monkeypatch.setattr("crewai.agent.LLM", FakeLLM)
out = MarketCrew().crew().kickoff(inputs={
"topic": "x", "industry": "y", "target_audience": "z",
})
assert "Edited brief." in out.rawLancez avec uv run pytest. La suite entière se termine en moins d'une seconde et vous donne une couverture de régression sur le câblage des prompts et des outils sans consommer de crédits API.
Tester votre implémentation
Vérifiez le comportement de bout en bout :
crewai runproduitoutput/brief.mdavec au moins 1100 mots- La note contient au moins huit citations en ligne
- Une deuxième exécution de
crewai runtire la mémoire long terme dans le prompt du chercheur (vérifiez le log verbose) - L'endpoint FastAPI retourne un payload JSON avec
outputettoken_usage - Le test pytest avec LLM factice passe en moins d'une seconde
Dépannage
"AuthenticationError: Missing OPENAI_API_KEY" — assurez-vous que votre shell a chargé .env. uv run le fait automatiquement, python simple non. Ajoutez from dotenv import load_dotenv; load_dotenv() en haut de main.py.
Les agents hallucinent des sources — resserrez le prompt du chercheur. Ajoutez une règle explicite : "Si vous ne trouvez pas de source, écrivez NO_SOURCE plutôt que d'en inventer une." Puis faites en sorte que la tâche d'éditeur fasse échouer l'exécution si un token NO_SOURCE apparaît.
Les exécutions hiérarchiques tournent à l'infini — fixez max_iter=15 sur l'agent manager. Le défaut est 25, trop généreux pour la plupart des workflows.
La mémoire déborde entre sujets — crewai reset-memories --all entre des exécutions sans rapport, ou isolez la mémoire long terme en réglant CREWAI_STORAGE_DIR par projet.
Les appels d'outils retournent du HTML brut — enveloppez SerperDevTool avec un convertisseur markdown ou utilisez ScrapeWebsiteTool de crewai_tools pour nettoyer la sortie avant que l'agent ne la voie.
Prochaines étapes
- Ajoutez une couche de sortie typée Pydantic AI devant l'équipe pour des schémas de note typés
- Branchez un superviseur LangGraph par-dessus pour des workflows ramifiés
- Programmez l'équipe sur un cron Hatchet et publiez la note sur Slack chaque lundi matin
- Remplacez le rédacteur par un sous-processus Claude Agent SDK pour des budgets de raisonnement plus longs
Conclusion
La force de CrewAI est qu'elle vous oblige à penser votre workflow IA de la même manière que vous penseriez à composer une équipe humaine. Chaque agent a un poste, un livrable et une boîte à outils étroite. Une fois que les YAML sont corrects, le code Python reste sous les cent lignes, et le chemin de mise à niveau d'un simple pipeline séquentiel vers une équipe hiérarchique, dotée de mémoire et instrumentée pour l'observabilité est essentiellement de la configuration.
Si votre problème comporte réellement plusieurs spécialistes, arrêtez d'essayer de faire tout faire à un seul agent. Embauchez une équipe.