Vai al contenuto

Tutorial

Tutorial CrewAI: dal primo crew alla produzione

Installazione, primo crew funzionante, strumenti, output strutturati e i parametri che contano quando il codice esce dal notebook. Ogni passaggio verificato sulla versione corrente del framework.

Aggiornato il 17 agosto 2026

Prerequisiti e installazione

Servono tre cose: Python in una versione fra la 3.10 e la 3.13 (la 3.14 non è supportata, il pacchetto dichiara esplicitamente il limite <3.14), un gestore di pacchetti e una chiave API di un fornitore di modelli. Un fornitore qualsiasi: OpenAI, Anthropic, Google, oppure nessuna chiave se userai un modello locale.

La documentazione ufficiale adotta uv come gestore di dipendenze e consiglia uv tool install crewai per la CLI. Se preferisci pip, per la libreria funziona altrettanto bene:

terminale
python -m venv .venv           # ambiente isolato
source .venv/bin/activate

pip install crewai             # il framework
pip install 'crewai[tools]'    # con gli strumenti pronti

crewai version                 # conferma l'installazione
Comandi verificati su PyPI e docs.crewai.com il 17 agosto 2026, crewai 1.15.16.

Le virgolette attorno a crewai[tools] non sono decorative: senza, alcune shell interpretano le parentesi quadre e il comando fallisce. L'extra tools aggiunge il pacchetto degli strumenti pronti; su PyPI sono elencati anche gli altri extra, fra cui embeddings e quelli per i singoli fornitori cloud.

Due strade: scaffolding o API diretta

Dalla serie 1.x ci sono due modi di lavorare con CrewAI, e quasi tutti i tutorial in circolazione ne mostrano uno solo, spesso nella forma vecchia.

La prima strada è lo scaffolding: crewai create crew nome genera un progetto completo con la configurazione degli agenti in file separati dal codice. Nella forma attuale i file sono JSONC, un crew.jsonc più un file per agente nella cartella agents/; con il flag --classic ottieni la struttura precedente, con crew.py e le configurazioni YAML in config/agents.yaml e config/tasks.yaml. Il progetto si avvia con crewai run, che capisce dal pyproject.toml cosa deve lanciare.

terminale
crewai create crew analisi_mercato
# progetto JSON-first: crew.jsonc + agents/*.jsonc

crewai create crew analisi_mercato --classic
# scaffold classico: crew.py + config/agents.yaml + config/tasks.yaml

cd analisi_mercato
crewai install    # risolve le dipendenze
crewai run        # esegue il crew
Struttura verificata sulla CLI di crewai 1.15.16 il 17 agosto 2026.

La seconda strada è l'API Python diretta: importi le classi e scrivi tutto in un file. Resta pienamente supportata ed è quella che troverai in quasi ogni guida online, perché esiste dalla prima versione. Il problema è che molte di quelle guide sono ferme alla serie 0.x, con import e parametri che nel frattempo sono cambiati. Qui usiamo l'API diretta per una ragione didattica, si vede ogni pezzo del meccanismo, ma sulla versione attuale: quando il progetto cresce, passare allo scaffolding conviene.

Il primo crew funzionante

L'esempio classico con due ruoli: uno cerca, l'altro scrive. Due agenti, due task, processo sequenziale. È il codice completo, non un frammento: con una chiave configurata gira così com'è.

primo_crew.py
from crewai import Agent, Task, Crew, Process

# I segnaposto {settore} vengono riempiti da kickoff(inputs=...)
ricercatore = Agent(
    role="Ricercatore di mercato",
    goal="Raccogliere dati verificabili sul mercato {settore} in Italia",
    backstory="Distingue le fonti primarie dai comunicati stampa.",
    llm="gpt-5.4-mini",
    verbose=True,        # mostra il ragionamento passo passo
)

