Construire RAG avec Milvus et Cognee
Cognee est une plate-forme axée sur le développement qui rationalise le développement d'applications d'IA grâce à des pipelines ECL (Extract, Cognify, Load) modulaires et évolutifs. En s'intégrant de manière transparente à Milvus, Cognee permet une connexion et une récupération efficaces des conversations, des documents et des transcriptions, réduisant ainsi les hallucinations et optimisant les coûts opérationnels.
Grâce à une prise en charge solide des magasins vectoriels tels que Milvus, des bases de données de graphes et des LLM, Cognee offre un cadre flexible et personnalisable pour la création de systèmes de génération augmentée par récupération (RAG). Son architecture prête à la production garantit une précision et une efficacité accrues pour les applications alimentées par l'IA.
Dans ce tutoriel, nous allons vous montrer comment construire un pipeline RAG (Retrieval-Augmented Generation) avec Milvus et Cognee.
$ pip install pymilvus git+https://github.com/topoteretes/cognee.git
Si vous utilisez Google Colab, pour activer les dépendances qui viennent d'être installées, vous devrez peut-être redémarrer le runtime (cliquez sur le menu "Runtime" en haut de l'écran, et sélectionnez "Restart session" dans le menu déroulant).
Par défaut, il utilise OpenAI comme LLM dans cet exemple. Vous devez préparer la clé api et la définir dans la fonction config set_llm_api_key()
.
Pour configurer Milvus en tant que base de données vectorielle, définissez VECTOR_DB_PROVIDER
sur milvus
et spécifiez VECTOR_DB_URL
et VECTOR_DB_KEY
. Comme nous utilisons Milvus Lite pour stocker les données dans cette démo, seul le VECTOR_DB_URL
doit être fourni.
import os
import cognee
cognee.config.set_llm_api_key("YOUR_OPENAI_API_KEY")
os.environ["VECTOR_DB_PROVIDER"] = "milvus"
os.environ["VECTOR_DB_URL"] = "./milvus.db"
Quant aux variables d'environnement VECTOR_DB_URL
et VECTOR_DB_KEY
:
- Définir
VECTOR_DB_URL
comme un fichier local, par exemple./milvus.db
, est la méthode la plus pratique, car elle utilise automatiquement Milvus Lite pour stocker toutes les données dans ce fichier. - Si vous avez des données à grande échelle, vous pouvez configurer un serveur Milvus plus performant sur docker ou kubernetes. Dans cette configuration, veuillez utiliser l'uri du serveur, par exemple
http://localhost:19530
, comme votreVECTOR_DB_URL
. - Si vous souhaitez utiliser Zilliz Cloud, le service cloud entièrement géré pour Milvus, ajustez les adresses
VECTOR_DB_URL
etVECTOR_DB_KEY
, qui correspondent au point de terminaison public et à la clé Api dans Zilliz Cloud.
Préparer les données
Nous utilisons les pages FAQ de la documentation Milvus 2.4.x comme connaissance privée dans notre RAG, qui est une bonne source de données pour un pipeline RAG simple.
Téléchargez le fichier zip et extrayez les documents dans le dossier milvus_docs
.
$ wget https://github.com/milvus-io/milvus-docs/releases/download/v2.4.6-preview/milvus_docs_2.4.x_en.zip
$ unzip -q milvus_docs_2.4.x_en.zip -d milvus_docs
Nous chargeons tous les fichiers markdown à partir du dossier milvus_docs/en/faq
. Pour chaque document, nous utilisons simplement "# " pour séparer le contenu du fichier, ce qui permet de séparer grossièrement le contenu de chaque partie principale du fichier markdown.
from glob import glob
text_lines = []
for file_path in glob("milvus_docs/en/faq/*.md", recursive=True):
with open(file_path, "r") as file:
file_text = file.read()
text_lines += file_text.split("# ")
Construire RAG
Réinitialisation des données de Cognee
await cognee.prune.prune_data()
await cognee.prune.prune_system(metadata=True)
Une fois que nous avons fait table rase du passé, nous pouvons maintenant ajouter notre jeu de données et le traiter pour en faire un graphe de connaissances.
Ajout de données et cognification
await cognee.add(data=text_lines, dataset_name="milvus_faq")
await cognee.cognify()
# [DocumentChunk(id=UUID('6889e7ef-3670-555c-bb16-3eb50d1d30b0'), updated_at=datetime.datetime(2024, 12, 4, 6, 29, 46, 472907, tzinfo=datetime.timezone.utc), text='Does the query perform in memory? What are incremental data and historical data?\n\nYes. When ...
# ...
La méthode add
charge l'ensemble de données (Milvus FAQs) dans Cognee et la méthode cognify
traite les données pour extraire les entités, les relations et les résumés, construisant ainsi un graphe de connaissances.
Recherche de résumés
Maintenant que les données ont été traitées, interrogeons le graphe de connaissances.
from cognee.api.v1.search import SearchType
query_text = "How is data stored in milvus?"
search_results = await cognee.search(SearchType.SUMMARIES, query_text=query_text)
print(search_results[0])
{'id': 'de5c6713-e079-5d0b-b11d-e9bacd1e0d73', 'text': 'Milvus stores two data types: inserted data and metadata.'}
Cette requête recherche dans le graphe de connaissances un résumé lié au texte de la requête, et le candidat le plus lié est imprimé.
Recherche de morceaux
Les résumés offrent des informations de haut niveau, mais pour obtenir des détails plus précis, nous pouvons interroger des morceaux de données spécifiques directement à partir de l'ensemble de données traitées. Ces morceaux sont dérivés des données originales qui ont été ajoutées et analysées lors de la création du graphe de connaissances.
from cognee.api.v1.search import SearchType
query_text = "How is data stored in milvus?"
search_results = await cognee.search(SearchType.CHUNKS, query_text=query_text)
Formatons et affichons-les pour une meilleure lisibilité !
def format_and_print(data):
print("ID:", data["id"])
print("\nText:\n")
paragraphs = data["text"].split("\n\n")
for paragraph in paragraphs:
print(paragraph.strip())
print()
format_and_print(search_results[0])
ID: 4be01c4b-9ee5-541c-9b85-297883934ab3
Text:
Where does Milvus store data?
Milvus deals with two types of data, inserted data and metadata.
Inserted data, including vector data, scalar data, and collection-specific schema, are stored in persistent storage as incremental log. Milvus supports multiple object storage backends, including [MinIO](https://min.io/), [AWS S3](https://aws.amazon.com/s3/?nc1=h_ls), [Google Cloud Storage](https://cloud.google.com/storage?hl=en#object-storage-for-companies-of-all-sizes) (GCS), [Azure Blob Storage](https://azure.microsoft.com/en-us/products/storage/blobs), [Alibaba Cloud OSS](https://www.alibabacloud.com/product/object-storage-service), and [Tencent Cloud Object Storage](https://www.tencentcloud.com/products/cos) (COS).
Metadata are generated within Milvus. Each Milvus module has its own metadata that are stored in etcd.
###
Dans les étapes précédentes, nous avons interrogé l'ensemble de données Milvus FAQ pour obtenir à la fois des résumés et des morceaux de données spécifiques. Bien que cela ait permis d'obtenir des informations détaillées et granulaires, l'ensemble de données était volumineux, ce qui rendait difficile la visualisation claire des dépendances au sein du graphe de connaissances.
Pour résoudre ce problème, nous réinitialiserons l'environnement Cognee et travaillerons avec un ensemble de données plus petit et plus ciblé. Cela nous permettra de mieux mettre en évidence les relations et les dépendances extraites au cours du processus de cognification. En simplifiant les données, nous pouvons clairement voir comment Cognee organise et structure les informations dans le graphe de connaissances.
Réinitialiser Cognee
await cognee.prune.prune_data()
await cognee.prune.prune_system(metadata=True)
Ajout de l'ensemble de données ciblé
Ici, un ensemble de données plus petit ne comportant qu'une seule ligne de texte est ajouté et traité pour garantir un graphe de connaissances ciblé et facilement interprétable.
# We only use one line of text as the dataset, which simplifies the output later
text = """
Natural language processing (NLP) is an interdisciplinary
subfield of computer science and information retrieval.
"""
await cognee.add(text)
await cognee.cognify()
Recherche d'informations
En nous concentrant sur cet ensemble de données plus petit, nous pouvons maintenant analyser clairement les relations et la structure du graphe de connaissances.
query_text = "Tell me about NLP"
search_results = await cognee.search(SearchType.INSIGHTS, query_text=query_text)
for result_text in search_results:
print(result_text)
# Example output:
# ({'id': UUID('bc338a39-64d6-549a-acec-da60846dd90d'), 'updated_at': datetime.datetime(2024, 11, 21, 12, 23, 1, 211808, tzinfo=datetime.timezone.utc), 'name': 'natural language processing', 'description': 'An interdisciplinary subfield of computer science and information retrieval.'}, {'relationship_name': 'is_a_subfield_of', 'source_node_id': UUID('bc338a39-64d6-549a-acec-da60846dd90d'), 'target_node_id': UUID('6218dbab-eb6a-5759-a864-b3419755ffe0'), 'updated_at': datetime.datetime(2024, 11, 21, 12, 23, 15, 473137, tzinfo=datetime.timezone.utc)}, {'id': UUID('6218dbab-eb6a-5759-a864-b3419755ffe0'), 'updated_at': datetime.datetime(2024, 11, 21, 12, 23, 1, 211808, tzinfo=datetime.timezone.utc), 'name': 'computer science', 'description': 'The study of computation and information processing.'})
# (...)
#
# It represents nodes and relationships in the knowledge graph:
# - The first element is the source node (e.g., 'natural language processing').
# - The second element is the relationship between nodes (e.g., 'is_a_subfield_of').
# - The third element is the target node (e.g., 'computer science').
Cette sortie représente les résultats d'une requête de graphe de connaissances, mettant en évidence les entités (nœuds) et leurs relations (arêtes) telles qu'elles ont été extraites de l'ensemble de données traité. Chaque tuple comprend une entité source, un type de relation et une entité cible, ainsi que des métadonnées telles que des identifiants uniques, des descriptions et des horodatages. Le graphique met en évidence les concepts clés et leurs connexions sémantiques, ce qui permet une compréhension structurée de l'ensemble de données.
Félicitations, vous avez appris l'utilisation de base de Cognee avec Milvus. Si vous souhaitez connaître l'utilisation plus avancée de Cognee, veuillez vous référer à sa page officielle.