Skip to content
BotServBotServ
MatrixBotOllamaIADescentralizadoE2EE

Bot Matrix con Ollama

Crea un Bot Matrix con Ollama. Chat descentralizado con IA, integración de salas, E2EE y ejemplos prácticos.

S

schutzgeist

6 min read
Bot Matrix con Ollama

Bot de Matrix con Ollama

Qué cubre este artículo

  • Cómo construir un bot de Matrix con Ollama como backend de IA.
  • Cómo integrar el bot en salas de Matrix.
  • Cómo funcionan RAG e integración de herramientas en Matrix.
  • Ejemplos prácticos para bots de soporte, moderación y automatización.
  • Mejores prácticas para E2EE, seguridad y privacidad.

Introducción: bot de Matrix con Ollama explicado

Matrix es un protocolo de chat descentralizado: autohospedado, cifrado, sin una empresa central. Un bot de Matrix con Ollama responde preguntas en tus salas de Matrix usando IA local: sin enviar datos a terceros, sin costos de API, control total.

Este artículo está dirigido a usuarios que quieren construir un bot de Matrix con IA local. Encontrarás información básica en Bots de Matrix y Ollama.

¿Por qué necesito un bot de Matrix con Ollama?

Los bots de Discord se ejecutan en servidores de Discord: tus datos están en Discord. Matrix es autohospedado: tu servidor, tus datos. Un bot de Matrix con Ollama es la solución más coherente para privacidad: protocolo descentralizado + IA local = nadie ve tus datos.

Bot de Matrix con Ollama en pocas palabras

Creas un bot de Matrix (matrix-nio o matrix-js-sdk) que reacciona a mensajes en salas. Cuando llega un mensaje, el bot invoca Ollama y publica la respuesta. Con E2EE, incluso los mensajes permanecen cifrados.

La idea central es: protocolo descentralizado + IA local = control máximo.

¿Para quién es este artículo?

  • Usuarios de Matrix que quieren un bot con IA.
  • Conscientes de privacidad que evitan Discord.
  • Autohospedadores que ejecutan su propio servidor de Matrix.
  • Desarrolladores que construyen bots de Matrix.

Es útil tener conocimientos previos en Python y Ollama.

Términos importantes

  • Matrix - Protocolo descentralizado de chat. Cuándo es útil: el protocolo.
  • Synapse - Homeserver de Matrix. Cuándo es útil: el software del servidor.
  • Element - Cliente de Matrix. Cuándo es útil: la interfaz.
  • matrix-nio - Librería de Python. Cuándo es útil: para el bot.
  • Ollama - Servidor de modelos local. Cuándo es útil: el backend de IA.
  • E2EE - Cifrado de extremo a extremo. Cuándo es útil: para mensajes privados.
  • RAG - Base de datos de conocimiento. Cuándo es útil: para preguntas frecuentes.

Configuración: crear el bot de Matrix

1. Cuenta de bot en tu homeserver

# En el servidor Synapse: crear usuario bot
register_new_matrix_user -c /etc/matrix-synapse/homeserver.yaml \
  -u ki-bot -p "sicheres-passwort" --no-admin

2. Bot con matrix-nio

# bot.py
import asyncio
import aiohttp
from nio import AsyncClient, RoomMessageText

OLLAMA_URL = "http://ollama:11434"
HOMESERVER = "https://matrix.deine-domain.de"
BOT_USER = "@ki-bot:deine-domain.de"
BOT_PASSWORD = "sicheres-passwort"

async def call_ollama(prompt, system=None):
    """Llamar a Ollama"""
    messages = []
    if system:
        messages.append({"role": "system", "content": system})
    messages.append({"role": "user", "content": prompt})

    async with aiohttp.ClientSession() as session:
        async with session.post(
            f"{OLLAMA_URL}/api/chat",
            json={
                "model": "llama3.1",
                "messages": messages,
                "stream": False
            },
            timeout=aiohttp.ClientTimeout(total=60)
        ) as response:
            data = await response.json()
            return data["message"]["content"]

