Introduzione: CrewAI e il Paradigma dei Team di Agenti
CrewAI è un framework open-source Python progettato per orchestrare team di agenti AI attraverso un paradigma ispirato al mondo aziendale: ogni agente interpreta un ruolo specifico, ha un obiettivo chiaro e collabora con gli altri membri del team per completare task complessi. A differenza di LangGraph, che modella i flussi come grafi, e di AutoGen, che si basa sulla conversazione libera tra agenti, CrewAI adotta una metafora intuitiva: costruire un team di lavoro dove ogni membro ha competenze distinte, strumenti dedicati e responsabilità ben definite.
Nato nel 2024 è giunto alla versione 0.80+ nel 2026, CrewAI ha guadagnato rapidamente popolarita grazie alla sua semplicità d'uso e alla curva di apprendimento estremamente bassa. Dove altri framework richiedono la comprensione di concetti avanzati come grafi di stato, messaggistica asincrona o protocolli di comunicazione, CrewAI permette di definire un sistema multi-agente funzionante in poche decine di righe di codice. Questo non significa che sia un framework limitato: la sua architettura supporta processi sequenziali, gerarchici e consensuali, memoria a lungo termine, integrazione con decine di strumenti e deployment in produzione.
Il punto di forza di CrewAI risiede nella chiarezza del modello mentale. Quando progettiamo un team di agenti con CrewAI, pensiamo esattamente come un manager che deve assemblare un team di lavoro: chi sono le persone giuste, quali competenze servono, chi fa cosa, in che ordine e con quali strumenti. Questa analogia naturale riduce drasticamente il tempo necessario per passare dall'idea all'implementazione.
Cosa Imparerai in Questo Articolo
- L'architettura di CrewAI: Agent, Task, Crew, Tool e come si connettono
- Come definire agenti con ruoli, obiettivi e backstory efficaci
- La gestione dei Task: expected_output, contesto e delegation
- I tipi di processo: Sequential, Hierarchical e quando usare ciascuno
- Come creare Custom Tools con il decoratore
@toole classi BaseTool - Il sistema di Memory e Context Sharing tra agenti
- Un case study completo: una crew per content creation con 3 agenti
- Confronto pratico tra CrewAI, LangGraph e AutoGen
- Best practices e limitazioni per l'uso in produzione
Architettura di CrewAI
L'architettura di CrewAI si fonda su quattro concetti fondamentali che lavorano in sinergia: Agent, Task, Crew e Tool. Comprendere come questi componenti si connettono è la chiave per progettare sistemi multi-agente efficaci.
I Quattro Pilastri
- Agent: un'entità autonoma con un ruolo, un obiettivo e una storia di background. Ogni agente ha accesso a un modello LLM e, opzionalmente, a un set di strumenti. L'agente è il "chi": chi esegue il lavoro.
- Task: un'unita di lavoro con una descrizione chiara, un output atteso e un agente assegnato. Il task è il "cosa": cosa deve essere fatto.
- Crew: il contenitore che riunisce agenti e task, definisce il processo di esecuzione e gestisce il coordinamento. La crew è il "come": come il lavoro viene organizzato.
- Tool: una funzione che gli agenti possono invocare per interagire con il mondo esterno (cercare sul web, leggere file, interrogare API). Il tool è il "con cosa": con quali strumenti si lavora.
Schema Architetturale
Architettura CrewAI:
+-------------------------------------------------+
| CREW |
| (processo: sequential / hierarchical) |
| |
| +-------------+ +-------------+ +-----------+ |
| | AGENT 1 | | AGENT 2 | | AGENT 3 | |
| | role: ... | | role: ... | | role: ... | |
| | goal: ... | | goal: ... | | goal: ... | |
| | tools: [A,B]| | tools: [C] | | tools: [] | |
| +------+------+ +------+------+ +-----+-----+ |
| | | | |
| +------v------+ +------v------+ +-----v-----+ |
| | TASK 1 | | TASK 2 | | TASK 3 | |
| | description | | description | | descript. | |
| | expected_ | | context: | | context: | |
| | output | | [task1] | | [task1,2] | |
| +-------------+ +-------------+ +-----------+ |
+-------------------------------------------------+
Il flusso è chiaro: la Crew coordina l'esecuzione dei Task, assegnandoli agli Agent in base al processo configurato. Ogni Task può ricevere come contesto l'output dei task precedenti, creando una catena di dipendenze dove ogni agente costruisce sul lavoro degli altri. Questo meccanismo di contesto è il cuore della collaborazione in CrewAI.
Definire gli Agenti
In CrewAI, ogni agente è definito da quattro proprietà fondamentali: role, goal,
backstory e tools. Queste proprietà non sono semplici metadati: vengono integrate
nel system prompt dell'agente e influenzano direttamente il comportamento dell'LLM sottostante. Un agente
ben definito produce risultati significativamente migliori di uno con proprietà generiche.
Le Proprietà di un Agente
- role: il titolo professionale dell'agente. Definisce la sua identità e il tipo di competenza che possiede. Esempi: "Senior Data Analyst", "Content Marketing Strategist", "QA Engineer".
- goal: l'obiettivo che l'agente cerca di raggiungere. Deve essere specifico e misurabile. L'LLM usa il goal per orientare le sue decisioni e valutare se il proprio output è adeguato.
- backstory: una narrativa che fornisce contesto e motivazione all'agente. La backstory arricchisce il prompt con dettagli che migliorano la qualità delle risposte: esperienza pregressa, stile di lavoro, principi guida.
- tools: la lista di strumenti a disposizione dell'agente. Un agente senza tool può solo ragionare e produrre testo. Un agente con tool può cercare sul web, leggere file, eseguire calcoli e interagire con sistemi esterni.
Esempio Pratico: Definizione di Agenti
from crewai import Agent
from crewai_tools import SerperDevTool, ScrapeWebsiteTool
# Tool per la ricerca web
search_tool = SerperDevTool()
scrape_tool = ScrapeWebsiteTool()
# Agente 1: Ricercatore
researcher = Agent(
role="Senior Research Analyst",
goal="Trovare informazioni accurate e aggiornate su un argomento, "
"verificando le fonti e sintetizzando i dati chiave",
backstory="""Sei un analista di ricerca con 15 anni di esperienza nel
settore tecnologico. Hai lavorato per think tank prestigiosi e sei noto
per la tua capacità di trovare dati affidabili e separare i fatti dalle
opinioni. Il tuo approccio è sempre evidence-based: non affermi nulla
che non sia supportato da fonti verificabili.""",
tools=[search_tool, scrape_tool],
verbose=True,
allow_delegation=False,
max_iter=5,
llm="gpt-4o"
)
# Agente 2: Scrittore
writer = Agent(
role="Content Writer",
goal="Scrivere articoli tecnici coinvolgenti, accurati e ottimizzati "
"per la SEO, basati sui dati forniti dal team di ricerca",
backstory="""Sei un technical writer con esperienza nella comunicazione
scientifica e tecnologica. Sai trasformare dati complessi in narrative
accessibili senza sacrificare la precisione tecnica. I tuoi articoli
sono noti per essere sia informativi che piacevoli da leggere. Segui
le best practice SEO per massimizzare la visibilità dei contenuti.""",
tools=[],
verbose=True,
allow_delegation=False,
llm="gpt-4o"
)
# Agente 3: Editor
editor = Agent(
role="Senior Content Editor",
goal="Revisionare i contenuti per garantire qualità, coerenza, "
"correttezza grammaticale e aderenza alle linee guida editoriali",
backstory="""Sei un editor senior con un occhio impeccabile per i
dettagli. Hai revisionato centinaia di articoli tecnici e sai
individuare errori logici, imprecisioni tecniche e problemi di
struttura. Il tuo feedback è sempre costruttivo e orientato al
miglioramento del contenuto finale.""",
tools=[],
verbose=True,
allow_delegation=False,
llm="gpt-4o"
)
Consigli per Backstory Efficaci
La backstory non è un campo opzionale da compilare con frasi generiche. È uno degli elementi più potenti per controllare il comportamento dell'agente. Ecco come scriverla al meglio:
- Specificità: "15 anni di esperienza nel settore fintech" è meglio di "molta esperienza"
- Principi operativi: includi le regole che l'agente deve seguire ("verifica sempre le fonti", "privilegia la chiarezza")
- Anti-pattern: indica esplicitamente cosa l'agente NON deve fare ("non inventare dati", "non usare jargon inutile")
- Tono e stile: definisci il registro comunicativo ("formale ma accessibile", "diretto e conciso")
Parametri Avanzati degli Agenti
Oltre alle proprietà fondamentali, CrewAI offre parametri avanzati per controllare finemente il comportamento degli agenti:
advanced_agent = Agent(
role="Data Scientist",
goal="Analizzare dataset e produrre insight statistici",
backstory="Esperto di data science con specializzazione in NLP.",
# Parametri avanzati
verbose=True, # Log dettagliato delle operazioni
allow_delegation=True, # Può delegare task ad altri agenti
max_iter=10, # Massimo numero di iterazioni per task
max_rpm=30, # Rate limit: max richieste al minuto
memory=True, # Abilita la memoria dell'agente
cache=True, # Cache dei risultati dei tool
step_callback=None, # Callback custom dopo ogni step
# Configurazione LLM
llm="gpt-4o", # Modello da utilizzare
function_calling_llm=None, # LLM separato per il function calling
max_tokens=4096, # Limite token per risposta
)
Task e Delegation
I Task sono le unita di lavoro fondamentali in CrewAI. Ogni task definisce un obiettivo specifico, l'output atteso, l'agente responsabile e, opzionalmente, il contesto proveniente da task precedenti. La qualità della definizione dei task e direttamente proporzionale alla qualità dei risultati prodotti dalla crew.
Anatomia di un Task
from crewai import Task
# Task 1: Ricerca
research_task = Task(
description="""Conduci una ricerca approfondita su {topic}.
Devi trovare:
1. Le ultime novità e sviluppi (ultimi 6 mesi)
2. I principali player e le loro soluzioni
3. Trend emergenti e previsioni degli esperti
4. Dati quantitativi (statistiche, market size, growth rate)
5. Almeno 5 fonti affidabili con URL
Concentrati su fonti autorevoli: paper accademici, report di
analisti, documentazione ufficiale e articoli di esperti riconosciuti.""",
expected_output="""Un report di ricerca strutturato con:
- Executive summary (3-5 righe)
- Sezione 'Stato dell'Arte' con i principali sviluppi
- Sezione 'Player Principali' con confronto
- Sezione 'Trend e Previsioni' con dati quantitativi
- Lista delle fonti con URL
Il report deve essere tra 800 e 1200 parole.""",
agent=researcher
)
# Task 2: Scrittura (dipende dalla ricerca)
writing_task = Task(
description="""Basandoti sul report di ricerca fornito, scrivi un
articolo tecnico completo su {topic}.
L'articolo deve:
1. Avere un titolo accattivante e ottimizzato SEO
2. Iniziare con un'introduzione che catturi l'attenzione
3. Sviluppare ogni sezione con esempi pratici
4. Includere code snippet dove appropriato
5. Concludere con takeaway actionable per il lettore
6. Usare un tono professionale ma accessibile""",
expected_output="""Un articolo tecnico di 1500-2000 parole con:
- Titolo SEO-friendly
- Introduzione coinvolgente
- 4-6 sezioni tematiche con sottotitoli H2/H3
- Almeno 2 code snippet pratici
- Conclusione con call-to-action
- Meta description di 150-160 caratteri""",
agent=writer,
context=[research_task] # Riceve l'output della ricerca
)
# Task 3: Revisione (dipende dalla scrittura)
editing_task = Task(
description="""Revisiona l'articolo prodotto dal writer.
Verifica:
1. Correttezza tecnica di tutte le affermazioni
2. Coerenza logica e strutturale
3. qualità della scrittura (grammatica, stile, leggibilità)
4. Ottimizzazione SEO (keyword density, meta tags)
5. Completezza rispetto al brief iniziale
Fornisci l'articolo finale corretto, non solo il feedback.""",
expected_output="""L'articolo finale revisionato e pronto per la
pubblicazione, con tutte le correzioni applicate. In coda,
includi una sezione 'Note Editoriali' con le modifiche effettuate
e la valutazione complessiva (voto da 1 a 10).""",
agent=editor,
context=[research_task, writing_task]
)
Il Parametro Context
Il parametro context è il meccanismo attraverso cui i task condividono informazioni.
Quando un task ha context=[task_precedente], l'output del task precedente viene
automaticamente iniettato nel prompt dell'agente che esegue il task corrente. Questo crea una
catena di dipendenze dove ogni agente costruisce sul lavoro dei colleghi.
Un task può ricevere il contesto da più task precedenti. Nell'esempio sopra, l'editor riceve sia il report di ricerca originale sia l'articolo scritto, potendo cosi verificare la coerenza tra la ricerca è il contenuto finale. Questo pattern di contesto accumulativo e fondamentale per garantire la qualità dell'output complessivo.
Delegation tra Agenti
Quando un agente ha allow_delegation=True, può decidere autonomamente di delegare
parte del suo lavoro ad altri agenti della crew. Questo meccanismo replica il comportamento di
un team manager che riconosce che un collega è più adatto per un certo sotto-task.
Attenzione alla Delegation Incontrollata
La delegation può essere potente ma anche pericolosa. Se troppi agenti hanno
allow_delegation=True, il sistema può entrare in loop di delegazioni circolari
dove l'agente A delega a B che delega di nuovo ad A. Per evitare questo:
- Abilita la delegation solo sugli agenti che hanno un ruolo di coordinamento
- Imposta
max_iterper limitare il numero di iterazioni - Nella pratica, tieni
allow_delegation=Falseper la maggior parte degli agenti
Tipi di Processo
CrewAI supporta due modalità principali di orchestrazione dei task: Sequential e Hierarchical. La scelta del processo determina come i task vengono eseguiti e come gli agenti interagiscono tra loro.
Processo Sequential
Nel processo Sequential, i task vengono eseguiti uno dopo l'altro nell'ordine in cui sono definiti. L'output di ogni task diventa disponibile come contesto per i task successivi. Questo è il processo più semplice e prevedibile, ideale per pipeline lineari dove ogni fase dipende dalla precedente.
from crewai import Crew, Process
# Crew con processo sequenziale
crew = Crew(
agents=[researcher, writer, editor],
tasks=[research_task, writing_task, editing_task],
process=Process.sequential,
verbose=True
)
# Esecuzione
result = crew.kickoff(
inputs={"topic": "AI Agents nel 2026"}
)
print(result.raw) # Output finale come stringa
print(result.token_usage) # Token consumati per agente
Flusso Sequential:
[research_task] --output--> [writing_task] --output--> [editing_task]
| | |
researcher writer editor
| | |
"Report di "Articolo "Articolo
ricerca" bozza" finale"
Processo Hierarchical
Nel processo Hierarchical, CrewAI introduce automaticamente un Manager Agent che coordina il lavoro del team. Il manager analizza i task, decide l'ordine di esecuzione, assegna i task agli agenti più appropriati e può richiedere revisioni. Questo processo è più flessibile ma anche meno prevedibile, perchè il manager prende decisioni autonome basate sul contesto.
from crewai import Crew, Process
# Crew con processo gerarchico
crew = Crew(
agents=[researcher, writer, editor],
tasks=[research_task, writing_task, editing_task],
process=Process.hierarchical,
manager_llm="gpt-4o", # LLM per il manager agent
verbose=True
)
result = crew.kickoff(
inputs={"topic": "AI Agents nel 2026"}
)
Flusso Hierarchical:
+-------------------+
| MANAGER AGENT |
| (creato da CrewAI) |
+--------+----------+
|
+--------------+--------------+
| | |
v v v
[researcher] [writer] [editor]
| | |
v v v
"Risultato" "Risultato" "Risultato"
| | |
+--------------+--------------+
|
v
Output Finale
Confronto tra i Processi
| Caratteristica | Sequential | Hierarchical |
|---|---|---|
| Prevedibilità | Alta - ordine fisso | Media - il manager decide |
| Flessibilità | Bassa - pipeline rigida | Alta - adattamento dinamico |
| Costo token | Prevedibile | Variabile (manager aggiuntivo) |
| Complessità | Minima | Media |
| Caso d'uso ideale | Pipeline lineari e note | Task con dipendenze complesse |
| Debugging | Semplice - flusso lineare | Complesso - decisioni del manager |
Nella pratica, il processo Sequential è la scelta consigliata per la maggior parte dei casi d'uso. E' più prevedibile, più facile da debuggare e più economico in termini di token. Il processo Hierarchical è utile quando la logica di coordinamento è complessa e non può essere definita staticamente in anticipo, ma introduce variabilità e costi aggiuntivi che possono rendere il sistema meno affidabile.
Custom Tools
I tool sono il ponte tra gli agenti e il mondo esterno. CrewAI supporta due approcci per
definire custom tools: il decoratore @tool per funzioni semplici
e la classe BaseTool per strumenti più complessi che richiedono
stato interno o configurazione avanzata.
Tool con Decoratore
from crewai.tools import tool
@tool("Search Database")
def search_database(query: str, table: str = "products") -> str:
"""Cerca nel database aziendale informazioni su prodotti,
clienti o ordini.
Args:
query: Termine di ricerca.
table: Tabella da interrogare (products, customers, orders).
Returns:
Risultati della ricerca formattati.
"""
import sqlite3
conn = sqlite3.connect("company.db")
cursor = conn.execute(
f"SELECT * FROM {table} WHERE name LIKE ?",
(f"%{query}%",)
)
results = cursor.fetchall()
conn.close()
if not results:
return f"Nessun risultato trovato per '{query}' nella tabella {table}."
formatted = [str(row) for row in results[:10]]
return f"Trovati {len(results)} risultati:\n" + "\n".join(formatted)
@tool("Calculate Metrics")
def calculate_metrics(data: str, metric_type: str = "mean") -> str:
"""Calcola metriche statistiche sui dati forniti.
Args:
data: Dati numerici separati da virgola (es. '10,20,30,40').
metric_type: Tipo di metrica: mean, median, std, min, max.
Returns:
Il valore della metrica calcolata.
"""
import statistics
values = [float(x.strip()) for x in data.split(",")]
metrics = {
"mean": statistics.mean,
"median": statistics.median,
"std": statistics.stdev if len(values) > 1 else lambda x: 0,
"min": min,
"max": max,
}
if metric_type not in metrics:
return f"Metrica '{metric_type}' non supportata. Usa: {list(metrics.keys())}"
result = metrics[metric_type](values)
return f"{metric_type} di {values}: {result:.4f}"
Tool con Classe BaseTool
Per tool che necessitano di stato interno, connessioni persistenti o logica di inizializzazione
complessa, CrewAI fornisce la classe BaseTool:
from crewai.tools import BaseTool
from pydantic import BaseModel, Field
from typing import Type
class APISearchInput(BaseModel):
"""Schema di input per il tool di ricerca API."""
endpoint: str = Field(description="Endpoint API da interrogare")
params: str = Field(
default="",
description="Parametri della query in formato key=value separati da &"
)
class APISearchTool(BaseTool):
name: str = "API Search"
description: str = (
"Interroga un'API REST esterna per recuperare dati. "
"Supporta endpoint GET con parametri di query."
)
args_schema: Type[BaseModel] = APISearchInput
base_url: str = "https://api.example.com"
api_key: str = ""
def _run(self, endpoint: str, params: str = "") -> str:
"""Esegue la richiesta API."""
import requests
url = f"{self.base_url}/{endpoint}"
headers = {"Authorization": f"Bearer {self.api_key}"}
query_params = {}
if params:
for pair in params.split("&"):
key, value = pair.split("=")
query_params[key.strip()] = value.strip()
try:
response = requests.get(
url, headers=headers, params=query_params, timeout=10
)
response.raise_for_status()
return str(response.json())
except requests.RequestException as e:
return f"Errore nella richiesta API: {str(e)}"
# Utilizzo
api_tool = APISearchTool(
base_url="https://api.example.com/v2",
api_key="your-api-key"
)
Tool Predefiniti di CrewAI
CrewAI fornisce un ricco set di tool predefiniti attraverso il pacchetto crewai-tools:
from crewai_tools import (
SerperDevTool, # Ricerca web via Serper.dev
ScrapeWebsiteTool, # Web scraping
WebsiteSearchTool, # Ricerca semantica su un sito
FileReadTool, # Lettura file
DirectoryReadTool, # Listing directory
PDFSearchTool, # Ricerca in file PDF
CSVSearchTool, # Ricerca in file CSV
JSONSearchTool, # Ricerca in file JSON
CodeDocsSearchTool, # Ricerca in documentazione codice
YoutubeVideoSearchTool, # Ricerca in video YouTube
)
# Configurazione
search = SerperDevTool()
scraper = ScrapeWebsiteTool()
pdf_reader = PDFSearchTool(pdf="report.pdf")
csv_reader = CSVSearchTool(csv="data.csv")
Tool Description e qualità dell'Agente
La description di un tool è la parte più critica per il corretto funzionamento
dell'agente. L'LLM decide quale tool invocare basandosi esclusivamente sulla descrizione.
Una descrizione vaga come "cerca cose" portera a invocazioni errate. Una descrizione precisa
come "cerca informazioni sul web utilizzando un motore di ricerca e restituisce i primi 5 risultati
con titolo, URL e snippet" permette all'LLM di decidere con precisione quando e come usare il tool.
Memory e Context Sharing
CrewAI implementa un sistema di memoria multi-livello che permette agli agenti di condividere informazioni, ricordare interazioni precedenti e accumulare conoscenza nel tempo. Il sistema di memoria è composto da tre componenti distinti che operano a scale temporali diverse.
I Tre Livelli di Memoria
-
Short-Term Memory: memorizza le informazioni relative all'esecuzione corrente
della crew. Include gli output dei task completati, le conversazioni tra agenti e i risultati
dei tool. Viene azzerata al termine dell'esecuzione. E il meccanismo che alimenta il parametro
contextdei task. - Long-Term Memory: persiste tra le esecuzioni. Memorizza le lezioni apprese, i pattern di successo e le strategie che hanno prodotto buoni risultati. Utilizza un database locale (SQLite) per la persistenza. E' utile quando la stessa crew viene eseguita ripetutamente su task simili.
- Entity Memory: mantiene un registro delle entità menzionate durante le esecuzioni (persone, organizzazioni, prodotti, concetti). Permette agli agenti di costruire una comprensione cumulativa del dominio in cui operano.
Configurazione della Memoria
from crewai import Crew, Process
crew = Crew(
agents=[researcher, writer, editor],
tasks=[research_task, writing_task, editing_task],
process=Process.sequential,
# Configurazione memoria
memory=True, # Abilita il sistema di memoria
embedder={
"provider": "openai",
"config": {
"model": "text-embedding-3-small"
}
},
verbose=True
)
# Prima esecuzione: la crew impara
result1 = crew.kickoff(inputs={"topic": "AI Agents"})
# Seconda esecuzione: la crew ricorda le lezioni apprese
result2 = crew.kickoff(inputs={"topic": "Multi-Agent Systems"})
Context Sharing tra Task
Il context sharing è il meccanismo primario di collaborazione in CrewAI. Quando
un task elenca altri task nel parametro context, gli output di quei task vengono
automaticamente inclusi nel prompt dell'agente che esegue il task corrente. Questo crea una
catena informativa dove ogni agente ha accesso al lavoro dei suoi predecessori.
# Task con contesto multiplo
final_review = Task(
description="Revisione finale del contenuto completo.",
expected_output="Contenuto approvato e pronto per la pubblicazione.",
agent=editor,
context=[research_task, writing_task] # Accede a entrambi gli output
)
# Il prompt dell'editor includera automaticamente:
# 1. L'output del research_task (report di ricerca)
# 2. L'output del writing_task (articolo bozza)
# L'editor può cosi verificare la coerenza tra ricerca e contenuto
Come Funziona il Context Sharing Internamente
Quando un task ha context=[task_a, task_b], CrewAI costruisce il prompt
dell'agente includendo una sezione dedicata con gli output dei task referenziati:
[System Prompt con role, goal, backstory dell'agente]
Contesto dalle attivita precedenti:
---
Output di Task A:
[output completo di task_a]
---
Output di Task B:
[output completo di task_b]
---
Task corrente:
[description del task corrente]
Expected Output:
[expected_output del task corrente]
Questo significa che l'intero output dei task precedenti viene incluso nel prompt. Per task
con output molto lungo, questo può consumare una quantità significativa di token. E' importante
definire expected_output in modo che l'output sia conciso ma completo.
Case Study: Crew per Content Creation
Implementiamo un esempio completo e funzionante di una crew per la creazione di contenuti. Il team è composto da tre agenti specializzati: un Researcher che raccoglie informazioni, un Writer che produce l'articolo e un Editor che revisiona il contenuto finale. Questo pattern è applicabile a qualsiasi pipeline di content creation: blog post, newsletter, report aziendali, documentazione tecnica.
Setup Completo
import os
from crewai import Agent, Task, Crew, Process
from crewai_tools import SerperDevTool, ScrapeWebsiteTool
# Configurazione API keys
os.environ["OPENAI_API_KEY"] = "your-openai-key"
os.environ["SERPER_API_KEY"] = "your-serper-key"
# --- TOOLS ---
search_tool = SerperDevTool()
scrape_tool = ScrapeWebsiteTool()
# --- AGENTS ---
researcher = Agent(
role="Senior Tech Research Analyst",
goal="Raccogliere informazioni complete, accurate e aggiornate "
"sull'argomento assegnato, con dati quantitativi e fonti verificabili",
backstory="""Sei un analista di ricerca con 12 anni di esperienza
nel settore tecnologico. Hai contribuito a report per Gartner e
Forrester. La tua metodologia prevede:
1. Ricerca iniziale ampia per mappare il panorama
2. Deep dive sulle fonti più rilevanti
3. Verifica incrociata dei dati tra almeno 3 fonti
4. Sintesi strutturata con distinzione tra fatti e opinioni""",
tools=[search_tool, scrape_tool],
verbose=True,
allow_delegation=False,
max_iter=7,
llm="gpt-4o"
)
writer = Agent(
role="Technical Content Writer",
goal="Trasformare i dati di ricerca in un articolo tecnico "
"coinvolgente, accurato e ottimizzato per SEO e leggibilità",
backstory="""Sei un technical writer con 8 anni di esperienza.
Hai scritto per pubblicazioni come Towards Data Science, Dev.to
e documentazione ufficiale di framework open-source. Il tuo stile
combina rigore tecnico e accessibilità: usi analogie concrete,
esempi pratici e una struttura chiara. Ogni articolo che scrivi
segue la formula: hook -> contesto -> profondità -> takeaway.""",
tools=[],
verbose=True,
allow_delegation=False,
llm="gpt-4o"
)
editor = Agent(
role="Senior Technical Editor",
goal="Garantire che l'articolo finale sia impeccabile dal punto "
"di vista tecnico, linguistico e strutturale",
backstory="""Sei un editor con background in computer science e
giornalismo tecnico. Hai revisionato oltre 500 articoli tecnici.
Il tuo processo di revisione:
1. Verifica correttezza tecnica (affermazioni, codice, dati)
2. Analisi strutturale (flusso logico, transizioni, coerenza)
3. Revisione linguistica (grammatica, chiarezza, concisione)
4. Check SEO (titolo, meta description, keyword placement)
Non ti limiti a segnalare problemi: correggi direttamente.""",
tools=[],
verbose=True,
allow_delegation=False,
llm="gpt-4o"
)
# --- TASKS ---
research_task = Task(
description="""Conduci una ricerca approfondita su: {topic}
Requisiti:
- Identifica almeno 5 sviluppi chiave degli ultimi 6 mesi
- Trova dati quantitativi (statistiche, benchmark, market data)
- Raccogli opinioni di esperti riconosciuti
- Individua trend emergenti e previsioni
- Documenta tutte le fonti con URL completi""",
expected_output="""Report di ricerca strutturato (800-1000 parole):
1. Executive Summary (5 righe)
2. Sviluppi Chiave (5+ punti con fonti)
3. Dati Quantitativi (statistiche con fonti)
4. Opinioni di Esperti (citazioni attribuite)
5. Trend Emergenti (3+ previsioni)
6. Bibliografia (5+ fonti con URL)""",
agent=researcher
)
writing_task = Task(
description="""Scrivi un articolo tecnico basato sul report di ricerca.
Specifiche:
- Titolo: accattivante, max 60 caratteri, con keyword principale
- Introduzione: hook + contesto + preview del contenuto
- Corpo: 4-6 sezioni con H2, esempi pratici e dati
- Conclusione: sintesi + takeaway actionable + CTA
- Tono: professionale ma accessibile, in italiano
- Lunghezza: 1500-2000 parole""",
expected_output="""Articolo completo in formato Markdown con:
- Titolo SEO-optimized
- Meta description (155 caratteri)
- 5-7 keyword target
- Contenuto strutturato con H2/H3
- Almeno 2 esempi pratici o code snippet
- Conclusione con 3 takeaway numerati""",
agent=writer,
context=[research_task]
)
editing_task = Task(
description="""Revisiona e finalizza l'articolo.
Checklist di revisione:
- [ ] Tutte le affermazioni tecniche sono corrette
- [ ] I dati citati corrispondono alle fonti
- [ ] La struttura è logica e fluida
- [ ] Non ci sono errori grammaticali o di stile
- [ ] Il titolo e la meta description sono efficaci
- [ ] Il SEO è ottimizzato
- [ ] La lunghezza è nei limiti richiesti
Produci la versione finale corretta dell'articolo.""",
expected_output="""Articolo finale revisionato e pronto per la
pubblicazione, con in coda:
- Note editoriali (modifiche effettuate)
- Score di qualità (1-10)
- Checklist completata""",
agent=editor,
context=[research_task, writing_task]
)
# --- CREW ---
content_crew = Crew(
agents=[researcher, writer, editor],
tasks=[research_task, writing_task, editing_task],
process=Process.sequential,
verbose=True,
memory=True,
embedder={
"provider": "openai",
"config": {"model": "text-embedding-3-small"}
}
)
# --- ESECUZIONE ---
result = content_crew.kickoff(
inputs={"topic": "L'impatto degli AI Agents sulla produttività aziendale nel 2026"}
)
# Accesso ai risultati
print("=== RISULTATO FINALE ===")
print(result.raw)
print(f"\n=== TOKEN USAGE ===")
print(f"Token totali: {result.token_usage}")
Output Tipico della Crew
Durante l'esecuzione, CrewAI logga ogni passo del processo con dettagli su quale agente sta
lavorando, quale tool sta usando e quale output ha prodotto. Il risultato finale è l'output
dell'ultimo task (editing_task), che contiene l'articolo revisionato è pronto per la pubblicazione.
Il campo token_usage fornisce un breakdown del consumo di token per agente e per task,
essenziale per il monitoraggio dei costi.
CrewAI vs LangGraph vs AutoGen
Per scegliere il framework giusto, è fondamentale comprendere le differenze architetturali e filosofiche tra CrewAI, LangGraph e AutoGen. Ogni framework eccelle in scenari specifici e presenta compromessi diversi tra semplicità, flessibilità e controllo.
Confronto Dettagliato
| Dimensione | CrewAI | LangGraph | AutoGen/AG2 |
|---|---|---|---|
| Paradigma | Team role-based | Graph stateful | Conversazione multi-agente |
| Metafora | Team aziendale | Diagramma di flusso | Chat di gruppo |
| Curva di apprendimento | Bassa | Alta | Media |
| Flessibilità | Media | Massima | Alta |
| Linee di codice tipiche | 30-80 | 80-200+ | 50-150 |
| Stato persistente | Memory system | Checkpointing nativo | Chat history |
| Human-in-the-Loop | Configurabile | Nativo (interrupt) | Nativo (4 modalità) |
| Tool Ecosystem | crewai-tools (ricco) | LangChain tools | Function registration |
| Code Execution | Via tools | Custom nodes | Nativo (Docker) |
| Caso d'uso ideale | Pipeline di contenuti, workflow strutturati | Workflow complessi con branching | Collaborazione iterativa e code gen |
Quando Scegliere CrewAI
- Prototipazione rapida: quando hai bisogno di un sistema multi-agente funzionante nel minor tempo possibile. La semplicità dell'API permette di passare dall'idea al prototipo in minuti.
- Pipeline lineari: quando il flusso di lavoro è una sequenza chiara di fasi (ricerca -> elaborazione -> revisione -> output).
- Team con ruoli distinti: quando ogni agente ha un ruolo ben definito e non c'è bisogno di coordinamento complesso.
- Content creation: CrewAI eccelle in pipeline di creazione contenuti dove diversi specialisti contribuiscono in sequenza.
Quando NON Scegliere CrewAI
- Workflow con branching complesso: se il flusso richiede decisioni condizionali multiple, loop con condizioni di uscita specifiche o esecuzione parallela di sub-flussi, LangGraph e la scelta migliore.
- Negoziazione tra agenti: se gli agenti devono discutere, negoziare e convergere su una soluzione attraverso iterazioni di conversazione, AutoGen è più adatto.
- Controllo granulare sul flusso: CrewAI astrae molti dettagli del flusso di esecuzione. Se hai bisogno di controllare ogni singola transizione di stato, usa LangGraph.
Best Practices per la Produzione
Utilizzare CrewAI in ambienti di produzione richiede attenzione a diversi aspetti che vanno oltre la semplice definizione di agenti e task. Ecco le best practice fondamentali basate sull'esperienza accumulata con il framework.
1. Design dei Prompt
- Ruoli specifici e non generici: "Senior Python Backend Developer con esperienza in FastAPI e PostgreSQL" è infinitamente meglio di "Programmatore".
- Goal misurabili: "Produrre un report di 800-1200 parole con almeno 5 fonti verificabili" è meglio di "Fare ricerca".
- Expected output dettagliato: definisci struttura, formato e lunghezza dell'output atteso. L'LLM produce risultati migliori quando sa esattamente cosa ci si aspetta.
- Anti-pattern nei prompt: includi istruzioni su cosa NON fare. "Non inventare dati", "Non usare fonti precedenti al 2024" prevengono errori comuni.
2. Gestione dei Costi
# Strategia per il controllo dei costi
crew = Crew(
agents=[researcher, writer, editor],
tasks=[research_task, writing_task, editing_task],
process=Process.sequential,
# Limiti per prevenire costi eccessivi
max_rpm=30, # Rate limit globale
verbose=True, # Monitoring attivo
)
# Dopo l'esecuzione, analizza il consumo
result = crew.kickoff(inputs={"topic": "Test Topic"})
usage = result.token_usage
print(f"Token totali input: {usage.total_tokens}")
print(f"Token totali output: {usage.prompt_tokens}")
print(f"Costo stimato: 






