12.5 Vector-Store-Datenbanken
Um die Vektor-Embeddings nicht bei jedem Start der Applikation erneut zu berechnen, werden wir den Index in einer Datenbank speichern.
Die Aufgabe der Vektor-Datenbank ist es, die numerische Repräsentation von unstrukturierten Daten (die Vektoren mit ihren Dimensionen) zu speichern und diese mit verschiedenen Algorithmen zu suchen. Dabei unterscheiden sich die Implementierungen in solche, bei denen externe Bibliotheken diese Suche in einer bestehenden (relationalen oder NoSQL-)Datenbank ausführen, solche, bei denen dafür Plug-ins in der Datenbank verwendet werden, und echte Vektor-Datenbanken.
Echte Vektor-Datenbanken sind auf eine Stufe mit SQL- und NoSQL-Datenbanken zu stellen. Während SQL-Datenbanken die Ausgangsdaten in eine starke Struktur zwängen (durch starre Tabellen mit vielen Datentypen), strukturiert NoSQL die Daten nur grob durch Schlüssel-Wert-Paare mit Datentypen wie Zahlen, Zeichenketten oder Datum. Bei Vektor-Datenbanken werden die Ausgangsdaten unstrukturiert abgelegt, und nur die errechneten Vektoren kommen bei der Suche zum Einsatz.
Ein prominenter Vertreter echter Vektor-Datenbanken ist Milvus. Die Datenbank steht unter der freien Apache-2-Lizenz und kann sehr einfach in unterschiedlichen Szenarien eingesetzt werden: Die Lite-Version eignet sich hervorragend zum Prototyping oder auf Geräten mit sehr schwacher Hardware. Für produktive Deployments kann Milvus Standalone sehr einfach im Docker-Container gestartet werden. Wer ganz groß denkt, kann Milvus auch im Kubernetes-Cluster in einer Cloud-nativen Architektur starten. Und Sie können Milvus auch als fertige Cloud-Lösung von der Firma Zilliz mieten, die maßgeblich hinter der Entwicklung steht.
Wir haben sowohl die Lite-Version als auch die Standalone-Variante ausprobiert. Beide Varianten konnten bei unserem sehr kleinen Datensatz überzeugen. Das Docker-Setup mit einer compose.yaml-Datei kann praktisch auf Knopfdruck gestartet werden. Die API-Aufrufe unterscheiden sich nicht, ob Sie mit Lite/Standalone oder der Cloud-Variante von Milvus arbeiten. So können Sie Ihr kleines Testprojekt in wenigen Sekunden zu einer skalierbaren Lösung umbauen.
Wir verwenden für unser RAG-Projekt die Standalone-Variante von Milvus im Docker-Setup mit compose. Wenn Sie die aktuelle Version von Docker und das compose-Plug-in installiert haben, reicht es, die auf GitHub bereitgestellte Konfigurationsdatei herunterzuladen und das Setup mit docker compose up -d zu starten.
https://github.com/milvus-io/milvus/releases/download/v2.4.6/milvus-standalone-docker-compose.yml
Neben der Datenbank werden noch zwei weitere Services gestartet: Der Konfigurationsdienst etcd und der Objektspeicher MinIO. Die Datenbank steht kurz danach auf dem Port 19530 ohne Authentifizierung zur Verfügung.
Zilliz hat auch eine grafische Oberfläche für die Verwaltung der Datenbank als Open-Source-Software entwickelt. Attu können Sie sehr einfach als weiteren Container in das Docker-Compose-Setup einhängen. Ergänzen Sie einfach folgende Zeilen im services-Bereich der heruntergeladenen Compose-Datei:
attu:
image: zilliz/attu:v2.4
environment:
MILVUS_URL: milvus-standalone:19530
ports:
- "8000:3000"
Nach dem Start des Containers mit docker compose up -d erreichen Sie die Weboberfläche unter http://localhost:8000 beziehungsweise dem Hostnamen, auf dem Sie das Docker-Compose-Setup gestartet haben. Wir fanden den Einblick in die interne Datenstruktur der Vektor-Datenbank sehr spannend .
Um die Milvus-Datenbank für unser Beispielprojekt zu verwenden, binden wir einen LlamaIndex StorageContext beim Erzeugen des VectorStoreIndex mit ein:
from llama_index.vector_stores.milvus import MilvusVectorStore
from llama_index.embeddings.ollama import OllamaEmbedding
from llama_index.core import StorageContext
vector_store = MilvusVectorStore(uri="http://localhost:19530",
dim=1024, overwrite=True)
storage_context = StorageContext.from_defaults(
vector_store=vector_store
)
index = VectorStoreIndex.from_documents(
documents=documents,
transformations=[
SentenceSplitter(),
TitleExtractor(),
OllamaEmbedding(model_name="mxbai-embed-large"),
],
storage_context=storage_context,
show_progress=True,
)
Neben der uri, die auf die zuvor in Docker gestartete Datenbank verweist, muss noch die Dimension der Vektoren angegeben werden. Diese muss an das verwendete Embedding-Modell angepasst werden. Das hier eingesetzte mxbai-embed-large verwendet Vektoren mit 1024 Dimensionen. Damit es zu keinen Duplikaten kommt, löscht der Parameter overwrite=True die Datenbank vor dem Erzeugen des Index. Damit ist die Applikation bereit, und wir können die ersten Abfragen in natürlicher Sprache über die indizierten Inhalte ausprobieren.
Abbildung 12.3 Die Webanwendung Attu zeigt die Inhalte der Vektor-Datenbank Milvus mit den indizierten PDF-Dokumenten und Webseiten. Im linken Teil sehen Sie drei Collections, die mit jeweils unterschiedlichen Embedding-Modellen erstellt wurden. width=100%