<EbeneX/>
Praxis & Anwendung · 20. Februar 2026

Vektordatenbanken und Embeddings

Wie Embeddings Text in Zahlen verwandeln – und warum das die Grundlage für RAG, Suche und KI-Anwendungen ist.

Über diesen Guide

Wie Embeddings funktionieren, welche Vektordatenbank du wählen solltest und wie du semantische Suche in der Praxis implementierst. Mit Python-Beispielen für Pinecone, Chroma und pgvector.

Fortgeschritten 14 Min. Lesezeit
Verstehen wie Embeddings Text in semantische Vektoren umwandeln
Cosine Similarity und andere Ähnlichkeitsmetriken erklären können
Die wichtigsten Vektordatenbanken vergleichen und die richtige wählen
Semantische Suche mit Python implementieren
Den Zusammenhang zwischen Embeddings, Vektordatenbanken und RAG verstehen

Was sind Embeddings?

Ein Embedding ist eine numerische Darstellung von Text (oder Bildern, Audio, etc.) als Vektor – eine Liste von Zahlen. Das Besondere: Texte mit ähnlicher Bedeutung haben ähnliche Vektoren, auch wenn sie völlig unterschiedliche Wörter verwenden.

"Wie trainiere ich ein ML-Modell?"
→ [0.023, -0.187, 0.445, 0.012, -0.334, ...]  # 1536 Zahlen

"Welche Schritte brauche ich um Machine Learning anzuwenden?"
→ [0.019, -0.201, 0.438, 0.008, -0.341, ...]  # sehr ähnliche Zahlen!

"Das Wetter ist heute schön."
→ [0.412, 0.089, -0.234, 0.567, 0.123, ...]   # völlig andere Zahlen

Diese Eigenschaft macht Embeddings zur Grundlage für semantische Suche, RAG und viele andere KI-Anwendungen.

Wie Ähnlichkeit gemessen wird

Cosine Similarity

Die häufigste Metrik ist Cosine Similarity – sie misst den Winkel zwischen zwei Vektoren, nicht ihre Distanz.

Cosine Similarity = 1.0  → identische Bedeutung
Cosine Similarity = 0.9  → sehr ähnlich
Cosine Similarity = 0.7  → verwandt
Cosine Similarity = 0.0  → keine Beziehung
Cosine Similarity = -1.0 → gegensätzlich
import numpy as np

def cosine_similarity(a: list[float], b: list[float]) -> float:
    a, b = np.array(a), np.array(b)
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

# Beispiel
vec_frage = [0.023, -0.187, 0.445]
vec_antwort = [0.019, -0.201, 0.438]
vec_unrelated = [0.412, 0.089, -0.234]

print(cosine_similarity(vec_frage, vec_antwort))   # ~0.999 – sehr ähnlich
print(cosine_similarity(vec_frage, vec_unrelated)) # ~0.1  – nicht verwandt

Andere Metriken

  • Euclidean Distance (L2): Misst den Abstand im Raum – funktioniert, aber Cosine ist bei normalisierten Vektoren meist besser
  • Dot Product: Schneller als Cosine, aber abhängig von der Vektorgröße
  • Manhattan Distance: Selten bei Embeddings genutzt

Embeddings generieren

OpenAI Embeddings API

from openai import OpenAI

client = OpenAI()

def get_embedding(text: str, model: str = "text-embedding-3-small") -> list[float]:
    text = text.replace("\n", " ")
    response = client.embeddings.create(input=[text], model=model)
    return response.data[0].embedding

# Einzelner Text
embedding = get_embedding("Was ist Machine Learning?")
print(f"Dimensionen: {len(embedding)}")  # 1536

# Batch (günstiger als einzeln)
texts = ["Text 1", "Text 2", "Text 3"]
response = client.embeddings.create(input=texts, model="text-embedding-3-small")
embeddings = [item.embedding for item in response.data]

Kosten: text-embedding-3-small kostet $0.02 pro Million Tokens – für die meisten Projekte vernachlässigbar.

Lokale Embeddings (kostenlos)

from sentence_transformers import SentenceTransformer

# Mehrsprachiges Modell – gut für Deutsch
model = SentenceTransformer("intfloat/multilingual-e5-large")

texts = ["Was ist Machine Learning?", "Wie funktioniert KI?"]
embeddings = model.encode(texts, normalize_embeddings=True)
print(embeddings.shape)  # (2, 1024)

Vektordatenbanken im Vergleich

