Creazione di workflow agentici con LangGraph e Granite

Autore

Vrunda Gadesha

AI Advocate | Technical Content Author

I moderni sistemi di AI si stanno evolvendo oltre le semplici interazioni di prompt-risposta. Gli agenti di oggi possono eseguire ragionamenti strutturati e in più fasi, processi decisionali e coordinare attività complesse in modo autonomo. Agente AI Questa capacità emergente è nota come workflow agentico—un potente cambiamento nel machine learning in cui gli agenti operano attraverso una serie di passaggi logici per risolvere i problemi in modo più efficace.

In questo tutorial, esploreremo come creare tali workflow di agentic AI utilizzando due strumenti chiave: LangGraph, un framework per la costruzione di percorsi di ragionamento basati su grafici e i modelli IBM Granite, una soluzione robusta che integra questa struttura. Ogni fase del workflow, chiamata "nodo", è gestita da un agente, tipicamente basato su modelli linguistici di grandi dimensioni. Questi agenti si spostano tra gli stati in base agli output del modello o alla logica condizionale, formando un grafico dinamico e basato sulle decisioni.

Per dare vita a questi workflow, esamineremo più da vicino due componenti essenziali: LangGraph e Granite.

Comprendere LangGraph

Un framework per workflow scalabile e basato su AI

LangGraph è un potente framework progettato per semplificare lo sviluppo di workflow basati su AI rappresentando i modelli AI come agenti stateful all'interno di un grafico computazionale. Consente agli sviluppatori di creare sistemi Scalabili, modulari in cui ogni comportamento o punto decisionale è definito come un nodo nel grafico.

Con LangGraph puoi:

  • Definire il comportamento di ogni agente come un nodo distinto
  • Usa algoritmi o output del modello per determinare il prossimo passo
  • Passare lo stato tra i nodi per preservare la memoria e il contesto
  • Visualizza, esegui il debug e controlla il flusso del ragionamento con facilità

I sistemi e i framework multiagente come LangGraph, se applicati alle attività di AI generativa (gen AI), in genere strutturano l'esecuzione delle attività come workflow sequenziali o condizionali. Che tu stia lavorando conLangChain, i modelli IBM Granite, i modelli GPT di OpenAI o altri strumenti di intelligenza artificiale, LangGraph aiuta a ottimizzare il workflow per scalabilità e prestazioni migliori.

Componenti chiave di LangGraph per l'automazione dei workflow complessi

LangGraph introduce un approccio moderno all'orchestrazione delle tecnologie AI, scomponendo i workflow complessi in componenti modulari e intelligenti. A differenza dell'automazione tradizionale o dell'automazione robotica dei processi (RPA), LangGraph consente l'esecuzione di attività dinamiche e sensibili al contesto utilizzando logica e memoria in tempo reale. Ecco i quattro componenti chiave su cui si basa questo framework:

  • Nodi: i nodi rappresentano singole unità di logica o azione, come chiamare uno strumento di AI, interrogare fonti di dati o eseguire un'attività specifica. Sono ideali per automatizzare le attività ripetitive all'interno di processi aziendali più ampi.
  • Edge: gli edge definiscono il flusso tra i nodi, guidando il modo in cui le attività vengono connesse ed eseguite. Questa struttura supporta processi decisionali flessibili e consente ai workflow di adattarsi in base agli esiti.
  • Edge condizionali (grafi ciclici): i grafi ciclici consentono loop e ramificazioni condizionali, consentendo al sistema di rivisitare i nodi in base alla logica o agli output. Questa capacità è fondamentale per gestire attività iterative e prendere decisioni informate in ambienti dinamici.
  • Stato (grafi stateful): lo stato funziona da memoria condivisa, preservando il contesto e consentendo l'uso di dati in tempo reale tra i nodi. Questa capacità consente a LangGraph di andare oltre i flussi statici e supportare progressi adattivi e intelligenti nell'nell'automazione del workflow.

Insieme, questi componenti consentono a LangGraph di trasformare il modo in cui le organizzazioni progettano ed eseguono i workflow basati su AI, colmando il divario tra gli strumenti AI e i processi aziendali del mondo reale.

Componenti chiave di LangGraph per l'automazione dei workflows complessi Figura 1 Componenti chiave di LangGraph per l'automazione di workflow complessi

Modello Granite: LLM leggero per la risoluzione dei problemi nel mondo reale

Granite-4.0-Tiny-Preview, sviluppato da IBM Research, è un modello di linguaggio open source leggero ma efficiente, progettato per risolvere problemi complessi e attività pratiche di elaborazione del linguaggio naturale (NLP). Sebbene sia più piccolo dei modelli commerciali come GPT-4, Granite è veloce, efficiente e completamente compatibile con Hugging Face, una caratteristica che lo rende un'ottima scelta per gli sviluppatori che cercano l'efficienza operativa senza rinunciare alle prestazioni.

