Vai al contenuto

10 esempi pratici

27Esempio 9 · Marketing e social

Una crew gerarchica prepara tre post social per un'attività locale: un manager assegna il lavoro a stratega, copywriter e revisore, e un guardrail in Python blocca promesse esagerate e formati sbagliati.

Tempo di lettura: 25 minuti

Un forno di quartiere lancia un pane nuovo e vuole annunciarlo su Instagram, Facebook e LinkedIn. Il titolare non ha tempo di studiare cosa fanno gli altri forni, di scrivere tre testi diversi e di rileggerli con attenzione. Un'agenzia piccola ha lo stesso problema moltiplicato per venti clienti.

In questo esempio costruisci una squadra che fa il lavoro di una mini agenzia: qualcuno studia il pubblico, qualcuno scrive, qualcuno rilegge. Questa volta però non decidi tu l'ordine: lo decide un manager, come nel processo Processo gerarchico: Un agente manager riceve i task, li assegna ai membri più adatti e controlla i risultati. Richiede manager_llm o manager_agent. glossario del capitolo 11. Il risultato finale è un Output strutturato: Un risultato con campi fissi (titolo, lista, numero…) invece di testo libero, così un programma può usarlo senza interpretarlo. In CrewAI: output_pydantic. glossario (canale, testo, Hashtag: Una parola preceduta da # (per esempio #Bologna) che sui social raggruppa i contenuti sullo stesso tema. glossario) controllato da un Guardrail: Un controllo automatico sul risultato di un task. Se il controllo fallisce, l'errore torna all'agente che riprova. glossario scritto in Python.

Problema
Preparare tre post per canali diversi su una novità di un'attività locale, basati su una breve analisi del pubblico e dei concorrenti, senza promesse esagerate né dettagli inventati.
La squadra (agenti)
Stratega di marketing (cerca sul web), copywriter (scrive), revisore del tono (corregge). Più un manager creato da CrewAI che assegna i task.
Strumenti
SerperDevTool per la ricerca web; un guardrail in Python; un modello Pydantic per l'uscita.
Chiavi e costi
Chiave del modello (per esempio OPENAI_API_KEY) e SERPER_API_KEY (Serper ha un piano gratuito). Il processo gerarchico fa più chiamate al modello di uno sequenziale, perché anche il manager ragiona.
Cosa impari di nuovo
Mettere insieme processo gerarchico, output strutturato e guardrail nello stesso crew; scrivere un guardrail che legge un risultato in formato JSON.

Perché è tra i più usati#

Nella classifica del corso il marketing con social e SEO: Search Engine Optimization: l'insieme di accorgimenti per far comparire un sito o un contenuto più in alto nei risultati dei motori di ricerca. glossario è al 9° posto, con 27,3 punti su 100. I segnali principali, raccolti il 15 settembre 2026:

  • Materiale ufficiale. Il repository crewAI-examples contiene due crew dedicati, marketing_strategy e instagram_post, entrambi messi in evidenza nella pagina degli esempi della documentazione. Il secondo corso di DeepLearning.AI su CrewAI ha una lezione sulla scrittura di testi per più piattaforme social.
  • Progetti su GitHub. 181 repository con "crewai marketing" nel nome o nella descrizione, 123 con "linkedin", 78 con "social media" e 74 con "seo". Tra i progetti che sembrano applicazioni vere, il 5,3% riguarda il marketing.
  • Sondaggi. Nel sondaggio di CrewAI sul 2026 il 39% dei dirigenti vede un impatto significativo degli agenti in vendite e marketing; nel sondaggio PwC del 2025 il 54% li usa o pensa di usarli in quell'area.

C'è anche un dato contrario: il sito di statistiche di CrewAI osserva che il marketing è un caso d'uso meno comune nelle grandi aziende. Per questo non sta più in alto.

Lo schema#

Schema dell'esempio 9: crew gerarchica per i post social Gli inputs con attività, novità, dettagli e tono arrivano al manager. Il manager assegna i tre task: analisi allo stratega, che usa SerperDevTool; scrittura al copywriter; revisione al revisore. Il risultato della revisione passa dal guardrail controlla_post: se fallisce il task di revisione si rifà, se passa diventa PianoPost con tre post, salvato in post_social.json. inputs attivita · citta novita · dettagli tono Manager creato da CrewAI con manager_llm assegna i task e controlla Process.hierarchical i task non hanno agent= delega Stratega task 1 · analisi di pubblico e concorrenti con le fonti tools=[SerperDevTool] Copywriter task 2 · tre bozze: Instagram, Facebook, LinkedIn Revisore del tono task 3 · toglie promesse e dettagli inventati output_pydantic=PianoPost controlla_post guardrail in Python non passa: si rifà post_social.json passa
Il manager riceve gli inputs e delega i tre task. Il risultato del revisore passa dal guardrail: se non va bene si rifà, se va bene diventa il file post_social.json.

