Skip to content
BotServBotServ
MattermostBotKI-BotOllamaSelf-HostingSlack-AlternativeOpen Source

Mattermost-Bot mit lokaler KI

Mattermost-Bot mit Ollama bauen: Self-Hosted Slack-Alternative, Bot-Accounts, Slash-Commands, WebSocket und Docker-Setup.

S

schutzgeist

5 min read
Mattermost-Bot mit lokaler KI

Mattermost-Bot mit lokaler KI

Was dieser Artikel behandelt

  • Wie Du einen Bot auf Deinem eigenen Mattermost-Server mit Ollama baust.
  • Bot-Account anlegen, REST-API und WebSocket-Events.
  • Slash-Commands und interaktive Posts.
  • Erweiterungen: RAG auf Firmenwissen, Moderation, Alerting.
  • Warum Mattermost + Ollama die komplett souveräne Kombination ist.

Einleitung

Mattermost ist der selbst-hostbare Slack-Klon: Open Source (Teams Edition kostenlos), läuft auf eigenem Server, alle Daten bleiben bei Dir. Kombiniert mit Ollama bekommst Du die komplett souveräne Lösung: Chat-Plattform UND KI lokal, nichts geht raus.

Die Bot-Integration ist offiziell und gut dokumentiert: Bot-Accounts mit eigenem Token, REST-API für alles, WebSocket für Echtzeit-Events, Slash-Commands, interaktive Message-Buttons.

Typische Anwendungsszenarien

  • Interner Wissensbot: Firmenwissen per RAG, komplett on-premise, DSGVO-freundlich.
  • DevSecOps-Assistent: Log-Analyse, Runbook-Antworten, Incident-Support.
  • Behörden/Regulierte: KI-Chat dort, wo Cloud-Dienste nicht zulässig sind.
  • Alarm-Drehscheibe: Monitoring → Mattermost-Channel → KI fasst zusammen.
  • Onboarding: Neue Mitarbeiter fragen den Bot, ohne Kollegen zu stören.

Voraussetzungen

  • Laufender Mattermost-Server (Docker: mattermost/mattermost-team-edition)
  • Admin-Zugang zum Anlegen des Bot-Accounts
  • Ollama mit Modell auf demselben Host/Netzwerk
  • Python 3.10+

Schritt 1: Mattermost selbst hosten (Kurzversion)

# docker-compose.yml — Mattermost-Grundgerüst
services:
  db:
    image: postgres:16
    environment:
      POSTGRES_DB: mattermost
      POSTGRES_USER: mmuser
      POSTGRES_PASSWORD: geheim-aendern
    volumes: [db_data:/var/lib/postgresql/data]
    restart: always

  mattermost:
    image: mattermost/mattermost-team-edition:latest
    depends_on: [db]
    ports: ["8065:8065"]
    environment:
      MM_SQLSETTINGS_DRIVERNAME: postgres
      MM_SQLSETTINGS_DATASOURCE: "postgres://mmuser:geheim-aendern@db:5432/mattermost?sslmode=disable"
      MM_SERVICESETTINGS_SITEURL: "https://chat.deine-domain.de"
    volumes: [mm_data:/mattermost/data]
    restart: always

volumes:
  db_data:
  mm_data:

Im Admin-Panel (System Console → Integrations) Bot Accounts aktivieren.

Schritt 2: Bot-Account anlegen

Im UI: System Console → Integrations → Bot Accounts → „Add Bot Account” → Username ki-assistent. Oder per API/CLI:

# per mmctl im Container
docker exec mattermost mmctl --local bot create ki-assistent --display-name "KI-Assistent" --description "Lokaler KI-Bot"

Du bekommst ein Bot-Token (xxx...), wie ein API-Key, in .env halten:

MM_URL=http://mattermost:8065
MM_TOKEN=dein-bot-token
MM_TEAM=dein-team
OLLAMA_URL=http://ollama:11434
OLLAMA_MODEL=llama3.1:8b

Schritt 3: Bot mit WebSocket (Echtzeit)

Mattermost hat eine einfache WebSocket-Event-API: Nachrichten kommen live rein:

import asyncio
import json
import os
import aiohttp
import websockets
import ollama
from dotenv import load_dotenv

load_dotenv()
MM_URL = os.environ["MM_URL"]
MM_TOKEN = os.environ["MM_TOKEN"]
MODEL = os.environ.get("OLLAMA_MODEL", "llama3.1:8b")