async def main():
    client = AsyncClient(HOMESERVER, BOT_USER)

    # Login
    response = await client.login(BOT_PASSWORD)
    print(f"Bot conectado: {response.user_id}")

    # Auto-join en invitaciones
    client.add_event_callback(on_invite, InviteEvent)

    async def on_message(room, event):
        """Con nuevo mensaje"""
        if event.sender == BOT_USER:
            return

        # Reaccionar a menciones o comandos
        if f"{BOT_USER}" in event.body or event.body.startswith("!"):
            async with client.typing(room.room_id):
                # Extraer pregunta
                question = event.body.replace(f"@{BOT_USER.split(':')[0][1:]}", "").strip()
                if question.startswith("!"):
                    question = question[1:].strip()

                # Llamar a Ollama
                answer = await call_ollama(
                    question,
                    system="Eres un asistente útil en un chat de Matrix. Responde brevemente y de forma útil."
                )

                # Enviar respuesta
                await client.room_send(
                    room_id=room.room_id,
                    message_type="m.room.message",
                    content={
                        "msgtype": "m.text",
                        "body": answer
                    }
                )

    client.add_event_callback(on_message, RoomMessageText)

    # Bucle de sincronización
    await client.sync_forever(timeout=30000)

asyncio.run(main())

3. Invitar el bot a una sala

# En Element (cliente de Matrix):
1. Crear o abrir una sala
2. /invite @ki-bot:deine-domain.de
3. El bot acepta automáticamente (callback on_invite)

Ejemplo práctico 1: bot de preguntas frecuentes con RAG

import chromadb

class MatrixFAQBot:
    def __init__(self):
        self.chroma = chromadb.HttpClient(host="chromadb", port=8000)
        self.collection = self.chroma.get_collection("faq")

    async def answer(self, question):
        """Responder pregunta con RAG"""
        results = self.collection.query(
            query_texts=[question],
            n_results=3
        )

        context = "\n".join(results["documents"][0])

        answer = await call_ollama(
            f"Contexto:\n{context}\n\nPregunta: {question}",
            system="Responde la pregunta basándote en el contexto. Proporciona fuentes."
        )

        return {
            "answer": answer,
            "sources": [m["source"] for m in results["metadatas"][0]]
        }

# En on_message:
if event.body.startswith("!faq"):
    question = event.body[4:].strip()
    result = await faq_bot.answer(question)
    await client.room_send(
        room_id=room.room_id,
        message_type="m.room.message",
        content={
            "msgtype": "m.text",
            "body": f"{result['answer']}\n\nFuentes: {', '.join(result['sources'])}"
        }
    )

Ejemplo práctico 2: Moderación

async def moderate_message(room, event, client):
    """Moderar mensaje"""
    analysis = await call_ollama(
        f"Analiza:\n{event.body}\n\n"
        "Categorías: ok, spam, tóxico, nsfw\n"
        "Responde: CATEGORÍA|RAZÓN",
        system="Eres un asistente de moderación."
    )

    category, reason = analysis.split("|", 1)

    if category != "ok":
        # Eliminar mensaje (el bot necesita permisos de moderador)
        await client.room_redact(
            room_id=room.room_id,
            event_id=event.event_id,
            reason=reason
        )
        # Enviar advertencia
        await client.room_send(
            room_id=room.room_id,
            message_type="m.room.message",
            content={
                "msgtype": "m.text",
                "body": f"⚠️ Mensaje eliminado: {reason}"
            }
        )

Caso práctico 3: Disparador de flujos de trabajo

if event.body.startswith("!workflow"):
    parts = event.body.split()
    workflow_name = parts[1] if len(parts) > 1 else "default"
    params = " ".join(parts[2:]) if len(parts) > 2 else ""

    # Llamar webhook de n8n
    async with aiohttp.ClientSession() as session:
        async with session.post(
            f"http://n8n:5678/webhook/{workflow_name}",
            json={"params": params, "user": event.sender}
        ) as r:
            result = await r.text()

    await client.room_send(
        room_id=room.room_id,
        message_type="m.room.message",
        content={
            "msgtype": "m.text",
            "body": f"Workflow {workflow_name}: {result}"
        }
    )

