DeepbitDesktop v0 β€” RAG Support Desk

Logfiles und Dokumente rein. Wissen aufbauen. Crew fragt. Antwort kommt.

Multi-Channel RAG-System fΓΌr RZ-Support-Teams β€” mit lokalem LLM-Coding-Assistenten.


Inhalt


Was ist das?

ozmai (OZM AI) ist ein RAG-System (Retrieval-Augmented Generation) das intern lΓ€uft.
Kein Cloud-Speicher fΓΌr die Dokumente. Kein Dritter sieht die Logfiles.

Wie es funktioniert:

Dokument / Logfile einmal ingestieren
         β”‚
         β–Ό
    Ollama zerlegt es in Chunks und erstellt Vektoren
         β”‚
         β–Ό
    pgvector speichert Vektoren + Inhalt in PostgreSQL
         β”‚
         β–Ό
    Crew stellt Frage im Browser
         β”‚
         β–Ό
    Frage β†’ Vektor β†’ Γ€hnliche Chunks gesucht β†’ Claude formuliert Antwort

Das Wissen bleibt lokal in PostgreSQL. Claude sieht nur den Kontext fΓΌr eine Anfrage β€” keine Daten wandern dauerhaft in die Cloud.


Stack

Komponente Rolle Port
FastAPI REST-Backend, alle Endpunkte 8080
PostgreSQL 17 + pgvector Vektordatenbank + Chat-History intern
Ollama (nomic-embed-text) Lokale Embeddings (768 dim) 11434
Anthropic Claude LLM-Reasoning, Antwortgenerierung API
Vanilla JS SPA Frontend, IRC-Style, kein Framework β€”
Docker Compose Orchestrierung: db, ollama, app β€”

Quickstart

Voraussetzungen

  • Docker + Docker Compose
  • Anthropic API Key

1. Einrichten

git clone <dieses-repo> DeepbitDesktop_v0
cd DeepbitDesktop_v0

2. API Key eintragen

# .env ΓΆffnen und ANTHROPIC_API_KEY eintragen
nano .env
DATABASE_URL=postgresql://rag:rag@db:5432/supportdesk
OLLAMA_URL=http://ollama:11434
ANTHROPIC_API_KEY=sk-ant-...

POSTGRES_USER=rag
POSTGRES_PASSWORD=rag
POSTGRES_DB=supportdesk

3. Starten

docker compose up --build

Beim ersten Start:
- Ollama lΓ€dt nomic-embed-text β€” je nach Verbindung 1–5 Minuten
- PostgreSQL importiert seed/02-seed.sql automatisch (nur einmal, auf leerem Volume)
- App wartet bis beide Services healthy sind

4. Γ–ffnen

http://localhost:8080

Das Wissen aus dem Seed ist sofort verfΓΌgbar β€” kein Re-Ingest nΓΆtig.


Architektur

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Browser (public/index.html)                                 β”‚
β”‚  IRC-Style SPA Β· Channels Β· Vektor- und LLM-Modus           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚ HTTP
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  FastAPI (api.py) Β· Port 8080                                β”‚
β”‚                                                              β”‚
β”‚  POST /query        β†’ Frage stellen (Vektor oder LLM)        β”‚
β”‚  POST /ingest-text  β†’ Text direkt ingestieren                β”‚
β”‚  POST /ingest       β†’ Datei ingestieren                      β”‚
β”‚  POST /analyze-log  β†’ Anonymisierte Log-Analyse              β”‚
β”‚  GET  /history      β†’ Chat-History eines Channels            β”‚
β”‚  GET  /channels     β†’ Alle Channels                          β”‚
β”‚  POST /admin/reset  β†’ Chunks lΓΆschen (channel-scoped)        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚                      β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Ollama             β”‚  β”‚  PostgreSQL 17 + pgvector             β”‚
β”‚  nomic-embed-text   β”‚  β”‚                                       β”‚
β”‚  768-dim Embeddings β”‚  β”‚  channels    β€” Kanal-Definitionen     β”‚
β”‚  Port 11434         β”‚  β”‚  chunks      β€” Vektoren + Inhalt      β”‚
β”‚  (auch fΓΌr         β”‚  β”‚  chat_history β€” GesprΓ€chsprotokoll     β”‚
β”‚   OpenCode)         β”‚  β”‚                                       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Anthropic Claude   β”‚
β”‚  Sonnet API         β”‚
β”‚  Antwortgenerierung β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Query-Pipeline

Frage β†’ Ollama Embedding β†’ pgvector cosine search (TOP 5)
      β†’ Claude (Vektor-Modus: nur Kontext | LLM-Modus: + eigenes Wissen)
      β†’ Antwort + Quellen β†’ Chat-History β†’ Browser

Channel-Scoping

Jede Anfrage sucht im Ziel-Channel. Der general-Channel wird immer als Fallback einbezogen. Das verhindert tote Anfragen wenn ein Channel leer ist.


