L'automazione nelle operazioni di marketing ha superato da tempo il livello di "invia email al momento giusto". Quando LLM come Claude 3.5 Sonnet entrano in produzione, la vera domanda non è quanto velocemente il workflow si completa, ma come hai strutturato la gestione degli errori. La combinazione n8n + Claude API ci ha consentito di generare 200+ articoli senza intervento manuale — ma questo risultato è stato possibile solo grazie a un'architettura basata su idempotency, retry strategy e state tracking correttamente implementati.

Cos'è un workflow autonomo

Un workflow autonomo è un sistema che completa il proprio compito dall'inizio alla fine senza richiedere intervento umano. Se puoi dire "avvia e dimentica", allora è autonomo. Nelle operazioni di marketing significa: estrarre keyword da Google Search Console, inviarle a Claude, ottenere il contenuto, fare commit su GitHub, gestire il controllo delle versioni — tutto con un solo trigger.

n8n è l'orchestrator. Viene attivato tramite webhook, mantiene lo stato tra ogni passaggio, e la logica di retry entra in gioco quando si verificano errori. Claude API è il generatore di contenuto — ma devi strutturare la generazione in modo che non richieda controllo manuale. Se codifichi il prompt direttamente nel workflow e lo inserisci da un URL raw su GitHub a ogni modifica, significa apportare 15 modifiche nel workflow. Gestisci il versionamento sin dall'inizio.

Nel nostro setup, n8n gira su un'istanza self-hosted gratuita. Cinque nodi nel workflow: webhook trigger, HTTP request (Claude API), trasformazione dati, GitHub API commit, Supabase logging. Il completamento totale richiede 3 minuti — di cui 90 secondi sono il tempo di Claude per generare 1500 parole, il resto è I/O.

Idempotency: stesso input, stesso output

L'idempotency garantisce che eseguendo la stessa operazione più volte il set di risultati non cambi. Nei workflow basati su LLM questo non è automatico — lo stesso prompt genera output diversi. Ma il file system e la logica di commit devono essere idempotenti.

Il nostro approccio: ogni contenuto è associato a un identificatore univoco (i18nKey). L'i18nKey segue il formato {category}-{seq}-{YYYY-MM}. Il workflow n8n genera questa chiave, la passa a Claude e la utilizza per il percorso del file. Se lo stesso keyword viene processato una seconda volta, il workflow verifica in Supabase — se esiste, SKIP; se no, PROCESS.

// n8n Function node — idempotency check
const existingRecord = await $('Supabase').first().json.data.find(
  (r) => r.i18n_key === $json.i18nKey
);
if (existingRecord) {
  return { skip: true, reason: 'already_published' };
}
return { skip: false };

Quando effettuiamo il commit su GitHub, verifichiamo anche il nome del file. Se il file esiste, GitHub restituisce 409 Conflict, il nodo di gestione errori n8n lo cattura e lo registra — ma il workflow non si ferma. In questo modo, processando un batch di 50 keyword, se 3 sono già stati generati, ne elaboriamo solo 47.

Claude API: versionamento dei prompt e budget di token

Quando utilizzi Claude API in produzione, il punto critico è la stabilità del prompt. Se codifichi il prompt direttamente in n8n, dovrai modificare manualmente il workflow ad ogni iterazione. Invece, conserva il prompt come file Markdown su GitHub e scaricalo tramite URL raw.

Nel nostro setup: il file prompts/roibase-master-it.md si trova su GitHub. Un nodo HTTP Request di n8n scarica questo URL, e il contenuto diventa il messaggio SYSTEM inviato a Claude. Il messaggio USER viene popolato dinamicamente nel workflow — keyword, categoria, lista di link interni, data odierna e altri variabili contestuali.

{
  "model": "claude-3-5-sonnet-20241022",
  "max_tokens": 200000,
  "system": "{{$node["Fetch_Prompt"].json.content}}",
  "messages": [
    {
      "role": "user",
      "content": "KEYWORD: {{$json.keyword}}\nCATEGORY: {{$json.category}}\n..."
    }
  ]
}

Budget di token: la context window di Claude 3.5 Sonnet è 200K token. Il nostro prompt occupa 8K token (prompt master italiano + linee guida specifiche per categoria), il messaggio USER 500 token, l'output di Claude mediamente 2.5K token (1500 parole). Totale circa 11K token per run; con batch pricing il costo è circa $0.04 per esecuzione. 200 articoli = $8 di costo API.

Gestione degli errori: retry, fallback e state logging

Nei workflow basati su LLM esistono tre classi di errori: transitori (rate limit), permanenti (output malformato) e inaspettati (timeout di rete). La logica di gestione errori di n8n non distingue tra questi — spetta a te strutturare la retry strategy.

Il nostro approccio: ogni nodo ha le impostazioni di retry abilitate. Nel nodo HTTP Request (Claude API) abilitiamo retryOnFail: true, maxRetries: 3, waitBetweenTries: 5000ms. Se riceviamo un rate limit (429), applichiamo backoff esponenziale. Se anche il terzo tentativo fallisce, entra in gioco il nodo di gestione errori — registriamo un log failed_generation su Supabase e il workflow si ferma, ma l'elaborazione degli altri keyword continua.