Tener en cuenta el cifrado E2EE

Los espacios de Matrix pueden estar cifrados de extremo a extremo. El bot solo puede leer mensajes sin cifrar, a menos que tenga acceso a las claves.

# Bot con E2EE usando matrix-nio
from nio import AsyncClient, MatrixRoom, RoomMessageText
from nio.crypto import OlmMachine

# Un bot con E2EE necesita:
# 1. Claves de dispositivo
# 2. Relación de confianza con otros dispositivos
# 3. Descifrado de mensajes

# Esto es complejo. Para empezar:
# - Usa el bot solo en espacios sin cifrar
# - O: utiliza una librería como pantalaimon

Consideraciones de seguridad

  • Contraseña del bot: Usa una contraseña fuerte y almacénala de forma segura. Consulta Secretos.
  • Permisos: El bot solo debe tener permisos de lectura y escritura, nunca de administrador.
  • E2EE: En espacios cifrados, el bot solo puede leer si tiene las claves.
  • Inyección de prompts: Los usuarios pueden intentar inyecciones. Consulta Inyección de prompts.
  • Federación: Matrix es federado: los mensajes pueden ir a otros servidores.

Errores comunes

  • Complejidad de E2EE: Los espacios cifrados requieren gestión de claves. Para empezar, usa espacios sin cifrar.
  • Token vs. contraseña: Un token de acceso es mejor que una contraseña. Guárdalo después del inicio de sesión.
  • Limitación de velocidad: Los servidores Matrix tienen límites. Implementa throttling.
  • Respuestas demasiado largas: Matrix tiene un límite (~65 KB por mensaje). Divide las respuestas largas.
  • Federación: El bot solo ve espacios en los que está. Los espacios remotos mediante federación funcionan de otra forma.

Enlaces de interés

Puntos clave:

  • Matrix + Ollama: chat descentralizado con IA local.
  • matrix-nio para bots en Python, matrix-js-sdk para JavaScript.
  • El bot responde a menciones y comandos.
  • RAG para preguntas frecuentes, moderación para seguridad, flujos de trabajo para automatización.
  • E2EE es complejo; para empezar, usa espacios sin cifrar.

Preguntas frecuentes

¿Cómo creo un bot de Matrix?

Crea una cuenta bot en tu servidor Synapse (register_new_matrix_user), luego programa con matrix-nio (Python) o matrix-js-sdk (JavaScript).

¿Matrix o Discord para bots?

Matrix para máximo control y privacidad (auto-alojado, descentralizado). Discord para comunidades más grandes y configuración más sencilla. Matrix es la opción de privacidad.

¿Funciona el bot en espacios cifrados?

Solo si el bot tiene las claves. Los bots con E2EE son complejos (gestión de claves, confianza de dispositivos). Para empezar, usa espacios sin cifrar.

¿Qué librería para bots de Matrix?

matrix-nio para Python (async, bien documentada). matrix-js-sdk para JavaScript. matrix-bot-sdk para abstracción más simple.

¿Necesito mi propio servidor?

No, puedes registrar el bot en cualquier servidor (p. ej., matrix.org). Pero para máximo control y privacidad, un servidor Synapse propio es mejor.

¿Es seguro el bot?

Sí, si guardas la contraseña de forma segura, asignas permisos mínimos y evitas inyecciones de prompts. Matrix es descentralizado: los mensajes pueden federarse.

¿Cuánto cuesta?

Gratis. Synapse, matrix-nio y Ollama son código abierto. Solo pagas infraestructura y hardware.

¿Para qué puedo usar el bot?

Bot de FAQ, soporte, moderación, disparadores de flujos de trabajo, Q&A de documentos (RAG), notificaciones, traducción, resumen.

Fuentes y lecturas complementarias

Volver al blog
Share:

Entradas relacionadas