Granite eccelle in:

  • Classificazione delle intenzioni: identificazione degli obiettivi degli utenti nei chatbot o nei sistemi basati su attività
  • Generazione creativa: produzione di riassunti, dialoghi o contenuti in formato breve
  • Ragionamento e riepilogo: l'ideale per workflow che coinvolgono il RAG o l'analisi dei dati

In questo tutorial, il modello Granite svolge un ruolo chiave in diverse fasi del workflow agentico, supportando sia la risoluzione dei problemi che la generazione di contenuti. Il suo design leggero lo rende adatto per le applicazioni del mondo reale in cui l'intervento umano potrebbe essere limitato e in cui modelli di progettazione scalabile sono essenziali per creare solide soluzioni di AI su diversi set di dati e fornitori.

Caso d’uso

In questo tutorial, creeremo un workflow che funge da assistente creativo per la scrittura di brevi sceneggiature animate.

Obiettivo

Data un'idea di storia da parte dell'utente, l'agente si occuperà di:

  • Identifica il genere e il tono adatti alla storia
  • Generare un breve schema della trama
  • Espanderlo in una scena chiave (ad esempio, climax o punto di svolta)
  • Scrivere i dialoghi per quella scena in formato sceneggiatura

Questo caso d'uso è progettato per mostrare sia le funzionalità di ragionamento che quelle generative di un modello linguistico, strutturato tramite il workflow compositivo di LangGraph.

Come funziona il workflow

Ognuno dei passaggi seguenti viene implementato come nodo LangGraph:

  • Input: l'utente fornisce un'idea di storia di alto livello per avviare il workflow.
  • Rilevamento del genere (node_name - select_genre): un LLM analizza l'input per dedurre il genere e il tono appropriati per la storia.
  • Generazione dello schema (node_name - generate_outline): l'LLM genera un breve riassunto della trama in base al genere selezionato.
  • Scrittura delle scene (node_name - generate_scene): l'LLM scrive una scena fondamentale in prosa, dando vita alla storia.
  • Scrittura dei dialoghi (node_name - write_dialogue): l'LLM riscrive la scena come dialogo di sceneggiatura formattato, adatto per la produzione o l'ulteriore editing.

Questi nodi sono collegati in sequenza in un LangGraph e il modello si sposta attraverso di essi portando avanti un dizionario di stati modificabile.

Questo workflow crea un equilibrio tra generazione creativa e pianificazione strutturale. Dimostra:

  • Coordinamento LLM tramite LangGraph
  • Narrazione in più fasi con un intervento manuale minimo
  • Automazione creativa in un settore in cui l'immaginazione umana è essenziale

Inoltre si ridimensiona bene, puoi facilmente estenderlo aggiungendo passaggi di revisione, più generatori di scene o persino ramificazioni basate sui personaggi.

Prerequisiti

Per creare un progetto watsonx.ai è necessario un account IBM Cloud .

Passaggi

Passaggio 1. Configurare il tuo ambiente

Sebbene sia possibile scegliere tra diversi strumenti, questo tutorial illustra come configurare un account IBM per utilizzare un Jupyter Notebook.

  1. Accedi a watsonx.ai utilizzando il tuo account IBM Cloud.
  2. Crea un progetto watsonx.ai. Puoi ottenere l'ID del tuo progetto dall'interno del tuo progetto. Clicca sulla scheda Gestisci. Quindi, copia l'ID del progetto dalla sezione Dettagli della pagina Generali. Per questo tutorial ti serve questo ID.
  3. Crea un Jupyter Notebook.

Questo passaggio apre un ambiente notebook in cui è possibile copiare il codice da questo tutorial. In alternativa, puoi scaricare questo notebook sul tuo sistema locale e caricarlo nel tuo progetto watsonx.ai come asset. Per visualizzare altri tutorial su Granite, visita l'IBM Granite Community. Questo tutorial è disponibile anche su GitHub

Passaggio 2. Configurare un servizio watsonx.ai Runtime e una chiave API

  1. Crea un'istanza di servizio watsonx.ai Runtime (scegli il piano Lite, che è un'istanza gratuita).
  2. Genera una chiave application programming interface (chiave API).
  3. Associa il servizio watsonx.ai Runtime al progetto che hai creato in watsonx.ai.

Passo 3. Installazione delle librerie necessarie

Questa cella installa le librerie di base necessarie per utilizzare il modello IBM Granite ospitato su Hugging Face:

  • transformers: Questa è la libreria principale per caricare e interagire con modelli linguistici preformati, tra cuigranite-4.0-tiny-preview .
  • accelerate:  Aiuta a caricare in modo efficiente i modelli e a posizionare i dispositivi, particolarmente utile per l'utilizzo delle GPU in modo continuo.

Il-q esegue l'installazione in modo silenzioso, sopprimendo l'output dettagliato per un'interfaccia notebook più pulita. Queste librerie sono essenziali per scaricare il modello e gestire l'inferenza in modo efficiente in questo tutorial.

