n8n Automation

n8n AI Workflow: automatizare inteligenta cu LLM

Petru Constantin
--11 min lectura
#n8n#AI integration#LLM#workflow automation#OpenAI

Integrarea AI transforma workflow-urile n8n din automatizari bazate pe reguli in sisteme inteligente de luare a deciziilor. Acest ghid acopera pattern-uri practice de workflow AI, folosind LLM-uri pentru procesarea documentelor, generarea de continut si rutarea inteligenta.

Configurarea nodurilor AI

Configurarea integrarii OpenAI

// OpenAI Configuration for n8n
// Store credentials securely in n8n
{
  "openAiApi": {
    "apiKey": "{{ $env.OPENAI_API_KEY }}",
    "organization": "{{ $env.OPENAI_ORG_ID }}"
  }
}
 
// Function Node: OpenAI API Helper
const OPENAI_API_URL = 'https://api.openai.com/v1';
 
async function callOpenAI(endpoint, payload) {
  const response = await fetch(`${OPENAI_API_URL}${endpoint}`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${$env.OPENAI_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(payload)
  });
 
  if (!response.ok) {
    throw new Error(`OpenAI API error: ${response.status}`);
  }
 
  return response.json();
}
 
// Export for use in other nodes
return [{
  json: {
    callOpenAI: callOpenAI.toString()
  }
}];

Integrarea cu Claude/Anthropic

// Function Node: Anthropic Claude Integration
const ANTHROPIC_API_URL = 'https://api.anthropic.com/v1/messages';
 
