Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung Künstliche Intelligenz 25.06.2026 · 11 min Lesezeit Geprüft 23.10.2026

Embedding-Server lokal betreiben: sentence-transformers und FastEmbed mit Qdrant

Qdrant läuft, aber was erzeugt die Vektoren? Diese Anleitung zeigt FastEmbed (direkt im qdrant-client, ONNX, keine GPU-Pflicht) und den Infinity Embedding Server (Docker, OpenAI-API), DSGVO-konform auf eigener Hardware.

Werbung Mit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Titelbild: Embedding-Server lokal betreiben, Modelle, Vektoren, Qdrant

Wer einen RAG-Stack auf eigener Hardware betreibt, stößt früher oder später auf dieselbe Lücke: Qdrant läuft, die Dokumente liegen bereit, aber was wandelt die Texte eigentlich in Vektoren um? Die Antwort ist ein Embedding-Dienst, und genau dieser Baustein fehlt in vielen Anleitungen. Dieser Artikel zeigt zwei komplementäre Wege: FastEmbed als leichtgewichtige, direkt in den qdrant-client integrierte Lösung für Entwicklung und kleinere Setups sowie den Infinity Embedding Server als eigenständigen HTTP-Dienst mit OpenAI-kompatibler API für den produktiven Mehrbenutzer-Betrieb. Beide laufen on-premises in Docker, beide unterstützen sentence-transformers-Modelle von HuggingFace, und beide brauchen keine Cloud-API.

Voraussetzungen

  • Server oder PC mit mindestens 4 GB RAM für FastEmbed, für den Infinity-Server 8 GB (im Test belegte Infinity bis zu 5,6 GB)
  • Docker und Docker Compose installiert (Compose-Plugin v2)
  • Laufende Qdrant-Instanz (lokal oder per Docker), siehe Lokales RAG-System mit Qdrant selbst bauen
  • Python 3.10 oder neuer für direkte FastEmbed-Nutzung
  • Internetverbindung für den erstmaligen Modell-Download von HuggingFace
  • Optional: NVIDIA-GPU mit aktuellen CUDA-Treibern und nvidia-container-toolkit für GPU-Beschleunigung

Schritt 1: Den richtigen Weg wählen (FastEmbed oder Infinity)

Treffen Sie zuerst eine Grundsatzentscheidung. FastEmbed eignet sich für Python-Skripte, Einzelanwendungen und Entwicklungsumgebungen. Infinity ist die bessere Wahl, wenn mehrere Dienste (RAGFlow, LangChain, eigene Microservices) auf denselben Embedding-Endpunkt zugreifen sollen oder wenn Sie Embedding-Dienst und Anwendungslogik klar trennen wollen.

KriteriumFastEmbed (qdrant-client)Infinity Embedding Server
DeploymentPython-Paket, kein DienstDocker-Container
APIPython-SDK direktHTTP REST, OpenAI-kompatibel
GPU-PflichtNein (ONNX CPU)Nein (CPU-Image verfügbar)
Mehrere ClientsNeinJa
Dynamisches BatchingNeinJa
RAGFlow-IntegrationIndirektDirekt (OpenAI-Schema)
LizenzApache 2.0MIT

Sie können benennen, welche Anwendungen den Embedding-Dienst nutzen. Ist es nur ein Python-Skript, wählen Sie Weg A (Schritt 3), sonst Weg B (Schritt 4).

Schritt 2: Modell wählen

Die Modellwahl entscheidet über Qualität, RAM-Bedarf und Vektordimension. Einmal festgelegt, muss die Entscheidung konsequent durchgehalten werden: Alle Dokumente in einer Qdrant-Collection müssen mit demselben Modell eingebettet sein.

ModellTypDimensionenGrößeSpracheLizenz
BAAI/bge-small-en-v1.5Dense38467 MBEnglischMIT
BAAI/bge-base-en-v1.5Dense768210 MBEnglischMIT
BAAI/bge-large-en-v1.5Dense10241,2 GBEnglischMIT
intfloat/multilingual-e5-largeDense10242,24 GBMehrsprachigMIT
snowflake/snowflake-arctic-embed-xsDense38490 MBEnglischApache 2.0
Qdrant/bm25Sparsevariabel10 MBMehrsprachigApache 2.0
BAAI/bge-reranker-baseRerankingentfällt1,04 GBEnglischMIT

Für deutschen Text empfiehlt sich intfloat/multilingual-e5-large (1024 Dimensionen, MIT-Lizenz). Für den Einstieg auf schwacher Hardware reicht BAAI/bge-small-en-v1.5 mit 67 MB.

