Skip to content
BotServBotServ
WhatsAppBotBot IAOllamawhatsapp-web.jsBaileysSelf-Hosting

Bot de WhatsApp con IA Local

Crea un bot de WhatsApp con Ollama: API Business vs whatsapp-web.js, emparejamiento QR, grupos y extensiones.

S

schutzgeist

7 min read
Bot de WhatsApp con IA Local

Bot de WhatsApp con IA local

Qué cubriremos aquí

  • Los dos caminos hacia un bot de WhatsApp: API Business oficial vs. librerías no oficiales.
  • Ejemplo práctico con whatsapp-web.js/Baileys y Ollama.
  • Emparejamiento por código QR, persistencia de sesión, funcionamiento en grupos.
  • Riesgos legales y técnicos, y cuándo conviene cada enfoque.
  • Extensiones: RAG, imágenes, notas de voz, moderación.

Introducción

WhatsApp es el mensajero más usado en Alemania, pero también la plataforma menos amigable con bots. No existe una API de bot oficial y gratuita para cuentas privadas. Hay dos caminos disponibles:

  1. WhatsApp Business Platform (Cloud API): Oficial, estable, pero compleja: requiere cuenta de desarrollador en Meta, verificación empresarial, mensajes de plantilla aprobados, y costos por conversación.
  2. Librerías no oficiales (whatsapp-web.js, Baileys): Simulan WhatsApp Web, funcionan con cuentas normales, pero violan los términos de servicio y conllevan riesgo de bloqueo.

Este artículo explora ambos caminos y aclara cuándo cada uno tiene sentido.

Casos de uso típicos

  • Asistente interno del equipo: Los empleados consultan al bot en WhatsApp, con documentación interna mediante RAG.
  • Atención al cliente de primer nivel: Responder preguntas frecuentes, escalar casos complejos a personas.
  • Notificaciones: Alertas del servidor, recordatorios de citas, estado de pedidos directamente al móvil.
  • Bot para familias o asociaciones: Obtener información, mantener listas, recordar fechas.
  • Cuidado con la visibilidad pública: Para canales de clientes públicos, la API Business es el único camino seguro.

Opción 1: Librerías no oficiales (whatsapp-web.js / Baileys)

Cómo funciona

whatsapp-web.js (Node.js) y Baileys (TypeScript) hablan el protocolo de WhatsApp Web: tu bot se empareja como un segundo dispositivo mediante código QR. Necesitas tu propio número (también funciona un teléfono fijo: verificación por llamada).

npm install whatsapp-web.js qrcode-terminal axios

Bot mínimo con Ollama

const { Client, LocalAuth } = require('whatsapp-web.js');
const qrcode = require('qrcode-terminal');
const axios = require('axios');

const client = new Client({
    authStrategy: new LocalAuth({ dataPath: './session' }),
    puppeteer: { headless: true, args: ['--no-sandbox'] }
});

client.on('qr', qr => qrcode.generate(qr, { small: true }));
client.on('ready', () => console.log('Bot bereit'));

client.on('message', async msg => {
    if (msg.fromMe || !msg.body) return;

    // Nur auf Direktnachrichten oder Erwähnungen reagieren
    const chat = await msg.getChat();
    if (chat.isGroup && !msg.body.startsWith('!ki')) return;

    const prompt = msg.body.replace(/^!ki\s*/, '');

    try {
        const res = await axios.post('http://localhost:11434/api/chat', {
            model: 'llama3.1:8b',
            messages: [
                { role: 'system', content: 'Du bist ein hilfsbereiter Assistent. Kurze Antworten.' },
                { role: 'user', content: prompt }
            ],
            stream: false
        });
        await msg.reply(res.data.message.content);
    } catch (e) {
        await msg.reply('Fehler: Ollama nicht erreichbar.');
    }
});

client.initialize();

Ejecuta el script, escanea el código QR en la terminal con tu móvil (WhatsApp → Dispositivos vinculados). Listo.

Variante con Baileys (sin navegador headless)

Baileys implementa el protocolo de forma nativa, sin necesidad de Chromium y con mucha menos memoria:

const { makeWASocket, useMultiFileAuthState } = require('@whiskeysockets/baileys');

const { state, saveCreds } = await useMultiFileAuthState('./session');
const sock = makeWASocket({ auth: state });