async function callClaude(systemPrompt, userMessage, options = {}) {
  const payload = {
    model: options.model || 'claude-3-sonnet-20240229',
    max_tokens: options.maxTokens || 1024,
    system: systemPrompt,
    messages: [
      { role: 'user', content: userMessage }
    ]
  };
 
  const response = await fetch(ANTHROPIC_API_URL, {
    method: 'POST',
    headers: {
      'x-api-key': $env.ANTHROPIC_API_KEY,
      'anthropic-version': '2023-06-01',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(payload)
  });
 
  if (!response.ok) {
    const error = await response.text();
    throw new Error(`Claude API error: ${error}`);
  }
 
  const data = await response.json();
  return data.content[0].text;
}
 
const input = $input.first().json;
 
const result = await callClaude(
  input.systemPrompt,
  input.userMessage,
  { maxTokens: input.maxTokens || 1024 }
);
 
return [{
  json: {
    response: result,
    model: 'claude-3-sonnet',
    timestamp: new Date().toISOString()
  }
}];

Procesarea inteligenta a documentelor

Clasificarea documentelor

// Function Node: AI Document Classifier
const document = $input.first().json;
 
const systemPrompt = `You are a document classification expert. Classify documents into one of these categories:
- invoice: Bills, invoices, payment requests
- contract: Legal agreements, terms of service
- resume: CVs, job applications
- correspondence: Letters, emails, memos
- report: Analysis, research, summaries
- receipt: Purchase receipts, transaction records
- form: Applications, registrations
- other: Anything that doesn't fit above
 
Respond with ONLY a JSON object containing:
- category: The classification category
- confidence: A number from 0 to 1 indicating confidence
- reasoning: Brief explanation of classification`;
 
const userMessage = `Classify this document:
 
Title: ${document.title || 'Untitled'}
Content Preview:
${document.content.substring(0, 2000)}`;
 
const response = await callClaude(systemPrompt, userMessage);
 
// Parse JSON response
let classification;
try {
  classification = JSON.parse(response);
} catch {
  // Handle non-JSON response
  classification = {
    category: 'other',
    confidence: 0.5,
    reasoning: response
  };
}
 
return [{
  json: {
    ...document,
    classification: {
      ...classification,
      classifiedAt: new Date().toISOString()
    }
  }
}];

Extragerea datelor din facturi

// Function Node: AI Invoice Data Extractor
const invoiceText = $input.first().json.content;
 
const systemPrompt = `You are an expert at extracting structured data from invoices. Extract the following information and return as JSON:
 
Required fields:
- vendor_name: Company issuing the invoice
- invoice_number: Invoice/bill number
- invoice_date: Date of invoice (ISO format YYYY-MM-DD)
- due_date: Payment due date (ISO format)
- total_amount: Total amount due (number only)
- currency: Currency code (USD, EUR, etc.)
 
Optional fields:
- line_items: Array of {description, quantity, unit_price, total}
- subtotal: Subtotal before tax
- tax_amount: Tax amount
- tax_rate: Tax percentage
- payment_terms: Net 30, etc.
- po_number: Purchase order reference
- vendor_address: Full address
- billing_address: Bill to address
 
If a field cannot be determined, use null.`;
 
const response = await callClaude(systemPrompt, `Extract data from this invoice:\n\n${invoiceText}`);
 
let extractedData;
try {
  extractedData = JSON.parse(response);
} catch {
  throw new Error('Failed to parse invoice extraction response');
}
 
// Validate required fields
const requiredFields = ['vendor_name', 'invoice_number', 'total_amount'];
const missingFields = requiredFields.filter(f => !extractedData[f]);
 
if (missingFields.length > 0) {
  extractedData._validation = {
    valid: false,
    missingFields
  };
} else {
  extractedData._validation = { valid: true };
}
 
return [{
  json: {
    original: invoiceText,
    extracted: extractedData,
    extractedAt: new Date().toISOString()
  }
}];

Generarea automata de continut

Generator de articole de blog

// Function Node: AI Blog Post Generator
const topic = $input.first().json;
 
const systemPrompt = `You are an expert content writer specializing in ${topic.industry || 'technology'}.
Write engaging, informative blog posts that are:
- SEO-optimized with natural keyword placement
- Well-structured with clear headings
- Actionable with practical takeaways
- Between 1000-1500 words
 
Format the output as JSON with:
- title: Compelling, SEO-friendly title
- meta_description: 150-160 character description
- slug: URL-friendly slug
- content: Full markdown content
- tags: Array of relevant tags
- estimated_reading_time: Minutes to read`;
 
const userMessage = `Write a blog post about: ${topic.title}
 
Target keywords: ${topic.keywords?.join(', ') || 'none specified'}
Target audience: ${topic.audience || 'general'}
Tone: ${topic.tone || 'professional'}
 
Additional context: ${topic.context || 'none'}`;
 
const response = await callOpenAI('/chat/completions', {
  model: 'gpt-4-turbo-preview',
  messages: [
    { role: 'system', content: systemPrompt },
    { role: 'user', content: userMessage }
  ],
  response_format: { type: 'json_object' },
  max_tokens: 4000
});
 
const blogPost = JSON.parse(response.choices[0].message.content);
 
return [{
  json: {
    ...blogPost,
    generatedAt: new Date().toISOString(),
    model: 'gpt-4-turbo-preview',
    topic: topic
  }
}];

Generator de raspunsuri email

// Function Node: AI Email Response Generator
const email = $input.first().json;
 
const systemPrompt = `You are a professional customer service representative.
Generate helpful, empathetic email responses that:
- Address all points in the customer's email
- Use a warm but professional tone
- Provide clear next steps when applicable
- Keep responses concise (under 200 words)
 
Respond with JSON containing:
- subject: Reply subject line
- body: Email body (plain text)
- sentiment: detected sentiment of original (positive/neutral/negative)
- urgency: low/medium/high
- suggested_actions: Array of internal actions to take`;
 
const userMessage = `Generate a response to this customer email:
 
From: ${email.from}
Subject: ${email.subject}
Body:
${email.body}
 
Customer history:
- Account age: ${email.customerData?.accountAge || 'unknown'}
- Previous tickets: ${email.customerData?.ticketCount || 0}
- VIP status: ${email.customerData?.isVip || false}`;
 
const response = await callClaude(systemPrompt, userMessage);
 
const emailResponse = JSON.parse(response);
 
return [{
  json: {
    originalEmail: email,
    response: emailResponse,
    generatedAt: new Date().toISOString()
  }
}];

Analiza sentimentului si rutare

Analizor de feedback clienti

// Function Node: Sentiment Analysis and Routing
const feedback = $input.first().json;
 
const systemPrompt = `Analyze customer feedback and provide:
1. Sentiment score (-1 to 1, where -1 is very negative, 1 is very positive)
2. Emotion categories present (joy, anger, frustration, satisfaction, confusion)
3. Key topics mentioned
4. Urgency level (1-5)
5. Suggested department routing
6. Recommended priority
 
Return as JSON with these exact fields:
- sentiment_score: number
- sentiment_label: "very_negative" | "negative" | "neutral" | "positive" | "very_positive"
- emotions: string[]
- topics: string[]
- urgency: number
- route_to: "support" | "sales" | "billing" | "technical" | "management"
- priority: "low" | "normal" | "high" | "urgent"
- requires_human: boolean
- summary: string (one sentence)`;
 
const response = await callClaude(systemPrompt, `Analyze this feedback:\n\n${feedback.text}`);
 
const analysis = JSON.parse(response);
 
// Enrich with routing logic
const routingRules = {
  escalate_to_management: analysis.sentiment_score < -0.7 && analysis.urgency >= 4,
  auto_respond: analysis.sentiment_score > 0.5 && !analysis.requires_human,
  priority_queue: analysis.urgency >= 4 || analysis.priority === 'urgent'
};
 
return [{
  json: {
    original: feedback,
    analysis,
    routing: routingRules,
    analyzedAt: new Date().toISOString()
  }
}];

Rutare inteligenta a tichetelor

// Function Node: AI-Powered Ticket Router
const ticket = $input.first().json;
 
const systemPrompt = `You are an expert at routing support tickets to the right team.
 
Available teams and their expertise:
- technical_support: Software bugs, errors, technical issues, API problems
- billing: Payments, invoices, refunds, subscription issues
- sales: Pricing questions, upgrades, enterprise inquiries
- onboarding: New user setup, getting started, tutorials
- account: Password resets, access issues, profile changes
- product: Feature requests, feedback, suggestions
- security: Data concerns, privacy, security incidents
 
Analyze the ticket and provide:
- primary_team: Main team to handle
- secondary_team: Backup team if needed
- confidence: 0-1 confidence in routing
- skills_required: Specific skills needed
- estimated_complexity: 1-5
- auto_response_possible: boolean
- suggested_response: Brief initial response if auto_response_possible`;
 
const ticketContext = `
Subject: ${ticket.subject}
Description: ${ticket.description}
Customer tier: ${ticket.customerTier || 'standard'}
Previous category: ${ticket.previousCategory || 'none'}
`;
 
const response = await callClaude(systemPrompt, ticketContext);
const routing = JSON.parse(response);
 
// Apply business rules
if (ticket.customerTier === 'enterprise') {
  routing.priority_boost = true;
  routing.sla_hours = 4;
} else if (ticket.customerTier === 'premium') {
  routing.sla_hours = 24;
} else {
  routing.sla_hours = 48;
}
 
return [{
  json: {
    ticket,
    routing,
    routedAt: new Date().toISOString()
  }
}];

Luarea deciziilor cu ajutorul AI

Workflow de aprobare cu AI

// Function Node: AI-Assisted Approval Decision
const request = $input.first().json;
 
const systemPrompt = `You are a risk assessment AI for expense and purchase approvals.
 
Evaluate requests based on:
1. Amount reasonableness for the category
2. Business justification quality
3. Policy compliance
4. Historical patterns (if provided)
5. Budget impact
 
Provide:
- recommendation: "approve" | "review" | "deny"
- confidence: 0-1
- risk_score: 1-10 (10 = highest risk)
- concerns: Array of potential issues
- questions: Questions for the requester if review needed
- policy_references: Relevant policies to check`;
 
const requestDetails = `
Request Type: ${request.type}
Amount: ${request.amount} ${request.currency}
Category: ${request.category}
Requester: ${request.requester.name} (${request.requester.department})
Justification: ${request.justification}
Budget remaining: ${request.budgetRemaining || 'unknown'}
Previous requests this month: ${request.monthlyRequestCount || 0}
Historical average for this category: ${request.categoryAverage || 'unknown'}
`;
 
const response = await callClaude(systemPrompt, requestDetails);
const assessment = JSON.parse(response);
 
// Apply thresholds
let finalDecision;
if (assessment.recommendation === 'approve' && assessment.confidence > 0.8) {
  finalDecision = 'auto_approve';
} else if (assessment.recommendation === 'deny' && assessment.confidence > 0.9) {
  finalDecision = 'auto_deny';
} else {
  finalDecision = 'human_review';
}
 
return [{
  json: {
    request,
    assessment,
    decision: finalDecision,
    assessedAt: new Date().toISOString()
  }
}];

RAG (Retrieval-Augmented Generation)

Cautare in baza de cunostinte si generare de raspunsuri

// Function Node: RAG-Enhanced Support Response
const query = $input.first().json;
 
// Step 1: Search knowledge base (using vector database)
async function searchKnowledgeBase(queryText) {
  // Generate embedding for query
  const embeddingResponse = await callOpenAI('/embeddings', {
    model: 'text-embedding-ada-002',
    input: queryText
  });
 
  const queryEmbedding = embeddingResponse.data[0].embedding;
 
  // Search vector database (e.g., Pinecone, Weaviate)
  const searchResults = await fetch(`${$env.VECTOR_DB_URL}/query`, {
    method: 'POST',
    headers: {
      'Api-Key': $env.VECTOR_DB_API_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      vector: queryEmbedding,
      topK: 5,
      includeMetadata: true
    })
  });
 
  return searchResults.json();
}
 