Notieren Sie Modellname und Dimension (z. B. 768 für bge-base-en-v1.5). Genau diese Dimension verwenden Sie später beim Anlegen der Collection.

Schritt 3: Weg A (FastEmbed direkt im qdrant-client)

FastEmbed (Apache 2.0, Version 0.9.0, Stand Oktober 2026) ist über die Inference-API in den qdrant-client integriert. Die ONNX-Runtime-Basis macht es schneller im Start und leichter im Speicherbedarf als eine rohe PyTorch-Installation. Eine Installation genügt:

pip install "qdrant-client[fastembed]"

Im Test installierte dieser Befehl unter Python 3.12 qdrant-client 1.20.0 zusammen mit FastEmbed 0.9.0. Beide Pakete verlangen Python 3.10 oder neuer. Unter Python 3.9 bricht pip install fastembed==0.9.0 mit ERROR: No matching distribution found for fastembed==0.9.0 ab, und pip install "qdrant-client[fastembed]" würde dort nur die älteren Versionen qdrant-client 1.16.1 und FastEmbed 0.7.4 installieren.

Das folgende Beispiel bettet Dokumente lokal ein und speichert sie in Qdrant. Seit qdrant-client 1.19 gibt es die früheren Methoden add() und query() nicht mehr. Sie übergeben stattdessen models.Document-Objekte an upsert() und query_points(), die Collection legen Sie selbst an:

from qdrant_client import QdrantClient, models

client = QdrantClient("http://localhost:6333")
modell = "BAAI/bge-small-en-v1.5"

docs = [
    "Qdrant ist eine Vektordatenbank für Semantiksuche.",
    "FastEmbed nutzt ONNX Runtime für schnelle Inferenz.",
]

if not client.collection_exists("meine_dokumente"):
    client.create_collection(
        "meine_dokumente",
        vectors_config=models.VectorParams(
            size=client.get_embedding_size(modell),
            distance=models.Distance.COSINE,
        ),
    )

client.upsert(
    collection_name="meine_dokumente",
    points=[
        models.PointStruct(
            id=i,
            vector=models.Document(text=d, model=modell),
            payload={"text": d, "quelle": "intern"},
        )
        for i, d in enumerate(docs)
    ],
)

# Semantische Suche
ergebnisse = client.query_points(
    collection_name="meine_dokumente",
    query=models.Document(text="Vektordatenbank Suche", model=modell),
    limit=3,
).points
for r in ergebnisse:
    print(r.payload["text"], r.score)

Bestehende Installationen mit FastEmbed 0.8 aktualisieren Sie mit pip install -U "qdrant-client[fastembed]". Im Test hob dieser Befehl qdrant-client 1.19.1 und FastEmbed 0.8.1 auf qdrant-client 1.20.0 und FastEmbed 0.9.0 an. Die vorher mit BAAI/bge-small-en-v1.5 gespeicherten Vektoren blieben gültig: Die Abfrage mit dem Text eines alten Eintrags fand genau diesen Eintrag mit Score 1,0. Seit Version 0.9.0 lädt FastEmbed eingebaute Modelle nur noch von Hugging Face. Bereits im Cache liegende Modelle nutzt es weiter. Bei snowflake/snowflake-arctic-embed-xs, dessen Quelle FastEmbed 0.9.0 als Snowflake/snowflake-arctic-embed-xs führt, meldete es im Test, dass es die von einer älteren Version gespeicherte Kopie lädt.

Das Skript läuft ohne Fehler durch. In der Qdrant-Web-UI unter http://localhost:6333/dashboard erscheint die Collection „meine_dokumente“ mit den eingetragenen Punkten.

Schritt 4: Weg B (Infinity Embedding Server per Docker)

Der Infinity Embedding Server (MIT-Lizenz, michaelf34/infinity) ist ein eigenständiger HTTP-Dienst auf Port 7997 mit OpenAI-kompatibler REST-API. Er eignet sich für den produktiven Einsatz, wenn mehrere Anwendungen denselben Embedding-Endpunkt nutzen sollen. Vier Docker-Images decken unterschiedliche Hardware ab:

Image-TagHardwareEngineEmpfehlung
michaelf34/infinity:latest-cpuCPU (kein GPU)ONNX/OptimumNAS, VM, Datenschutz-Setup
michaelf34/infinity:latestNVIDIA CUDATorch + FlashAttentionWorkstation mit NVIDIA-GPU
michaelf34/infinity:latest-amdAMD ROCmROCmAMD-GPU-Server
michaelf34/infinity:latest-trt-onnxNVIDIA TensorRTTensorRT + ONNXNVIDIA für höchsten Durchsatz