Wissen ingestieren

Text direkt (API)

curl -X POST http://localhost:8080/ingest-text \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Inhalt des Dokuments...",
    "source": "mein_dokument.md",
    "channel_id": "dns"
  }'

Markdown-Datei via Browser

Im Frontend: Channel wΓ€hlen β†’ Ingest β†’ Datei hochladen oder Text einfΓΌgen.

Empfohlene Chunk-Struktur

Chunks werden nach 20 Zeilen aufgeteilt. FΓΌr gute Retrieval-QualitΓ€t:

  • FAQ-Format fΓΌr Grundbegriffe: Frage direkt in die erste Zeile des Abschnitts:
    Frage: Was ist X und wie funktioniert es? Antwort: X ist ...
  • Kommando-BlΓΆcke fΓΌr Procedures: Kommentare + Befehl in einem Block
  • Nicht vermischen: Ein Chunk = ein Thema

Log-Analyse (anonym)

curl -X POST http://localhost:8080/analyze-log \
  -H "Content-Type: application/json" \
  -d '{
    "log_text": "Apr  1 03:22:11 srv01 sshd[1234]: Failed password...",
    "question": "Was ist hier auffΓ€llig?"
  }'

IPs, Hostnamen und User werden automatisch anonymisiert. Die Rohdaten werden nie gespeichert.


Channels

Channel Kategorie Inhalt
general β€” Fallback, Cross-Channel-Wissen
dns Service DNS-Records, AuflΓΆsung, Debugging
ssh Service Key-Auth, HΓ€rtung, sshd_config
iptables Service Tables/Chains, Regeln, Persistenz
ozm Repos OZMAI-Systemdoku, Architektur
debian System Debian-Administration
ubuntu System Ubuntu-spezifische Docs
bashpanda-admin Repos Bashpanda Admin Tools
bashpanda-magic Repos Bashpanda Magic
ckl Repos CKL-Projektdoku
claudcat Repos ClaudCat-Projektdoku

Neuen Channel anlegen:

curl -X POST http://localhost:8080/channels \
  -H "Content-Type: application/json" \
  -d '{"name": "Nginx", "category": "Service"}'

OpenRouter

OpenRouter gibt Zugriff auf 200+ Modelle ΓΌber eine einzige OpenAI-kompatible API β€” Claude, GPT-4o, Llama, Mistral, Gemini und mehr.

API Key besorgen

  1. https://openrouter.ai/keys β†’ Key erstellen
  2. In .env eintragen:
OPENROUTER_API_KEY=sk-or-v1-...
OPENROUTER_MODEL=anthropic/claude-3.5-haiku

Modell wΓ€hlen

Beliebtes Modell fΓΌr Kosten/QualitΓ€t:

Modell StΓ€rke Kosten
anthropic/claude-3.5-haiku Schnell, gut gΓΌnstig
anthropic/claude-sonnet-4-5 Stark mittel
meta-llama/llama-3.1-70b-instruct Open-Source sehr gΓΌnstig
google/gemini-flash-1.5 Schnell sehr gΓΌnstig
openai/gpt-4o-mini Allround gΓΌnstig

VollstΓ€ndige Liste: https://openrouter.ai/models

Im Frontend nutzen

Nach dem Stack-Neustart erscheint im Header ein Provider-Toggle:

πŸ”’ Vektor  🧠 LLM  β”‚  πŸ”΅ Claude  🌐 OpenRouter
  • πŸ”΅ Claude β†’ Anthropic API direkt
  • 🌐 OpenRouter β†’ konfiguriertes OPENROUTER_MODEL

Der Nick zeigt welcher Provider geantwortet hat: πŸŒπŸ”’ ozmai oder πŸ”΅πŸ§  ozmai.

Stack neu starten nach .env-Γ„nderung

docker compose down && docker compose up --build

OpenCode β†’ Ollama

OpenCode ist ein KI-Coding-Assistent fΓΌr das Terminal β€” Γ€hnlich wie Claude Code, aber mit lokalem LLM. Der Ollama-Stack lΓ€uft bereits auf Port 11434 und ist OpenAI-API-kompatibel.

OpenCode installieren

curl -fsSL https://opencode.ai/install | bash

Coding-Modell laden

nomic-embed-text ist nur fΓΌr Embeddings. FΓΌr Code-Assistance ein Coding-Modell nachladen:

# Empfohlen: Qwen 2.5 Coder (7B β€” lΓ€uft auf 16 GB RAM)
docker compose exec ollama ollama pull qwen2.5-coder:7b

# Alternativ kleiner (8 GB RAM):
docker compose exec ollama ollama pull qwen2.5-coder:3b

# Oder CodeLlama:
docker compose exec ollama ollama pull codellama:7b

OpenCode konfigurieren

Das Setup-Script legt die Konfiguration automatisch an. Manuell:

~/.config/opencode/config.json