Nel processo sequenziale ogni task ha già il suo agente. Qui invece i task non hanno agent=: CrewAI crea un agente manager con il modello indicato in manager_llm, e il manager decide a chi affidare ciascun task e controlla i risultati. La documentazione lo dice così: i task non sono preassegnati, il manager li distribuisce in base alle capacità degli agenti.

Se parti da zero

Serve davvero un manager per tre passi in fila? Per un lavoro così lineare, un processo sequenziale funzionerebbe altrettanto bene e costerebbe meno. Lo usiamo qui perché è il modo più semplice di vederlo all'opera su un caso reale. Il gerarchico conviene quando i task sono tanti e non sai in anticipo chi è più adatto a ciascuno.

Preparazione#

Crea una cartella, per esempio post-social, e dentro il file .env con le chiavi (capitolo 7):

.env
MODEL=openai/gpt-4.1-mini
OPENAI_API_KEY=sk-...la-tua-chiave...
SERPER_API_KEY=...la-tua-chiave-serper...
CREWAI_DISABLE_TELEMETRY=true

La chiave di Serper: Servizio online (serper.dev) che restituisce i risultati di ricerca di Google a un programma. Lo usa SerperDevTool; serve la chiave SERPER_API_KEY. glossario si ottiene registrandosi su serper.dev (capitolo 12). Non servono file di dati: l'attività, il prodotto e i dettagli si passano nel kickoff. Il Forno Spiga Antica dell'esempio è inventato, come il suo pane, il prezzo e l'orario.

Il codice, pezzo per pezzo#

1. La forma del risultato#

Prima descrivi con Pydantic: Libreria Python per descrivere la forma dei dati (campi e tipi) e controllarla. CrewAI la usa per ottenere risposte strutturate e verificate. glossario com'è fatto un post e com'è fatto il piano completo. È lo stesso meccanismo del capitolo 13:

Python
class Post(BaseModel):
    canale: str = Field(description="Instagram, Facebook oppure LinkedIn")
    testo: str = Field(description="Il testo del post, pronto da copiare")
    hashtag: list[str] = Field(description="Da 2 a 5 hashtag, ognuno inizia con #")


class PianoPost(BaseModel):
    post: list[Post]

Le description dei campi finiscono nel prompt: aiutano il modello a capire cosa mettere in ciascun campo. Il piano è una lista di post, così un programma può leggerlo e, per esempio, caricarlo in un calendario editoriale.

2. Il guardrail che controlla i post#

Questa funzione riceve il risultato del revisore e decide se accettarlo. Controlla cose che il codice sa verificare con certezza:

Python
CANALI = ("Instagram", "Facebook", "LinkedIn")
MAX_CARATTERI = 600  # limite scelto da noi per post brevi, non una regola dei social
PROMESSE_VIETATE = ("garantit", "il migliore", "la migliore", "numero uno", "100%", "certificat", "unico in citt")


def controlla_post(risultato) -> tuple[bool, Any]:
    """Guardrail: controlla forma e contenuto dei post prima di accettarli."""
    testo = risultato.raw
    inizio, fine = testo.find("{"), testo.rfind("}")  # tengo solo la parte JSON
    try:
        piano = PianoPost.model_validate_json(testo[inizio:fine + 1])
    except ValueError:
        return (False, "Rispondi solo con il JSON richiesto: un oggetto con la lista 'post'.")
    if sorted(p.canale for p in piano.post) != sorted(CANALI):
        return (False, f"Serve esattamente un post per ciascun canale: {', '.join(CANALI)}.")
    for p in piano.post:
        if len(p.testo) > MAX_CARATTERI:
            return (False, f"Il post per {p.canale} supera {MAX_CARATTERI} caratteri: accorcialo.")
        if not 2 <= len(p.hashtag) <= 5 or any(not h.startswith("#") or " " in h for h in p.hashtag):
            return (False, f"Il post per {p.canale} deve avere da 2 a 5 hashtag, senza spazi, che iniziano con #.")
        trovate = [parola for parola in PROMESSE_VIETATE if parola in p.testo.lower()]
        if trovate:
            return (False, f"Il post per {p.canale} contiene promesse non dimostrabili ({', '.join(trovate)}): riformula.")
    return (True, piano.model_dump_json())  # tutto a posto: passo avanti il JSON pulito