Die latest-Tags wandern mit jeder Version. Legen Sie die Version fest; aktuell ist 0.0.77 (Tags 0.0.77-cpu, 0.0.77, 0.0.77-amd, 0.0.77-trt-onnx). Erstellen Sie eine compose.yaml im Projektverzeichnis. Der Port ist nur an 127.0.0.1 gebunden, weil Infinity ohne gesetzten INFINITY_API_KEY keine Anmeldung verlangt:

services:
  embedding:
    image: michaelf34/infinity:0.0.77-cpu
    # image: michaelf34/infinity:0.0.77   # GPU-Variante (nvidia-container-toolkit erforderlich)
    container_name: infinity-embedding
    ports:
      - "127.0.0.1:7997:7997"
    volumes:
      - ./infinity_cache:/app/.cache
    environment:
      INFINITY_MODEL_ID: "BAAI/bge-base-en-v1.5"
      INFINITY_PORT: "7997"
      INFINITY_BATCH_SIZE: "8"
      INFINITY_ANONYMOUS_USAGE_STATS: "0"
    restart: unless-stopped

Container starten und prüfen:

docker compose up -d
# Logs verfolgen (Modell wird beim ersten Start heruntergeladen)
docker compose logs -f embedding

Die Swagger-UI unter http://localhost:7997/docs zeigt alle verfügbaren Endpunkte. Ein schneller API-Test:

curl -X POST http://localhost:7997/embeddings \
  -H "Content-Type: application/json" \
  -d '{"model":"BAAI/bge-base-en-v1.5","input":["Hallo Welt","Test Embedding"]}'

Die Antwort enthält ein JSON-Objekt mit "data"-Array, das pro Eingabe ein "embedding"-Feld mit 768 Floats enthält. Infinity stellt seine Endpunkte ohne das Präfix /v1 bereit: Ein Aufruf von /v1/embeddings endet mit HTTP 404 und {"detail":"Not Found"}.

Schritt 5: Mehrere Modelle gleichzeitig laden

Infinity unterstützt dynamisches Batching und mehrere Modelle innerhalb einer Instanz. So betreiben Sie etwa ein englisches und ein mehrsprachiges Modell in einem Container. Stoppen Sie vorher den Container aus Schritt 4 (docker compose down), sonst ist Port 7997 belegt:

docker run -it \
  -v $PWD/infinity_cache:/app/.cache \
  -p 127.0.0.1:7997:7997 \
  michaelf34/infinity:0.0.77-cpu \
  v2 \
  --model-id BAAI/bge-base-en-v1.5 \
  --model-id intfloat/multilingual-e5-large \
  --port 7997 \
  --engine torch

Das CPU-Image nutzt standardmäßig die ONNX-Engine (INFINITY_ENGINE=optimum). Mit ihr brach dieser Start im Test beim Aufwärmen von multilingual-e5-large wegen Speichermangels ab (siehe Troubleshooting). --engine torch gilt für beide Modelle und lädt sie über sentence-transformers mit PyTorch. So belegte der Container im Test bis zu 5,6 GB RAM laut docker stats, und zwar bei Anfragen mit je 32 langen Texten an beide Modelle, im Leerlauf 3,7 GB. Mit zusätzlich --memory 4g lief derselbe Befehl ebenfalls fehlerfrei, das Limit schützt den Host vor einem Speicherüberlauf. Weil Infinity die Modelle nacheinander lädt und aufwärmt, antwortete /health erst nach knapp drei Minuten.

Sobald curl -s http://localhost:7997/health antwortet, listet curl -s http://localhost:7997/models beide Modell-IDs, BAAI/bge-base-en-v1.5 und intfloat/multilingual-e5-large.

Schritt 6: Infinity-API in Qdrant nutzen (Python)

Das folgende Beispiel holt Embeddings über den Infinity-HTTP-Endpunkt, legt eine Qdrant-Collection an und pflegt Dokumente ein. Die frühere Methode recreate_collection() ist im qdrant-client als veraltet markiert (DeprecationWarning). Das Beispiel prüft deshalb mit collection_exists(), löscht eine vorhandene Collection und legt sie mit create_collection() neu an:

from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct
import requests

def embed(texts: list[str], model="BAAI/bge-base-en-v1.5") -> list[list[float]]:
    resp = requests.post(
        "http://localhost:7997/embeddings",
        json={"model": model, "input": texts},
    )
    resp.raise_for_status()
    return [d["embedding"] for d in resp.json()["data"]]

client = QdrantClient("http://localhost:6333")

# Collection anlegen (768 Dimensionen für bge-base-en-v1.5)
if client.collection_exists("docs"):
    client.delete_collection("docs")