Nota: se stai eseguendo questo tutorial in un ambiente virtuale e non hai langgrapg preinstallato, usa pip install langgraph per installarlo nel tuo ambiente locale.

!pip install -q transformers accelerate
Schermata di un terminale che notifica una nuova versione di PiP Frammento di output: creazione di un workflow agentico: installazione delle librerie

Passo 4. Importare le librerie necessarie

Questa cella importa tutte le librerie principali necessarie per creare ed eseguire il workflow:

AutoTokenizer eAutoModelForCausalLM datransformers : utilizzato per caricare il modello Granite e tokenizzare i prompt di input per la generazione.

torch : fornisce l'accelerazione della GPU e le operazioni tensoriali necessarie per l'inferenza del modello.

time: Consente il monitoraggio facoltativo del tempo e delle prestazioni.

StateGraph eEND dalanggraph.graph : vengono utilizzati per definire e compilare il grafo del workflow agentico.

IPython.display ,base64: Utilizzato per rendere l'output in modo ordinato e abilitare le caratteristiche di download opzionali per i contenuti generati nei Jupyter Notebook.

Insieme, queste importazioni preparano l'ambiente per l'interazione dei modelli, la strutturazione del workflow e la presentazione dell'output.

# Import libraries
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
import time
from langgraph.graph import StateGraph, END
from IPython.display import display, HTML
import base64

Fase 5. Caricamento del modello e del tokenizer Granite

Questa cella carica un modellogranite-4.0-tiny-preview IBM e il suo tokenizzatore corrispondente da Hugging Face:

model_id: Specifica l'identificatore del modello preaddestrato ospitato su Hugging Face.

AutoTokenizer.from_pretrained(model_id): Carica il tokenizzatore associato al modello Granite. Il tokenizzatore è responsabile della conversione del testo leggibile dall'uomo in token di input per il modello.

AutoModelForCausalLM.from_pretrained(...): Carica il modello linguistico effettivo per la modellazione del linguaggio causale (cioè generativa). Questo modello può prevedere e generare output di testo in base all'input.

Iltorch_dtype=torch.float32 imposta esplicitamente il tipo di dati su float32, che è più efficiente in termini di memoria e ampiamente compatibile, particolarmente utile in ambienti con vincoli di GPU.

Questo passaggio inizializza efficacemente il modello Granite come "motore di ragionamento" alla base del nostro workflow.

#Load Granite-4.0-Tiny-Preview model and tokenizer from Hugging Face
model_id = "ibm-granite/granite-4.0-tiny-preview"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id, torch_dtype=torch.float32)
Frammento di output che indica che il percorso rapido non è disponibile Frammento di output: crea un workflow agentico: caricamento del modello Granite

Fase 6. Funzione utility per generare testo con Granite

Questa funzione,generate_with_granite , racchiude il processo di generazione del testo utilizzando il modello Granite. Accetta il prompt che costituisce il testo di input per guidare la risposta del modello.

max_tokens : il numero massimo di token da generare nell'output (impostazione predefinita: 200).

use_gpu : un flag che indica se eseguire l'inferenza sulla GPU (se disponibile).

Dettagli principali:

device = torch.device(...): Seleziona dinamicamente la GPU (cuda) se richiesta e disponibile; in caso contrario, il valore predefinito è CPU.

model.to(device): Carica il modello sul dispositivo appropriato appena in tempo, contribuendo a risparmiare memoria.

tokenizer(prompt, return_tensors="pt"): Converte la stringa di input in tensori token per l'elaborazione del modello.

model.generate(...): Avvia la generazione del testo con strategie di campionamento, tra cui:

  • do_sample=True: Consente la casualità per output più creativi.

  • temperature=0.7 etop_p=0.9: Controlla la diversità del testo generato.

tokenizer.decode(...): Converte nuovamente i token generati in testo leggibile, rimuovendo eventuali token speciali.

Questa funzione verrà riutilizzata in tutto il workflow agentico per richiamare il modello Granite in vari nodi decisionali o di generazione.

def generate_with_granite(prompt: str, max_tokens: int = 200, use_gpu: bool = False) -> str:
    device = torch.device("cuda" if use_gpu and torch.cuda.is_available() else "cpu")

    # Move model to device only at generation time
    model.to(device)
    inputs = tokenizer(prompt, return_tensors="pt").to(device)

    outputs = model.generate(
        **inputs,
        max_new_tokens=max_tokens,
        do_sample=True,
        temperature=0.7,
        top_p=0.9,
        pad_token_id=tokenizer.eos_token_id
    )

    return tokenizer.decode(outputs[0], skip_special_tokens=True).strip()

 

Passaggio 7. Creare un nodo per la selezione del genere e del tono (node-1)

