n8n + AI Agents: Workflow Automation with Artificial Intelligence
Introduction
n8n is an open-source, self-hostable workflow automation platform that allows you to connect various applications and services visually without writing much code. With the introduction of AI Agent features in n8n, the platform becomes significantly more powerful by enabling integration of Large Language Model (LLM) capabilities from OpenAI and Anthropic directly into your workflows.
In this tutorial, we will learn how to use n8n from installation, basic workflow concepts, to building an automated customer support pipeline powered by AI. This tutorial is suitable for developers, data engineers, and anyone looking to automate business processes with artificial intelligence.
Prerequisites
Before getting started, make sure you have:
- Docker and Docker Compose installed (for self-hosted deployment)
- Node.js v18+ (for npm installation)
- API key from OpenAI or Anthropic
- Basic understanding of REST APIs and JSON
Installing n8n
Method 1: Docker Self-Hosted (Recommended)
Docker is the easiest and most reliable way to run n8n on your own server.
# Create a directory for n8n
mkdir n8n-docker && cd n8n-docker
Create docker-compose.yml file
cat > docker-compose.yml << 'EOF'
version: '3.8'
services:
n8n:
image: docker.n8n.io/n8nio/n8n
restart: always
ports:
- "5678:5678"
environment:
- N8NBASICAUTHACTIVE=true
- N8NBASICAUTHUSER=admin
- N8NBASICAUTHPASSWORD=securepassword
- N8NHOST=localhost
- N8NPORT=5678
- N8NPROTOCOL=http
- GENERICTIMEZONE=Asia/Jakarta
volumes:
- n8ndata:/home/node/.n8n
volumes:
n8ndata:
EOF
Start n8n
docker compose up -d
Once the container is running, open your browser and navigate to http://localhost:5678. You will see the n8n initial setup page.
Method 2: Installation via npm
If you prefer running n8n directly without Docker:
# Install n8n globally
npm install -g n8n
Start n8n
n8n start
Or start with tunnel for webhook testing
n8n start --tunnel
To run n8n as a background service on Linux, you can use pm2:
npm install -g pm2
pm2 start n8n
pm2 save
pm2 startup
Basic Workflow Concepts
Nodes
A node is the fundamental unit in n8n. Each node performs one specific task, such as sending an HTTP request, processing data, or interacting with external services. There are several types of nodes:
- Trigger Nodes: Start workflows (e.g., Webhook, Schedule, Email Trigger)
- Regular Nodes: Process data (e.g., HTTP Request, Code, IF)
- AI Nodes: Interact with AI models (e.g., AI Agent, LLM Chain)
Connections
Connections link the output of one node to the input of another. Data flows through connections as JSON items. Each item is a single unit of data being processed.
[
{
"json": {
"name": "John",
"email": "john@example.com",
"message": "I need help with my order"
}
}
]
Triggers
Triggers determine when a workflow runs. Some commonly used triggers include:
- Webhook Trigger: Runs the workflow when an HTTP request is received
- Schedule Trigger: Runs the workflow on a specific schedule (cron)
- Email Trigger: Runs the workflow when a new email is received
- Manual Trigger: Runs the workflow manually from the editor
Setting Up AI Agent Nodes
Adding Credentials
Before using AI nodes, you need to add credentials for your LLM provider. Go to Settings > Credentials and add:
For OpenAI:Credentials Management Best Practices
Important tips for managing credentials in n8n:
- Use environment variables to store API keys in production
- Never hard-code API keys inside Code nodes
- Rotate API keys regularly
- Restrict access to the credentials page to administrators only
You can also set credentials through environment variables:
# In docker-compose.yml, add:
environment:
- CREDENTIALSOVERWRITEDATA={"openAiApi":{"apiKey":"sk-your-key"}}
Connecting to OpenAI and Anthropic
OpenAI Chat Model Node
To use OpenAI models in your workflow:
{
"model": "gpt-4o",
"temperature": 0.7,
"maxTokens": 2048,
"topP": 1
}
Anthropic Chat Model Node
To use Anthropic models:
{
"model": "claude-sonnet-4-20250514",
"temperature": 0.7,
"maxTokens": 2048
}
Tool Nodes
Tool nodes allow your AI agent to interact with the outside world. Here are some important tool nodes:
HTTP Request Tool
Allows the AI agent to make HTTP requests to external APIs:
{
"name": "Customer API",
"description": "Fetches customer data by ID",
"url": "https://api.example.com/customers/{{ $json.customerId }}",
"method": "GET",
"headers": {
"Authorization": "Bearer {{ $credentials.apiToken }}"
}
}
Code Tool
Runs JavaScript or Python code to process data:
// Code Tool - Simple sentiment analysis example
const message = $input.first().json.message;
const positiveWords = ['good', 'happy', 'thank you', 'satisfied', 'excellent'];
const negativeWords = ['bad', 'disappointed', 'angry', 'slow', 'failed'];
let sentiment = 'neutral';
const lowerMessage = message.toLowerCase();
if (positiveWords.some(word => lowerMessage.includes(word))) {
sentiment = 'positive';
} else if (negativeWords.some(word => lowerMessage.includes(word))) {
sentiment = 'negative';
}
return [{ json: { message, sentiment } }];
Database Tool
Allows the AI agent to access databases for reading or writing data:
-- Example query for Database Tool (PostgreSQL)
SELECT orderid, status, createdat
FROM orders
WHERE customeremail = '{{ $json.email }}'
ORDER BY createdat DESC
LIMIT 5;
AI Chains
Basic LLM Chain
The Basic LLM Chain is the simplest way to use an LLM in n8n. This chain accepts a prompt and returns a response:
You are a friendly and professional customer support assistant.
Analyze the following customer message and provide a classification:
Message: {{ $json.message }}
Classify into one of the following categories:
- billing: Questions about invoices or payments
- technical: Technical issues with the product
- general: General inquiries
- complaint: Customer complaints
Provide your response in JSON format:
{"category": "...", "priority": "high/medium/low", "summary": "..."}
Conversational Chain
The Conversational Chain maintains conversation context through memory:
You are a virtual assistant for the online store "ShopForward".
You help customers with:
- Product information and stock availability
- Order shipping status
- Return processes
- General service inquiries
Always be friendly and professional.
If you don't know the answer, direct the customer to the human support team.
Vector Store Integration
Vector stores allow your AI agent to search for information from a document knowledge base using semantic search.
Setup with Pinecone
{
"vectorStore": "Pinecone",
"indexName": "knowledge-base",
"namespace": "customer-support",
"embedding": {
"model": "text-embedding-3-small",
"dimensions": 1536
}
}
Setup with Qdrant (Self-Hosted)
For a self-hosted option, you can use Qdrant:
# Add to docker-compose.yml
services:
qdrant:
image: qdrant/qdrant
ports:
- "6333:6333"
volumes:
- qdrantdata:/qdrant/storage
Then in n8n:
http://qdrant:6333Retrieval Workflow
Here is an example workflow for retrieval from a vector store:
Webhook Trigger → Extract Question → Vector Store Retriever → AI Agent → Response
The AI Agent will use results from the vector store as additional context to answer customer questions.
Webhook Triggers
Webhooks are the most common way to receive data from external applications in real-time.
Creating a Webhook Endpoint
{
"httpMethod": "POST",
"path": "customer-support",
"authentication": "headerAuth",
"headerName": "X-API-Key",
"headerValue": "{{ $credentials.webhookApiKey }}"
}
https://your-n8n-domain.com/webhook/customer-supportTesting the Webhook
curl -X POST http://localhost:5678/webhook/customer-support \
-H "Content-Type: application/json" \
-H "X-API-Key: your-secret-key" \
-d '{
"customerid": "C001",
"name": "John Smith",
"email": "john@example.com",
"message": "My order has not arrived after 5 days",
"channel": "web"
}'
Error Handling
n8n provides several mechanisms for handling errors in workflows:
Error Trigger Node
This node catches errors from other workflows and allows you to create error handling logic:
// In a Code node after the Error Trigger,const errorData = $input.first().json;
const notification = {
text:
Workflow Error Alert!Workflow: ${errorData.workflow.name}
Node: ${errorData.execution.error.node}
Message: ${errorData.execution.error.message}
Time: ${new Date().toISOString()}
channel: "#alerts"
};
return [{ json: notification }];
Try-Catch Pattern
Use an IF node to check whether an operation succeeded:
// Check if API response is valid
const statusCode = $input.first().json.statusCode;
if (statusCode >= 200 && statusCode < 300) {
// Success path
return [{ json: { success: true, data: $input.first().json.body } }];
} else {
// Error path - send to fallback
return [{ json: { success: false, error: $input.first().json.body } }];
}
Retry Logic
Every node in n8n can be configured for automatic retries:
{
"retry": {
"enabled": true,
"maxRetries": 3,
"waitBetweenRetries": 1000
}
}
Practical Example: Automated Customer Support Pipeline
Now we will build a complete automated customer support pipeline. This pipeline receives customer messages via webhook, classifies intent using AI, routes to the appropriate handler, and responds via API.
Pipeline Architecture
Webhook (Receive Message)
↓
AI Agent (Classify Intent)
↓
Switch Node (Routing)
├── billing → Billing Handler → Response
├── technical → Technical Handler → Response
├── complaint → Complaint Handler + Escalation → Response
└── general → General Handler → Response
↓
HTTP Request (Send Response via API)
Step 1: Setup Webhook Trigger
Create a new workflow and add a Webhook node:
{
"node": "Webhook",
"parameters": {
"httpMethod": "POST",
"path": "support-inbox",
"responseMode": "responseNode",
"options": {
"rawBody": false
}
}
}
Step 2: AI Classification Agent
Add an AI Agent node connected to an OpenAI Chat Model:
System Prompt:
You are a customer support message classification system.
Analyze the customer message and return a classification result in JSON format.
Available categories:
billing - Invoice questions, payments, refunds
technical - Technical issues, bugs, errors, access problems
complaint - Complaints, dissatisfaction, grievances
general - General questions, product information, operating hours
Priority levels:
- high: Requires immediate attention (serious complaints, service down)
- medium: Needs to be handled within 24 hours
- low: Can be handled within normal timeframes
Output format:
{
"category": "billing|technical|complaint|general",
"priority": "high|medium|low",
"summary": "brief summary of the issue",
"suggestedresponse": "suggested response for the customer"
}
Step 3: Switch Node for Routing
Add a Switch node to route messages based on category:
// Routing rules in Switch node
// Rule 1: Billing
$json.category === "billing"
// Rule 2: Technical
$json.category === "technical"
// Rule 3: Complaint
$json.category === "complaint"
// Rule 4: General (fallback)
true
Step 4: Handlers for Each Category
Billing Handler (Code Node):const classification = $input.first().json;
const originalMessage = $('Webhook').first().json;
const response = {
customerid: originalMessage.customerid,
category: "billing",
response: classification.suggestedresponse,
metadata: {
priority: classification.priority,
handledby: "ai-agent",
timestamp: new Date().toISOString()
}
};
// If high priority, flag for escalation
if (classification.priority === "high") {
response.escalate = true;
response.escalationteam = "billing-senior";
}
return [{ json: response }];
Technical Handler (Code Node):
const classification = $input.first().json;
const originalMessage = $('Webhook').first().json;
const response = {
customerid: originalMessage.customerid,
category: "technical",
response: classification.suggestedresponse,
metadata: {
priority: classification.priority,
handledby: "ai-agent",
timestamp: new Date().toISOString()
},
createticket: true,
ticketdata: {
title: classification.summary,
priority: classification.priority,
assignedteam: "engineering"
}
};
return [{ json: response }];
Complaint Handler (Code Node):
const classification = $input.first().json;
const originalMessage = $('Webhook').first().json;
const response = {
customerid: originalMessage.customerid,
category: "complaint",
response: classification.suggestedresponse,
metadata: {
priority: "high", // Complaints are always high priority
handledby: "ai-agent",
timestamp: new Date().toISOString()
},
escalate: true,
escalationteam: "customer-relations",
notification: {
channel: "slack",
message: New complaint from ${originalMessage.name}: ${classification.summary}
}
};
return [{ json: response }];
Step 5: Send Response via API
Add an HTTP Request node at the end of each handler:
{
"node": "HTTP Request",
"parameters": {
"method": "POST",
"url": "https://api.example.com/support/responses",
"headers": {
"Content-Type": "application/json",
"Authorization": "Bearer {{ $credentials.supportApiToken }}"
},
"body": {
"customerid": "{{ $json.customerid }}",
"responsetext": "{{ $json.response }}",
"category": "{{ $json.category }}",
"metadata": "{{ JSON.stringify($json.metadata) }}"
}
}
}
Step 6: Respond to Webhook
Add a "Respond to Webhook" node to return a response to the caller:
const result = $input.first().json;
return [{
json: {
success: true,
message: "Message processed successfully",
category: result.category,
priority: result.metadata.priority,
response: result.response,
escalated: result.escalate || false
}
}];
Testing the Pipeline
# Test with a billing message
curl -X POST http://localhost:5678/webhook/support-inbox \
-H "Content-Type: application/json" \
-d '{
"customerid": "C001",
"name": "Alice Johnson",
"email": "alice@example.com",
"message": "I already paid but the invoice still shows as unpaid"
}'
Test with a technical message
curl -X POST http://localhost:5678/webhook/support-inbox \
-H "Content-Type: application/json" \
-d '{
"customerid": "C002",
"name": "Bob Williams",
"email": "bob@example.com",
"message": "The app shows error 500 when I try to upload a PDF file"
}'
Test with a complaint
curl -X POST http://localhost:5678/webhook/support-inbox \
-H "Content-Type: application/json" \
-d '{
"customerid": "C003",
"name": "Carol Davis",
"email": "carol@example.com",
"message": "I am very disappointed with your service, I have complained 3 times with no resolution"
}'
Production Deployment Tips
Security
# Use HTTPS with reverse proxy (nginx)
server {
listen 443 ssl;
servername n8n.yourdomain.com;
sslcertificate /etc/ssl/certs/your-cert.pem;
sslcertificatekey /etc/ssl/private/your-key.pem;
location / {
proxypass http://localhost:5678;
proxysetheader Host $host;
proxysetheader X-Real-IP $remoteaddr;
proxysetheader X-Forwarded-For $proxyaddxforwardedfor;
proxysetheader X-Forwarded-Proto $scheme;
# WebSocket support
proxyhttpversion 1.1;
proxysetheader Upgrade $httpupgrade;
proxysetheader Connection "upgrade";
}
}
Monitoring
Enable logging and monitoring for production:
# Environment variables for logging
N8NLOGLEVEL=info
N8NLOGOUTPUT=console,file
N8NLOGFILELOCATION=/var/log/n8n/
EXECUTIONSDATASAVEONERROR=all
EXECUTIONSDATASAVEONSUCCESS=all
Backup
# Backup n8n data regularly
#!/bin/bash
BACKUPDIR="/backups/n8n"
DATE=$(date +%Y%m%d%H%M%S)
Export all workflows
n8n export:workflow --all --output="$BACKUPDIR/workflows$DATE.json"
Export credentials (encrypted)
n8n export:credentials --all --output="$BACKUPDIR/credentials$DATE.json"
Backup database
docker exec n8n-db pgdump -U n8n n8n > "$BACKUPDIR/db$DATE.sql"
Conclusion
n8n with AI Agent features provides incredible capabilities for automating complex business processes. In this tutorial, we covered:
- How to install n8n using Docker and npm
- Basic workflow concepts: nodes, connections, and triggers
- Setting up AI Agents with OpenAI and Anthropic models
- Using tool nodes for interacting with external systems
- AI Chains for natural language processing
- Vector store integration for knowledge bases
- Error handling and best practices
- Building an end-to-end automated customer support pipeline
With this foundation, you can build more complex automations such as automated lead scoring, content moderation, document processing, and much more. The power of n8n lies in its ability to combine a visual workflow builder with AI capabilities, making it accessible to both developers and non-developers alike.