sock.ev.on('creds.update', saveCreds);
sock.ev.on('messages.upsert', async ({ messages }) => {
    const m = messages[0];
    if (!m.message?.conversation || m.key.fromMe) return;
    // Llamada a Ollama como arriba, luego:
    await sock.sendMessage(m.key.remoteJid, { text: 'Respuesta...' });
});

Los riesgos, siendo honestos

  • Bloqueo de cuenta: Meta borra regularmente los clientes no oficiales. Usa un número extra, nunca la principal.
  • Las sesiones se rompen: Las sesiones de WhatsApp Web expiran, tu bot debe manejar el reemparejamiento.
  • Sin garantías de operación: No es apto para clientes empresariales, el número puede desaparecer en cualquier momento.
  • E2EE se mantiene: Los mensajes siguen siendo E2E cifrados, el bot descifra localmente, lo cual es bueno para la privacidad.

Opción 2: WhatsApp Business Platform (Cloud API)

Configuración general

  1. Cuenta de desarrollador en Meta → Crear app → Añadir «WhatsApp»
  2. Verificar número de prueba o tu número empresarial propio (requiere verificación de empresa)
  3. Configurar webhook en tu servidor
  4. Generar token permanente

Recibir mensajes (Webhook)

from flask import Flask, request
import requests

app = Flask(__name__)
VERIFY_TOKEN = "dein-verify-token"
WA_TOKEN = "dein-permanent-token"
PHONE_ID = "deine-phone-number-id"

@app.route("/webhook", methods=["GET"])
def verify():
    if request.args.get("hub.verify_token") == VERIFY_TOKEN:
        return request.args.get("hub.challenge")
    return "Forbidden", 403

@app.route("/webhook", methods=["POST"])
def receive():
    data = request.json
    for entry in data.get("entry", []):
        for change in entry.get("changes", []):
            for msg in change.get("value", {}).get("messages", []):
                text = msg["text"]["body"]
                sender = msg["from"]
                answer = ask_ollama(text)
                send_message(sender, answer)
    return "OK", 200

def ask_ollama(prompt):
    r = requests.post("http://localhost:11434/api/chat", json={
        "model": "llama3.1:8b",
        "messages": [{"role": "user", "content": prompt}],
        "stream": False
    })
    return r.json()["message"]["content"]

def send_message(to, text):
    requests.post(
        f"https://graph.facebook.com/v19.0/{PHONE_ID}/messages",
        headers={"Authorization": f"Bearer {WA_TOKEN}"},
        json={
            "messaging_product": "whatsapp",
            "to": to,
            "type": "text",
            "text": {"body": text[:4000]}
        }
    )

Limitaciones importantes de la API Business

  • Ventana de 24 horas: Los mensajes sin costo solo funcionan si el usuario escribió en las últimas 24 horas. Si no, solo mensajes de plantilla (aprobados por Meta).
  • Costos: Aproximadamente 0,07-0,11 € por conversación en Alemania. Desde 2024, algunas conversaciones de servicio son gratuitas, pero las de marketing son más caras.
  • Verificación obligatoria: Sin empresa verificada, estás limitado a 250 conversaciones en 24 horas.

Extensiones

RAG: Conocimiento de documentos

Mismo patrón que en el bot de Telegram, mensaje entrante → embedding → búsqueda en Qdrant → contexto a Ollama:

def ask_ollama_with_rag(prompt):
    context = search_qdrant(prompt)   # Top-3-Chunks
    r = requests.post("http://localhost:11434/api/chat", json={
        "model": "llama3.1:8b",
        "messages": [
            {"role": "system", "content": f"Nutze diesen Kontext:\n{context}"},
            {"role": "user", "content": prompt}
        ],
        "stream": False
    })
    return r.json()["message"]["content"]

Transcribir notas de voz

Notas de voz de WhatsApp (Opus-OGG) → Whisper local → texto → Ollama. Con whatsapp-web.js usa msg.downloadMedia(), con la API Business: obtén la ID de media → descarga desde el endpoint.

Funcionamiento en grupos

  • En grupos, reacciona solo ante el prefijo (!ki) o menciones, si no el bot leerá todo el chat.
  • Lista de administradores para comandos de moderación (!kick, !warn).
  • Whitelist de IDs de grupo: el bot debe estar activo solo en grupos autorizados.

Transferencia a humanos (Business API)

