3D-Visualisierung der LizardDocu-Embeddings (MistralAI mistral-embed, 1024-dim)
für eine Präsentation: Eine drehbare Punktwolke zeigt, dass semantisch ähnliche
Chunks im Raum nah beieinander liegen — obwohl alle aus einem Dokument stammen.
Zwei Deliverables:
embeddings.html— eigenständige Datei, läuft offline in jedem Browser. Drehen/Zoomen/Hover (Chunk-Text + Zeilen), Umschalter UMAP ↔ PCA.- Live-App (
app.py) — Suchtext eintippen → wird viamistral-embedembedded, in Qdrant gesucht, der Query-Punkt landet sichtbar bei seinen echten Nachbarn (Verbindungslinien, restliche Wolke dimmt ab).
Die komplette Demo (klassisches RAG und GraphRAG) läuft lokal in Docker — du brauchst nur einen Mistral-API-Key. Qdrant (Vektor-DB) und LightRAG (Wissensgraph) laufen als mitgelieferte Container mit vorgebauten Daten; nichts Externes wird kontaktiert. Mistral wird ausschließlich für Live-Embeddings und -Antworten genutzt (dein Key).
0. Voraussetzung: Docker Desktop installieren und starten (das Wal-Symbol muss laufen). Mehr brauchst du nicht — kein Python, kein Node, nichts weiter.
1. Projekt herunterladen — eine der beiden Varianten:
- Ohne Git (am einfachsten): Auf der GitHub-Seite des Projekts oben rechts auf den
grünen Button
Code→Download ZIP. Das ZIP entpacken und ein Terminal in diesem Ordner öffnen. - Mit Git:
(Das Repo muss dafür öffentlich sein bzw. du brauchst Zugriff.)
git clone https://github.com/straussbastian/RAG-graphRAG_example.git cd RAG-graphRAG_example
2. Mistral-API-Key holen: auf https://console.mistral.ai/ einloggen → API Keys → Create new key → den Schlüssel kopieren (ein langer Buchstaben-/Zahlen-String).
3. Konfigurationsdatei .env anlegen (kopiert die Vorlage):
cp env.example .env # Windows (cmd): copy env.example .env4. Key eintragen: die neue Datei .env in einem Texteditor öffnen (z. B. VS Code,
oder im Terminal nano .env). Dort steht die Zeile:
MISTRAL_API_KEY=
Schreibe deinen Key direkt dahinter — ohne Leerzeichen, ohne Anführungszeichen:
MISTRAL_API_KEY=dEinKopierterSchluessel
Speichern. Die Zeile LOKAL=true steht schon drin und bleibt so.
5. Starten:
docker compose upDer erste Start lädt die Container herunter — das dauert ein paar Minuten (nur
beim ersten Mal). Wenn in der Konsole Application startup complete erscheint, läuft
alles.
6. Im Browser öffnen: http://localhost:8888 🎉
Beenden: im Terminal Strg+C drücken (optional danach docker compose down).
Später wieder starten: einfach erneut docker compose up im selben Ordner — dann
geht's sofort, ohne erneuten Download.
Optional sichtbar: Qdrant-Dashboard http://localhost:6333/dashboard · LightRAG-WebUI http://localhost:9621.
Beim ersten Start befüllt die App den lokalen Qdrant aus data/qdrant_seed.json;
der LightRAG-Wissensgraph ist in lightrag_storage/ bereits vorgebaut (kein
Ingest-Aufwand, keine Wartezeit).
LOKAL=true(Default inenv.example) → die mitgelieferten lokalen Container.LOKAL=false→ die App spricht mit externen Qdrant-/LightRAG-Diensten; dann zusätzlichQDRANT_URL/_API_KEYundLIGHTRAG_URL/_API_KEYin.envsetzen und die App ohne Compose starten (uv run uvicorn app:app …).
.envim Projektordner mit:LOKAL=false QDRANT_URL=https://dein-qdrant-host QDRANT_API_KEY=... LIGHTRAG_URL=https://dein-lightrag-host LIGHTRAG_API_KEY=... MISTRAL_API_KEY=...- Abhängigkeiten installieren:
uv sync
uv run python build_data.py
Zieht alle 249 Vektoren aus Qdrant, reduziert 1024D→3D (UMAP + PCA), clustert für die Farben (K-Means, k via Silhouette) und schreibt:
data/points.json— die Punktwolke (Koordinaten, Cluster, Text, Zeilen)data/reducer.pkl— das gespeicherte UMAP-Modellembeddings.html— die eigenständige statische Visualisierung
uv run uvicorn app:app --host 127.0.0.1 --port 8000
Dann http://127.0.0.1:8000 öffnen. Suchbegriff eingeben (z. B. „Listenansicht").
uv run pytest
qdrant_viz/
config.py # .env laden, QDRANT_URL auf :443 normalisieren, Settings
mistral.py # embed_text() via mistral-embed
data.py # fetch_points(), reduce_3d() (UMAP+PCA), cluster_labels(), build_points_json()
placement.py # weighted_centroid() — platziert den Live-Query-Punkt
build_data.py # Build-Skript → points.json + reducer.pkl + embeddings.html
app.py # FastAPI: GET / , /api/points , /api/query
web/ # Plotly.js-Frontend (Plotly lokal gebündelt, kein CDN)
- Port:
QDRANT_URLwird intern auf:443normalisiert. Der öffentliche Ingress serviert auf 443;qdrant-clientwürde sonst auf 6333 defaulten und timeouten.:6333in der URL wird automatisch entfernt. - Modell: Die Live-Query nutzt
mistral-embed— dasselbe Modell, das die gespeicherten Vektoren erzeugt hat. Andernfalls wären die Nachbarn bedeutungslos. - Offline: Sowohl
embeddings.html(Plotly inline) als auch die Live-App (Plotly unterweb/plotly.min.jsgebündelt) brauchen im Vortrag kein Internet fürs Rendering — nur die Live-Query selbst ruft Mistral/Qdrant. - Platzierung: Der Live-Query-Punkt wird als ähnlichkeitsgewichteter
Schwerpunkt seiner echten Qdrant-Nachbarn im 3D-Raum platziert (robust, keine
instabile Einzelpunkt-Projektion). Das
reducer.pklist für eine optionale „ehrliche" UMAP-Projektion gespeichert, wird aktuell aber nicht genutzt.
3D-Visualisierung des LightRAG-Knowledge-Graphen (~1240 Entities, ~1600 Relationen;
im Frontend auf 1000 Knoten begrenzt) als Gegenstück zur Vektor-Punktwolke:
Farbe = entity_type, Knotengröße = Grad (Hubs wie Lizard, Betriebsmittel,
Prüfauftrag treten hervor). Eine Live-Query zeigt, welchen Teilgraphen LightRAG
für eine Frage traversiert.
Im lokalen Docker-Modus (LOKAL=true) ist dieser Graph in lightrag_storage/
bereits vorgebaut — der lightrag-Container nutzt Mistral als LLM + Embedding.
Im externen Modus (LOKAL=false) zusätzlich LIGHTRAG_URL, LIGHTRAG_API_KEY
in .env setzen.
uv run python build_graph.py
Zieht den Graphen via LightRAG GET /graphs, transformiert ihn und schreibt:
data/graph.json— Nodes/Links/Typen fürs Frontendgraph.html— eigenständige Offline-Visualisierung (3d-force-graph inline)
uv run uvicorn app:app --host 127.0.0.1 --port 8000
Dann http://127.0.0.1:8000 öffnen. Auf / liegt der RAG ⇄ GraphRAG-Umschalter
(Shell mit iframe); der GraphRAG-View direkt unter /graph, die Qdrant-Punktwolke
unter /qdrant.
Frage eingeben → via LightRAG POST /query/data wird der traversierte Subgraph
ermittelt und hervorgehoben (Entities + Relationen leuchten auf, Rest dimmt ab);
die extrahierten Keywords (high/low-level) erscheinen. Der Modus
(local/global/hybrid/mix) ist umschaltbar.
graph_viz/
config.py # .env laden, LIGHTRAG_* validieren, GraphSettings
client.py # LightRAGClient: GET /graphs, POST /query/data (nur X-API-Key)
transform.py # build_graph_json(), build_highlight() — pure, keine I/O
build_graph.py # Build-Skript → data/graph.json + graph.html
graph_web/ # 3d-force-graph-Frontend (Library lokal gebündelt, kein CDN)
app.py # vereinte FastAPI: Shell / , /qdrant , /graph , /api/graph[/query]
- Auth gegenüber LightRAG ist ausschließlich der
X-API-Key-Header — ein zusätzlicherAuthorization: Bearer-Header führt zu „Invalid token". - Der Browser spricht nie direkt mit LightRAG: die App proxyt server-seitig, der API-Key bleibt im Backend.
graph.htmlist vollständig offline (Library + Daten inline, kein CDN).- Der Query-Subgraph mappt direkt:
entity_name→ Node-ID,src_id/tgt_id→ Kante. Entities, die (z. B. durch das Node-Limit) nicht im Graphen sind, werden übersprungen statt zu crashen.