Questa funzione,select_genre_node , definisce il primo nodo nel nostro workflow di generazione di sceneggiature agentiche. Utilizza il modello Granite per determinare il genere e il tono della storia in base all'input dell'utente.

Input:state , un dizionario che include"user_input" (per esempio, "Voglio scrivere una storia fantasy stravagante per bambini").

Costruzione del prompt: la richiesta chiede al modello di:

  • Svolgere il ruolo di assistente creativo.
  • Analizzare l'input dell'utente.
  • Consigliare un genere e un tono utilizzando un formato di output specifico:Genre: <genre> eTone: <tone>

Generazione del testo: il prompt viene passato alla funzione di utilitàgenerate_with_granite() per generare una risposta creativa.

Analisi dell'output: un semplice ciclo estrae il genere e il tono dalla risposta del modello in base ai prefissi di riga ("Genre:" e"Tone:" ).

Aggiornamento stato: i valorigenre etone estratti vengono reinseriti nel dizionario di stato che verrà passato al nodo successivo.

Questo nodo agisce come classificatore creativo, consentendo ai nodi successivi di generare contorni, strutture e scene contestualmente allineati, utilizzando il genere e il tono come parametri fondamentali.

def select_genre_node(state: dict) -> dict:
    prompt = f"""
You are a creative assistant. The user wants to write a short animated story.
Based on the following input, suggest a suitable genre and tone for the story.
User Input: {state['user_input']}

Respond in this format:
Genre: <genre>
Tone: <tone>
""".strip()

    response = generate_with_granite(prompt)

    # Basic parsing of output
    genre, tone = None, None
    for line in response.splitlines():
        if "Genre:" in line:
            genre = line.split("Genre:")[1].strip()
        elif "Tone:" in line:
            tone = line.split("Tone:")[1].strip()

    # Update state
    state["genre"] = genre
    state["tone"] = tone
    return state

Passaggio 8. Creare un nodo per la generazione del contorno del grafico (node - 2)

Ilgenerate_outline_node definisce il secondo nodo nel workflow di generazione della sceneggiatura. Si basa sul genere e sul tono selezionati per generare una trama concisa per la storia.

Input: la funzione riceve il dizionario di stato contenente:

  • user_input: l'idea originale della storia.
  • genre: selezionato nel nodo precedente.
  • tone: selezionato nel nodo precedente.

Costruzione del prompt: il modello è incaricato di:

  • Agire come assistente di scrittura creativa.
  • Considerare l'idea, il genere e il tono dell'utente.
  • Generare un breve schema della trama (3-5 frasi) adatto per una breve sceneggiatura animata.

Generazione del testo: il prompt viene inviato agenerate_with_granite() con un valore più altotoken limit (max_tokens=250) per lasciare spazio a uno schema di più frasi.

Aggiornamento dello stato: il contorno della trama generata viene aggiunto allo stato sotto la chiave"outline" , pronto per l'uso nella fase successiva di espansione della struttura.

Questo nodo traduce l'intento creativo astratto in uno schizzo narrativo, fornendo un'impalcatura per la struttura dettagliata in tre atti che segue. Assicura che i nodi a valle funzionino a partire da una linea di base coerente e fantasiosa.

def generate_outline_node(state: dict) -> dict:
    prompt = f"""
You are a creative writing assistant helping to write a short animated screenplay.
The user wants to write a story with the following details:
Genre: {state.get('genre')}
Tone: {state.get('tone')}
Idea: {state.get('user_input')}

Write a brief plot outline (3–5 sentences) for the story.
""".strip()

    response = generate_with_granite(prompt, max_tokens=250)
    state["outline"] = response
    return state

Passaggio 9. Creare un nodo per generare una scena chiave dal contorno (node - 3)

Ilgenerate_scene_node definisce la terza fase del workflow in cui lo schema della trama viene trasformato in una ricca scena narrativa. Questa scena funge da vivida drammatizzazione di una svolta nella storia, spostando l'idea dal riassunto alla narrazione.

Input: il nodo accetta il dizionario di stato, che ora include:

  • genre etone
  • Ilplot outline dal nodo precedente

Costruzione del prompt: il modello è incaricato di:

  • Agire come sceneggiatore
  • Generare una scena di svolta o di climax utilizzando la storiagenre ,tone eoutline
  • Scrivere in formato prosa per preservare la leggibilità e una descrizione adatta alle animazioni

