Effectuer une recherche avec la pertinence marginale maximale avec LangChain sur Bigtable
Cette page explique comment effectuer une recherche MMR (Maximal Marginal Relevance) à l'aide de l'intégration BigtableVectorStore pour LangChain dans Bigtable et Vertex AI en tant que service d'embedding.
MMR est une technique de recherche utilisée pour la récupération d'informations. Elle permet de renvoyer un ensemble de résultats à la fois pertinents pour la requête et diversifiés, en évitant la redondance. Alors que la recherche de similarité vectorielle standard (par exemple, une recherche qui utilise la méthode des k-plus proches voisins) peut renvoyer de nombreux éléments similaires, MMR fournit un ensemble plus varié de meilleurs résultats. Cela s'avère utile lorsque votre base de données vectorielle contient des données potentiellement chevauchantes ou en double.
Par exemple, dans une application d'e-commerce, si un utilisateur recherche "tomates rouges", une recherche par similarité vectorielle peut renvoyer plusieurs fiches du même type de tomates rouges fraîches. Une recherche MMR viserait à renvoyer un ensemble plus diversifié, comme "tomates rouges fraîches", "tomates rouges concassées en conserve", "tomates cerises bio" et peut-être même "recette de salade de tomates".
Avant de lire cette page, il est important que vous connaissiez les concepts suivants :
- Pertinence : mesure de la correspondance entre le document et la requête.
- Diversité : mesure de la différence entre un document et ceux déjà sélectionnés dans l'ensemble de résultats.
- Multiplicateur lambda : facteur compris entre 0 et 1 qui équilibre la pertinence et la diversité. Plus la valeur est proche de 1, plus la pertinence est privilégiée. Plus elle est proche de 0, plus la diversité est privilégiée.
La classe BigtableVectorStore pour LangChain implémente MMR en tant qu'algorithme de réorganisation.
Cet algorithme récupère d'abord un ensemble plus important de documents pertinents pour la requête, puis sélectionne ceux qui y correspondent de manière équilibrée en termes de pertinence et de diversité.
Avant de commencer
Ce guide utilise Vertex AI comme service d'intégration. Assurez-vous que l'API Vertex AI est activée dans votre projet.
Rôles requis
Pour utiliser Bigtable avec LangChain, vous avez besoin des rôles IAM suivants :
- Utilisateur Bigtable
(
roles/bigtable.user) sur l'instance Bigtable. - Si vous initialisez la table, vous devez également disposer du rôle Administrateur Bigtable (
roles/bigtable.admin).
Configurer votre environnement
Installez les packages LangChain requis :
pip install --upgrade --quiet langchain-google-bigtable langchain-google-vertexaiAuthentifiez-vous auprès de Google Cloud avec votre compte utilisateur.
gcloud auth application-default loginDéfinissez l'ID de votre projet, l'ID de votre instance Bigtable et l'ID de votre table :
PROJECT_ID = "your-project-id" INSTANCE_ID = "your-instance-id" TABLE_ID = "your-table-id"
Initialiser le service d'embedding et créer une table
Pour utiliser le magasin de vecteurs Bigtable, vous devez fournir des embeddings générés par un modèle d'IA. Dans ce guide, vous allez utiliser le modèle d'embedding textuel gemini-embedding-004 sur Vertex AI.
from langchain_google_vertexai import VertexAIEmbeddings
from langchain_google_bigtable.vector_store import init_vector_store_table, BigtableVectorStore, ColumnConfig
# Initialize an embedding service
embedding_service = VertexAIEmbeddings(model_name="text-embedding-004", project=PROJECT_ID)
# Define column families
DATA_COLUMN_FAMILY = "product_data"
# Initialize the table (if it doesn't exist)
try:
init_vector_store_table(
project_id=PROJECT_ID,
instance_id=INSTANCE_ID,
table_id=TABLE_ID,
content_column_family=DATA_COLUMN_FAMILY,
embedding_column_family=DATA_COLUMN_FAMILY,
)
print(f"Table {TABLE_ID} created successfully.")
except ValueError as e:
print(e) # Table likely already exists
Instancier BigtableVectorStore
Créez l'instance de magasin en transmettant le service d'intégration et les identifiants de table Bigtable.
# Configure columns
content_column = ColumnConfig(
column_family=DATA_COLUMN_FAMILY, column_qualifier="product_description"
)
embedding_column = ColumnConfig(
column_family=DATA_COLUMN_FAMILY, column_qualifier="embedding"
)
# Create the vector store instance
vector_store = BigtableVectorStore.create_sync(
project_id=PROJECT_ID,
instance_id=INSTANCE_ID,
table_id=TABLE_ID,
embedding_service=embedding_service,
collection="ecommerce_products",
content_column=content_column,
embedding_column=embedding_column,
)
print("BigtableVectorStore instantiated.")
Remplir le magasin de vecteurs
Dans ce guide, nous utilisons un exemple de scénario de service d'e-commerce fictif dans lequel les utilisateurs souhaitent rechercher des articles liés aux tomates rouges. Tout d'abord, nous devons ajouter des produits et des descriptions liés à la tomate au vector store.
from langchain_core.documents import Document
products = [
Document(page_content="Fresh organic red tomatoes, great for salads.", metadata={"type": "fresh produce", "color": "red", "name": "Organic Vine Tomatoes"}),
Document(page_content="Ripe red tomatoes on the vine.", metadata={"type": "fresh", "color": "red", "name": "Tomatoes on Vine"}),
Document(page_content="Sweet cherry tomatoes, red and juicy.", metadata={"type": "fresh", "color": "red", "name": "Cherry Tomatoes"}),
Document(page_content="Canned diced red tomatoes in juice.", metadata={"type": "canned", "color": "red", "name": "Diced Tomatoes"}),
Document(page_content="Sun-dried tomatoes in oil.", metadata={"type": "preserved", "color": "red", "name": "Sun-Dried Tomatoes"}),
Document(page_content="Green tomatoes, perfect for frying.", metadata={"type": "fresh", "color": "green", "name": "Green Tomatoes"}),
Document(page_content="Tomato paste, concentrated flavor.", metadata={"type": "canned", "color": "red", "name": "Tomato Paste"}),
Document(page_content="Mixed salad greens with cherry tomatoes.", metadata={"type": "prepared", "color": "mixed", "name": "Salad Mix with Tomatoes"}),
Document(page_content="Yellow pear tomatoes, mild flavor.", metadata={"type": "fresh", "color": "yellow", "name": "Yellow Pear Tomatoes"}),
Document(page_content="Heirloom tomatoes, various colors.", metadata={"type": "fresh", "color": "various", "name": "Heirloom Tomatoes"}),
]
vector_store.add_documents(products)
print(f"Added {len(products)} products to the vector store.")
Effectuer une recherche MMR
Le magasin propose de nombreux produits à base de tomates, mais les utilisateurs souhaitent rechercher uniquement les offres associées aux "tomates rouges". Pour obtenir un ensemble varié de résultats, utilisez la technique MMR pour effectuer la recherche.
La méthode clé à utiliser est max_marginal_relevance_search, qui accepte les arguments suivants :
query(str) : texte de recherche.k(int) : nombre final de résultats de recherche.fetch_k(int) : nombre initial de produits similaires à récupérer avant d'appliquer l'algorithme MMR. Nous vous recommandons de définir ce nombre sur une valeur supérieure à celle du paramètrek.lambda_mult(float) : paramètre d'ajustement de la diversité. Utilisez0.0pour une diversité maximale et1.0pour une pertinence maximale.
user_query = "red tomatoes"
k_results = 4
fetch_k_candidates = 10
print(f"Performing MMR search for: '{user_query}'")
# Example 1: Balanced relevance and diversity
mmr_results_balanced = vector_store.max_marginal_relevance_search(
user_query, k=k_results, fetch_k=fetch_k_candidates, lambda_mult=0.5
)
print(f"MMR Results (lambda=0.5, k={k_results}, fetch_k={fetch_k_candidates}):")
for doc in mmr_results_balanced:
print(f" - {doc.metadata['name']}: {doc.page_content}")
print("\n")
# Example 2: Prioritizing Diversity
mmr_results_diverse = vector_store.max_marginal_relevance_search(
user_query, k=k_results, fetch_k=fetch_k_candidates, lambda_mult=0.1
)
print(f"MMR Results (lambda=0.1, k={k_results}, fetch_k={fetch_k_candidates}):")
for doc in mmr_results_diverse:
print(f" - {doc.metadata['name']}: {doc.page_content}")
print("\n")
# Example 3: Prioritizing Relevance
mmr_results_relevant = vector_store.max_marginal_relevance_search(
user_query, k=k_results, fetch_k=fetch_k_candidates, lambda_mult=0.9
)
print(f"MMR Results (lambda=0.9, k={k_results}, fetch_k={fetch_k_candidates}):")
for doc in mmr_results_relevant:
print(f" - {doc.metadata['name']}: {doc.page_content}")
Différentes valeurs lambda_mult génèrent différents ensembles de résultats, en équilibrant la similarité avec "tomates rouges" et l'unicité des produits affichés.
Utiliser MMR avec un récupérateur
Pour utiliser la recherche MMR, vous pouvez également configurer un récupérateur LangChain. Le récupérateur fournit une interface uniforme qui vous permet d'intégrer de manière fluide des méthodes de recherche spécialisées, telles que MMR, directement dans vos chaînes et applications.
retriever = vector_store.as_retriever(
search_type="mmr",
search_kwargs={
"k": 3,
"fetch_k": 10,
"lambda_mult": 0.3,
}
)
retrieved_docs = retriever.invoke(user_query)
print(f"\nRetriever MMR Results for '{user_query}':")
for doc in retrieved_docs:
print(f" - {doc.metadata['name']}: {doc.page_content}")
Étapes suivantes
- Découvrez les autres types de recherche et options de filtrage disponibles dans
BigtableVectorStore. - En savoir plus sur LangChain dans Bigtable