Orchestrez une equipe d'agents IA avec CrewAI : roles Agent, Task et Crew, outils, process sequentiel ou hierarchique, agents locaux via Ollama et maitrise des couts.
Pourquoi une equipe d'agents
Un seul agent IA generaliste peut accomplir beaucoup, mais il atteint vite ses limites sur les taches complexes ou multi-facettes. L'approche multi-agents s'inspire d'une equipe humaine : plutot qu'un employe polyvalent, on assigne des roles specialises qui collaborent.
CrewAI est le framework Python qui rend cette orchestration simple et declarative. Vous definissez des agents avec un role, un objectif et une personnalite, vous leur confiez des taches, et la « crew » les fait collaborer. La specialisation ameliore la qualite : un agent concentre sur la relecture trouve des erreurs qu'un agent generaliste laisse passer.
Les concepts : Agent, Task, Crew
CrewAI repose sur trois briques que l'on assemble.
| Concept | Role |
|---|---|
| Agent | Un travailleur IA avec un role, un objectif (goal) et une histoire (backstory) |
| Task | Une mission precise assignee a un agent, avec une sortie attendue |
| Crew | L'equipe : un ensemble d'agents et de taches orchestres selon un process |
| Tool | Une capacite externe (recherche web, calcul, API) donnee a un agent |
| Process | La strategie d'execution : sequentielle ou hierarchique |
CrewAI vs LangGraph
| Critere | CrewAI | LangGraph |
|---|---|---|
| Modele mental | Roles et collaboration | Graphe d'etats |
| Courbe d'apprentissage | Douce, declaratif | Plus technique |
| Controle du flux | Implicite (process) | Explicite (transitions) |
| Cas ideal | Equipes de roles specialises | Workflows a branches complexes |
| Langage | Python | Python / TypeScript |
Installation et configuration
- Python 3.10+
- Cle API du LLM (ex:
OPENAI_API_KEY) - Optionnel : Ollama pour les agents en local
# Installer CrewAI et ses outils
pip install crewai crewai-tools
# Stocker la cle (jamais commitee)
echo "OPENAI_API_KEY=sk-..." >> .env
Premiere crew : recherche + redaction
Construisons une equipe de deux agents : un chercheur qui collecte l'information, et un redacteur qui produit un article a partir de ses trouvailles.
# crew_basic.py — une equipe de deux agents collaboratifs
from crewai import Agent, Task, Crew, Process
# 1. Definir les agents avec leur role, objectif et backstory
chercheur = Agent(
role="Chercheur technique",
goal="Rassembler des informations precises et a jour sur {sujet}",
backstory="Expert en veille technologique, rigoureux et factuel.",
verbose=True,
)
redacteur = Agent(
role="Redacteur technique",
goal="Rediger un article clair et structure a partir des recherches",
backstory="Pedagogue, tu transformes des notes techniques en contenu accessible.",
verbose=True,
)
# 2. Definir les taches, chacune assignee a un agent
tache_recherche = Task(
description="Recherche les points cles sur {sujet}. Liste 5 elements essentiels.",
expected_output="Une liste a puces de 5 points techniques verifies.",
agent=chercheur,
)
tache_redaction = Task(
description="Redige un article de 400 mots a partir des recherches fournies.",
expected_output="Un article structure avec introduction, corps et conclusion.",
agent=redacteur,
context=[tache_recherche], # recoit la sortie de la tache precedente
)
# 3. Assembler la crew et l'executer
crew = Crew(
agents=[chercheur, redacteur],
tasks=[tache_recherche, tache_redaction],
process=Process.sequential, # les taches s'enchainent dans l'ordre
)
resultat = crew.kickoff(inputs={"sujet": "les Signals dans Angular 19"})
print(resultat)
context est central : il transmet la sortie d'une tache a la suivante. Le redacteur recoit ainsi automatiquement les recherches du chercheur, sans glue code manuel.
Donner des outils aux agents
Un agent devient vraiment utile quand il peut agir sur le monde : chercher sur le web, lire un fichier, appeler une API. CrewAI fournit des outils prets a l'emploi et permet d'en creer.
# crew_tools.py — agent equipe d'un outil de recherche web
from crewai import Agent, Task, Crew
from crewai_tools import SerperDevTool # outil de recherche web
search_tool = SerperDevTool() # necessite une cle SERPER_API_KEY
chercheur = Agent(
role="Analyste de marche",
goal="Trouver des donnees recentes sur {sujet}",
backstory="Tu exploites la recherche web pour des informations a jour.",
tools=[search_tool], # l'agent peut desormais chercher sur le web
verbose=True,
)
tache = Task(
description="Recherche les tendances 2026 sur {sujet} et synthetise-les.",
expected_output="Une synthese de 3 tendances avec sources.",
agent=chercheur,
)
crew = Crew(agents=[chercheur], tasks=[tache])
print(crew.kickoff(inputs={"sujet": "les frameworks JavaScript"}))
Creer un outil personnalise
# Outil maison : interroger une base interne
from crewai.tools import tool
@tool("Recherche produit")
def recherche_produit(reference: str) -> str:
"""Recupere les details d'un produit par sa reference."""
# Votre logique metier : appel DB, API interne, etc.
produit = ma_base.get(reference)
return f"{produit['nom']} — {produit['prix']} EUR — stock: {produit['stock']}"
# Donner cet outil a un agent
agent_sav = Agent(
role="Conseiller produit",
goal="Renseigner les clients sur les produits",
backstory="Tu connais le catalogue sur le bout des doigts.",
tools=[recherche_produit],
)
Process sequentiel vs hierarchique
CrewAI propose deux strategies d'orchestration. Le sequentiel enchaine les taches dans l'ordre. Le hierarchique introduit un agent manager qui delegue et coordonne.
# crew_hierarchical.py — un manager coordonne l'equipe
from crewai import Agent, Task, Crew, Process
# Le manager n'execute pas, il delegue et synthetise
redacteur = Agent(role="Redacteur", goal="...", backstory="...")
relecteur = Agent(role="Relecteur qualite", goal="...", backstory="...")
seo = Agent(role="Expert SEO", goal="...", backstory="...")
tache_globale = Task(
description="Produire un article optimise SEO, relu et de qualite sur {sujet}.",
expected_output="Un article final pret a publier.",
)
crew = Crew(
agents=[redacteur, relecteur, seo],
tasks=[tache_globale],
process=Process.hierarchical, # un manager orchestre les delegations
manager_llm="gpt-4o", # le LLM qui joue le role de manager
)
print(crew.kickoff(inputs={"sujet": "le RAG en production"}))
Orchestrer des agents en local
Pour la confidentialite ou reduire les couts, CrewAI peut piloter des modeles locaux via Ollama. L'orchestration multi-agents tourne alors entierement sur votre machine.
# crew_local.py — agents propulses par un modele local Ollama
from crewai import Agent, Task, Crew, LLM
# Pointer vers un modele servi par Ollama en local
llm_local = LLM(
model="ollama/llama3.1",
base_url="http://localhost:11434",
)
agent = Agent(
role="Assistant prive",
goal="Traiter des donnees sensibles sans cloud",
backstory="Tu travailles entierement en local pour la confidentialite.",
llm=llm_local, # ce modele local pilote l'agent
)
tache = Task(
description="Resume ce document interne : {document}",
expected_output="Un resume en 3 points.",
agent=agent,
)
crew = Crew(agents=[agent], tasks=[tache])
print(crew.kickoff(inputs={"document": texte_confidentiel}))
Exposer une crew derriere une API web
Une crew met souvent plusieurs dizaines de secondes a produire son resultat (plusieurs agents, plusieurs appels LLM). On ne l'execute donc jamais dans une requete HTTP synchrone : on la lance en tache de fond et on expose un endpoint de statut que le front interroge. Cote Python, FastAPI fait le job.
# api.py — exposer la crew en tache de fond avec FastAPI
from fastapi import FastAPI, BackgroundTasks
from uuid import uuid4
app = FastAPI()
jobs = {} # en prod : Redis plutot qu'un dict en memoire
def run_crew(job_id: str, sujet: str):
jobs[job_id] = {"etat": "en_cours", "resultat": None}
resultat = crew.kickoff(inputs={"sujet": sujet}) # bloquant, hors requete
jobs[job_id] = {"etat": "termine", "resultat": str(resultat)}
@app.post("/api/crew/run")
def lancer(sujet: str, bg: BackgroundTasks):
job_id = str(uuid4())
jobs[job_id] = {"etat": "en_file", "resultat": None}
bg.add_task(run_crew, job_id, sujet) # demarre sans bloquer
return {"jobId": job_id} # reponse immediate
@app.get("/api/crew/status/{job_id}")
def statut(job_id: str):
return jobs.get(job_id, {"etat": "introuvable"})
Cote front, on consomme cette API comme n'importe quel traitement asynchrone. Dans une application Angular, un service encapsule le lancement puis le polling du statut jusqu'a completion.
// crew.service.ts — piloter la crew depuis une app Angular
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { interval, switchMap, takeWhile, lastValueFrom } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class CrewService {
private http = inject(HttpClient);
async generer(sujet: string): Promise<string> {
// 1. Lancer la crew : on recupere un jobId immediatement
const { jobId } = await lastValueFrom(
this.http.post<{ jobId: string }>('/api/crew/run', { sujet }),
);
// 2. Interroger le statut toutes les 2s jusqu'a "termine"
const flux = interval(2000).pipe(
switchMap(() => this.http.get<{ etat: string; resultat: string }>(`/api/crew/status/${jobId}`)),
takeWhile((s) => s.etat !== 'termine', true), // inclut la derniere emission
);
let dernier = { etat: '', resultat: '' };
await lastValueFrom(flux.pipe(switchMap(async (s) => (dernier = s))));
return dernier.resultat;
}
}
Observabilite : suivre et deboguer
Une crew est une boite a moitie noire : plusieurs agents echangent, et quand le resultat decoit, il faut comprendre quel agent a derape. CrewAI expose des callbacks declenches a chaque etape — branchez-y votre logging pour tracer la collaboration.
# observability.py — tracer chaque etape des agents
import logging
logging.basicConfig(level=logging.INFO)
def log_etape(etape):
# Appele a chaque action d'agent (pensee, appel d'outil, sortie)
logging.info("Agent: %s | Action: %s", getattr(etape, "agent", "?"), etape)
crew = Crew(
agents=[chercheur, redacteur],
tasks=[tache_recherche, tache_redaction],
step_callback=log_etape, # trace fine de chaque etape
verbose=True,
)
# Lancement non bloquant + remontee de progression vers l'API
async def run_crew_async(job_id: str, sujet: str):
def on_task_end(output):
# Mettre a jour la progression apres chaque tache terminee
jobs[job_id]["progress"] = jobs[job_id].get("progress", 0) + 1
crew.task_callback = on_task_end
resultat = await crew.kickoff_async(inputs={"sujet": sujet})
jobs[job_id] = {"etat": "termine", "resultat": str(resultat)}
Cas d'usage concrets cote produit
Le multi-agents brille quand une tache se decompose en roles complementaires. Voici des configurations de crew eprouvees pour des fonctionnalites d'application web.
| Fonctionnalite | Composition de la crew | Process |
|---|---|---|
| Generation d'article de blog | Chercheur + Redacteur + Relecteur SEO | Sequentiel |
| Reponse SAV complexe | Analyste demande + Expert produit + Redacteur reponse | Hierarchique |
| Analyse de CV / matching | Extracteur + Evaluateur + Synthese | Sequentiel |
| Revue de code automatisee | Securite + Performance + Style | Hierarchique |
| Resume de reunion | Transcripteur + Synthese + Extracteur d'actions | Sequentiel |
Bonnes pratiques et couts
Le multi-agents multiplie les appels LLM : chaque agent, chaque etape de raisonnement et chaque appel d'outil consomme des tokens. La latence et le cout grimpent vite.
- Limiter le nombre d'agents au strict necessaire
- Utiliser un modele rapide (Groq, gpt-4o-mini) pour les agents simples
- Reserver les gros modeles aux roles critiques (manager, relecteur)
- Activer le prompt caching sur les backstories stables
- Plafonner les iterations pour eviter les boucles d'agents
- Logger chaque etape pour deboguer la collaboration
- Definir des
expected_outputprecis pour cadrer chaque agent
Erreurs frequentes
L'erreur de conception la plus repandue : des roles et objectifs flous. Un agent dont le goal et la backstory sont vagues produit des resultats generiques et empiete sur le travail des autres. Chaque agent doit avoir une mission unique et un expected_output precis ; c'est cette specialisation qui justifie le surcout du multi-agents face a un agent unique.
Deuxieme piege, fatal en production : executer la crew dans le cycle requete-reponse HTTP. Une crew prend des dizaines de secondes ; la lancer dans un handler synchrone provoque des timeouts et bloque vos workers web. Le pattern tache de fond + endpoint de statut presente plus haut n'est pas optionnel des que la crew est exposee a des utilisateurs.
Enfin, deux derives de cout classiques : empiler les agents par enthousiasme (trois agents nets battent huit agents flous) et oublier de plafonner les iterations, ce qui laisse un agent confus boucler en accumulant les appels LLM. Definissez un max_iter, branchez le step_callback pour tracer la collaboration, et utilisez un modele rapide et bon marche pour les roles secondaires en reservant les gros modeles au manager et au relecteur.
Conclusion
CrewAI rend l'orchestration multi-agents accessible et lisible : on raisonne en roles, objectifs et collaboration, comme avec une equipe humaine. Les briques Agent, Task et Crew suffisent a construire des pipelines de recherche, redaction et relecture qui surpassent un agent unique grace a la specialisation.
Donnez des outils a vos agents pour qu'ils agissent, choisissez le process (sequentiel ou hierarchique) selon la complexite, et n'oubliez pas que chaque agent coute en tokens et en latence. Avec des roles bien definis, un modele adapte par agent et le prompt caching, vous obtenez une equipe d'agents efficace — du cloud jusqu'au 100% local via Ollama. C'est la prochaine etape naturelle apres l'agent unique.
- Agent + Task + Crew = orchestration multi-agents declarative
contexttransmet la sortie d'une tache a la suivante- Outils integres ou maison pour faire agir les agents
- Process sequentiel pour les pipelines, hierarchique pour la delegation
- Fonctionne en local via Ollama pour la confidentialite
- Maitriser couts et latence : peu d'agents, roles precis, caching