Patrón “Bot primero, fallback humano”: cuando la IA tiene dudas, deriva la conversación a un empleado mediante notificación interna o sistema de tickets como Chatwoot.

Deployment

whatsapp-web.js consume más recursos por Puppeteer y Chromium:

FROM node:20-slim
RUN apt-get update && apt-get install -y chromium fonts-liberation \
    && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
CMD ["node", "bot.js"]
services:
  whatsapp-bot:
    build: .
    restart: always
    volumes:
      - wa_session:/app/session   # ¡Persistir la sesión!
    environment:
      - OLLAMA_URL=http://ollama:11434

volumes:
  wa_session:

Importante: sin volumen de sesión persistente, deberás escanear el código QR en cada reinicio.

Consideraciones legales

  • GDPR: los bots de WhatsApp procesan números de teléfono y contenido de chat, datos personales. En uso empresarial: documenta política de privacidad, contrato de procesamiento con Meta, consentimiento de usuarios.
  • Términos de servicio: las bibliotecas no oficiales violan los términos de WhatsApp, riesgo de bloqueo de cuenta. Tolerado para proyectos personales, no para negocio.
  • Sin spam: los mensajes no solicitados son contrarios a la competencia leal en Alemania; responde solo a consultas.

Trampas comunes

  • Código QR caducado: volumen de sesión no persistente o el teléfono estuvo sin conexión. Usa LocalAuth con volumen.
  • Cuenta bloqueada: demasiados mensajes muy rápido o usuarios reportan el bot. Implementa rate limits, agrega retrasos de 2-5s entre respuestas.
  • Chromium consume RAM: whatsapp-web.js necesita ~500MB+. Alternativa: Baileys (protocolo WebSocket puro, sin navegador).
  • Olvidar la ventana de 24h: la Business API rechaza mensajes gratuitos después de 24h, usa plantillas o requiere que el usuario escriba primero.
  • Las IDs de grupo cambian: al reinscribirse, los JID varían, no hardcodes identificadores.

Enlaces de interés

Puntos clave:

  • WhatsApp no tiene una API bot gratuita: bibliotecas no oficiales (riesgo de bloqueo) o Business API (compleja, paga).
  • whatsapp-web.js para proyectos personales con número extra; Business API para atención al cliente.
  • Persiste la sesión o deberás escanear el código QR en cada reinicio.
  • Respeta la ventana de 24h en Business API; las plantillas necesitan aprobación de Meta.
  • Para la mayoría de self-hosters, Telegram es la opción más práctica.

FAQ

La API Business oficial sí. Las bibliotecas no oficiales violan los términos de servicio de WhatsApp, no son ilegales en sentido penal, pero tu cuenta puede bloquearse. Para proyectos personales con número extra está bien, para negocio solo la API oficial.

¿whatsapp-web.js o Baileys?

Baileys es más ligero (sin Chromium, ~100MB RAM), whatsapp-web.js es más simple y mejor documentado. Para proyectos a largo plazo: Baileys.

¿Cómo evito que bloqueen mi cuenta?

Usa número extra, nunca el principal. Rate limits (máx. 20-30 mensajes/min), retrasos de 2-5s entre respuestas, sin envíos masivos a desconocidos, sin mensajes no solicitados.

¿Cuánto cuesta la Business API?

Conversaciones de servicio (usuario escribe primero): generalmente gratuito hasta ~0,03 €. Plantillas de marketing/utilidad: ~0,07-0,11 € por conversación. Además, posibles comisiones de BSPs como Twilio o 360dialog.

¿Se mantiene el cifrado end-to-end?

Con bibliotecas no oficiales sí, se descifran localmente como WhatsApp Web. Con la Cloud API el E2EE termina en Meta: Meta teóricamente puede leer los mensajes.

¿Hay alternativas más simples?

Sí: Telegram (API bot libre, sin proceso de aprobación) o Signal (signal-cli, E2EE se mantiene). WhatsApp vale la pena solo si tu audiencia realmente está allí.

¿Funciona el bot sin el teléfono?

Sí, desde Multi-Device el bot funciona incluso si el teléfono está desconectado (la sesión dura ~14 días sin contacto con el teléfono, después necesita reemparejamiento). Pero el teléfono debe estar en línea durante la configuración inicial.

Fuentes y lecturas adicionales

Volver al blog
Share:

Entradas relacionadas