Per l'output malformato (quando Claude genera meno di 1400 parole o il frontmatter è incompleto), abbiamo un nodo di validazione. Esegue il parsing JSON, verifica i campi readingTime e title. Se la validazione fallisce, inviamo a Claude il messaggio "rigenerare con vincoli di lunghezza più rigorosi" — questa volta aumentiamo il parametro max_tokens. Se il secondo tentativo fallisce ugualmente, il record finisce in una coda per revisione manuale.

Lo state logging viene mantenuto in Supabase con questo schema:

CampoTipoDescrizione
i18n_keytextIdentificatore univoco
keywordtextQuery da Google Search Console
statusenumpending, generated, failed
retry_countintNumero di retry effettuati
error_logjsonbDettagli dell'errore
created_attimestampOrario del primo run
completed_attimestampOrario del completamento (null se in corso)

Questa tabella serve sia per il monitoraggio che per il debugging. Su Grafana, i record dove retry_count > 2 appaiono nel dashboard — così vediamo quali keyword causano continui blocchi di Claude.

Esperienza in produzione: 200+ articoli, tasso di fallimento del 4%

I primi 50 articoli li abbiamo generati con monitoraggio manuale. I 150 successivi completamente in autonomo. I risultati:

  • Tasso di successo: 96% (192/200)
  • Tempo medio di completamento: 3.2 minuti
  • Rate limit hits: 7 volte (tutti con retry di successo)
  • Intervento manuale necessario: 8 articoli (output malformato + ambiguità keyword)

Il 50% dei fallimenti era dovuto a keyword troppo generici ("marketing digitale"). Claude non riesce a raggiungere 1500 parole su questi argomenti senza generare contenuto filler — il nodo di validazione lo rileva ma la rigenerazione non aiuta. Mettiamo questi keyword nella blacklist.

L'altro 50% era dovuto all'API di GitHub che restituiva 409 Conflict (file esiste già ma Supabase non ha il record — race condition). Per risolvere, abbiamo aggiunto un controllo atomico: scrivi pending status su Supabase prima del commit a GitHub, quindi aggiorna a generated se il commit ha successo. Il tasso è sceso da 4% a 1.5%.

Profilo di latenza: 90 secondi Claude API, 45 secondi GitHub commit (file markdown grandi), 15 secondi Supabase write, 30 secondi n8n internal processing. Il collo di bottiglia è Claude — ma non occorre parallelizzare perché il rate limit non lo consentirebbe. Processiamo in batch: 10 keyword all'ora, capacità di 240 keyword al giorno.

Tradeoff: cosa abbiamo guadagnato, cosa perso

Strutturare un workflow autonomo comporta tre tradeoff principali:

  1. Qualità vs velocità: La qualità dell'output di Claude dipende dal tuning del prompt. Nella prima versione avevamo un tasso di reject del 40% — aggiungendo la regola "1400-1600 parole OBBLIGATORIO" al prompt è sceso al 4%. Ma questo causa a volte contenuto filler da parte di Claude. Un editor umano lo noterebbe, un'IA no.
  2. Costo vs affidabilità: Una logica di retry aggressiva aumenta il consumo di token. Nel setup iniziale, ogni retry inviava il prompt completo (8K token × 3 = 24K). Ora con prompt caching di Claude (feature aggiunta a maggio 2025), solo il messaggio USER viene riscaricato — il SYSTEM rimane in cache. Il costo è sceso del 60%.
  3. Flessibilità vs complessità: Volevamo versioni diverse del prompt per ogni categoria (AI è più tecnico, marketing è più business-focused). Ma questo significa 6 file di prompt diversi — versionamento complicato. La soluzione: un unico master prompt con un blocco CATEGORY_GUIDANCE categoria-specifico inserito nel messaggio USER. Aumenta la complessità ma guadagniamo flessibilità.

Futuro: multi-agent e self-healing

L'architettura attuale è single-agent — Claude lavora da solo. Nel prossimo ciclo testeremo un'architettura multi-agent: un agente genera il contenuto, un altro lo rivede, un terzo ottimizza per SEO. La feature di sub-workflow di n8n lo supporta, ma il costo di token triplica.

Self-healing significa: quando il workflow fallisce, eseguire un'analisi della causa radice e auto-correggesi. Esempio: se Claude genera costantemente contenuto breve, aggiungere automaticamente una nota al prompt: "output length must increase", quindi riprovare. È meta-ottimizzazione — l'LLM evolve il proprio prompt. Rischioso ma efficace.

Nel lavoro di Roibase su First-Party Data & Architettura di Misurazione utilizziamo un approccio simile: raccogliere autonomamente segnali di conversione, rilevare anomalie, auto-correggersi. Quando costruisci sistemi autonomi in produzione, il principio è coerente: struttura la gestione errori sin dall'inizio, registra lo stato, rendi la logica di retry idempotente.