redattore = Agent(
    role="Redattore tecnico",
    goal="Trasformare i dati raccolti in una sintesi onesta",
    backstory="Frasi brevi. Non aggiunge nulla che non sia nei dati.",
    llm="gpt-5.4-mini",
)

ricerca = Task(
    description="Raccogli 5 dati recenti sul mercato {settore} in Italia.",
    expected_output="Elenco numerato: dato, anno, fonte.",
    agent=ricercatore,
)

sintesi = Task(
    description="Scrivi una sintesi di 200 parole dai dati raccolti.",
    expected_output="Testo di circa 200 parole che cita i 5 dati.",
    agent=redattore,
    context=[ricerca],     # riceve l'output del task precedente
)

crew = Crew(
    agents=[ricercatore, redattore],
    tasks=[ricerca, sintesi],
    process=Process.sequential,
)

esito = crew.kickoff(inputs={"settore": "fotovoltaico"})
print(esito.raw)
Verificato con crewai 1.15.16 il 17 agosto 2026.

Tre dettagli che i tutorial saltano. Primo: i valori passati a kickoff(inputs=...) sostituiscono i segnaposto fra graffe in ruoli, obiettivi e descrizioni, quindi lo stesso crew serve per settori diversi senza toccare il codice. Secondo: il campo expected_output non è un commento, è la specifica del risultato, e la qualità dell'output dipende più da lì che dal modello. Terzo: context=[ricerca] dichiara esplicitamente da quale task arriva il materiale, invece di affidarsi solo all'ordine di esecuzione.

Configurare il modello

Il parametro llm dell'agente accetta una stringa o un oggetto. Se lo ometti, il framework usa il modello indicato nella variabile d'ambiente OPENAI_MODEL_NAME e, in mancanza, ripiega su un modello OpenAI: in entrambi i casi serve una chiave OpenAI valida.

errore

Chiede la chiave OpenAI anche se non la volevi usare

È il primo errore che incontra chiunque: nessun parametro llm, esecuzione avviata, e il crew si ferma chiedendo OPENAI_API_KEY. Non è un difetto della tua installazione, è il comportamento predefinito. Dichiara sempre il modello su ogni agente, anche quando usi OpenAI: il codice resta leggibile e il giorno in cui cambi fornitore modifichi una riga.

Per puntare a un fornitore diverso si usa la notazione fornitore/modello. CrewAI ha integrazioni native per OpenAI, Anthropic, Google, Azure e Bedrock; tutti gli altri fornitori passano da LiteLLM, con le stesse stringhe. L'oggetto LLM serve quando vuoi controllare temperatura, limiti di token o l'indirizzo di un server locale:

modelli.py
from crewai import Agent, LLM

# stringa "fornitore/modello": la via rapida
redattore = Agent(
    role="Redattore tecnico",
    goal="...",
    backstory="...",
    llm="anthropic/claude-sonnet-4-6",
)

# oggetto LLM: controllo fine, endpoint locali
locale = LLM(
    model="ollama/llama3:70b",
    base_url="http://localhost:11434",   # indirizzo standard di Ollama
    temperature=0.2,
)
analista = Agent(
    role="Analista",
    goal="...",
    backstory="...",
    llm=locale,
)
Verificato con crewai 1.15.16 il 17 agosto 2026.

Far girare tutto in locale, senza chiavi e senza mandare dati fuori, merita un discorso a parte: la guida per il locale copre installazione di Ollama, scelta del modello e i limiti reali dei modelli piccoli con gli strumenti.

Aggiungere strumenti

Senza strumenti un agente può solo scrivere. Il pacchetto crewai_tools, installato con l'extra visto sopra, ne porta decine già pronti: SerperDevTool fa ricerche Google tramite serper.dev e richiede la variabile SERPER_API_KEY, ScrapeWebsiteTool legge il contenuto di una pagina, FileReadTool legge file locali.

