Skip to main content

Overview

KAIU Natural Living’s AI chatbot provides 24/7 customer support via WhatsApp using Claude AI (Anthropic). The system handles product inquiries, provides recommendations, and seamlessly transfers to human agents when needed.

Architecture

System Components

Queue System

BullMQ + RedisMessage processing queue ensures reliable handling of customer messages even under high load.

AI Engine

Claude 3 HaikuAnthropic’s fast, cost-effective model with native tool calling for inventory and knowledge base queries.

RAG System

Retrieval-Augmented GenerationReal-time database queries for product information and company policies instead of static knowledge.

WhatsApp API

Meta Business APIOfficial WhatsApp Business integration for sending/receiving messages and media.

Message Processing Flow

WhatsApp Integration

Message Queue

The queue system (backend/whatsapp/queue.js) provides:
BullMQ Worker Configuration
export const worker = new Worker('whatsapp-ai', async job => {
  const { wamid, from, text } = job.data;
  console.log(`⚙️ Processing Job: ${job.id} - ${text}`);
  
  // Process message with AI
  const aiResponse = await generateSupportResponse(text, history);
  
  // Send response via WhatsApp
  await axios.post(
    `https://graph.facebook.com/v21.0/${PHONE_ID}/messages`,
    {
      messaging_product: "whatsapp",
      to: from,
      text: { body: aiResponse.text }
    }
  );
}, {
  connection: workerConnection,
  limiter: {
    max: 10, // Max 10 concurrent jobs
    duration: 1000
  }
});
The queue prevents overwhelming the AI API and ensures messages are processed in order.

AI Assistant

Claude AI Configuration

The AI service (backend/services/ai/Retriever.js) uses Claude with custom tools:
const chatModel = new ChatAnthropic({
  modelName: "claude-3-haiku-20240307", // Fast & Cheap
  temperature: 0.1, // Low temp for consistency
  anthropicApiKey: process.env.ANTHROPIC_API_KEY,
});

const modelWithTools = chatModel.bindTools(tools);

Native Tool System

Claude AI has access to two tools for real-time data:
Product Database SearchQueries the live product inventory:
{
  name: "searchInventory",
  description: "Busca en el inventario actual de KAIU para responder sobre precios, disponibilidad y variantes. ÚSALA SIEMPRE que el cliente pregunte por un producto.",
  input_schema: {
    type: "object",
    properties: {
      query: {
        type: "string",
        description: "Nombre del producto o ingrediente (Ej: 'Lavanda', 'Gotero 10ml')"
      }
    },
    required: ["query"]
  }
}
Implementation:
async function executeSearchInventory(query) {
  const terms = query.split(' ').filter(w => w.length > 3);
  const searchConditions = terms.map(t => ({
    OR: [
      { name: { contains: t, mode: 'insensitive' } },
      { category: { contains: t, mode: 'insensitive' } },
      { variantName: { contains: t, mode: 'insensitive' } }
    ]
  }));
  
  const products = await prisma.product.findMany({
    where: { OR: searchConditions },
    select: {
      id: true,
      name: true,
      variantName: true,
      price: true,
      stock: true,
      isActive: true,
      category: true,
      description: true
    }
  });
  
  return JSON.stringify(products.filter(p => p.isActive));
}
Tool returns only active products with available stock information, ensuring AI never recommends unavailable items.
Policy & Information SearchSearches company policies, shipping times, and general information:
{
  name: "searchKnowledgeBase",
  description: "Busca manuales de la empresa, tiempos de envío, costos de envío a ciudades, y políticas generales de la marca.",
  input_schema: {
    type: "object",
    properties: {
      query: {
        type: "string",
        description: "Pregunta o concepto (Ej: 'Tiempos de envío Bogotá', 'Manejan contra entrega')"
      }
    },
    required: ["query"]
  }
}
Currently disabled due to memory constraints on free-tier hosting. Returns placeholder response instructing handover to human agent for policy questions.

Anti-Hallucination Measures

Multiple safeguards prevent the AI from making up information:
1

Forced Tool Calls

When customers ask for photos, system injects instruction:
if (/(foto|imagen|ver|mostrar)/i.test(userQuestion)) {
  userQuestion += "\n[SISTEMA: Obligatorio ejecutar searchInventory "
                + "para obtener IDs reales (UUID). NO inventes IDs.]";
}
2

Short Context Window

History limited to last 4 messages to force fresh database queries:
const recentHistory = chatHistory.slice(-4);
Prevents AI from relying on outdated information from earlier in conversation.
3