DatenbankTypStärkenWann nutzen?
ChromaLokal / CloudEinfach, Python-nativ, kostenlosPrototypen, kleine Projekte
PineconeCloud (managed)Skalierbar, einfache API, Metadaten-FilterProduktion, wenn kein eigener Server
WeaviateSelf-hosted / CloudHybrid Search, GraphQL, sehr flexibelKomplexe Anforderungen
pgvectorPostgreSQL-ExtensionKein neues System, SQL-QueriesWenn PostgreSQL schon im Stack
QdrantSelf-hosted / CloudSchnell, Rust-basiert, gute FilterPerformance-kritische Anwendungen
FAISSLibrary (Meta)Extrem schnell, kein ServerWenn du alles selbst kontrollieren willst

Chroma – für den Einstieg

import chromadb
from openai import OpenAI

client = OpenAI()
chroma = chromadb.Client()

collection = chroma.create_collection("meine-dokumente")

# Dokumente hinzufügen
dokumente = [
    "Machine Learning ist ein Teilbereich der KI.",
    "RAG kombiniert Retrieval mit Sprachmodellen.",
    "Embeddings kodieren semantische Bedeutung als Vektoren.",
]

# Embeddings generieren und speichern
embeddings = [
    client.embeddings.create(input=[doc], model="text-embedding-3-small").data[0].embedding
    for doc in dokumente
]

collection.add(
    documents=dokumente,
    embeddings=embeddings,
    ids=[f"doc_{i}" for i in range(len(dokumente))]
)

# Suche
results = collection.query(
    query_embeddings=[
        client.embeddings.create(
            input=["Was sind Vektoren in der KI?"],
            model="text-embedding-3-small"
        ).data[0].embedding
    ],
    n_results=2
)
print(results["documents"])

pgvector – wenn PostgreSQL schon im Stack

-- Extension aktivieren
CREATE EXTENSION vector;

-- Tabelle mit Vektor-Spalte
CREATE TABLE dokumente (
    id SERIAL PRIMARY KEY,
    inhalt TEXT,
    embedding vector(1536),
    kategorie TEXT,
    erstellt_am TIMESTAMP DEFAULT NOW()
);

-- Index für schnelle Suche
CREATE INDEX ON dokumente USING ivfflat (embedding vector_cosine_ops);

-- Ähnlichkeitssuche mit Metadaten-Filter
SELECT inhalt, 1 - (embedding <=> '[0.1, 0.2, ...]'::vector) AS similarity
FROM dokumente
WHERE kategorie = 'technik'
ORDER BY embedding <=> '[0.1, 0.2, ...]'::vector
LIMIT 5;
import psycopg2
from openai import OpenAI

client = OpenAI()
conn = psycopg2.connect("postgresql://user:pass@localhost/db")

def semantic_search(query: str, kategorie: str = None, top_k: int = 5):
    query_embedding = client.embeddings.create(
        input=[query], model="text-embedding-3-small"
    ).data[0].embedding

    with conn.cursor() as cur:
        if kategorie:
            cur.execute("""
                SELECT inhalt, 1 - (embedding <=> %s::vector) AS score
                FROM dokumente WHERE kategorie = %s
                ORDER BY embedding <=> %s::vector LIMIT %s
            """, (query_embedding, kategorie, query_embedding, top_k))
        else:
            cur.execute("""
                SELECT inhalt, 1 - (embedding <=> %s::vector) AS score
                FROM dokumente ORDER BY embedding <=> %s::vector LIMIT %s
            """, (query_embedding, query_embedding, top_k))

        return cur.fetchall()

Metadaten-Filter: oft wichtiger als die Vektorsuche

Reine Vektorsuche findet semantisch ähnliche Dokumente – aber oft willst du zusätzlich filtern:

# Nur Dokumente aus 2024, Kategorie "Technik", Sprache "de"
results = collection.query(
    query_embeddings=[query_embedding],
    n_results=5,
    where={
        "$and": [
            {"jahr": {"$eq": 2024}},
            {"kategorie": {"$eq": "technik"}},
            {"sprache": {"$eq": "de"}}
        ]
    }
)

Praxistipp: Plane Metadaten von Anfang an mit. Nachträglich hinzufügen bedeutet alle Dokumente neu zu indexieren.

Hybrid Search: Vektor + Keyword

Reine Vektorsuche hat Schwächen bei exakten Begriffen (Produktnummern, Namen, Abkürzungen). Hybrid Search kombiniert Vektorsuche mit klassischer BM25-Keyword-Suche:

from rank_bm25 import BM25Okapi

# BM25 für Keyword-Suche
tokenized_docs = [doc.split() for doc in dokumente]
bm25 = BM25Okapi(tokenized_docs)

