← Anleitungen
KI & Vektor-DatenbankenFortgeschritten4 Min

Chroma

Chroma ist eine schlanke Open-Source-Vektordatenbank, die Texte als Embeddings speichert und per Ähnlichkeitssuche abfragt – der Kernbaustein für RAG und semantische Suche in LLM-Anwendungen. So bringst du Chroma sauber und persistent in Docker zum Laufen.

Sobald deine LLM-Anwendung mehr können soll als auf vortrainiertem Wissen herumzuraten, brauchst du eine Stelle, an der deine eigenen Dokumente landen – durchsuchbar nach Bedeutung, nicht nach Stichwort. Genau das leistet eine Vektordatenbank. Chroma ist die wohl bekannteste Open-Source-Variante in diesem Feld: leichtgewichtig, schnell aufgesetzt und eng auf RAG-Workflows (Retrieval-Augmented Generation) zugeschnitten. In dieser Anleitung erfährst du, was Chroma genau macht, wann sich der Einsatz lohnt und wie du den Server sauber und vor allem persistent in Docker betreibst – damit deine Embeddings einen Neustart überleben.

Was ist Chroma?

Organisiert wird das Ganze in Collections. Eine Collection ist vergleichbar mit einer Tabelle: ein benannter Container, der zusammengehörige Embeddings, die zugehörigen Originaltexte (Documents) und beliebige Metadaten bündelt. So kannst du etwa pro Mandant, pro Wissensdomäne oder pro Dokumenttyp eine eigene Collection führen und gezielt darin suchen.

Technisch ist Chroma bewusst schlank: Der Server läuft als einzelner Dienst, spricht eine REST-API auf Port 8000 und bringt einen Python-Client mit (pip install chromadb), der sich per chromadb.HttpClient(host="SERVER", port=8000) verbindet. Damit ist Chroma in Minuten einsatzbereit und braucht keinen schwergewichtigen Cluster, um produktiv Nutzen zu stiften.

Vektordatenbank statt Tabellen. Chroma speichert Texte nicht als Zeilen mit Spalten, sondern als Vektoren – sogenannte Embeddings. Ein Embedding ist eine Zahlenfolge, die die Bedeutung eines Textstücks im Raum verortet. Zwei inhaltlich ähnliche Sätze liegen in diesem Raum nah beieinander, auch wenn sie kein einziges Wort teilen.

Ähnlichkeitssuche als Kernfunktion. Statt nach exakten Treffern zu filtern, sucht Chroma die nächsten Nachbarn (nearest neighbor) zu einer Anfrage. Du stellst eine Frage, Chroma wandelt sie in einen Vektor um und liefert die inhaltlich passendsten Textstücke zurück – sortiert nach Distanz (Cosine, L2 oder Inner Product).

Wann und wofür setzt du Chroma ein?

Im Kontext einer Plattform wie ueli-bot ist Chroma genau der Baustein, der hochgeladene Dokumente durchsuchbar macht: Beim Upload wird jedes Dokument in Abschnitte zerlegt, in Embeddings übersetzt und in einer Collection abgelegt. Stellt jemand später eine Frage, liefert Chroma die passenden Abschnitte, die das LLM dann zu einer fundierten, quellenbasierten Antwort verarbeitet.

Chroma ist die richtige Wahl, wenn du schnell starten, lokal oder selbst gehostet bleiben und ohne grossen Betriebsaufwand auskommen willst – etwa aus Souveränitäts- oder Datenschutzgründen. Bei sehr grossen, hochverfügbaren Produktiv-Setups mit Millionen von Vektoren und harten Latenz-SLAs lohnt sich später der Blick auf spezialisierte Alternativen; für den Einstieg, Prototypen und viele Produktiv-Workloads ist Chroma aber ausgesprochen praktikabel.

RAG für LLM-Anwendungen. Der klassische Fall: Du willst, dass ein Sprachmodell auf Basis deiner eigenen Dokumente antwortet, statt zu halluzinieren. Du legst die Texte als Embeddings in Chroma ab, holst zu jeder Nutzerfrage die relevantesten Passagen heraus und reichst sie dem LLM als Kontext mit. Das ist das Herzstück von Retrieval-Augmented Generation.

Semantische Suche jenseits von RAG. Auch ohne nachgeschaltetes LLM ist die Ähnlichkeitssuche wertvoll: Duplikat-Erkennung, Empfehlungen, Klassifikation oder eine Suche, die «Kündigungsfrist» auch dann findet, wenn im Dokument «Vertragsbeendigung» steht.

Achtung Datenverlust: Chroma legt Embeddings im Container unter /data ab. Ohne benanntes Volume (chroma_data:/data) sind nach jedem Container-Neustart alle Vektoren weg – und du musst sämtliche Dokumente neu einlesen. Binde das Volume immer ein und setze IS_PERSISTENT=TRUE – ohne diese Variable startet das Docker-Image stillschweigend im In-Memory-Modus.

