Esegui la ricerca di massima pertinenza marginale con LangChain su Bigtable

Questa pagina descrive come eseguire una ricerca di massima pertinenza marginale (MMR) utilizzando l'integrazione BigtableVectorStore per LangChain in Bigtable e Vertex AI come servizio di incorporamento.

MMR è una tecnica di ricerca utilizzata nel recupero di informazioni per restituire un insieme di risultati pertinenti alla query e diversi, evitando la ridondanza. Mentre la ricerca standard di similarità vettoriale (ad esempio, una ricerca che utilizza il metodo k-nearest neighbor) potrebbe restituire molti elementi simili, MMR fornisce un insieme più vario di risultati principali. Questa funzionalità è utile quando hai dati potenzialmente sovrapposti o duplicati nel tuo archivio vettoriale.

Ad esempio, in un'applicazione di e-commerce, se un utente cerca "pomodori rossi", una ricerca di similarità vettoriale potrebbe restituire più schede dello stesso tipo di pomodoro rosso fresco. Una ricerca MMR mirerebbe a restituire un insieme più diversificato, ad esempio "pomodori rossi freschi", "pomodori rossi a cubetti in scatola", "pomodorini biologici" e magari anche "ricetta insalata di pomodori".

Prima di leggere questa pagina, è importante che tu conosca i seguenti concetti:

  • Pertinenza: una misura del grado di corrispondenza tra il documento e la query.
  • Diversità: una misura di quanto un documento sia diverso dai documenti già selezionati nel set di risultati.
  • Moltiplicatore lambda: un fattore compreso tra 0 e 1 che bilancia pertinenza e diversità. Un valore più vicino a 1 dà la priorità alla pertinenza, mentre un valore più vicino a 0 dà la priorità alla diversità.

La classe BigtableVectorStore per LangChain implementa MMR come algoritmo di riordinamento. Questo algoritmo recupera innanzitutto un insieme più ampio di documenti pertinenti alla query e seleziona i documenti che corrispondono alla query in modo equilibrato per pertinenza e diversità.

Prima di iniziare

Questa guida utilizza Vertex AI come servizio di incorporamento. Assicurati di aver abilitato l'API Vertex AI nel tuo progetto.

Abilita l'API Vertex AI

Ruoli obbligatori

Per utilizzare Bigtable con LangChain, devi disporre dei seguenti ruoli IAM:

Configura l'ambiente

  1. Installa i pacchetti LangChain richiesti:

    pip install --upgrade --quiet langchain-google-bigtable langchain-google-vertexai
    
  2. Esegui l'autenticazione per Google Cloud con il tuo account utente.

    gcloud auth application-default login
    
  3. Imposta l'ID progetto, l'ID istanza Bigtable e l'ID tabella:

    PROJECT_ID = "your-project-id"
    INSTANCE_ID = "your-instance-id"
    TABLE_ID = "your-table-id"
    

Inizializza il servizio di incorporamento e crea una tabella

Per utilizzare l'archivio vettoriale Bigtable, devi fornire gli embedding generati da un modello di AI. In questa guida utilizzerai il modello di text embedding gemini-embedding-004 su 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

Instanzia BigtableVectorStore

Crea l'istanza del negozio passando il servizio di incorporamento e gli identificatori della tabella 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.")

Compila il datastore vettoriale

In questa guida utilizziamo uno scenario di esempio di un servizio di e-commerce fittizio in cui gli utenti vogliono cercare articoli correlati ai pomodori rossi. Innanzitutto, dobbiamo aggiungere alcuni prodotti e descrizioni correlati al pomodoro al 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.")

Il negozio contiene molti prodotti correlati ai pomodori, ma gli utenti vogliono cercare solo le offerte associate ai "pomodori rossi". Per ottenere un insieme diversificato di risultati, utilizza la tecnica MMR per eseguire la ricerca.

Il metodo chiave da utilizzare è max_marginal_relevance_search che accetta i seguenti argomenti:

  • query (str): il testo di ricerca.
  • k (int): il numero finale di risultati di ricerca.
  • fetch_k (int): il numero iniziale di prodotti simili da recuperare prima di applicare l'algoritmo MMR. Ti consigliamo che questo numero sia maggiore del parametro k.
  • lambda_mult (float): il parametro di ottimizzazione della diversità. Utilizza 0.0 per la massima diversità e 1.0 per la massima pertinenza.
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}")

Valori di lambda_mult diversi producono insiemi di risultati diversi, bilanciando la somiglianza con "pomodori rossi" con l'unicità dei prodotti mostrati.

Utilizzo di MMR con un retriever

Per utilizzare la ricerca MMR, puoi anche configurare un recuperatore LangChain. Il recuperatore fornisce un'interfaccia uniforme che ti consente di integrare facilmente metodi di ricerca specializzati, come MMR, direttamente nelle tue catene e applicazioni.

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}")

Passaggi successivi