Strict Prompting

System prompt explicitly forbids making up data:
“ESTRICTAMENTE PROHIBIDO ADIVINAR O ALUCINAR DATOS. NUNCA respondas sobre la existencia, precios, variantes o imágenes de un producto basándote en tu memoria.”

Image Sending

The bot can send product images via special tags:
When AI wants to send an image:
¡Claro! Aquí está nuestro Aceite Esencial de Lavanda en presentación de 10ml por $45.000. [SEND_IMAGE: a1b2c3d4-uuid-here]

Human Handover

Automatic Transfer

The system detects when customers need human assistance:
const HANDOVER_KEYWORDS = /\b(humano|agente|asesor|persona|queja|reclamo|ayuda|contactar|hablar con alguien)\b/i;

if (HANDOVER_KEYWORDS.test(text)) {
  console.log(`🚨 Handover triggered for ${from}`);
  
  // 1. Disable bot
  await prisma.whatsAppSession.update({
    where: { id: session.id },
    data: {
      isBotActive: false,
      handoverTrigger: "KEYWORD_DETECTED",
      sessionContext: { history }
    }
  });
  
  // 2. Notify customer
  await axios.post(
    `https://graph.facebook.com/v21.0/${PHONE_ID}/messages`,
    {
      messaging_product: "whatsapp",
      to: from,
      text: {
        body: "Te estoy transfiriendo con un asesor humano. Un momento por favor."
      }
    }
  );
  
  // 3. Alert dashboard
  if (io) io.emit('session_update', { id: session.id, status: 'handover' });
  
  return; // STOP AI PROCESSING
}
Trigger keywords (Spanish):
  • humano, agente, asesor, persona
  • queja, reclamo
  • ayuda, contactar
  • hablar con alguien
Once handover occurs, all subsequent messages from that customer are routed directly to human agents until they manually re-enable the bot.

Dashboard Integration

Human agents receive:
  • Real-time notification of handover
  • Full conversation history
  • Customer phone number
  • Reason for handover (keyword detected)
  • Ability to respond directly through dashboard

Conversation Management

History Tracking

Each session maintains conversation context:
// Retrieve existing history
let history = session.sessionContext?.history || [];

// Append user message (with PII redacted)
const cleanText = redactPII(text);
history.push({ role: 'user', content: cleanText });

// AI processes with context
const aiResponse = await generateSupportResponse(text, history);

// Append AI response
history.push({ role: 'assistant', content: aiResponse.text });

// Keep only last 10 messages
if (history.length > 10) history = history.slice(-10);

// Save updated history
await prisma.whatsAppSession.update({
  where: { id: session.id },
  data: { sessionContext: { history } }
});
Memory & Performance
  • Reduces token usage (lower costs)
  • Forces AI to query database for fresh info
  • Prevents context drift and hallucinations
  • Faster response times
Customers can always ask again if they need earlier information.
Sessions automatically expire after 24 hours of inactivity:
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000)
This ensures:
  • Clean slate for returning customers
  • GDPR compliance (data retention)
  • Database cleanup

Response Formatting

All AI messages include a footer for transparency:
const footer = "\n\n_🤖 Asistente Virtual KAIU_";
return { text: aiMessage.content + footer };
Customers always know they’re chatting with AI.

Example Conversations

Customer: Hola, tienen aceite de lavanda?AI: (calls searchInventory with query “lavanda”)AI: ¡Hola! Sí, manejamos Aceite Esencial de Lavanda en estas presentaciones:
  • 10ml - $45.000
  • 30ml - $120.000
  • 50ml - $180.000
¿Cuál te gustaría?🤖 Asistente Virtual KAIU

Error Handling

Queue Failures

Exponential Backoff
settings: {
  backoffStrategy: 'exponential'
}
Failed jobs retry with increasing delays.

AI Errors

Fallback Response
catch (error) {
  return {
    text: "Lo siento, tuve un error interno. Por favor intenta más tarde."
  };
}

WhatsApp API

Retry LogicIf message send fails, BullMQ automatically retries the entire job.

Database

Graceful DegradationIf session lookup fails, creates new session rather than failing.

Performance Metrics

MetricTargetActual
Response Time< 3s~2s avg
Queue Processing10 concurrent
Token Usage< 1000/msg~500 avg
Handover Rate< 10%~5%

Admin Dashboard

Monitor conversations and manage handovers

Inventory

Product database queried by AI

Build docs developers (and LLMs) love