Utiliser SelfQueryRetriever avec LangChain pour interroger une base de données vectorielle
LangChain est bien connu pour orchestrer les interactions avec les grands modèles de langage (LLM). Récemment, LangChain a introduit une manière d’effectuer de l’auto-interrogation, leur permettant d’interroger la « chaîne » ou les modules eux-mêmes à l’aide d’une requête saisie par l’utilisateur. Cet article vous montrera comment effectuer de l’auto-interrogation sur Milvus, la base de données vectorielle la plus populaire au monde. En interprétant une requête utilisateur, le système peut affiner les recherches dans les magasins vectoriels, améliorant ainsi les résultats de récupération. Vous pouvez trouver le code de cet exemple sur CoLab ici.
Configurons l’auto-interrogation sur Milvus avec LangChain. Ce processus se compose de quatre étapes logiques.
Configurer les bases de LangChain et Milvus.
Obtenir ou créer les données nécessaires.
Informer le modèle du format de données attendu.
Démontrer l’auto-interrogation et expliquer son fonctionnement.
Introduction à l’auto-interrogation
L’auto-interrogation est une technique puissante utilisée dans le traitement du langage naturel (NLP) et la recherche d’informations. Elle permet à un système de s’interroger lui-même à l’aide de la requête saisie par un utilisateur, produisant des résultats plus précis et pertinents. Dans le contexte de LangChain, l’auto-interrogation est utilisée pour récupérer des informations à partir d’un magasin vectoriel, qui est une base de données stockant des vecteurs représentant des documents ou des points de données. Le récupérateur d’auto-interrogation est un composant clé du framework LangChain, permettant la création de requêtes et de récupérations complexes en langage naturel.
En exploitant l’auto-interrogation, LangChain peut décomposer la requête d’un utilisateur en un format structuré que le magasin vectoriel peut comprendre. Ce processus garantit que les documents récupérés sont très pertinents par rapport à la requête de l’utilisateur, ce qui facilite la recherche des informations dont il a besoin. Que vous construisiez un modèle d’IA conversationnelle ou un moteur de recherche, l’auto-interrogation peut améliorer considérablement la précision et la pertinence de vos résultats.
Configuration de LangChain et Milvus
La première étape consiste à configurer les bibliothèques nécessaires. Vous pouvez installer les bibliothèques requises à l’aide de pip install openai langchain milvus python-dotenv. Si vous avez suivi mes tutoriels précédents, vous connaissez déjà python-dotenv, ma bibliothèque préférée pour gérer les variables d’environnement. Nous utilisons la bibliothèque OpenAI avec LangChain pour accéder à GPT et utiliser Milvus comme magasin vectoriel.
Une fois connecté à la clé API OpenAI, importez les modules LangChain nécessaires. Nous avons besoin des six modules suivants :
Document: Un type de données LangChain pour le stockage des données.OpenAIetOpenAIEmbeddings: Deux fonctionnalités pour accéder à OpenAI et à ses embeddings.Milvus: Un module permettant d’accéder à Milvus depuis LangChain.SelfQueryRetriever: Un module de récupération.AttributeInfo: Un module définissant notre structure de données pour LangChain.
Après avoir importé les modules, nous définissons la variable embeddings sur la fonction par défaut d’OpenAI Embeddings. La dernière étape du processus de configuration consiste à utiliser la bibliothèque milvus pour lancer une instance de Milvus Lite dans notre notebook.
Maintenant, examinons les données.
import os
from dotenv import load_dotenv
load_dotenv()
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")
from langchain.schema import Document
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Milvus
from langchain.llms import OpenAI
from langchain.retrievers.self_query.base import SelfQueryRetriever
from langchain.chains.query_constructor.base import AttributeInfo
embeddings = OpenAIEmbeddings()
from milvus import default_server
default_server.start()
Rassemblons quelques données. Vous pouvez extraire vos données par scraping, utiliser les données fournies telles quelles, ou les utiliser comme modèle pour créer vos données. J’ai préparé une liste de documents sur des films pour cet exemple, notamment Jurassic Park, Toy Story, Finding Nemo, The Unbearable Weight of Massive Talent, Lord of War et Ghost Rider. Bien que je n’inclue pas les titres dans nos données, je veux que vous sachiez à quels films ils font référence.
Je stocke chacun de ces films sous forme d’objet LangChain Document. Il contient une clé page_content correspondant à une chaîne de caractères, dans ce cas, la description du film. Il inclut également des métadonnées, telles que l’année, la note et le genre du film.
docs = [
# jurassic park
Document(page_content="A bunch of scientists bring back dinosaurs and mayhem breaks loose",
metadata={"year": 1993, "rating": 7.7, "genre": "action"}),
# toy story
Document(page_content="Toys come alive and have a blast doing so",
metadata={"year": 1995, "genre": "animated", "rating": 9.3 }),
# finding nemo
Document(page_content="A dad teams up with a mentally disabled partner to break into a dentist\'s office to save his son.",
metadata={"year": 2003, "genre": "animated", "rating": 8.2 }),
# unbearable weight of massive talent
Document(page_content="Nicholas Cage plays Nicholas Cage in this movie about Nicholas Cage.",
metadata={"year": 2022, "genre": "comedy", "rating": 7.0 }),
# lord of war
Document(page_content="Nicholas Cage sells guns until he has enough money to marry his favorite model. Then he sells more guns.",
metadata={"year": 2005, "genre": "comedy", "rating": 7.6 }),
# ghost rider
Document(page_content="Nicholas Cage loses his skin and sets his skull on fire. Then he rides a motorcycle.",
metadata={"year": 2007, "genre": "action", "rating": 5.3 }),
]
Définir les métadonnées self-query et le self query retriever pour LangChain et Milvus
Nous avons terminé les deux premières étapes du puzzle, et il est maintenant temps de passer à la troisième.
Tout d’abord, configurons notre base de données vectorielle pour l’ingestion. Nous pouvons utiliser l’implémentation LangChain Milvus pour ingérer nos documents et créer une base de données vectorielle basée sur nos documents existants. C’est également à cette étape que la fonction d’embedding entre en jeu, en utilisant la variable embeddings que nous avons créée précédemment. L’instruction de comparaison prend en compte les formats et directives spécifiques nécessaires à la création de conditions de filtre qui guident les processus de récupération des données.
Le paramètre connection_args est le seul paramètre requis pour se connecter à Milvus. Dans ce tutoriel, j’utilise également le paramètre collection_name pour attribuer un nom à la collection où nous stockons nos données. Chaque collection dans Milvus doit avoir un nom. Par défaut, LangChain utilise LangChainCollection.
vector_store = Milvus.from_documents(
docs,
embedding=embeddings,
connection_args={"host": "localhost", "port": default_server.listen_port},
collection_name="movies"
)
Ensuite, définissons les informations de métadonnées à l’aide de la fonctionnalité AttributeInfo afin que LangChain sache à quoi s’attendre. Cette section créera une liste d’informations d’attribut pour les données. Nous préciserons le nom, la description et le type de données de chaque attribut. C’est ici qu’une instruction de condition logique devient essentielle pour formuler des comparaisons et des opérations logiques dans le processus de construction de la requête.
metadata_field_info = [
AttributeInfo(
name="genre",
description="The genre of the movie",
type="string",
),
AttributeInfo(
name="year",
description="The year the movie was released",
type="integer",
),
AttributeInfo(
name="rating",
description="A 1-10 rating for the movie",
type="float"
),
]
Les derniers éléments décrivent le document, initialisent le LLM et définissent le Self-Query Retriever. Nous définissons le self-query retriever en appelant sa méthode « from_llm ». Nous devons utiliser cette méthode pour connecter le LLM, le vector store, la description du contenu du document et les informations des champs de métadonnées. Dans cet exemple, nous définissons également « verbose = True » pour activer une sortie détaillée pour ce self-query retriever. La chaîne de requête ne doit inclure que le texte pertinent correspondant au contenu des documents, en veillant à ce que toutes les conditions des filtres soient clairement séparées et non incluses dans la chaîne de requête elle-même.
document_content_description = "Brief summary of a movie"
llm = OpenAI(temperature=0)
retriever = SelfQueryRetriever.from_llm(
llm, vector_store, document_content_description, metadata_field_info, verbose=True
)
Résultats du self-querying
Nous avons terminé la configuration du self-query retriever. Voyons maintenant comment il fonctionne en pratique. Dans cet exemple, j’ai utilisé trois descriptions de films liées à Nicholas Cage. La question que nous posons est donc : quels sont quelques films sur Nicholas Cage ?
# This example only specifies a relevant query
retriever.get_relevant_documents("What are some movies about Nicholas Cage?")
Nous devrions obtenir une sortie comme celle ci-dessous.
langchain-query-vector-database.png
En définissant verbose=True, nous pouvons afficher la requête, le filtre et la limite. Le LLM convertit notre requête de « What are some movies about Nicholas Cage? » en « Nicholas Cage ». En examinant les résultats, nous pouvons constater que les trois premiers résultats sont tous des films mettant en scène Nicholas Cage. Cependant, le quatrième résultat, Finding Nemo, n’est pas pertinent en raison du paramètre défini pour récupérer quatre résultats.
J’espère que la présentation du code a clarifié le concept de self-querying sur une base de données vectorielle. Sur le site Web de LangChain, LangChain décrit le self-querying comme une méthode permettant à un LLM de s’interroger lui-même à l’aide du vector store sous-jacent. En d’autres termes, LangChain développe une application simple de génération augmentée par récupération (RAG) dans le framework CVP qui inclut une fonction de self-querying.
Dans ce tutoriel, nous avons exploré la fonctionnalité de self-query de LangChain en utilisant Milvus comme vector store sous-jacent. Le self-querying vous permet de créer une application RAG simple en combinant un LLM et une base de données vectorielle. Le LLM décompose la requête en langage naturel en une chaîne, puis elle est vectorisée pour l’interrogation.
Dans notre exemple, nous avons généré quelques données d’exemple liées aux films. Une façon d’étendre cet exemple consiste à collecter vos données. Lors de la définition du self-query retriever, n’oubliez pas de fournir les descriptions à la fois pour le vector store et pour les métadonnées.
Pour commencer et expérimenter la fonctionnalité de self-query de LangChain, consultez le notebook colab.
Interroger le Vector Store avec des instructions d’opérations logiques
Lors de l’interrogation du vector store, des instructions d’opérations logiques sont utilisées pour spécifier des conditions de filtrage des documents. Une instruction d’opération logique prend la forme op(statement1, statement2, …), où op est un opérateur logique tel que AND, OR ou NOT. Chaque instruction peut être une instruction de comparaison, qui prend la forme comp(attr, val), où comp est un comparateur tel que EQ, LT ou GT, et attr et val sont respectivement l’attribut et la valeur comparés.
Par exemple, une instruction d’opération logique pourrait ressembler à ceci : AND(EQ(language, “English”), GT(rating, 4)). Cette instruction filtrerait les documents dont l’attribut de langue est égal à « English » et dont l’attribut de note est supérieur à 4. En utilisant des instructions d’opérations logiques, vous pouvez créer des requêtes complexes qui combinent plusieurs conditions, permettant un filtrage plus précis des documents dans le vector store.
Traitement de la requête de l’utilisateur
Lorsqu’un utilisateur saisit une requête, le récupérateur self-query utilise un constructeur de requêtes pour générer une requête structurée. La requête structurée est ensuite traduite en requêtes de magasin vectoriel, qui sont exécutées sur le magasin vectoriel afin de récupérer les documents pertinents. Le constructeur de requêtes utilise un prompt et un analyseur de sortie pour générer la requête structurée, qui capture les filtres spécifiés par l’utilisateur.
Par exemple, si un utilisateur saisit la requête « Find movies with a rating greater than 4 and a runtime less than 2 hours », le constructeur de requêtes pourrait générer une requête structurée comme celle-ci : AND(GT(rating, 4), LT(runtime, 120)). Cette requête structurée serait ensuite traduite en requêtes de magasin vectoriel et exécutée sur le magasin vectoriel afin de récupérer les documents pertinents. En traitant la requête de l’utilisateur de cette manière, le récupérateur self-query garantit que les résultats sont adaptés aux exigences spécifiques de l’utilisateur.
Bonnes pratiques et conclusion
Lors de l’utilisation du récupérateur self-query, il est important de suivre les bonnes pratiques afin de garantir des résultats précis et pertinents. Voici quelques conseils :
Utilisez un langage spécifique et concis lors de la saisie des requêtes.
Utilisez des instructions d’opérations logiques pour spécifier les conditions de filtrage des documents.
Utilisez des instructions de comparaison pour comparer les attributs et les valeurs.
Utilisez le comparateur EQ pour spécifier des correspondances exactes.
Utilisez les comparateurs LT et GT pour spécifier des requêtes par plage.
Utilisez les opérateurs logiques AND et OR pour combiner les conditions.
En conclusion, le récupérateur self-query est un outil puissant pour créer des modèles d’IA conversationnelle capables de récupérer et de traiter des informations provenant de diverses sources. En utilisant des instructions d’opérations logiques et des instructions de comparaison, les utilisateurs peuvent spécifier des requêtes complexes et récupérer des documents pertinents depuis un magasin vectoriel. En suivant les bonnes pratiques et en utilisant efficacement le récupérateur self-query, les développeurs peuvent créer des modèles d’IA plus précis et pertinents, capables de traiter un large éventail de requêtes utilisateur.
Continuer à lire

Why Not All VectorDBs Are Agent-Ready
Explore why choosing the right vector database is critical for scaling AI agents, and why traditional solutions fall short in production.

Selecting the Right ETL Tools for Unstructured Data to Prepare for AI
Learn the right ETL tools for unstructured data to power AI. Explore key challenges, tool comparisons, and integrations with Milvus for vector search.

OpenAI o1: What Developers Need to Know
In this article, we will talk about the o1 series from a developer's perspective, exploring how these models can be implemented for sophisticated use cases.