// Step 2: Search knowledge base
const searchResults = await searchKnowledgeBase(query.question);
 
// Step 3: Build context from results
const context = searchResults.matches
  .filter(m => m.score > 0.7)
  .map(m => m.metadata.content)
  .join('\n\n---\n\n');
 
// Step 4: Generate response with context
const systemPrompt = `You are a helpful support assistant. Use the provided context to answer questions.
If the context doesn't contain relevant information, say so and provide general guidance.
Always cite which source you're using when possible.`;
 
const userMessage = `Context from knowledge base:
${context}
 
---
 
User question: ${query.question}
 
Provide a helpful, accurate response based on the context above.`;
 
const response = await callClaude(systemPrompt, userMessage);
 
return [{
  json: {
    question: query.question,
    answer: response,
    sources: searchResults.matches.slice(0, 3).map(m => ({
      title: m.metadata.title,
      score: m.score
    })),
    generatedAt: new Date().toISOString()
  }
}];

Gestionarea erorilor si fallback-uri

Handler de erori pentru workflow-uri AI

// Function Node: AI Error Handler with Fallbacks
const input = $input.first().json;
const error = $input.first().json.error;
 
// Categorize error
let errorType;
let fallbackAction;
 
if (error.message?.includes('rate limit')) {
  errorType = 'rate_limit';
  fallbackAction = 'retry_with_backoff';
} else if (error.message?.includes('context length')) {
  errorType = 'context_too_long';
  fallbackAction = 'truncate_and_retry';
} else if (error.message?.includes('API')) {
  errorType = 'api_error';
  fallbackAction = 'use_fallback_model';
} else {
  errorType = 'unknown';
  fallbackAction = 'human_review';
}
 