Installation mit Docker

Chroma läuft als offizielles Image chromadb/chroma. Entscheidend ist die Persistenz: Das Verzeichnis /data im Container muss auf ein benanntes Docker-Volume zeigen, sonst gehen die Embeddings beim Neustart verloren. Mit IS_PERSISTENT=TRUE schreibt Chroma seine Daten dauerhaft auf die Platte – fehlt die Variable, läuft der Server trotz Volume nur im Arbeitsspeicher. Mit ANONYMIZED_TELEMETRY=FALSE schaltest du die Telemetrie ab.

1# Benanntes Volume anlegen (überlebt Container-Neustarts)
2docker volume create chroma_data
3
4# Chroma-Server starten
5docker run -d \
6 --name chroma \
7 -p 8000:8000 \
8 -v chroma_data:/data \
9 -e IS_PERSISTENT=TRUE \
10 -e ANONYMIZED_TELEMETRY=FALSE \
11 --restart unless-stopped \
12 chromadb/chroma

Oder als wiederverwendbare docker-compose.yml:

1# docker-compose.yml
2services:
3 chroma:
4 image: chromadb/chroma
5 container_name: chroma
6 ports:
7 - "8000:8000"
8 environment:
9 - IS_PERSISTENT=TRUE
10 - ANONYMIZED_TELEMETRY=FALSE
11 # Optional: Token-Auth aktivieren (BEIDE Variablen nötig)
12 # - CHROMA_SERVER_AUTHN_PROVIDER=chromadb.auth.token_authn.TokenAuthenticationServerProvider
13 # - CHROMA_SERVER_AUTHN_CREDENTIALS=dein-geheimes-token
14 volumes:
15 - chroma_data:/data
16 restart: unless-stopped
17 # Hinweis: Das chromadb/chroma-Image ist schlank und enthält KEIN curl.
18 # Daher Healthcheck über Bash-Builtin /dev/tcp statt curl:
19 healthcheck:
20 test: ["CMD", "/bin/bash", "-c", "</dev/tcp/localhost/8000"]
21 interval: 30s
22 timeout: 10s
23 retries: 3
24
25volumes:
26 chroma_data:

Verwende ausdrücklich ein BENANNTES Volume (chroma_data:/data), kein anonymes. Anonyme Volumes werden bei docker compose down -v oder einem docker run --rm verworfen – und damit deine komplette Wissensbasis. Beachte ausserdem zwei Stolpersteine: Erstens enthält das schlanke chromadb/chroma-Image kein curl – ein klassischer curl-Healthcheck schlägt mit «executable file not found» fehl; nutze stattdessen den Bash-Builtin /dev/tcp wie oben. Zweitens reicht für Token-Auth die Variable CHROMA_SERVER_AUTHN_CREDENTIALS allein NICHT: Du musst zusätzlich CHROMA_SERVER_AUTHN_PROVIDER auf den Token-Provider setzen, sonst bleibt der Server offen. Für den Zugriff von aussen solltest du Chroma nicht ungeschützt ins Internet stellen, sondern Token-Auth aktivieren oder den Port nur intern (z. B. hinter einem Reverse-Proxy) erreichbar machen.

Prüfe nach dem Start, ob der Server antwortet und ob du dich per Python-Client verbinden kannst:

1# REST-Heartbeat – muss ein Nanosekunden-Timestamp zurückgeben
2curl http://localhost:8000/api/v2/heartbeat
3
4# Python-Client installieren
5pip install chromadb
6
7# Verbindung testen (Python)
8python3 -c "import chromadb; c = chromadb.HttpClient(host='localhost', port=8000); print(c.heartbeat())"

Fazit

Chroma ist der schnellste Weg, eigene Dokumente für ein LLM durchsuchbar zu machen: Texte rein, Embeddings raus, Ähnlichkeitssuche fertig. Der grösste Stolperstein im Betrieb ist die Persistenz – wer das benannte Volume chroma_data:/data und IS_PERSISTENT=TRUE vergisst, verliert seine Wissensbasis beim nächsten Neustart, weil das Image sonst stillschweigend im Arbeitsspeicher läuft. Zwei weitere Fallen lauern in der Praxis: Das schlanke Image bringt kein curl mit (Healthcheck über Bash-/dev/tcp lösen), und Token-Auth braucht neben den Credentials zwingend den passenden AUTHN-Provider. Mit dem gezeigten Docker-Setup, abgeschalteter Telemetrie und optionaler Token-Auth hast du eine schlanke, selbst gehostete Vektordatenbank, die sich nahtlos in RAG-Pipelines wie die von ueli-bot einfügt. Für den Einstieg und viele Produktiv-Workloads ist das eine solide, souveränitätsfreundliche Basis.