Retrieval-erweiterte Generierung (RAG) mit Milvus und LlamaIndex
Diese Anleitung zeigt, wie man ein Retrieval-Augmented Generation (RAG) System mit LlamaIndex und Milvus aufbaut.
Das RAG-System kombiniert ein Retrieval-System mit einem generativen Modell, um neuen Text auf der Grundlage einer vorgegebenen Aufforderung zu generieren. Das System sucht zunächst mit Milvus relevante Dokumente aus einem Korpus und verwendet dann ein generatives Modell, um neuen Text auf der Grundlage der gefundenen Dokumente zu generieren.
LlamaIndex ist ein einfaches, flexibles Daten-Framework für die Verbindung benutzerdefinierter Datenquellen mit großen Sprachmodellen (LLMs). Milvus ist die weltweit fortschrittlichste Open-Source-Vektordatenbank, die für die Einbettung von Ähnlichkeitssuche und KI-Anwendungen entwickelt wurde.
In diesem Notizbuch zeigen wir eine kurze Demo zur Verwendung des MilvusVectorStore.
Bevor Sie beginnen
Abhängigkeiten installieren
Die Codeschnipsel auf dieser Seite benötigen die Abhängigkeiten pymilvus und llamaindex. Sie können diese mit den folgenden Befehlen installieren:
$ pip install pymilvus>=2.4.2 milvus-lite
$ pip install llama-index-vector-stores-milvus
$ pip install llama-index
Wenn Sie Google Colab verwenden, müssen Sie möglicherweise die Runtime neu starten, um die gerade installierten Abhängigkeiten zu aktivieren. (Klicken Sie auf das Menü "Runtime" am oberen Rand des Bildschirms und wählen Sie "Restart session" aus dem Dropdown-Menü).
OpenAI einrichten
Beginnen wir mit dem Hinzufügen des openai api Schlüssels. Dies wird uns den Zugang zu chatgpt ermöglichen.
import openai
openai.api_key = "sk-***********"
Daten vorbereiten
Sie können Beispieldaten mit den folgenden Befehlen herunterladen:
! mkdir -p 'data/'
! wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/paul_graham/paul_graham_essay.txt' -O 'data/paul_graham_essay.txt'
! wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/10k/uber_2021.pdf' -O 'data/uber_2021.pdf'
Erste Schritte
Generieren Sie unsere Daten
Als erstes Beispiel wollen wir ein Dokument aus der Datei paul_graham_essay.txt generieren. Es handelt sich um einen einzelnen Aufsatz von Paul Graham mit dem Titel What I Worked On. Um die Dokumente zu generieren, werden wir den SimpleDirectoryReader verwenden.
from llama_index.core import SimpleDirectoryReader
# load documents
documents = SimpleDirectoryReader(
input_files=["./data/paul_graham_essay.txt"]
).load_data()
print("Document ID:", documents[0].doc_id)
Document ID: 95f25e4d-f270-4650-87ce-006d69d82033
Erstellen Sie einen Index über die Daten
Nun, da wir ein Dokument haben, können wir einen Index erstellen und das Dokument einfügen. Für den Index werden wir einen MilvusVectorStore verwenden. MilvusVectorStore nimmt ein paar Argumente entgegen:
Grundargumente
uri (str, optional): Die URI, zu der eine Verbindung hergestellt werden soll, kommt in Form von "https://address:port" für Milvus oder Zilliz Cloud Service, oder "path/to/local/milvus.db" für das lite local Milvus. Die Standardeinstellung ist "./milvus_llamaindex.db".token (str, optional): Das Token für den Log-In. Leer, wenn kein rbac verwendet wird. Wenn rbac verwendet wird, wird es wahrscheinlich "username:password" sein.collection_name (str, optional): Der Name der Sammlung, in der die Daten gespeichert werden sollen. Standardwert ist "llamalection".overwrite (bool, optional): Ob eine bestehende Sammlung mit demselben Namen überschrieben werden soll. Der Standardwert ist False.
skalare Felder einschließlich doc id & text
doc_id_field (str, optional): Der Name des doc_id-Feldes für die Sammlung. Der Standardwert ist DEFAULT_DOC_ID_KEY.text_key (str, optional): Welcher Schlüsseltext in der übergebenen Sammlung gespeichert wird. Wird verwendet, wenn Sie Ihre eigene Sammlung mitbringen. Der Standardwert ist DEFAULT_TEXT_KEY.scalar_field_names (list, optional): Die Namen der zusätzlichen skalaren Felder, die in das Sammlungsschema aufgenommen werden sollen.scalar_field_types (list, optional): Die Typen der zusätzlichen skalaren Felder.
dichtes Feld
enable_dense (bool): Ein boolesches Flag zum Aktivieren oder Deaktivieren der dichten Einbettung. Der Standardwert ist True.dim (int, optional): Die Dimension der Einbettungsvektoren für die Sammlung. Erforderlich bei der Erstellung einer neuen Sammlung mit enable_sparse ist False.embedding_field (str, optional): Name des dichten Einbettungsfeldes für die Sammlung, Standardwert ist DEFAULT_EMBEDDING_KEY.index_config (dict, optional): Die für die Erstellung des Dense Embedding Index verwendete Konfiguration. Der Standardwert ist None.search_config (dict, optional): Die Konfiguration, die für die Suche im dichten Milvus-Index verwendet wird. Beachten Sie, dass dies mit dem durchindex_configangegebenen Indextyp kompatibel sein muss. Der Standardwert ist None.similarity_metric (str, optional): Die Ähnlichkeitsmetrik, die für die dichte Einbettung verwendet werden soll. Derzeit werden IP, COSINE und L2 unterstützt.
sparse field
enable_sparse (bool): Ein boolesches Flag zum Aktivieren oder Deaktivieren der Sparse-Einbettung. Der Standardwert ist False.sparse_embedding_field (str): Der Name des Sparse-Embedding-Feldes, Standardwert ist DEFAULT_SPARSE_EMBEDDING_KEY.sparse_embedding_function (Union[BaseSparseEmbeddingFunction, BaseMilvusBuiltInFunction], optional): Wenn enable_sparse True ist, sollte dieses Objekt bereitgestellt werden, um Text in eine Sparse-Einbettung zu konvertieren. Wenn None, wird die Standard-Sparse-Embedding-Funktion (BGEM3SparseEmbeddingFunction) verwendet.sparse_index_config (dict, optional): Die Konfiguration, die zur Erstellung des Sparse Embedding Index verwendet wird. Der Standardwert ist None.
Hybrid-Rangierer
hybrid_ranker (str): Gibt den Typ des Rankers an, der in hybriden Suchanfragen verwendet wird. Unterstützt derzeit nur ["RRFRanker", "WeightedRanker"]. Der Standardwert ist "RRFRanker".hybrid_ranker_params (dict, optional): Konfigurationsparameter für den hybriden Ranker. Die Struktur dieses Wörterbuchs hängt von dem spezifischen Ranker ab, der verwendet wird:- Für "RRFRanker" sollte es enthalten:
- "k" (int): Ein bei der Reciprocal Rank Fusion (RRF) verwendeter Parameter. Dieser Wert wird zur Berechnung der Rank Scores als Teil des RRF-Algorithmus verwendet, der mehrere Ranking-Strategien zu einem einzigen Score kombiniert, um die Suchrelevanz zu verbessern.
- Für "WeightedRanker" wird erwartet:
- "Gewichte" (Liste von Floats): Eine Liste mit genau zwei Gewichten:
- Die Gewichtung für die dichte Einbettungskomponente.
- Die Gewichtung für die spärliche Einbettungskomponente. Diese Gewichte werden verwendet, um die Wichtigkeit der dichten und spärlichen Komponenten der Einbettungen im hybriden Retrievalprozess anzupassen. Der Standardwert ist ein leeres Wörterbuch, was bedeutet, dass der Ranker mit seinen vordefinierten Standardeinstellungen arbeitet.
- "Gewichte" (Liste von Floats): Eine Liste mit genau zwei Gewichten:
- Für "RRFRanker" sollte es enthalten:
andere
collection_properties (dict, optional): Die Eigenschaften der Sammlung wie TTL (Time-To-Live) und MMAP (Memory Mapping). Die Standardeinstellung ist Keine. Sie könnte enthalten:- "collection.ttl.seconds" (int): Sobald diese Eigenschaft gesetzt ist, laufen die Daten in der aktuellen Sammlung nach der angegebenen Zeit ab. Abgelaufene Daten in der Sammlung werden bereinigt und nicht in Suchvorgänge oder Abfragen einbezogen.
- "mmap.enabled" (bool): Ob die Memory-Mapped-Speicherung auf der Ebene der Sammlung aktiviert werden soll.
index_management (IndexManagement): Gibt die zu verwendende Indexverwaltungsstrategie an. Der Standardwert ist "create_if_not_exists".batch_size (int): Konfiguriert die Anzahl der in einem Stapel verarbeiteten Dokumente beim Einfügen von Daten in Milvus. Der Standardwert ist DEFAULT_BATCH_SIZE.consistency_level (str, optional): Welche Konsistenzstufe für eine neu erstellte Sammlung verwendet werden soll. Der Standardwert ist "Session".
# Create an index over the documents
from llama_index.core import VectorStoreIndex, StorageContext
from llama_index.vector_stores.milvus import MilvusVectorStore
vector_store = MilvusVectorStore(uri="./milvus_demo.db", dim=1536, overwrite=True)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(documents, storage_context=storage_context)
Für die Parameter von MilvusVectorStore:
- Die Einstellung von
urials lokale Datei, z. B../milvus.db, ist die bequemste Methode, da Milvus Lite automatisch alle Daten in dieser Datei speichert. - Wenn Sie große Datenmengen haben, können Sie einen leistungsfähigeren Milvus-Server auf Docker oder Kubernetes einrichten. Bei dieser Einrichtung verwenden Sie bitte die Server-Uri, z. B.
http://localhost:19530, alsuri. - Wenn Sie Zilliz Cloud, den vollständig verwalteten Cloud-Service für Milvus, verwenden möchten, passen Sie
uriundtokenan, die dem öffentlichen Endpunkt und dem Api-Schlüssel in Zilliz Cloud entsprechen.
Abfrage der Daten
Nun, da unser Dokument im Index gespeichert ist, können wir Fragen an den Index stellen. Der Index wird die in ihm gespeicherten Daten als Wissensbasis für chatgpt verwenden.
query_engine = index.as_query_engine()
res = query_engine.query("What did the author learn?")
print(res)
The author learned that philosophy courses in college were boring to him, leading him to switch his focus to studying AI.
res = query_engine.query("What challenges did the disease pose for the author?")
print(res)
The disease posed challenges for the author as it affected his mother's health, leading to a stroke caused by colon cancer. This resulted in her losing her balance and needing to be placed in a nursing home. The author and his sister were determined to help their mother get out of the nursing home and back to her house.
Der nächste Test zeigt, dass das Überschreiben die vorherigen Daten entfernt.
from llama_index.core import Document
vector_store = MilvusVectorStore(uri="./milvus_demo.db", dim=1536, overwrite=True)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(
[Document(text="The number that is being searched for is ten.")],
storage_context,
)
query_engine = index.as_query_engine()
res = query_engine.query("Who is the author?")
print(res)
The author is the individual who created the context information.
Der nächste Test zeigt das Hinzufügen zusätzlicher Daten zu einem bereits bestehenden Index.
del index, vector_store, storage_context, query_engine
vector_store = MilvusVectorStore(uri="./milvus_demo.db", overwrite=False)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(documents, storage_context=storage_context)
query_engine = index.as_query_engine()
res = query_engine.query("What is the number?")
print(res)
The number is ten.
res = query_engine.query("Who is the author?")
print(res)
Paul Graham
Filtern von Metadaten
Wir können Ergebnisse erzeugen, indem wir bestimmte Quellen filtern. Das folgende Beispiel zeigt, wie alle Dokumente aus dem Verzeichnis geladen und anschließend nach Metadaten gefiltert werden.
from llama_index.core.vector_stores import ExactMatchFilter, MetadataFilters
# Load all the two documents loaded before
documents_all = SimpleDirectoryReader("./data/").load_data()
vector_store = MilvusVectorStore(uri="./milvus_demo.db", dim=1536, overwrite=True)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(documents_all, storage_context)
Wir wollen nur Dokumente aus der Datei uber_2021.pdf abrufen.
filters = MetadataFilters(
filters=[ExactMatchFilter(key="file_name", value="uber_2021.pdf")]
)
query_engine = index.as_query_engine(filters=filters)
res = query_engine.query("What challenges did the disease pose for the author?")
print(res)
The disease posed challenges related to the adverse impact on the business and operations, including reduced demand for Mobility offerings globally, affecting travel behavior and demand. Additionally, the pandemic led to driver supply constraints, impacted by concerns regarding COVID-19, with uncertainties about when supply levels would return to normal. The rise of the Omicron variant further affected travel, resulting in advisories and restrictions that could adversely impact both driver supply and consumer demand for Mobility offerings.
Wir erhalten diesmal ein anderes Ergebnis, wenn wir aus der Datei paul_graham_essay.txt abrufen.
filters = MetadataFilters(
filters=[ExactMatchFilter(key="file_name", value="paul_graham_essay.txt")]
)
query_engine = index.as_query_engine(filters=filters)
res = query_engine.query("What challenges did the disease pose for the author?")
print(res)
The disease posed challenges for the author as it affected his mother's health, leading to a stroke caused by colon cancer. This resulted in his mother losing her balance and needing to be placed in a nursing home. The author and his sister were determined to help their mother get out of the nursing home and back to her house.