// Prepare fallback
let fallbackConfig = null;
 
switch (fallbackAction) {
  case 'retry_with_backoff':
    fallbackConfig = {
      delay: 60000,
      maxRetries: 3,
      currentRetry: (input._retryCount || 0) + 1
    };
    break;
 
  case 'truncate_and_retry':
    fallbackConfig = {
      maxTokens: 2000,
      truncatedContent: input.content?.substring(0, 8000)
    };
    break;
 
  case 'use_fallback_model':
    fallbackConfig = {
      primaryModel: input.model,
      fallbackModel: 'gpt-3.5-turbo',
      reason: 'Primary model unavailable'
    };
    break;
 
  case 'human_review':
    fallbackConfig = {
      assignTo: 'ai-failures-queue',
      originalInput: input
    };
    break;
}
 
return [{
  json: {
    errorType,
    errorMessage: error.message,
    fallbackAction,
    fallbackConfig,
    originalInput: input,
    timestamp: new Date().toISOString()
  }
}];

Bune practici

  1. Foloseste output-uri structurate: Cere raspunsuri JSON pentru parsare fiabila
  2. Implementeaza fallback-uri: Ai modele de rezerva si cai de review uman
  3. Monitorizeaza costurile: Urmareste consumul de token-uri si implementeaza limite
  4. Foloseste cache: Stocheaza raspunsurile comune pentru a reduce apelurile API
  5. Gestioneaza rate limits: Implementeaza exponential backoff
  6. Valideaza output-urile: Valideaza intotdeauna raspunsurile AI inainte de utilizare
  7. Logheaza totul: Pastreaza log-uri detaliate pentru debugging si imbunatatire
  8. Seteaza timeout-uri: Previne blocarea workflow-urilor la apeluri API lente

Integrarea AI cu n8n permite automatizare inteligenta care depaseste regulile simple. Incepe cu cazuri de utilizare clare si extinde pe masura ce capeti incredere in workflow-urile asistate de AI.


Sistemul tau AI e conform cu EU AI Act? Evaluare gratuita de risc - afla in 2 minute →

Ai nevoie de ajutor cu conformitatea EU AI Act sau securitatea AI?

Programeaza o consultatie gratuita de 30 de minute. Fara obligatii.

Programeaza un Apel

Weekly AI Security & Automation Digest

Get the latest on AI Security, workflow automation, secure integrations, and custom platform development delivered weekly.

No spam. Unsubscribe anytime.