client.create_collection(
    collection_name="docs",
    vectors_config=VectorParams(size=768, distance=Distance.COSINE),
)

# Dokumente einpflegen
texts = ["Erster Satz", "Zweiter Satz"]
vektoren = embed(texts)
client.upsert(
    collection_name="docs",
    points=[
        PointStruct(id=i, vector=v, payload={"text": t})
        for i, (t, v) in enumerate(zip(texts, vektoren))
    ],
)

# Suche
query_vec = embed(["Semantische Suche"])[0]
treffer = client.query_points(collection_name="docs", query=query_vec, limit=3).points
for t in treffer:
    print(t.score, t.payload["text"])

Das Skript gibt zwei Treffer mit Score und Text aus. curl -s http://localhost:6333/collections/docs meldet "points_count":2 und "size":768.

Schritt 7: GPU-Betrieb einrichten (optional)

Wer eine NVIDIA-GPU hat und auf dem Host das nvidia-container-toolkit installiert hat, wechselt das Image und ergänzt --gpus all:

# Voraussetzung: nvidia-container-toolkit auf dem Host
docker run -it --gpus all \
  -v $PWD/infinity_cache:/app/.cache \
  -p 127.0.0.1:7997:7997 \
  michaelf34/infinity:0.0.77 \
  v2 \
  --model-id BAAI/bge-large-en-v1.5 \
  --port 7997

Ohne nvidia-container-toolkit startet das GPU-Image mit einem CUDA-Fehler. In diesem Fall das 0.0.77-cpu-Image verwenden. Es läuft auf reiner CPU mit ONNX-Engine und ist für die meisten KMU-Workloads ausreichend. Die CUDA-Einrichtung ist in der Anleitung CUDA-Umgebung korrekt aufsetzen beschrieben.

nvidia-smi auf dem Host zeigt während einer Embedding-Anfrage einen Prozess mit belegtem VRAM, das Log meldet das Gerät cuda.

Troubleshooting / Typische Fehler

Vektordimension stimmt nicht

Haben Sie eine Collection mit 768 Dimensionen angelegt und wechseln das Modell auf eines mit 384 Dimensionen, schlägt der Upsert mit einem Dimension-Mismatch-Fehler fehl. Lösung: Die Collection löschen (client.delete_collection("docs")) und mit der neuen Dimension neu anlegen. Alle Dokumente müssen danach neu eingelesen werden.

GPU-Container startet nicht

Fehlermeldung wie CUDA error: no kernel image is available for execution on the device oder Container-Exit ohne Log. Ursache: Das GPU-Image setzt das nvidia-container-toolkit voraus. Installieren Sie das Toolkit oder wechseln Sie auf 0.0.77-cpu.

Modell wird bei jedem Neustart neu heruntergeladen

Ohne Volume-Mount lädt Infinity das Modell bei jedem Containerstart neu von HuggingFace. Bei bge-large (1,2 GB) kostet das mehrere Minuten. Abhilfe: Den -v $PWD/infinity_cache:/app/.cache-Mount immer mitangeben.

RAM-Engpass bei großen Modellen

Ohne --engine torch wählt Infinity im CPU-Image für intfloat/multilingual-e5-large die quantisierte Datei onnx/model_qint8_avx512_vnni.onnx. Deren Optimierung scheitert, das Log meldet Optimization failed with [ONNXRuntimeError] : 6 : und Going to use the unoptimized model. Beim anschließenden Aufwärmen stieg der Prozessspeicher im Test auf 13,9 GB, bei 14,9 GB verfügbarem RAM. Dann beendete der Kernel den Container: docker inspect meldete OOMKilled true und Exit-Code 137, /health antwortete nie. Dasselbe geschah mit --batch-size 8; mit --no-model-warmup startete er, endete aber bei der ersten Anfrage mit 32 langen Texten an e5-large. Abhilfe: --engine torch wie in Schritt 5. Damit liefen beide Modelle im Test auch in einem auf 4 GiB begrenzten Container (--memory 4g, höchstens 3,9 GB laut docker stats).

Telemetrie aktiv

Infinity sendet standardmäßig anonyme Nutzungsstatistiken. Für datenschutzkonforme Deployments die Umgebungsvariable INFINITY_ANONYMOUS_USAGE_STATS=0 explizit setzen. Im obigen Compose-Beispiel ist sie bereits enthalten.

FastEmbed unterstützt das Wunschmodell nicht

