Maximale marginale Relevanzsuche mit LangChain in Bigtable durchführen

Auf dieser Seite wird beschrieben, wie Sie eine Suche mit maximaler marginaler Relevanz (Maximal Marginal Relevance, MMR) mit der BigtableVectorStore-Integration für LangChain in Bigtable und Gemini Enterprise Agent Platform als Einbettungsdienst durchführen.

MMR ist eine Suchtechnik, die beim Informationsabruf verwendet wird, um eine Reihe von Ergebnissen zurückzugeben, die sowohl für die Abfrage relevant als auch vielfältig sind, um Redundanz zu vermeiden. Während die Standardsuche nach Vektorähnlichkeit (z. B. eine Suche, bei der die Methode der k-nächsten Nachbarn verwendet wird) viele ähnliche Elemente zurückgeben kann, liefert MMR eine vielfältigere Menge von Top-Ergebnissen. Dies ist nützlich, wenn Sie potenziell überlappende oder doppelte Daten in Ihrem Vektorspeicher haben.

Wenn ein Nutzer in einer E-Commerce-Anwendung beispielsweise nach „roten Tomaten“ sucht, kann eine Suche nach Vektorähnlichkeit mehrere Einträge desselben Typs von frischen roten Tomaten zurückgeben. Eine MMR-Suche würde versuchen, eine vielfältigere Menge zurückzugeben, z. B. „frische rote Tomaten“, „gewürfelte rote Tomaten aus der Dose“, „Bio-Cherry-Tomaten“ und vielleicht sogar „Tomatensalatrezept“.

Bevor Sie diese Seite lesen, sollten Sie mit den folgenden Konzepten vertraut sein:

  • Relevanz: Ein Maß dafür, wie gut das Dokument mit der Abfrage übereinstimmt.
  • Vielfalt: Ein Maß dafür, wie unterschiedlich ein Dokument von den Dokumenten ist, die bereits im Ergebnissatz ausgewählt wurden.
  • Lambda-Multiplikator: Ein Faktor zwischen 0 und 1, der Relevanz und Vielfalt ausgleicht. Ein Wert näher an 1 priorisiert die Relevanz, während ein Wert näher an 0 die Vielfalt priorisiert.

Die Klasse BigtableVectorStore für LangChain implementiert MMR als Algorithmus zur Neusortierung. Dieser Algorithmus ruft zuerst eine größere Menge von Dokumenten ab, die für die Abfrage relevant sind, und wählt die Dokumente aus, die auf eine Weise mit der Abfrage übereinstimmen, die Relevanz und Vielfalt ausgleicht.

Hinweis

In dieser Anleitung wird Agent Platform als Einbettungsdienst verwendet. Achten Sie darauf, dass die Agent Platform API in Ihrem Projekt aktiviert ist.

Agent Platform API aktivieren

Erforderliche Rollen

Wenn Sie Bigtable mit LangChain verwenden möchten, benötigen Sie die folgenden IAM-Rollen:

Umgebung einrichten

  1. Installieren Sie die erforderlichen LangChain-Pakete:

    pip install --upgrade --quiet langchain-google-bigtable langchain-google-vertexai
    
  2. Authentifizieren Sie sich bei Google Cloud mit Ihrem Nutzerkonto.

    gcloud auth application-default login
    
  3. Legen Sie Ihre Projekt-ID, Bigtable-Instanz-ID und Tabellen-ID fest:

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

Einbettungsdienst initialisieren und Tabelle erstellen

Wenn Sie den Bigtable-Vektorspeicher verwenden möchten, müssen Sie Einbettungen bereitstellen, die von einem KI-Modell generiert wurden. In dieser Anleitung verwenden Sie das Texteinbettungs gemini-embedding-001modell in Agent Platform.


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-001", 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

BigtableVectorStore instanziieren

Erstellen Sie die Speicherinstanz, indem Sie die Kennungen für den Einbettungsdienst und die Bigtable-Tabelle übergeben.

# 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.")

Vektorspeicher füllen

In dieser Anleitung verwenden wir ein Beispielszenario eines fiktiven E-Commerce-Dienstes, bei dem Nutzer nach Artikeln suchen möchten, die sich auf rote Tomaten beziehen. Zuerst müssen wir dem Vektorspeicher einige tomatenbezogene Produkte und Beschreibungen hinzufügen.

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

Der Speicher enthält viele tomatenbezogene Produkte, aber Nutzer möchten nur nach Angeboten suchen, die mit „roten Tomaten“ verknüpft sind. Verwenden Sie die MMR-Technik, um eine vielfältige Menge von Ergebnissen zu erhalten.

Die wichtigste Methode ist die max_marginal_relevance_search , die die folgenden Argumente verwendet:

  • query (String): Der Suchtext.
  • k (Ganzzahl): Die endgültige Anzahl der Suchergebnisse.
  • fetch_k (Ganzzahl): Die anfängliche Anzahl ähnlicher Produkte, die vor Anwendung des MMR-Algorithmus abgerufen werden sollen. Wir empfehlen, dass diese Zahl größer als der Parameter k ist.
  • lambda_mult (Float): Der Parameter zur Abstimmung der Vielfalt. Verwenden Sie 0.0 für maximale Vielfalt und 1.0 für maximale Relevanz.
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}")

Verschiedene lambda_mult-Werte führen zu unterschiedlichen Ergebnissätzen, wobei die Ähnlichkeit zu „roten Tomaten“ mit der Einzigartigkeit der angezeigten Produkte ausgeglichen wird.

MMR mit einem Retriever verwenden

Wenn Sie die MMR-Suche verwenden möchten, können Sie auch einen LangChain-Retriever konfigurieren. Der Retriever bietet eine einheitliche Schnittstelle, mit der Sie spezielle Suchmethoden wie MMR nahtlos direkt in Ihre Chains und Anwendungen einbinden können.

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

Nächste Schritte