n8n e AI Agent: come automatizzare senza perdere il controllo
Guida pratica per usare gli AI Agent in n8n con guardrail, human-in-the-loop, validazione output, monitoring dei costi e fallback chain per mantenere il controllo.

Il problema: AI potente ma imprevedibile
Gli AI Agent sono la funzionalità più potente di n8n. Puoi creare assistenti che leggono email, rispondono ai clienti, analizzano documenti, prendono decisioni e agiscono autonomamente. Ma questa potenza porta un rischio reale: un agent senza controlli può inviare email sbagliate, modificare dati critici o accumulare costi imprevisti.
Questa guida ti mostra come sfruttare gli AI Agent di n8n mantenendo il pieno controllo su cosa fanno, quanto costano e quando devono fermarsi.
Come funzionano gli AI Agent in n8n
n8n integra nativamente gli AI Agent con un'architettura a nodi:
Trigger (webhook, schedule, email)
-> AI Agent node
-> LLM (GPT-4, Claude, Llama)
-> Tools (funzioni che l'agent può chiamare)
-> Memory (contesto delle conversazioni)
-> Output (azione, risposta, decisione)
L'agent riceve un input, ragiona usando il modello LLM, decide quali tool usare, esegue azioni e produce un output. Il problema è che ogni passo di questa catena può produrre risultati inattesi.
Principio 1: guardrail sull'input
Il problema
Se l'agent riceve input inaspettati (prompt injection, dati malformati, richieste fuori contesto), può comportarsi in modi imprevedibili.
La soluzione: validazione prima dell'agent
// Nodo Code: prima dell'AI Agent
const input = $json;
// 1. Sanitizza l'input
let cleanInput = input.message
.replace(/<[^>]*>/g, '') // Rimuovi HTML
.replace(/\{[^}]*\}/g, '') // Rimuovi template injection
.trim();
// 2. Verifica lunghezza
if (cleanInput.length > 2000) {
cleanInput = cleanInput.substring(0, 2000) + '... [troncato]';
}
if (cleanInput.length < 3) {
return [{ json: { skip: true, reason: 'Input troppo corto' } }];
}
// 3. Rileva prompt injection base
const injectionPatterns = [
/ignora le istruzioni/i,
/ignore previous/i,
/system prompt/i,
/forget your instructions/i,
/sei ora un/i,
/you are now/i,
/act as/i,
/new role/i
];
const isInjection = injectionPatterns.some(p => p.test(cleanInput));
if (isInjection) {
return [{
json: {
skip: true,
reason: 'Possibile prompt injection rilevata',
alert: true
}
}];
}
// 4. Classifica il tipo di richiesta
const categories = {
support: /ordine|spedizione|reso|rimborso|problema|aiuto/i,
sales: /prezzo|costo|preventivo|sconto|offerta|acquist/i,
info: /come|cosa|quando|dove|perch/i,
other: /.*/
};
let category = 'other';
for (const [cat, pattern] of Object.entries(categories)) {
if (pattern.test(cleanInput)) {
category = cat;
break;
}
}
return [{
json: {
original_input: input.message,
clean_input: cleanInput,
category,
skip: false
}
}];
Principio 2: system prompt robusto
Il problema
Un system prompt generico come "Sei un assistente utile" dà troppa libertà all'agent. Senza confini chiari, l'agent può inventare informazioni, promettere sconti non autorizzati o rispondere a domande fuori ambito.
Il template system prompt
Sei l'assistente AI di {{ nomeAzienda }}.
RUOLO: rispondi alle domande dei clienti sul supporto e-commerce.
CONFINI RIGIDI - NON FARE MAI:
- Non inventare informazioni su prodotti, prezzi o disponibilità
- Non promettere sconti, rimborsi o azioni che richiedono approvazione umana
- Non rispondere a domande su argomenti non correlati al business
- Non eseguire azioni irreversibili senza conferma
- Non condividere informazioni interne dell'azienda
- Non fornire consigli legali, medici o finanziari
QUANDO NON SAI:
- Rispondi: "Non ho questa informazione. Ti metto in contatto
con un operatore che potrà aiutarti."
- Non inventare mai una risposta
TONO: professionale ma cordiale. Usa il "tu".
Rispondi sempre in italiano.
DATI DISPONIBILI:
- Catalogo prodotti: usa il tool "search_products"
- Stato ordini: usa il tool "check_order"
- FAQ: usa il tool "search_faq"
AZIONI PERMESSE:
- Cercare informazioni (prodotti, ordini, FAQ)
- Creare ticket di supporto
- Aggiornare informazioni di contatto del cliente
AZIONI CHE RICHIEDONO APPROVAZIONE UMANA:
- Rimborsi superiori a 50 euro
- Modifiche a ordini già spediti
- Sconti personalizzati
- Cancellazione account
Perché funziona
I modelli linguistici seguono meglio le istruzioni quando:
- I confini sono espliciti e specifici (non vaghi)
- Le azioni proibite sono elencate chiaramente
- C'è un fallback definito per i casi incerti
- Il tono e la lingua sono specificati
Principio 3: human-in-the-loop
Il concetto
Non tutto deve essere completamente automatico. Per le azioni ad alto rischio, inserisci un punto di controllo umano.
Implementazione in n8n
AI Agent produce una risposta/azione
-> Nodo Code: valuta il rischio
-> IF rischio basso (informazioni, FAQ):
-> Esegui automaticamente
-> IF rischio medio (creazione ticket, aggiornamento dati):
-> Esegui ma notifica il team
-> IF rischio alto (rimborso, cancellazione, promessa al cliente):
-> Metti in pausa
-> Invia richiesta approvazione (Slack/email)
-> Attendi approvazione umana (webhook callback)
-> IF approvato: esegui
-> IF rifiutato: rispondi al cliente con alternativa
Valutazione rischio automatica
// Nodo Code: classifica il rischio dell'azione proposta dall'agent
const agentOutput = $json;
let riskLevel = 'low';
const reasons = [];
// Azioni finanziarie
if (agentOutput.action === 'refund' || agentOutput.action === 'discount') {
riskLevel = 'high';
reasons.push('Azione finanziaria');
}
// Importo elevato
if (agentOutput.amount && agentOutput.amount > 50) {
riskLevel = 'high';
reasons.push(`Importo: ${agentOutput.amount} EUR`);
}
// Modifiche irreversibili
if (['delete', 'cancel', 'close'].includes(agentOutput.action)) {
riskLevel = 'high';
reasons.push('Azione irreversibile');
}
// Comunicazione esterna
if (agentOutput.sends_email || agentOutput.sends_sms) {
if (riskLevel !== 'high') riskLevel = 'medium';
reasons.push('Comunicazione esterna al cliente');
}
// Incertezza dell'agent
if (agentOutput.confidence && agentOutput.confidence < 0.7) {
if (riskLevel === 'low') riskLevel = 'medium';
reasons.push(`Confidenza bassa: ${agentOutput.confidence}`);
}
return [{
json: {
...agentOutput,
risk_level: riskLevel,
risk_reasons: reasons,
requires_approval: riskLevel === 'high'
}
}];
Flusso di approvazione via Slack
-> Invia messaggio Slack con bottoni:
L'AI Agent richiede approvazione:
Azione: {{ action }}
Cliente: {{ customerName }}
Importo: {{ amount }} EUR
Motivo: {{ reasoning }}
Rischio: {{ riskLevel }} ({{ riskReasons }})
[Approva] [Rifiuta] [Modifica e approva]
-> Webhook attende callback dal bottone Slack
-> Processa in base alla risposta
Principio 4: validazione dell'output
Il problema
L'AI può generare output plausibile ma sbagliato: prezzi inventati, date impossibili, email con tono inappropriato, risposte in lingua sbagliata.
Controlli automatici sull'output
// Nodo Code: valida output dell'agent prima dell'invio
const output = $json;
const errors = [];
const warnings = [];
// 1. Lingua
const italianWords = output.response.match(
/\b(il|lo|la|di|che|è|per|un|una|con|sono|non|come|più|questo|questa)\b/g
);
if (!italianWords || italianWords.length < 3) {
errors.push('La risposta potrebbe non essere in italiano');
}
// 2. Lunghezza ragionevole
if (output.response.length < 20) {
warnings.push('Risposta molto corta');
}
if (output.response.length > 2000) {
warnings.push('Risposta molto lunga, potrebbe confondere il cliente');
}
// 3. Informazioni sensibili
const sensitivePatterns = [
/password/i,
/chiave api/i,
/api key/i,
/credenzial/i,
/\b\d{16}\b/, // Numeri carta di credito
/\b[A-Z]{2}\d{2}[A-Z0-9]{11,30}\b/ // IBAN
];
for (const pattern of sensitivePatterns) {
if (pattern.test(output.response)) {
errors.push('Possibile informazione sensibile nella risposta');
break;
}
}
// 4. Promesse non autorizzate
const promisePatterns = [
/ti garantiamo/i,
/rimborso totale/i,
/sconto del \d+/i,
/gratis/i,
/omaggio/i
];
for (const pattern of promisePatterns) {
if (pattern.test(output.response)) {
warnings.push(`Possibile promessa non autorizzata: "${output.response.match(pattern)[0]}"`);
}
}
// 5. Allucinazioni su prodotti/prezzi
if (output.mentioned_products) {
// Verifica che i prodotti esistano nel catalogo
for (const product of output.mentioned_products) {
const exists = await checkProductExists(product);
if (!exists) {
errors.push(`Prodotto non trovato nel catalogo: "${product}"`);
}
}
}
const isValid = errors.length === 0;
return [{
json: {
...output,
validation: {
is_valid: isValid,
errors,
warnings,
checked_at: new Date().toISOString()
}
}
}];
Cosa fare quando la validazione fallisce
IF errori di validazione:
-> Non inviare la risposta al cliente
-> Genera risposta di fallback:
"Grazie per la tua domanda. Ti metto in contatto
con un operatore che potrà aiutarti al meglio."
-> Crea ticket per il team con:
- Domanda originale del cliente
- Risposta generata (per review)
- Errori di validazione
-> Log per miglioramento futuro
Principio 5: monitoring dei costi
Il problema
Un agent mal configurato può generare centinaia di chiamate API al minuto. Con GPT-4 a circa 10 euro per milione di token in input, un loop incontrollato può costare centinaia di euro in poche ore.
Budget cap nel workflow
// Nodo Code: prima di ogni chiamata LLM
const dailyBudget = 10; // euro
const monthlyBudget = 200; // euro
// Leggi contatore dal Google Sheet o database
const todayCost = $('Get Daily Cost').first().json.total || 0;
const monthCost = $('Get Monthly Cost').first().json.total || 0;
if (todayCost >= dailyBudget) {
return [{
json: {
blocked: true,
reason: `Budget giornaliero raggiunto: ${todayCost.toFixed(2)} EUR`,
fallback: 'Usa risposta template'
}
}];
}
if (monthCost >= monthlyBudget) {
return [{
json: {
blocked: true,
reason: `Budget mensile raggiunto: ${monthCost.toFixed(2)} EUR`,
fallback: 'Disabilita agent, usa solo risposte manuali'
}
}];
}
// Alert al 80% del budget
if (todayCost >= dailyBudget * 0.8) {
// Invia alert ma continua
return [{
json: {
blocked: false,
warning: `Budget giornaliero all'${((todayCost/dailyBudget)*100).toFixed(0)}%`
}
}];
}
return [{ json: { blocked: false } }];
Tracking costi per chiamata
// Dopo ogni chiamata LLM: registra il costo
const usage = $json.usage;
const costs = {
model: 'gpt-4o',
input_tokens: usage.prompt_tokens,
output_tokens: usage.completion_tokens,
// Prezzi GPT-4o (aggiorna periodicamente)
input_cost: (usage.prompt_tokens / 1000000) * 2.50,
output_cost: (usage.completion_tokens / 1000000) * 10.00,
total_cost: 0,
timestamp: new Date().toISOString()
};
costs.total_cost = costs.input_cost + costs.output_cost;
return [{ json: costs }];
Report costi settimanale
Schedule Trigger (lunedi alle 9:00)
-> Somma costi della settimana per:
- Modello LLM
- Workflow
- Tipo di azione
-> Genera report:
Report costi AI - Settimana {{ weekNumber }}
Costo totale: {{ totalCost }} EUR
Chiamate totali: {{ totalCalls }}
Costo medio per chiamata: {{ avgCost }} EUR
Top 5 workflow per costo:
1. {{ workflow1 }}: {{ cost1 }} EUR ({{ calls1 }} chiamate)
2. ...
Budget rimanente: {{ remaining }} EUR ({{ percentUsed }}% usato)
Principio 6: fallback chain
Il concetto
Mai dipendere da un singolo modello o provider. Se OpenAI è giù, il tuo servizio clienti AI non deve fermarsi.
Implementazione
Richiesta al primo LLM (GPT-4o)
-> IF risposta ok: usa questa
-> IF errore/timeout:
-> Secondo LLM (Claude 3.5 Sonnet)
-> IF risposta ok: usa questa
-> IF errore/timeout:
-> Terzo LLM (Llama locale via Ollama)
-> IF risposta ok: usa questa
-> IF errore:
-> Risposta template dal database FAQ
-> Crea ticket manuale
Nodo Code: fallback con timeout
// Wrapper per chiamate LLM con fallback
const models = [
{
name: 'gpt-4o',
provider: 'openai',
timeout: 15000,
maxTokens: 500
},
{
name: 'claude-3-5-sonnet',
provider: 'anthropic',
timeout: 15000,
maxTokens: 500
},
{
name: 'llama3',
provider: 'ollama',
timeout: 30000,
maxTokens: 500
}
];
let lastError = null;
for (const model of models) {
try {
// Tenta la chiamata (gestita dai nodi n8n successivi)
return [{
json: {
selected_model: model.name,
provider: model.provider,
timeout: model.timeout,
attempt: models.indexOf(model) + 1
}
}];
} catch (error) {
lastError = error;
// Log dell'errore e prova il successivo
continue;
}
}
// Tutti i modelli hanno fallito
return [{
json: {
fallback: true,
use_template: true,
error: lastError?.message
}
}];
Principio 7: logging e audit trail
Cosa registrare per ogni interazione
// Log completo per audit
const auditLog = {
// Identificazione
interaction_id: crypto.randomUUID(),
timestamp: new Date().toISOString(),
workflow_id: $workflow.id,
execution_id: $execution.id,
// Input
user_input: $json.original_input,
sanitized_input: $json.clean_input,
input_category: $json.category,
// Agent
model_used: $json.selected_model,
system_prompt_version: 'v2.3',
tools_called: $json.tools_used || [],
tokens_used: $json.usage?.total_tokens || 0,
cost: $json.cost || 0,
// Output
agent_response: $json.response,
action_taken: $json.action || 'none',
risk_level: $json.risk_level,
// Validazione
validation_passed: $json.validation?.is_valid,
validation_errors: $json.validation?.errors || [],
// Risultato
sent_to_customer: $json.sent || false,
required_human: $json.requires_approval || false,
human_approved: $json.approved || null,
// Feedback (compilato dopo)
customer_satisfied: null,
feedback: null
};
return [{ json: auditLog }];
Dashboard di performance
Metriche da monitorare mensilmente:
| Metrica | Target | Calcolo |
|---|---|---|
| Tasso di risposta autonoma | > 70% | Risposte senza intervento umano / totale |
| Tasso di escalation | < 20% | Richieste passate a umano / totale |
| Accuratezza | > 90% | Risposte corrette / risposte verificate |
| Tempo medio di risposta | < 10 secondi | Media dei tempi di risposta |
| Costo per interazione | < 0,05 euro | Costo LLM totale / interazioni |
| Soddisfazione cliente | > 4/5 | Feedback post-interazione |
Esempio completo: assistente e-commerce
Mettiamo insieme tutti i principi in un workflow reale:
1. Cliente invia messaggio (webhook/chat)
2. Validazione input (sanitizzazione, anti-injection)
3. Budget check (costo giornaliero sotto soglia?)
4. AI Agent con system prompt robusto:
- Tool: search_products (catalogo)
- Tool: check_order (stato ordini)
- Tool: search_faq (knowledge base)
- Tool: create_ticket (supporto)
5. Validazione output (lingua, contenuto, promesse)
6. Risk assessment (basso/medio/alto)
7. IF rischio basso: invia risposta al cliente
IF rischio medio: invia + notifica team
IF rischio alto: pausa + richiesta approvazione
8. Log audit completo
9. Tracking costi
10. IF errore in qualsiasi punto: fallback chain
Questo workflow gestisce il 70-80% delle richieste in autonomia, escala il 15-20% con notifica e blocca il 5% per approvazione umana. Il risultato è un servizio clienti che risponde in secondi, 24 ore su 24, senza perdere il controllo.
La regola fondamentale
Automatizzare con l'AI non significa "lasciare fare all'AI". Significa progettare un sistema dove l'AI fa il lavoro pesante ma le decisioni critiche restano sotto il tuo controllo. I guardrail non rallentano l'automazione: la rendono affidabile.
Vuoi implementare AI Agent con guardrail nel tuo n8n? Contattaci per una consulenza specializzata.
Team n8n.it
Specialisti in Automazione
Siamo un team di esperti n8n focalizzati sull'automazione dei processi aziendali e la sicurezza delle implementazioni self-hosted.
Articoli correlati

Audit di sicurezza n8n: checklist per proteggere la tua istanza
Checklist pratica e completa per mettere in sicurezza la tua istanza n8n: reverse proxy, SSL, autent...
Leggi di più
Il costo reale di n8n self-hosted: server, manutenzione e tempo
n8n è gratuito, ma il self-hosting ha costi nascosti. Analizziamo il TCO reale: server, SSL, backup,...
Leggi di più
I 7 errori più comuni con n8n in produzione (e come evitarli)
Errori reali che abbiamo visto in decine di installazioni n8n in produzione: nessun error handling, ...
Leggi di più