Quando serve qualcosa di tuo, la via più corta è il decoratore @tool su una funzione. Per strumenti con più argomenti e validazione si estende la classe BaseTool, definendo name, description, uno schema Pydantic in args_schema e il metodo _run. In entrambi i casi la descrizione è la parte che conta: è il testo che il modello legge per decidere se e quando usare lo strumento.

strumenti.py
from crewai import Agent
from crewai.tools import tool
from crewai_tools import SerperDevTool, ScrapeWebsiteTool

# strumento personalizzato: una funzione con docstring
@tool("Cambio euro dollaro")
def cambio_eur_usd() -> str:
    """Restituisce il cambio euro dollaro corrente."""
    return leggi_cambio_da_api()   # la tua logica

ricercatore = Agent(
    role="Ricercatore di mercato",
    goal="Raccogliere dati verificabili su {settore}",
    backstory="Cita la fonte di ogni numero che riporta.",
    tools=[SerperDevTool(), ScrapeWebsiteTool(), cambio_eur_usd],
    llm="gpt-5.4-mini",
)
Verificato con crewai 1.15.16 e crewai-tools il 17 agosto 2026.

Un avvertimento pratico: ogni strumento in più allarga il prompt e dà al modello un'occasione in più di sbagliare chiamata, un problema frequente con i modelli non OpenAI. Dai a ogni agente solo gli strumenti che il suo compito richiede davvero.

Output strutturati

Finché il risultato lo legge una persona, il testo libero di esito.raw basta. Appena il risultato entra in un altro programma servono campi, non prosa. I Task hanno tre parametri per questo: output_pydantic valida l'output contro un modello Pydantic e restituisce un'istanza tipizzata, output_json usa lo stesso schema ma restituisce un dizionario, output_file scrive il risultato su un percorso.

output_strutturato.py
from pydantic import BaseModel
from crewai import Task

class SchedaMercato(BaseModel):
    settore: str
    dati: list[str]
    fonti: list[str]

sintesi = Task(
    description="Componi la scheda del mercato {settore}.",
    expected_output="Scheda con settore, 5 dati e le fonti.",
    agent=redattore,
    output_pydantic=SchedaMercato,
)

esito = crew.kickoff(inputs={"settore": "fotovoltaico"})
scheda = esito.pydantic          # istanza di SchedaMercato
print(scheda.dati)
Verificato con crewai 1.15.16 il 17 agosto 2026.

Lo schema Pydantic fa due lavori insieme: dice al modello che forma deve avere la risposta e blocca l'esecuzione se la forma non torna. Per la variante JSON il dizionario si legge da esito.json_dict. Esiste anche un parametro guardrail sui Task, una funzione che valida l'output prima di passare al task successivo: utile quando la validazione è logica e non solo di forma.

Da sequenziale a gerarchico

Con process=Process.hierarchical l'ordine dei task non lo decidi più tu: CrewAI crea un agente manager che assegna i compiti, valuta i risultati e può rimandarli indietro. Il processo gerarchico richiede un modello per il manager, indicato in manager_llm, oppure un agente tuo in manager_agent: senza uno dei due l'esecuzione non parte. Al manager conviene dare un modello capace, perché coordinare è il lavoro più delicato del crew.

attenzione

Il gerarchico moltiplica i costi

Ogni assegnazione, valutazione e ripetizione è una chiamata al modello in più, e i giri di revisione non sono prevedibili in anticipo. Su un crew piccolo il passaggio da sequenziale a gerarchico può raddoppiare i token consumati. Provalo solo dopo che la versione sequenziale funziona, e confronta token_usage prima e dopo: se la qualità non sale in proporzione, torna indietro.

Verso la produzione