Cosa succede, in ordine:

  • Il testo del risultato dovrebbe essere JSON: Formato di testo per dati strutturati con graffe, virgolette e due punti. È il formato predefinito dei nuovi progetti CrewAI (crew.jsonc). glossario. I modelli a volte lo circondano di parole o di segni come tre apici inversi; per questo si prende solo il pezzo tra la prima { e l'ultima }.
  • model_validate_json prova a trasformare quel testo in un PianoPost. Se mancano campi o i tipi sono sbagliati, solleva un errore e il guardrail risponde False con una spiegazione.
  • Poi controlla che ci sia un post per canale, la lunghezza, gli hashtag e alcune espressioni come «garantito» o «il migliore». Le radici come garantit prendono anche «garantita» e «garantiti».
  • Se tutto va bene restituisce True e il JSON ripulito, che CrewAI converte nel PianoPost finale.

Perché leggere risultato.raw e non risultato.pydantic? Abbiamo verificato nel codice di CrewAI 1.15.21 che, quando un task ha un guardrail, il testo viene convertito in Pydantic dopo l'ok del guardrail. Solo con i modelli che restituiscono direttamente l'oggetto strutturato pydantic è già pieno. Il testo in raw invece c'è sempre: per questo il guardrail parte da lì.

Se parti da zero

Un guardrail in Python non capisce il senso delle frasi: cerca parole. «Il pane più buono della zona» passa il controllo anche se è una promessa esagerata. Per i giudizi di tono esistono i guardrail scritti come frase, valutati da un modello (capitolo 13); qui il lavoro di giudizio lo fa il revisore, e il codice controlla quello che si può controllare con certezza.

3. Gli agenti#

Tre ruoli davvero diversi: chi cerca, chi scrive, chi corregge. La skill ufficiale design-agent suggerisce di aggiungere agenti solo quando cambiano strumenti o personalità; qui cambiano entrambi.

Python
stratega = Agent(
    role="Stratega di marketing per attività locali",
    goal="Capire a chi parlare e come comunicano le attività simili nella zona, citando solo fonti trovate",
    backstory=(
        "Hai aiutato decine di negozi e botteghe a farsi conoscere in città. "
        "Parti sempre dai fatti: se non trovi un'informazione, lo dici invece di immaginarla."
    ),
    tools=[SerperDevTool(n_results=5)],  # ricerca web (serve SERPER_API_KEY)
    llm=MODELLO,
    max_iter=8,
    verbose=True,
)

Solo lo stratega ha lo strumento di ricerca, con 5 risultati per ricerca invece dei 10 predefiniti: meno testo da leggere, meno Token: Il pezzetto di testo con cui ragiona un modello: una parola corta, un pezzo di parola o un segno di punteggiatura. Secondo le stime di OpenAI, in inglese un token vale in media circa ¾ di parola. I servizi a pagamento contano (e fanno pagare) i token. glossario da pagare. Copywriter e revisore non hanno strumenti: lavorano sul testo che ricevono. Nel revisore la backstory insiste su una cosa sola: togliere superlativi, prezzi, date o premi che nessuno ha confermato.

4. I task, senza agente#

I tre task descrivono il lavoro, ma nessuno ha agent=. Il collegamento tra loro lo dà context (capitolo 10):

Python
revisione = Task(
    description=(
        "Rivedi le tre bozze. Il tono deve essere: {tono}. Togli promesse non dimostrabili "
        "(garantito, il migliore, 100%...) e ogni prezzo, orario o dettaglio che non compare in: {dettagli}"
    ),
    expected_output=(
        "Un JSON con la lista 'post': per ogni canale i campi canale, testo (massimo 600 caratteri, "
        "in italiano) e hashtag (da 2 a 5, ognuno inizia con #)."
    ),
    context=[scrittura],
    output_pydantic=PianoPost,
    guardrail=controlla_post,
    guardrail_max_retries=2,
    output_file="post_social.json",
)

Nota il segnaposto {dettagli}: è la lista dei fatti veri (prezzo, orario, ingredienti) passata al kickoff. Scrittore e revisore la ricevono entrambi, così hanno un riferimento preciso per capire cosa è inventato. guardrail_max_retries=2 vuol dire che, se il controllo fallisce, il task si rifà al massimo altre due volte; poi la crew si ferma con un errore invece di consegnare post sbagliati.

5. La crew gerarchica#

Python
crew = Crew(
    agents=[stratega, copywriter, revisore],
    tasks=[analisi, scrittura, revisione],  # nessun task ha agent=: li assegna il manager
    process=Process.hierarchical,
    manager_llm=MODELLO,  # obbligatorio con il processo gerarchico
    verbose=True,
)

Senza manager_llm (o manager_agent, un manager scritto da te) la crew non parte: CrewAI 1.15.21 si ferma subito con l'errore «Attribute `manager_llm` or `manager_agent` is required when using hierarchical process».

Il codice completo#

Salva questo file come post_social.py nella cartella con il file .env.

post_social.py
# /// script
# requires-python = ">=3.10,<3.14"
# dependencies = ["crewai[tools]==1.15.21"]
# ///
"""Prepara tre post social per un'attività locale: un manager coordina stratega, copywriter e revisore."""
import os
from typing import Any

from crewai import Agent, Crew, Process, Task
from crewai_tools import SerperDevTool
from pydantic import BaseModel, Field

# Il modello si sceglie nel file .env (capitolo 7). Se MODEL manca, si usa quello scritto qui.
MODELLO = os.getenv("MODEL", "openai/gpt-4.1-mini")

CANALI = ("Instagram", "Facebook", "LinkedIn")
MAX_CARATTERI = 600  # limite scelto da noi per post brevi, non una regola dei social
PROMESSE_VIETATE = ("garantit", "il migliore", "la migliore", "numero uno", "100%", "certificat", "unico in citt")


class Post(BaseModel):
    canale: str = Field(description="Instagram, Facebook oppure LinkedIn")
    testo: str = Field(description="Il testo del post, pronto da copiare")
    hashtag: list[str] = Field(description="Da 2 a 5 hashtag, ognuno inizia con #")


class PianoPost(BaseModel):
    post: list[Post]


def controlla_post(risultato) -> tuple[bool, Any]:
    """Guardrail: controlla forma e contenuto dei post prima di accettarli."""
    testo = risultato.raw
    inizio, fine = testo.find("{"), testo.rfind("}")  # tengo solo la parte JSON
    try:
        piano = PianoPost.model_validate_json(testo[inizio:fine + 1])
    except ValueError:
        return (False, "Rispondi solo con il JSON richiesto: un oggetto con la lista 'post'.")
    if sorted(p.canale for p in piano.post) != sorted(CANALI):
        return (False, f"Serve esattamente un post per ciascun canale: {', '.join(CANALI)}.")
    for p in piano.post:
        if len(p.testo) > MAX_CARATTERI:
            return (False, f"Il post per {p.canale} supera {MAX_CARATTERI} caratteri: accorcialo.")
        if not 2 <= len(p.hashtag) <= 5 or any(not h.startswith("#") or " " in h for h in p.hashtag):
            return (False, f"Il post per {p.canale} deve avere da 2 a 5 hashtag, senza spazi, che iniziano con #.")
        trovate = [parola for parola in PROMESSE_VIETATE if parola in p.testo.lower()]
        if trovate:
            return (False, f"Il post per {p.canale} contiene promesse non dimostrabili ({', '.join(trovate)}): riformula.")
    return (True, piano.model_dump_json())  # tutto a posto: passo avanti il JSON pulito


stratega = Agent(
    role="Stratega di marketing per attività locali",
    goal="Capire a chi parlare e come comunicano le attività simili nella zona, citando solo fonti trovate",
    backstory=(
        "Hai aiutato decine di negozi e botteghe a farsi conoscere in città. "
        "Parti sempre dai fatti: se non trovi un'informazione, lo dici invece di immaginarla."
    ),
    tools=[SerperDevTool(n_results=5)],  # ricerca web (serve SERPER_API_KEY)
    llm=MODELLO,
    max_iter=8,
    verbose=True,
)

copywriter = Agent(
    role="Copywriter per i social",
    goal="Scrivere post brevi, concreti e adatti a ciascun canale",
    backstory=(
        "Sai che su Instagram conta l'immagine evocata, su Facebook la comunità del quartiere "
        "e su LinkedIn il racconto del lavoro. Usi solo i dettagli che ti vengono dati."
    ),
    llm=MODELLO,
    verbose=True,
)

revisore = Agent(
    role="Revisore del tono e della correttezza",
    goal="Consegnare post coerenti con il tono richiesto, senza promesse esagerate né dettagli inventati",
    backstory=(
        "Hai lavorato in un ufficio legale e in una redazione: togli superlativi, prezzi, date "
        "o premi che nessuno ti ha confermato, e mantieni il testo naturale."
    ),
    llm=MODELLO,
    verbose=True,
)

analisi = Task(
    description=(
        "Analizza pubblico e concorrenti per {attivita}, a {citta}, che vuole promuovere {novita}. "
        "Cerca sul web 2 o 3 attività simili nella zona e osserva come comunicano. "
        "Cita solo nomi e informazioni trovati, con il link della fonte."
    ),
    expected_output=(
        "Un brief in italiano con: il pubblico ideale in 3 punti, 3 osservazioni sui concorrenti "
        "ciascuna con il link della fonte, 3 messaggi chiave da usare."
    ),
)

scrittura = Task(
    description=(
        "Usando il brief, scrivi un post per ciascun canale (Instagram, Facebook, LinkedIn) "
        "per promuovere {novita} di {attivita}. Usa solo questi dettagli, senza aggiungerne: {dettagli}"
    ),
    expected_output="Tre bozze di post in italiano, una per canale, ognuna con 2-5 hashtag.",
    context=[analisi],
)

revisione = Task(
    description=(
        "Rivedi le tre bozze. Il tono deve essere: {tono}. Togli promesse non dimostrabili "
        "(garantito, il migliore, 100%...) e ogni prezzo, orario o dettaglio che non compare in: {dettagli}"
    ),
    expected_output=(
        "Un JSON con la lista 'post': per ogni canale i campi canale, testo (massimo 600 caratteri, "
        "in italiano) e hashtag (da 2 a 5, ognuno inizia con #)."
    ),
    context=[scrittura],
    output_pydantic=PianoPost,
    guardrail=controlla_post,
    guardrail_max_retries=2,
    output_file="post_social.json",
)

crew = Crew(
    agents=[stratega, copywriter, revisore],
    tasks=[analisi, scrittura, revisione],  # nessun task ha agent=: li assegna il manager
    process=Process.hierarchical,
    manager_llm=MODELLO,  # obbligatorio con il processo gerarchico
    verbose=True,
)

if __name__ == "__main__":
    risultato = crew.kickoff(
        inputs={
            "attivita": "il Forno Spiga Antica (attività inventata)",
            "citta": "Bologna",
            "novita": "il pane ai grani antichi del sabato",
            "dettagli": "pane con farina di grani antichi, solo il sabato dalle 8, 6 euro al chilo",
            "tono": "caldo e familiare, senza esagerazioni",
        }
    )
    print("\n=== POST PRONTI DA RILEGGERE ===")
    print(risultato)  # i tre post in formato JSON, salvati anche in post_social.json

Eseguirlo#

Dal terminale, nella cartella del progetto:

Terminale
uv run --env-file .env post_social.py

Con verbose=True vedrai prima il manager (il suo ruolo compare come Crew Manager) che ragiona su chi deve fare cosa e usa lo strumento di delega per passare il lavoro a un collega. Poi vedrai lo stratega che chiama la ricerca, il copywriter che scrive e il revisore che corregge. Se il guardrail blocca un tentativo, compare un riquadro rosso «Guardrail Failed» con il motivo e il task riparte.

Alla fine trovi il file post_social.json nella cartella. Ha questa forma (esempio illustrativo, il tuo sarà diverso):

post_social.json
{"post": [
  {"canale": "Instagram",
   "testo": "Il sabato mattina a Bologna profuma di grani antichi. Dalle 8 trovi il nostro pane nuovo, 6 euro al chilo.",
   "hashtag": ["#Bologna", "#panefresco", "#granigantichi"]},
  {"canale": "Facebook", "testo": "...", "hashtag": ["#Bologna", "#forno"]},
  {"canale": "LinkedIn", "testo": "...", "hashtag": ["#artigianato", "#Bologna"]}
]}

Non abbiamo eseguito questo esempio dal vivo con un modello: richiede una chiave Serper e un modello online. Lo script è stato verificato «a secco» con CrewAI 1.15.21 (costruzione di agenti, task e crew) e il guardrail è stato provato da solo su post validi, su post con «il migliore» e «garantito», su un canale mancante e su una risposta non in JSON: nei tre casi sbagliati restituisce False con il messaggio atteso.

Con un modello locale piccolo via Ollama: Programma gratuito che scarica ed esegue modelli linguistici sul tuo computer, senza chiavi e senza costi a consumo. glossario puoi provarlo gratis cambiando MODEL, ma tieni d'occhio il terminale: il manager deve usare correttamente gli strumenti di delega, e la ricerca Serper resta a pagamento oltre la quota gratuita.

Come migliorarlo#

  • Un umano approva prima della pubblicazione. Aggiungi human_input=True al task di revisione, oppure metti la crew dentro un flow con un passo di approvazione: è il Human in the loop: Un punto del processo in cui una persona controlla o approva prima che il lavoro prosegua. In CrewAI: human_input=True o @human_feedback. glossario del capitolo 3.
  • Un manager scritto da te. Invece di manager_llm, passa manager_agent= con un agente «Responsabile di account» con una backstory precisa sulle priorità dell'agenzia (capitolo 11). Il manager non deve avere strumenti propri: CrewAI 1.15.21 lo rifiuta.
  • Il tono dell'attività come knowledge. Metti in un file le linee guida del cliente (parole da usare, parole da evitare, esempi di post passati) e collegale come Knowledge: Documenti tuoi (PDF, testi, CSV…) messi a disposizione degli agenti come fonte da consultare. Ancora le risposte ai tuoi dati. glossario al copywriter e al revisore (capitolo 15).
  • Più canali, più controlli. Aggiungi un canale con un limite di caratteri diverso: trasforma MAX_CARATTERI in un dizionario canale → limite e usalo nel guardrail.
  • Una versione più economica. Passa a Process.sequential assegnando agent= a ciascun task: stesso risultato atteso, meno chiamate al modello. Confronta i token nel CrewOutput.
Attenzione

Contenuti inventati. Un modello scrive testi plausibili, non verifica fatti: può aggiungere un premio mai vinto, un ingrediente sbagliato o un orario falso. È un'Allucinazione: Quando un modello scrive con sicurezza una cosa falsa o inventata. Succede perché il modello genera testo plausibile, non verifica fatti. glossario come le altre, ma in un post pubblico diventa pubblicità ingannevole. Il guardrail riduce il rischio, non lo elimina: rileggi sempre ogni post confrontandolo con i dettagli veri.

Marchi e concorrenti. Lo stratega trova nomi reali di altre attività. Usali per capire il mercato, non per citarli o imitarli nei post: nomi, loghi e slogan altrui sono protetti. Non copiare testi trovati sul web.

Pubblicazione automatica. Questo script non pubblica niente, e va bene così. Collegarlo direttamente ai profili social (con strumenti di automazione o server MCP) significa che un errore del modello finisce online senza che nessuno lo veda. Se lo fai, tieni un'approvazione umana obbligatoria e account con permessi minimi (capitolo 17).

Prova tu: vieta le emoji nei post LinkedIn

Il cliente vuole post LinkedIn senza emoji. Aggiungi un controllo nel guardrail. Un modo semplice, che non richiede librerie: considera emoji i caratteri con codice Unicode maggiore di 0x1F000.

Soluzione: dentro il ciclo for p in piano.post:, prima del return (True, ...) finale, aggiungi:

if p.canale == "LinkedIn" and any(ord(c) > 0x1F000 for c in p.testo):
    return (False, "Il post LinkedIn non deve contenere emoji: toglile.")

Scrivi anche nella description del task di revisione «nessuna emoji nel post LinkedIn»: il guardrail controlla, ma è meglio che l'agente sappia la regola prima di sbagliare.

In breve
  • Con Process.hierarchical i task non hanno agente: un manager creato con manager_llm li assegna e controlla.
  • Il risultato finale è un PianoPost Pydantic: canale, testo e hashtag per ogni post, salvato in JSON.
  • Il guardrail legge il testo grezzo (risultato.raw), che c'è sempre; risultato.pydantic di solito si riempie solo dopo il suo ok.
  • Il codice controlla ciò che è certo (formato, lunghezza, parole vietate); il giudizio sul tono resta al revisore e, alla fine, a te.
  • Mai pubblicare in automatico: contenuti inventati e marchi altrui sono rischi reali.

Nell'ultimo esempio affronti il caso più delicato: usare gli agenti per aiutare chi seleziona il personale, con tutte le cautele che la legge europea richiede.

Corso indipendente, non affiliato a CrewAI Inc. Contenuti verificati su CrewAI 1.15.21 il 15 settembre 2026.