FastEmbed unterstützt nur Modelle aus seiner eigenen Model-Liste (ONNX-optimiert). Eigene oder sehr neue HuggingFace-Modelle erfordern einen manuellen ONNX-Export. Infinity hingegen unterstützt alle sentence-transformers-Modelle von HuggingFace direkt.

Häufige Fragen

Muss ich einen separaten Embedding-Server betreiben oder genügt FastEmbed?

Für Entwicklung und kleine Workloads genügt qdrant-client[fastembed] vollständig, ein separater Dienst ist nicht nötig. Für Produktion, mehrere Dienste oder wenn RAGFlow separat embedden soll, empfiehlt sich Infinity als eigenständiger HTTP-Dienst.

Welches Modell soll ich für deutschen Text wählen?

intfloat/multilingual-e5-large (1024 Dimensionen, MIT-Lizenz) ist die bewährte Wahl für mehrsprachige Inhalte inklusive Deutsch. Für kleinere Deployments mit weniger RAM: intfloat/multilingual-e5-small (384 Dimensionen, ca. 117 MB).

Wie integriere ich Infinity als Embedding-Quelle in RAGFlow?

RAGFlow kann externe Embedding-Endpunkte nutzen. Da Infinity dem OpenAI-Schema folgt (/embeddings), lässt sich RAGFlow mit dem Infinity-Endpunkt (http://infinity:7997) als „OpenAI-kompatibler Anbieter“ konfigurieren. Voraussetzung: Beide Container sind im selben Docker-Netzwerk. Die RAGFlow-Einrichtung selbst ist in RAGFlow mit Docker installieren beschrieben.

Läuft das auch auf einem NAS ohne GPU?

Ja. Das latest-cpu-Image mit ONNX-Engine läuft auf reiner CPU. BAAI/bge-small-en-v1.5 (67 MB) ist für schwache Hardware geeignet. Auf einem modernen NAS mit x86-CPU sind ca. 50 bis 200 ms pro Anfrage realistisch.

Was ist der Unterschied zwischen Dense-, Sparse- und Late-Interaction-Vektoren?

Dense (z. B. bge-base): Ein Vektor pro Dokument, gut für semantische Ähnlichkeit. Sparse (SPLADE): Viele Nullen, gut für Keyword-nahe Suche. Late Interaction (ColBERT): Mehrere Vektoren pro Dokument, höhere Qualität aber mehr Speicher. Qdrant unterstützt alle drei; für einfache RAG-Anwendungen genügen Dense-Vektoren. Mehr dazu in RAG produktiv betreiben: Chunking, Hybrid-Search und Reranking.

Kann ich FastEmbed und Infinity gleichzeitig nutzen?

Ja, und das kann sinnvoll sein: FastEmbed direkt im Python-Code für schnelle Abfragen, Infinity als HTTP-Dienst für andere Anwendungen. Wichtig: Beide müssen dasselbe Modell verwenden, wenn sie auf dieselbe Qdrant-Collection schreiben.

Fazit

Ein lokaler Embedding-Dienst ist kein optionales Extra, sondern der fehlende Baustein jedes datenschutzkonformen RAG-Stacks. FastEmbed senkt die Einstiegshürde: ein pip-Befehl, und der qdrant-client erledigt Einbettung und Datenbankzugriff in einem Schritt. Für den produktiven Mehrbenutzer-Betrieb oder die Integration mit RAGFlow und anderen Diensten liefert der Infinity Embedding Server eine saubere, OpenAI-kompatible HTTP-Schnittstelle mit dynamischem Batching und GPU-Option bei Bedarf. Beide Wege laufen vollständig on-premises, ohne Cloud-Abhängigkeit und ohne Datenschutzrisiko. Die wichtigste Faustregel: Modell einmal wählen, konsequent durchhalten und das Volume für den Modell-Cache nicht vergessen.

Weiterführende Anleitungen und Quellen

  1. Lokales RAG-System mit Qdrant und Embeddings selbst bauen
  2. RAGFlow mit Docker installieren
  3. RAG produktiv betreiben: Chunking, Hybrid-Search, Reranking und Antwortqualität messen
  4. CUDA-Umgebung korrekt aufsetzen: Treiber, Toolkit, cuDNN und PyTorch
  5. FastEmbed: offizielles GitHub-Repository (qdrant/fastembed)
  6. FastEmbed 0.9.0: Release Notes
  7. Infinity Embedding Server: GitHub (michaelf34/infinity)
  8. FastEmbed: unterstützte Modelle (offizielle Dokumentation)
  9. Qdrant Embeddings: Integrationsübersicht

Passende Anleitungen auf S-EDV

  1. NVIDIA GPU Display Driver: 14 Sicherheitslücken geschlossen, Update dringend nötig