Un crew che gira sul portatile e un crew che gira cento volte al giorno sono due problemi diversi. I parametri che separano i due mondi sono già nel framework, e conviene conoscerli prima che servano.

  • max_iter, sull'agente, limita i cicli di ragionamento (il default è 20). È la difesa contro l'errore "Maximum iterations reached" e contro gli agenti che girano a vuoto accumulando token.
  • max_rpm, sull'agente o sull'intero crew, limita le richieste al minuto. È la mitigazione concreta degli errori 429 dei fornitori.
  • verbose stampa il ragionamento: prezioso in sviluppo, rumore in produzione. Per i log persistenti c'è output_log_file: con True scrive logs.txt nella cartella corrente, con un percorso che finisce in .json scrive log strutturati.
  • esito.token_usage riporta i token della singola esecuzione, crew.usage_metrics le metriche aggregate. È il numero da guardare prima di decidere quante esecuzioni al giorno puoi permetterti.
produzione.py
crew = Crew(
    agents=[ricercatore, redattore],
    tasks=[ricerca, sintesi],
    process=Process.sequential,
    max_rpm=30,                        # tetto alle richieste al minuto
    output_log_file="crew_log.json",  # log strutturati su file
)

esito = crew.kickoff(inputs={"settore": "fotovoltaico"})

print(esito.token_usage)      # token di questa esecuzione
print(crew.usage_metrics)     # metriche aggregate del crew
Verificato con crewai 1.15.16 il 17 agosto 2026.

E qui va detta la cosa che i tutorial di solito omettono: nessun tutorial, questo compreso, rende un sistema pronto per la produzione. Quello che hai a fine pagina è un crew che funziona e che sai misurare. Mancano ancora la gestione dei fallimenti a metà esecuzione, una valutazione sistematica della qualità degli output, un tetto di spesa vero e la struttura deterministica che un processo ripetibile richiede: per quest'ultima il framework offre i Flows, che governano i passaggi a codice e chiamano i crew solo dove l'autonomia serve. E quando qualcosa si rompe, perché succederà, la pagina sugli errori comuni raccoglie i casi che incontrano quasi tutti, con le cause verificate.

Domande

Domande frequenti

Le domande che riceviamo più spesso da chi inizia con CrewAI.

  • Serve una carta di credito per seguire il tutorial?

    Il framework è gratuito, i token del modello no: ogni esecuzione consuma credito del fornitore scelto. Con un modello economico un crew di due agenti costa pochi centesimi a esecuzione. L'alternativa a costo zero è un modello locale via Ollama, accettando tempi più lunghi e qualità inferiore.

  • Posso usare CrewAI senza chiave OpenAI?

    Sì. La chiave OpenAI serve solo se non indichi un modello: senza il parametro llm il framework ripiega su OpenAI. Basta passare a ogni agente una stringa fornitore/modello, per esempio anthropic/claude-sonnet-4-6, oppure un oggetto LLM che punta a un server locale.

  • Meglio crewai create o l'API Python diretta?

    Per imparare, l'API diretta: tutto il codice sta in un file e ogni pezzo si vede. Per un progetto destinato a crescere, lo scaffolding: separa la configurazione dal codice e si esegue con crewai run. I concetti sono identici, passare dall'una all'altro costa poco.

  • Quanto Python bisogna sapere?

    Le basi: funzioni, dizionari, import. Un crew si scrive in modo dichiarativo, senza programmazione avanzata. Le classi servono solo per gli strumenti personalizzati con BaseTool e per i modelli Pydantic degli output strutturati.

  • Il codice funziona con le versioni 0.x di CrewAI?

    Non è garantito, e spesso no. Questo tutorial è verificato sulla 1.15.16. Le guide scritte per la serie 0.x, comprese quasi tutte quelle in italiano, usano import e parametri che nel frattempo sono cambiati. Se una guida non dichiara la versione su cui è stata provata, diffida.

  • Quanto tempo serve per il primo crew funzionante?

    Con una chiave API già pronta, meno di mezz'ora: dieci minuti per l'installazione e il resto per scrivere due agenti e due task. Il tempo vero si spende dopo, a calibrare descrizioni ed expected_output finché la qualità del risultato non diventa stabile.