Ein Embedding-Modell wählen, das wirklich zum Projekt passt
23.03.2026
Es gibt einen Moment in den meisten NLP-Projekten, an dem ich aufhöre, mich für Benchmarks zu interessieren, und anfange, mich zu fragen, ob das Ding überhaupt auf meinem Server läuft, ohne den gesamten RAM zu fressen. Dieser Beitrag handelt genau von diesem Moment — und davon, wie ich eine vernünftige Entscheidung treffe, bevor es so weit kommt.
Ich erkläre, was Embedding-Modelle eigentlich tun, gehe einige der praktischsten verfügbaren Optionen durch, spreche über mehrsprachige Unterstützung (was ein eigenes Thema ist) und ende mit einer unkomplizierten Möglichkeit, eines davon in Docker zum Laufen zu bringen — ohne eine einzige Zeile Python.
Was Embedding-Modelle eigentlich machen
Das Versprechen ist simpel: Ich gebe Text rein, ich bekomme einen Vektor aus Zahlen heraus. Dieser Vektor repräsentiert die Bedeutung des Textes auf eine mathematisch nutzbare Weise — Texte mit ähnlicher Bedeutung landen nah beieinander im Vektorraum, und Texte mit unterschiedlicher Bedeutung landen weit voneinander entfernt.
Das klingt abstrakt, bis ich mir klarmache, was es ermöglicht: semantische Suche (Dokumente finden, die das bedeuten, was der Nutzer gefragt hat, nicht nur Dokumente mit denselben Wörtern), Clustering, Empfehlungssysteme, Retrieval-Augmented Generation, Klassifikation ohne gelabelte Trainingsdaten und ein Dutzend weitere Dinge, die Keyword-Matching nicht kann.
Der Haken: Nicht alle Embedding-Modelle sind gleich. Sie unterscheiden sich in der Anzahl der Dimensionen ihrer Vektoren, der Menge an Text, die sie auf einmal verarbeiten können, ob sie mehrere Sprachen unterstützen, wie viel Speicher sie benötigen und wie schnell sie sind. Diese Dinge sind nicht voneinander unabhängig, weshalb die Wahl immer Kompromisse beinhaltet.
Die zwei Modelle, auf die ich zuerst gestoßen bin
Wenn ich mir Embedding-Modelle auf Hugging Face angeschaut habe, bin ich fast zwangsläufig auf All-MiniLM-L6-v2 gestoßen. Es ist seit einigen Jahren das Standard-Leichtgewichts-Embedding-Modell für Englisch — und das aus gutem Grund: ca. 22 MB, 384-dimensionale Vektoren, läuft schnell auf der CPU, und es funktioniert einfach.
Das „L6" im Namen weist darauf hin, dass es 6 Transformer-Schichten hat — es wurde aus einem deutlich größeren Modell destilliert, was erklärt, wie es bei so geringem Speicherbedarf eine ordentliche Qualität erreicht. Der Kompromiss ist ein hartes Limit von 256 Token Eingabe. Für kurze Texte — Produktbewertungen, Support-Tickets, kurze Beschreibungen — ist das in Ordnung. Für längere Inhalte muss ich den Text vor dem Embedding in Chunks aufteilen, was die Komplexität erhöht und die Qualität beeinträchtigen kann, wenn sich der Inhalt nicht sauber trennen lässt.
nomic-embed-text-v1.5 liegt eine Stufe drüber. Es ist größer (~137 MB), produziert 768-dimensionale Vektoren und verarbeitet bis zu 8.192 Token Eingabe — ungefähr 30-mal mehr als MiniLM. Diese letzte Zahl macht in der Praxis einen großen Unterschied. Wenn ich ein RAG-System über lange Dokumente aufbaue, möchte ich sinnvolle Chunks einbetten, keine winzigen Fragmente. Mit einem 8K-Kontextfenster kann ich mehrere Absätze auf einmal einbetten und den Kontext bewahren, der sonst an einer Chunk-Grenze verloren gehen würde.
Es verwendet außerdem etwas namens Matryoshka Representation Learning (MRL), was bedeutet, dass die ersten 64 Dimensionen des Outputs bereits eine brauchbare Repräsentation enthalten, die ersten 128 noch mehr, und so weiter bis 768. Das erlaubt mir, Vektorspeicher und Suchgeschwindigkeit gegen Retrieval-Qualität abzuwägen — nützlich, wenn ich mit Millionen von Dokumenten arbeite und eine grobe Vorauswahl gefolgt von einer präzisen Suche benötige.
Der praktische Unterschied: MiniLM für leichtgewichtige, schnelle, englischsprachige Anwendungen, bei denen ich die Textlänge kontrolliere. Nomic v1.5 für dokumentenlastige Retrieval-Pipelines, bei denen ich mehr Kontext brauche. Für nicht-englische Texte taugen beide wenig.
Das mehrsprachige Problem
Mehrsprachiges Embedding ist ein eigenständiges Problem, und ich habe unterschätzt, wie stark ein auf Englisch trainiertes Modell bei anderen Sprachen einbricht. MiniLM und Nomic v1.5 wurden beide hauptsächlich auf englischen Daten trainiert. Ich kann ihnen serbischen oder kroatischen Text geben und sie geben mir einen Vektor zurück — nur keinen besonders guten.
multilingual-e5-small ist eine vernünftige Lösung im niedrigeren Speicherbereich. Es ist ca. 117 MB groß, produziert 384-dimensionale Vektoren, unterstützt rund 100 Sprachen und verarbeitet bis zu 512 Token. Die MTEB-Ergebnisse für sprachübergreifendes Retrieval sind deutlich besser als bei einem englischen Modell auf nicht-englischem Text. Es wurde von Microsoft entwickelt und auf einem großen mehrsprachigen Datensatz mit einem ähnlichen kontrastiven Lernansatz wie MiniLM trainiert.
Das 512-Token-Limit ist nach wie vor eine Einschränkung, und die Qualität bei wenig repräsentierten Sprachen wird nicht mit Englisch oder ressourcenreichen Sprachen wie Französisch, Deutsch oder Chinesisch mithalten können. Aber für den praktischen Einsatz — Suche in einem Bibliothekskatalog, ähnliche Produktbeschreibungen auf Deutsch finden, mehrsprachige FAQ-Suche — ist es eine solide Wahl.
Wenn ich sowohl mehrsprachige Unterstützung als auch ein längeres Kontextfenster brauche, ist nomic-embed-text-v2-moe die aktuelle Antwort. Es ist eine neuere Architektur mit Mixture of Experts (MoE) — anstatt alle Modellparameter für jede Eingabe zu aktivieren, leitet es jede Eingabe durch eine Teilmenge von „Experten"-Subnetzwerken. Das Modell hat 475M Gesamtparameter, aktiviert bei der Inferenz aber nur rund 305M. Es verarbeitet 8.192 Token und wurde auf über 1,6 Milliarden mehrsprachigen Textpaaren trainiert.
Der Preis ist erheblich: Das Modell wiegt in float32 etwa 1,9 GB. Mit halber Präzision (float16) kommt man auf ca. 950 MB, und mit GGUF Q4-Quantisierung auf etwa 290 MB — allerdings mit etwas Qualitätsverlust. Für einen dedizierten Server ist das handhabbar. Für einen kleinen VPS oder ein Edge-Gerät möglicherweise nicht.
Das Query/Passage-Präfix
Das hat mich beim ersten Mal mit einem E5-Modell verwirrt, und ich sehe, dass es anderen Leuten ähnlich geht — deshalb erkläre ich es hier klar.
Die meisten Embedding-Modelle behandeln alle Eingabetexte gleich: Text rein, Vektor raus. Die E5-Familie (zu der auch multilingual-e5-small gehört) wurde anders trainiert. Während des Trainings wurde jeder Text entweder mit query: oder passage: präfixiert, um dem Modell zu signalisieren, welche Rolle dieser Text spielt. Query-Texte waren Suchanfragen und Fragen. Passage-Texte waren die durchsuchten Dokumente.
Weil das Modell aus so gelabelten Daten gelernt hat, produziert es geometrisch besser aufeinander abgestimmte Vektoren, wenn ich diese Präfixe verwende. Wenn ich die Ähnlichkeit zwischen einem Query-Vektor und einem Passage-Vektor berechne, erhalte ich ein genaueres Signal für semantische Relevanz, als wenn beide Vektoren ohne Präfixe erzeugt worden wären.
In der Praxis bedeutet das:
Beim Indexieren meiner Dokumente präfixiere ich jedes mit passage:
passage: Schuld und Sühne ist ein Roman von Fjodor Dostojewski aus dem Jahr 1866.
Wenn ein Nutzer sucht, präfixiere ich seine Anfrage mit query:
query: Roman über Schuld und moralisches Dilemma
Die Präfixe sind keine JSON-Feldnamen oder API-Parameter — sie sind buchstäblich die ersten Zeichen des Strings, den ich einbette. Das Feld inputs in der API-Anfrage ist einfach der Name, den die TEI-API dem Feld gibt, das meinen Text enthält.
Ich kann die Präfixe weglassen und das Modell funktioniert trotzdem. Die Embeddings sind dann für Retrieval-Aufgaben etwas weniger präzise. Wenn ich kein Retrieval mache — etwa nur Dokumente thematisch clustere — spielt es keine große Rolle, welchen Präfix ich verwende oder ob ich überhaupt einen verwende. Hauptsache, ich bin konsistent.
Die Optionen im Überblick
Hier ist eine ehrliche Zusammenfassung, wo jedes Modell seinen Platz hat:
All-MiniLM-L6-v2 — Ich nutze das, wenn ich etwas Schnelles und Leichtgewichtiges für englische Texte brauche. Es läuft problemlos auf einem Gerät mit 512 MB RAM, verarbeitet Embeddings in Echtzeit ohne GPU und ist ein vernünftiger Standard für kurze englische Inhalte. Das 256-Token-Limit ist das Wichtigste, das ich im Blick behalte.
nomic-embed-text-v1.5 — Das nutze ich, wenn ich ein Dokumenten-Retrieval-System für englische Inhalte aufbaue und längeren Kontext brauche. Das 8K-Token-Fenster ist in der Praxis wirklich nützlich. MRL-Unterstützung ist ein nettes Extra für Systeme, bei denen Speicher ein Thema ist. Für mehrsprachige Arbeit nicht geeignet.
multilingual-e5-small — Das nutze ich, wenn ich mehrsprachige Unterstützung brauche und unter 500 MB RAM bleiben möchte. Das 512-Token-Limit ist enger als bei Nomic, aber für die meisten Dokumente handhabbar. Die Qualität ist bei nicht-englischen Texten deutlich besser als bei englischen Modellen. Präfix nicht vergessen.
nomic-embed-text-v2-moe — Das nutze ich, wenn ich mehrsprachige Unterstützung UND ein langes Kontextfenster UND genug Speicher habe. Das Modell ist wirklich beeindruckend, aber es ist eine andere Gewichtsklasse — eher ein Server-Deployment als ein kleiner Sidecar-Service.
multilingual-e5-small mit Docker starten — ohne Python
Das Hugging Face Text Embeddings Inference-Projekt (TEI) bietet einen produktionsreifen Container in Rust, der eine REST-API für jedes unterstützte Modell bereitstellt. Ich schreibe keinen Code — ich starte einfach den Container.
docker run -d \ --name embeddings \ -p 8080:80 \ -v $HOME/tei-cache:/data \ --memory="512m" \ ghcr.io/huggingface/text-embeddings-inference:cpu-1.5 \ --model-id intfloat/multilingual-e5-small \ --pooling mean
Das Modell wird beim ersten Start in ~/tei-cache heruntergeladen (117 MB) und bei jedem weiteren Neustart aus dem Cache verwendet. Ich beobachte die Logs, bis eine Ready-Meldung erscheint:
docker logs -f embeddings
Dann teste ich es:
curl http://localhost:8080/embed \ -X POST \ -H "Content-Type: application/json" \ -d '{"inputs": "passage: Berlin ist die Hauptstadt Deutschlands."}'
Ich bekomme ein JSON-Array mit 384 Floats zurück. TEI stellt außerdem eine Swagger-UI unter http://localhost:8080/docs bereit, wenn ich die API lieber im Browser erkunden möchte.
Für Buchbeschreibungen oder einen anderen Dokumentenkorpus schicke ich jedes Dokument mit dem Präfix passage:, wenn ich meinen Index aufbaue, und Suchanfragen der Nutzer mit dem Präfix query: — das ist die gesamte Integrationsfläche.
Ein paar Dinge, die ich noch wissen wollte
Wenn ich Embedding-Modelle lokal betreibe, kontrolliere ich meine Daten — nichts verlässt meine Infrastruktur. Für Projekte mit sensiblen Inhalten ist das wichtiger als jede Benchmark-Zahl.
Das MTEB-Leaderboard ist der kanonische Benchmark für Embedding-Modelle, aber Benchmark-Ergebnisse und Produktions-Performance korrelieren nicht immer sauber. Modelle, die auf MTEB gut abschneiden, wurden oft auf englischlastigen Aufgaben evaluiert. Für weniger repräsentierte Sprachen gibt es kaum öffentliche Evaluierungsdaten, weshalb sich etwas eigenes Testen auf dem tatsächlichen Inhalt lohnt, bevor ich mich für ein Modell in der Produktion entscheide.
Außerdem: Vektor-Dimensionen sind relevant für den Speicherbedarf. Bei 384 Dimensionen pro float32-Wert ist jedes Embedding 1,5 KB groß. Ein Korpus von 100.000 Dokumenten benötigt etwa 150 MB Vektorspeicher. Wenn ich in dieser Größenordnung oder darüber arbeite, ermöglicht die MRL-Unterstützung (Nomic-Modelle) kürzere Vektoren für die Näherungssuche und längere nur bei Bedarf — was Speicher und Suchlatenz spürbar reduzieren kann, ohne das Modell selbst zu ändern.