def hybrid_search(query: str, alpha: float = 0.5, top_k: int = 5):
    """alpha=1.0: nur Vektor, alpha=0.0: nur BM25"""
    # Vektor-Scores
    vector_scores = get_vector_scores(query)  # normalisiert 0-1

    # BM25-Scores
    bm25_scores = bm25.get_scores(query.split())
    bm25_scores = bm25_scores / bm25_scores.max()  # normalisieren

    # Kombinieren
    combined = alpha * vector_scores + (1 - alpha) * bm25_scores
    return sorted(enumerate(combined), key=lambda x: x[1], reverse=True)[:top_k]

Faustregel: alpha=0.6 (60% Vektor, 40% BM25) ist ein guter Startpunkt für die meisten Anwendungen.

Häufige Probleme

Problem: Suche findet irrelevante Ergebnisse

Ursache: Embedding-Modell passt nicht zum Domänenvokabular, oder Chunks zu groß. Lösung: Kleinere Chunks (200–400 Token), domänenspezifisches Embedding-Modell, Hybrid Search.

Problem: Suche ist zu langsam

Ursache: Kein Index, oder Index-Typ falsch gewählt. Lösung: ivfflat für Geschwindigkeit, hnsw für bessere Recall-Rate. Bei pgvector: SET ivfflat.probes = 10.

Problem: Unterschiedliche Ergebnisse bei gleicher Anfrage

Ursache: Approximate Nearest Neighbor (ANN) Algorithmen sind nicht deterministisch. Lösung: nprobe/ef_search erhöhen für mehr Genauigkeit (auf Kosten der Geschwindigkeit).

Problem: Embedding-Modell gewechselt, alte Daten passen nicht mehr

Ursache: Embeddings verschiedener Modelle sind nicht kompatibel. Lösung: Alle Dokumente neu einbetten wenn das Modell wechselt. Modellversion in Metadaten speichern.

Semantische Suche mit Chroma und OpenAI

Baue in 20 Minuten eine semantische Suche über eigene Texte – lokal, ohne Cloud-Datenbank.

  1. Installieren: `pip install chromadb openai`
  2. OpenAI Client initialisieren und Chroma-Collection erstellen
  3. 5-10 eigene Texte (z.B. FAQ-Antworten) als Dokumente hinzufügen
  4. Embeddings automatisch von Chroma generieren lassen (mit OpenAI-Embedding-Modell)
  5. Suchanfrage stellen: `collection.query(query_texts=['Deine Frage'], n_results=3)`
  6. Ergebnisse mit klassischer Keyword-Suche vergleichen – wo ist semantische Suche besser?
Was ist der Unterschied zwischen Embeddings und Tokens?

Tokens sind die kleinsten Einheiten in die Text zerlegt wird (Teilwörter). Embeddings sind numerische Vektoren die die semantische Bedeutung eines Textes kodieren – sie entstehen nachdem der Text tokenisiert wurde. Ein Embedding kann einen Token, ein Wort, einen Satz oder ein ganzes Dokument repräsentieren.

Brauche ich eine Vektordatenbank oder reicht ein Array?

Für unter 10.000 Dokumente reicht oft ein einfaches Array mit NumPy-Cosine-Similarity. Ab 100.000+ Dokumenten brauchst du eine echte Vektordatenbank für performante Suche. Chroma ist ein guter Einstieg der beides abdeckt.

Welches Embedding-Modell soll ich nutzen?

Für den Einstieg: OpenAI text-embedding-3-small (günstig, gut). Für Mehrsprachigkeit: multilingual-e5-large (kostenlos, lokal). Für Produktion mit hohem Volumen: Eigenes Modell oder Cohere Embed. Wichtig: Immer dasselbe Modell für Indexierung und Suche nutzen.

Kann ich Vektordatenbank und LLM von verschiedenen Anbietern kombinieren?

Ja, vollständig. Embeddings von OpenAI in Pinecone speichern und mit Claude als LLM nutzen – kein Problem. Embedding-Modell, Vektordatenbank und LLM sind unabhängige Komponenten.

  • Embeddings sind Vektoren – Listen von Zahlen die semantische Bedeutung kodieren. Ähnliche Texte haben ähnliche Vektoren
  • Cosine Similarity misst den Winkel zwischen Vektoren – nicht die Distanz. Werte nahe 1.0 = sehr ähnlich
  • Für Prototypen: Chroma (lokal, kostenlos). Für Produktion: Pinecone oder pgvector je nach Stack
  • Embedding-Modell und Vektordatenbank sind unabhängig – du kannst sie frei kombinieren
  • Metadaten-Filter sind oft wichtiger als die Vektorsuche selbst – immer mitplanen