{
  "$schema": "https://opencode.ai/config.json",
  "autoshare": false,
  "providers": {
    "ollama": {
      "npm": "@opensdks/runtime",
      "baseURL": "http://localhost:11434/v1",
      "apiKey": "ollama"
    }
  },
  "model": "ollama/qwen2.5-coder:7b"
}

Starten

# Im Projektverzeichnis
opencode

OpenCode nutzt dann das lokale Coding-Modell über den laufenden Stack. Keine Daten gehen nach außen.

VerfΓΌgbare Modelle prΓΌfen

docker compose exec ollama ollama list
# oder direkt:
curl http://localhost:11434/api/tags | python3 -m json.tool

Deployment & Updates

Setup-Script (bei neuem Rechner / neuem Deploy)

# Laufenden Original-Stack vorausgesetzt:
bash setup_deploy_crewscript.sh

Das Script:
1. Exportiert den aktuellen DB-Stand (pg_dump)
2. Kopiert App-Quellcode
3. Erstellt docker-compose.yml mit Seed
4. Legt .env-Vorlage an
5. Konfiguriert OpenCode β†’ Ollama (falls installiert)

Wissen aktualisieren (neuen Snapshot machen)

# Neuen Seed aus laufendem Stack exportieren:
docker exec rkl-ozm-chat-hook-v00-db-1 \
  pg_dump -U rag -d supportdesk --data-only --no-privileges --no-owner \
  > seed/02-seed.sql

# Vollbackup mit Zeitstempel:
docker exec rkl-ozm-chat-hook-v00-db-1 \
  pg_dump -U rag -d supportdesk --no-privileges --no-owner \
  > seed/backup_$(date +%Y%m%d_%H%M%S).sql

Wissen auf neuer Instanz zurΓΌckspielen

# pgdata-Volume lΓΆschen (erzwingt Neu-Import beim nΓ€chsten Start):
docker compose down -v
docker compose up --build

Der Seed wird beim ersten Start automatisch importiert.


Troubleshooting

Ollama startet nicht / Modell fehlt

# Logs prΓΌfen:
docker compose logs ollama

# Modell manuell ziehen:
docker compose exec ollama ollama pull nomic-embed-text

DB nicht erreichbar

# Health-Check:
docker compose ps
curl http://localhost:8080/health

# DB direkt:
docker compose exec db psql -U rag -d supportdesk -c "SELECT COUNT(*) FROM chunks;"

Seed wurde nicht importiert

Der docker-entrypoint-initdb.d-Mechanismus greift nur auf leerem Volume. Wenn das Volume schon Daten hat:

docker compose down -v   # Volume lΓΆschen
docker compose up        # Neu starten mit Seed-Import

"Keine Information im Vektor" trotz vorhandenem Wissen

Das passiert wenn:
- Die Frage im Vektor-Modus ist, aber kein passender Chunk im Top-5 landet
- LΓΆsung A: LLM-Modus wΓ€hlen (Claude darf eigenes Wissen ergΓ€nzen)
- LΓΆsung B: Fehlendes Wissen als FAQ-Chunk ingestieren (Frage + Antwort direkt im Text)

Port 8080 belegt

# Original-Stack stoppen:
cd /Users/bmt/Documents/RKL-OZM-Chat-Hook-v.0.0 && docker compose down
# Dann hier:
docker compose up

OpenCode findet Ollama nicht

# Stack lΓ€uft?
curl http://localhost:11434/api/tags

# Modell geladen?
docker compose exec ollama ollama list

# Config prΓΌfen:
cat ~/.config/opencode/config.json

Dateien

DeepbitDesktop_v0/
β”œβ”€β”€ api.py                    ← FastAPI App, alle Endpunkte
β”œβ”€β”€ ingest.py                 ← Ingest-Pipeline
β”œβ”€β”€ query.py                  ← RAG-Query + Log-Analyse
β”œβ”€β”€ embeddings.py             ← Ollama Embedding-Client
β”œβ”€β”€ requirements.txt
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ schema.sql                ← DB-Schema (DDL)
β”œβ”€β”€ ollama-entrypoint.sh      ← Modell-Autoload beim Start
β”œβ”€β”€ docker-compose.yml        ← Stack-Definition
β”œβ”€β”€ .env                      ← Secrets (nicht ins Git!)
β”œβ”€β”€ public/                   ← Frontend SPA
β”‚   └── index.html
β”œβ”€β”€ seed/
β”‚   β”œβ”€β”€ 02-seed.sql           ← Aktueller Wissens-Snapshot
β”‚   └── backup_*.sql          ← Vollbackups mit Zeitstempel
β”œβ”€β”€ logs/                     ← Runtime-Logs
β”œβ”€β”€ docs/
β”‚   └── opencode_config_example.json
└── setup_deploy_crewscript.sh ← Dieses Script

kein Wald ist einfach β€” aber jeder Baum fΓ€ngt mit einem Samen an.