ollama_client = ollama.Client(host=os.environ["OLLAMA_URL"])
HEADERS = {"Authorization": f"Bearer {MM_TOKEN}"}

SYSTEM = "Du bist der interne KI-Assistent. Antworte kurz auf Deutsch."


async def api(method, path, payload=None):
    async with aiohttp.ClientSession() as s:
        async with s.request(method, f"{MM_URL}/api/v4{path}",
                             headers=HEADERS, json=payload) as r:
            return await r.json()


async def post_message(channel_id, text, root_id=None):
    await api("POST", "/posts", {
        "channel_id": channel_id,
        "message": text[:16000],
        "root_id": root_id,
    })


def ask_ollama(text, history=None):
    msgs = [{"role": "system", "content": SYSTEM}]
    if history:
        msgs += history
    msgs.append({"role": "user", "content": text})
    return ollama_client.chat(model=MODEL, messages=msgs)["message"]["content"]


async def main():
    me = await api("GET", "/users/me")
    bot_id = me["id"]

    ws_url = MM_URL.replace("http", "ws") + "/api/v4/websocket"
    async with websockets.connect(ws_url) as ws:
        await ws.send(json.dumps({
            "seq": 1, "action": "authentication_challenge",
            "data": {"token": MM_TOKEN}
        }))
        async for raw in ws:
            evt = json.loads(raw)
            if evt.get("event") != "posted":
                continue
            post = json.loads(evt["data"]["post"])
            if post["user_id"] == bot_id:   # eigene Posts ignorieren
                continue

            text = post["message"]
            mention = f"@{me['username']}"
            channel_type = evt["data"].get("channel_type")

            # Nur auf DM oder @mention reagieren
            if channel_type != "D" and mention not in text:
                continue
            text = text.replace(mention, "").strip()
            if not text:
                continue

            # Thread-Kontext aus Root-Posts laden
            history = []
            if post.get("root_id"):
                thread = await api("GET", f"/posts/{post['root_id']}")
                for p in thread["posts"].values():
                    role = "assistant" if p["user_id"] == bot_id else "user"
                    history.append({"role": role, "content": p["message"]})

            answer = ask_ollama(text, history)
            await post_message(post["channel_id"], answer,
                               root_id=post.get("root_id") or post["id"])

asyncio.run(main())

Slash-Commands

In der Admin-Console einen Slash-Command /ki auf Deinen HTTP-Endpoint registrieren (Mattermost pusht dann an Dich, dafür braucht der Bot einen HTTP-Port):

from aiohttp import web

async def slash_ki(request):
    data = await request.post()
    prompt = data.get("text", "").strip()
    if not prompt:
        return web.json_response({"text": "Nutzung: `/ki <Frage>`",
                                  "response_type": "ephemeral"})
    answer = ask_ollama(prompt)
    return web.json_response({
        "text": answer,
        "response_type": "ephemeral",   # nur der Fragende sieht es
    })

app = web.Application()
app.router.add_post("/slash/ki", slash_ki)
web.run_app(app, port=8080)

Erweiterungen

RAG auf Firmenwissen

Identisch zum Slack-Bot: Embeddings der Frage → Qdrant-Suche in firmenwissen-Collection → Kontext in den System-Prompt. Bei Mattermost einfacher zu rechtfertigen, alle Daten ohnehin on-premise.

Interaktive Posts (Buttons)

await api("POST", "/posts", {
    "channel_id": channel_id,
    "message": "Antwort hilfreich?",
    "props": {"attachments": [{
        "actions": [
            {"id": "good", "name": "👍 Hilfreich", "type": "button",
             "integration": {"url": f"{BOT_URL}/action", "context": {"vote": "up"}}},
            {"id": "bad", "name": "👎 Falsch", "type": "button",
             "integration": {"url": f"{BOT_URL}/action", "context": {"vote": "down"}}},
        ]
    }]},
})

Proaktive Alerts

Der Bot schreibt selbst in Channels: Monitoring-Integration:

# Cron/Systemd-Timer oder Event-Handler ruft:
async def alert(channel_id, service, status):
    summary = ask_ollama(
        f"Fasse diesen Monitoring-Alert kurz zusammen und schlage den "
        f"wahrscheinlichsten Fix vor:\nService: {service}\nStatus: {status}"
    )
    await post_message(channel_id, f"🚨 **{service}**\n{summary}")