Requisiti della scena:

  • Vivida e descrittiva (adatta all'animazione)
  • Centrale nell'arco emotivo o narrativo (ad esempio, scoperta, conflitto o risoluzione)

Generazione di testo:generate_with_granite è chiamato conmax_tokens=300 , lasciando abbastanza spazio per la creazione di scene immersive.

Aggiornamento dello stato: la scena generata viene aggiunta al dizionario di stato sotto la chiave"scene" .

Introduce l'immersione narrativa e la narrazione visiva nel workflow. Invece di limitarsi a riassumere la storia, questo nodo la fa rivivere con dettagli sensoriali ed emotivi, essenziali per la sceneggiatura di cortometraggi animati.

def generate_scene_node(state: dict) -> dict:
    prompt = f"""
You are a screenwriter.
Based on the following plot outline, write a key scene from the story.
Focus on a turning point or climax moment. Make the scene vivid, descriptive, and suitable for an animated short film.

Genre: {state.get('genre')}
Tone: {state.get('tone')}
Outline: {state.get('outline')}

Write the scene in prose format (not screenplay format).
""".strip()

    response = generate_with_granite(prompt, max_tokens=300)
    state["scene"] = response
    return state

Passaggio 10. Creare un nodo per la scrittura dei dialoghi dei personaggi in formato sceneggiatura (node - 4)

Ilwrite_dialogue_node definisce la quarta fase creativa del workflow di narrazione: la conversione di una scena narrativa in dialoghi formattati dei personaggi. Questo passaggio colma il divario tra la prosa e la sceneggiatura pronta per lo schermo, dando voce ai personaggi.

Input: il nodo si aspetta lo statoscene per contenere un momento vivido della storia (in genere una svolta o un climax).

Costruzione del prompt: il modello viene guidato verso:

  • Agire come scrittore di dialoghi
  • Estrarre e adatta i dialoghi dalla scena
  • Formattare l'output in stile sceneggiatura utilizzando:CHARACTER: Dialogue line

Linee guida per il dialogo:

  • Essere brevi ed espressivi
  • Assicurarsi che sia appropriato per l'animazione (visiva, emotiva, concisa)
  • Inventare dei nomi se necessario per chiarezza

Generazione: la chiamatagenerate_with_granite() utilizzamax_tokens=300 , che bilancia espressività e brevità, l'ideale per brevi sceneggiature animate.

Aggiornamento dello stato: la finestra di dialogo viene salvata nello stato con la chiavedialogue per i passaggi futuri (ad esempio, visualizzazione o modifica).

def write_dialogue_node(state: dict) -> dict:
    prompt = f"""
You are a dialogue writer for an animated screenplay.

Below is a scene from the story:
{state.get('scene')}

Write the dialogue between the characters in screenplay format.
Keep it short, expressive, and suitable for a short animated film.

Use character names (you may invent them if needed), and format as:

CHARACTER:
Dialogue line

CHARACTER:
Dialogue line
""".strip()

    response = generate_with_granite(prompt, max_tokens=300)
    state["dialogue"] = response
    return state

Fase 11. Aggiungere dei report sullo stato di avanzamento a ciascun nodo

Questa funzione ausiliariawith_progress è progettata per integrare ogni nodo del workflow con indicatori di avanzamento in tempo reale. Non altera la logica della funzione originale: si limita a tracciare e stampare lo stato e i tempi di esecuzione per rendere più trasparenti i workflow lunghi.

Scopo della funzione: racchiudere un nodo (ad esempio, generate_scene_node) con un decorator che registra:

  • Quale passaggio è in esecuzione
  • Indice dei passaggi e conteggio totale
  • Quanto tempo impiega il passaggio

Parametri:

  • fn : la funzione del nodo effettiva (ad esempio, write_dialogue_node)
  • label : un'etichetta leggibile per quella funzione
  • index : numero di passaggi nella sequenza (ad esempio, 2)
  • total : numero totale di passaggi nel workflow

Wrapper interno:

  • Stampa un messaggio iniziale
  • Orario di inizio delle registrazioni
  • Chiama la funzione originale
  • Stampa un messaggio di completamento con la durata trascorsa

Restituisce: una versione modificata della funzione che aggiunge messaggi di avanzamento ma per il resto si comporta in modo identico.

Man mano che i workflow progrediscono, diventa importante tenere traccia della fase che viene eseguita, soprattutto se alcune fasi (come la generazione o la modifica) richiedono più tempo o possono causare problemi come il sovraccarico della memoria. Il wrapper dell'avanzamento garantisce la trasparenza ed è utile per il debug e la diagnostica del tempo di esecuzione.

# Wrap with progress reporting

def with_progress(fn, label, index, total):
    def wrapper(state):
        print(f"\n[{index}/{total}] Starting: {label}")
        start = time.time()
        result = fn(state)
        duration = time.time() - start
        print(f"[{index}/{total}] Completed: {label} in {duration:.2f} seconds")
        return result
    return wrapper

Passaggio 12. Definizione del workflow LangGraph

Questa cella definisce la logica del workflow per generare una breve storia animata utilizzando LangGraph, un framework di programmazione basato su grafici compositivi progettato per il flusso di lavoro LLM. Ogni passaggio nel grafico rappresenta un'attività creativa e viene eseguito in una sequenza specifica per produrre la sceneggiatura finale.

Componenti del workflow:StateGraph(dict)  - Inizializza il workflow con uno stato basato su un dizionario (ovvero, la memoria di lavoro è un dict passato da un nodo all'altro).

Registrazione del nodo con monitoraggio dei progressi: ogni passaggio (selezione del genere, generazione di contorni, scrittura di scene, scrittura di dialoghi) viene aggiunto come nodo con il wrapper with_progress () - 

graph.add_node("select_genre", with_progress(select_genre_node, "Select Genre", 1, 4)) 

Questo approccio garantisce che ogni nodo registri il tempo di esecuzione e il progresso quando viene eseguito.

Edge dei workflow (sequenziamento dei nodi): la sequenza della pipeline creativa è chiaramente definita:

select_genre → generate_outline → generate_scene → write_dialogue

 

set_entry_point() eset_finish_point(): Definiscono i nodi di inizio e fine del workflow.

graph.compile(): Compila il workflow in una forma eseguibile (workflow) che ora può essere richiamato con uno stato iniziale.

Questa struttura consente un workflow LLM modulare, leggibile e debuggabile. Ogni fase del processo creativo è isolata, può essere profilata separatamente e successivamente scambiata o estesa (ad esempio, aggiungendo un passaggio "revisiona scena" o un nodo "riepiloga output"). Il flagworkflow è ora pronto per essere eseguito con un prompt ed eseguirà la sua pipeline creativa passo dopo passo, mostrando i progressi in tempo reale.

# Define LangGraph

graph = StateGraph(dict)
graph.add_node("select_genre", with_progress(select_genre_node, "Select Genre", 1, 4))
graph.add_node("generate_outline", with_progress(generate_outline_node, "Generate Outline", 2, 4))
graph.add_node("generate_scene", with_progress(generate_scene_node, "Generate Scene", 3, 4))
graph.add_node("write_dialogue", with_progress(write_dialogue_node, "Write Dialogue", 4, 4))

graph.set_entry_point("select_genre")
graph.add_edge("select_genre", "generate_outline")
graph.add_edge("generate_outline", "generate_scene")
graph.add_edge("generate_scene", "write_dialogue")
graph.set_finish_point("write_dialogue")

workflow = graph.compile()

 

Fase 13. Esecuzione del workflow LangGraph e visualizzazione dell'output

Quest'ultima cella di codice è dove esegui l'intero workflow creativo e mostra i risultati di ogni fase della generazione della storia.

initial_state: Questo comando è il punto di partenza del workflow, in cui l'utente fornisce un'idea creativa o un tema. L'user_input funge da seme per la pipeline della storia.

final_state: Questo comando attiva l'intera pipeline LangGraph. L'input viene passato attraverso ogni nodo registrato (select_genre, generate_outline, generate_scene e write_dialogue) in sequenza.

Visualizzazione dei risultati: il dizionario di stato finale ora contiene chiavi popolate da vari nodi:

  • "genre": Il genere identificato in base all'input dell'utente.
  • "tone": La qualità tonale della storia.
  • "outline": un riassunto della trama di 3-5 frasi.
  • "scene": Una vivida scena di svolta scritta in prosa.
  • "dialogue": Dialogo dei personaggi formattato come sceneggiatura.

Questa sezione dimostra come l'intento dell'utente viene trasformato in un miniscript completo attraverso un workflow modulare e graduale. Si tratta di una pipeline creativa end-to-end interattiva, interpretabile e personalizzabile.

Nota: l'esecuzione del codice richiederà circa 15-17 minuti se si utilizza una GPU o un TPU. Ci vorranno circa 65-70 minuti di tempo su un ambiente virtuale locale per eseguire e generare l'output, in base all'infrastruttura utilizzata per eseguire il cede.

# Run workflow
initial_state = {
    "user_input": "I want to write a whimsical fantasy story for children about a lost dragon finding its home."
}
final_state = workflow.invoke(initial_state)

# Display Results
print("\n=== Final Output ===")
print("Genre:", final_state.get("genre"))
print("Tone:", final_state.get("tone"))
print("\nPlot Outline:\n", final_state.get("outline"))
print("\nKey Scene:\n", final_state.get("scene"))
print("\nDialogue:\n", final_state.get("dialogue"))
Snippet di output che registra il tempo impiegato per ogni passaggio (da 90 a 260 secondi)
Output della trama e delle scene chiave di una storia fantasy
Frammenti di output di una storia fantasy
Frammenti di output di una storia fantasy
Frammenti di output di una storia fantasy

Cerchiamo di capire come il sistema trasforma il prompt dell'utente, "Voglio scrivere una storia fantasy per bambini su un drago perduto che trova la sua casa", in una storia animata completa. Ogni passaggio si basa su quello precedente, guidato dai nodi creativi del workflow e potenziato dal modello Granite.

1. Genere e tono. Il workflow inizia interpretando il prompt dell'utente: Voglio scrivere una storia fantasy per bambini su un drago perduto che trova la sua casa. Sulla base di questo input, select_genre_node classifica correttamente la narrazione come fantasy stravagante e identifica il tono incantevole e commovente appropriato. Questo risultato è accurato e contestualmente allineato, poiché l'uso di frasi come "stravagante", "per bambini" e "drago perduto che trova la sua casa" segnala chiaramente uno stile narrativo magico ma delicato. Il genere e il tono agiscono come parametri fondamentali che modellano ogni fase di generazione successiva nel workflow.

2. Trama e descrizioni dei personaggi. Nella fase successiva, al modello viene chiesto di creare una trama basata sul genere, sul tono e sull'idea originale dell'utente identificati. L'output include non solo un riepilogo della storia di 3-5 frasi, ma anche descrizioni di personaggi bonus, probabilmente dovute a un leakage del prompt o alla formattazione conservata delle istruzioni rispetto alle iterazioni precedenti.

La trama è incentrata su una ragazza di nome Lily che scopre un drago ferito e lo aiuta a tornare nella foresta incantata con la guida di un vecchio erborista. Questa trama rispecchia esattamente l'intento dell'utente: concentrarsi su un viaggio magico a misura di bambino con sfumature emotive sulla guarigione, l'appartenenza e l'amicizia. Gli schizzi dei personaggi del drago, di Lily e dell'erborista aggiungono profondità, trasformando un'idea vaga in un concetto strutturato con ruoli, personalità e responsabilità narrative definiti. Questo passaggio garantisce che la storia passi da un'intenzione astratta a una struttura tangibile adatta all'adattamento cinematografico.

3. Scena chiave. Dato lo schema completo della trama,generate_scene_node scrive una scena vivida in prosa che cattura un punto di svolta nella storia, un altro elemento esplicitamente richiesto nell'intento originale dell'utente di sviluppare una breve sceneggiatura di animazione.

Il momento scelto è quando Lily si prende cura del drago ferito nella foresta incantata, stabilendo un rapporto emotivo e una comprensione reciproca tra i personaggi. Questo momento è critico perché fa da snodo alla storia verso il ritorno a casa del drago. La scena è ricca di immagini ed emozioni, aderisce ai vincoli "stravaganti" e "commoventi" pur essendo visivamente espressiva, perfettamente adatta per un breve formato animato.

La capacità del modello di mantenere la coerenza del tono e del genere tra le fasi dimostra il valore del workflow di LangGraph per il passaggio degli stati e le funzionalità del modello Granite.

4. Dialogo in formato sceneggiatura. Infine,write_dialogue_node converte la scena in prosa in un dialogo strutturato in formato sceneggiatura. Il prompt dell'utente, incentrato sulla creazione di una storia per l'animazione, richiede implicitamente che la narrazione sia presentata in un formato pronto per la produzione o la visualizzazione. Questo nodo raggiunge l'obiettivo offrendo un dialogo ben formattato tra Lily, Drago (il drago) e il vecchio erborista in due scene distinte: il cottage e la foresta incantata. Il dialogo preserva gli spunti emotivi e l'intento del personaggio ed è formattato per soddisfare le convenzioni di scrittura degli script di animazione (ad esempio, i nomi dei personaggi in maiuscolo, i titoli delle scene come[INT. LILY’S COTTAGE - DAY]) L'output rimane breve, espressivo ed emotivamente coinvolgente, un aspetto essenziale per coinvolgere il un pubblico giovane in un contesto animato.

Ogni fase del workflow traduce il prompt originale "una storia fantasy per bambini su un drago perduto che trova la sua casa" in un output narrativo strutturato, creativo ed espressivo. Dalla selezione del genere alla formattazione dei dialoghi, il sistema crea in modo incrementale un arco narrativo coerente. Il framework LangGraph garantisce che le transizioni tra le attività siano connesse logicamente e il modello IBM Granite consente la generazione di testo sensibile al contesto con un tono coerente. Il risultato è una breve storia di animazione compatta e pronta per lo schermo che emerge interamente da un input utente a riga singola e che dimostra la potenza pratica dei workflow agentici nelle applicazioni di AI creative.

Per rendere l'esperienza di narrazione ancora più coinvolgente, ecco una semplice visualizzazione basata su HTML che formatta magnificamente gli elementi della storia generati: genere, tono, trama, scena e dialogo. Inoltre, con un solo clic, è possibile scaricare l'intero script come file di testo per un uso futuro o per la condivisione. Diamo vita alla storia sullo schermo!

# Beautification and Downloadable option creation for user

def display_output_with_download(final_state):
    genre = final_state.get("genre", "")
    tone = final_state.get("tone", "")
    outline = final_state.get("outline", "")
    scene = final_state.get("scene", "")
    dialogue = final_state.get("dialogue", "")

    # Combine scene and dialogue into a full script
    script = f"""Genre: {genre}
Tone: {tone}
Outline:
{outline}
Scene:
{scene}
Dialogue:
{dialogue}
"""

    # Encode to base64
    b64_script = base64.b64encode(script.encode()).decode()

    # Create downloadable HTML content
    html = f"""
    <h2>Genre & Tone</h2>
    <p><strong>Genre:</strong> {genre}</p>
    <p><strong>Tone:</strong> {tone}</p>

    <h2>Outline</h2>
    <pre>{outline}</pre>

    <h2>Scene</h2>
    <pre>{scene}</pre>

    <h2>Dialogue</h2>
    <pre>{dialogue}</pre>

    <a download="screenplay_script.txt" href="data:text/plain;base64,{b64_script}">
        <button style="margin-top: 20px; padding: 10px 20px; font-size: 16px;">Download Script as .txt</button>
    </a>
    """
    display(HTML(html))

# Run this after workflow.invoke()
display_output_with_download(final_state)

Note sull'utilizzo della GPU e sull'infrastruttura

Questo tutorial utilizza il modello per la generazione di testo Granite-4.0-Tiny-Preview. Sebbene sia uno dei modelli più piccoli della famiglia Granite, richiede comunque un ambiente abilitato alla GPU per funzionare in modo efficiente, soprattutto quando si eseguono più nodi in un workflow LangGraph.

Configurazione consigliata:

  • Almeno una GPU NVIDIA V100 o A100
  • Almeno 16 GB di memoria GPU per prestazioni stabili
  • Python 3.8+ con torch, trasformatori e langgraph installati

Note sulle prestazioni:

  • Se si eseguono tutti i nodi in sequenza senza cancellare la memoria della GPU, potrebbero verificarsi errori di memoria CUDA insufficiente.
  • Per ridurre al minimo i problemi di memoria:
    • Sposta il modello su GPU solo durante la generazione e poi di nuovo su CPU.
    • Mantieni modesti i token di generazione (max_tokens=200-300).
    • Facoltativamente, rimuovere o semplificare nodi come la revisione o l'espansione dettagliata della scena.

Se stai eseguendo questo tutorial in un ambiente notebook in hosting (ad esempio, IBM watsonx.ai o Google Colab Pro), assicurati che la GPU sia abilitata nelle impostazioni di tempo di esecuzione.

Per gli ambienti con poche risorse, prendi in considerazione:

Riepilogo

In questo tutorial, abbiamo creato un workflow modulare e agentico per lo storytelling utilizzando LangGraph e il modello linguistico Granite-4.0-Tiny-Preview di IBM. Partendo da un semplice prompt, abbiamo costruito una pipeline passo dopo passo che classifica genere e tono, genera una struttura della trama, scrive una scena chiave e termina con dialoghi in stile sceneggiatura. Lungo il percorso, abbiamo dimostrato come:

  • Strutturare i workflow dinamici utilizzando LangGraph
  • Integrare LLM leggeri come Granite per un ragionamento creativo
  • Gestire i vincoli di memoria della GPU con il caricamento del modello ad hoc
  • Visualizzare ed esportare l'output della storia in un formato facile da usare

Questo framework agentico non è solo potente per la scrittura delle sceneggiature, ma può essere esteso a un'ampia gamma di casi d'uso creativi o di routing delle attività. Con pochi nodi, hai costruito un assistente di scrittura in miniatura in grado di trasformare un'idea stravagante in una storia pronta per la sceneggiatura.

Che tu sia uno sviluppatore, un narratore o un ricercatore, questo tutorial ti offre una base pratica per esplorare l'ingegneria del workflow basata su LLM nei domini creativi.

Vuoi creare i tuoi agenti? Lascia fluire la creatività con i modelli IBM Granite e IBM watsonx Orchestrate.

Soluzioni correlate
Agenti AI per il Business

Crea, implementa e gestisci assistenti e agenti AI potenti che automatizzano workflow e processi con l'AI generativa.

    Scopri watsonx Orchestrate
    Soluzioni per agenti AI IBM

    Costruisci il futuro della tua azienda con soluzioni AI di cui puoi fidarti.

    Esplora le soluzioni basate su agenti AI
    Servizi AI di IBM Consulting

    I servizi di AI di IBM Consulting aiutano a reinventare il modo in cui le aziende lavorano con l'AI per la trasformazione.

    Esplora i servizi di intelligenza artificiale
    Prossimi passi

    Sia che tu scelga di personalizzare app e competenze precostituite o di creare e implementare servizi di agenti personalizzati utilizzando uno studio di AI, la piattaforma IBM watsonx è la soluzione che fa per te.

    Scopri watsonx Orchestrate Esplora watsonx.ai
    Note a piè di pagina

    1 Lang Cao. 2024. GraphReason: Enhancing Reasoning Capabilities of Large Language Models through A Graph-Based Verification Approach. In Proceedings of the 2nd Workshop on Natural Language Reasoning and Structured Explanations (@ACL 2024), pagine 1–12, Bangkok, Thailandia. Association for Computational Linguistics.