Moderation

Neue Posts klassifizieren lassen (OK/SPAM/TOXIC), bei Verstoß Post löschen (DELETE /posts/{id}) und User warnen, gleiches Muster wie im Telegram-Artikel.

Deployment: Alles in einem Stack

services:
  mm-bot:
    build: ./bot
    restart: always
    env_file: .env
    depends_on: [mattermost, ollama]
    ports: ["127.0.0.1:8080:8080"]   # für Slash-Commands/Actions

  ollama:
    image: ollama/ollama:latest
    volumes: [ollama_data:/root/.ollama]
    restart: always

Bot, Mattermost und Ollama im selben Docker-Netz → keine externen Abhängigkeiten, keine Daten gehen raus.

Sicherheit

  • Bot-Token: Volle Bot-Rechte, wie ein Admin-Token behandeln. In .env/Docker Secrets.
  • Channel-Isolation: Der Bot sieht nur Channels, in denen er Mitglied ist, nicht automatisch alles.
  • Rate-Limiting: Bei öffentlichen Teams Zugriffs-Limit pro User einbauen (Token-Bucket).
  • Logging: Bot-Aufrufe protokollieren (Audit Logging).
  • TLS: Für Slash-Commands/Actions über HTTPS, intern reicht HTTP im Docker-Netz.

Typische Stolpersteine

  • Bot sieht Channel nicht: Bot muss Channel-Mitglied sein, per UI oder POST /channels/{id}/members hinzufügen.
  • WebSocket trennt sich: Reconnect-Logik einbauen: Netzwerk-Blips sind normal.
  • Eigene Posts als Loop: post.user_id == bot_id prüfen, sonst antwortet sich der Bot selbst.
  • SiteURL falsch: Interaktive Buttons und Attachments brauchen korrekte SiteURL.
  • Message-Limit: Posts auf ~16.383 Zeichen limitiert, lange Antworten splitten.

Key Takeaways:

  • Mattermost + Ollama = komplett souveräne KI-Chat-Plattform, 100% on-premise.
  • Bot-Account + REST/WebSocket reichen, kein App-Approval-Prozess wie bei Slack.
  • WebSocket-Events für Echtzeit, REST für Posts, Slash-Commands per HTTP-Endpoint.
  • Ideal für Firmen, Behörden und alle, die keine Chat-Daten rausgeben wollen.
  • Team-Edition ist kostenlos und unbegrenzt nutzbar.

FAQ

Welche Mattermost-Edition brauche ich?

Die kostenlose Team Edition reicht komplett: Bots, Slash-Commands, WebSocket sind alle dabei. Professional/Enterprise braucht es nur für SAML, Compliance-Exports und Clustering.

Mattermost oder Slack?

Mattermost wenn Datenhoheit zählt (alles on-premise, keine Cloud). Slack wenn das Team schon dort ist und du keine Infrastruktur pflegen willst. API-Konzepte sind fast identisch: Code ist portierbar.

Bot-Account oder normaler User?

Immer Bot-Account: eigenes Token, als Bot markiert (wird in der UI angezeigt), kann nicht per Passwort einloggen, klarere Berechtigungen. Normale User-Accounts als Bot zu missbrauchen verstößt gegen Mattermost-Richtlinien.

Wie viele Ressourcen braucht Mattermost?

Mattermost selbst: ~1 GB RAM, wenig CPU. Plus Postgres ~500 MB. Plus Ollama mit Modell (8B Q4: ~6 GB VRAM). Ein Mini-PC mit 16 GB RAM + GPU reicht für kleine Teams.

Sieht der Bot alle Channels?

Nein, nur Channels, in denen er Mitglied ist, plus DMs. Das ist ein Feature: Zugriffskontrolle über Channel-Mitgliedschaft statt Code.

Bots oder Mattermost-Plugins?

Für KI-Integrationen reicht ein Bot (einfacher, sprachunabhängig, eigenständig deploybar). Plugins (Go/React) nur für tiefe UI-Integration nötig. Es gibt übrigens auch offizielle KI-Plugins (mattermost-ai).

Was muss ich sichern?

Postgres-Datenbank (Chats), /mattermost/data (Uploads) und Deine Bot-Session/Config. Siehe Backup-Artikel. Der Bot-Code selbst ist zustandslos.

Quellen und weiterführende Literatur

Zurück zum KI Blog
Share:

Ähnliche Beiträge