Melakukan penelusuran Maximal Marginal Relevance dengan LangChain di Bigtable

Halaman ini menjelaskan cara melakukan penelusuran Maximal Marginal Relevance (MMR) menggunakan integrasi BigtableVectorStore untuk LangChain di Bigtable dan Vertex AI sebagai layanan embedding.

MMR adalah teknik penelusuran yang digunakan dalam pengambilan informasi untuk menampilkan serangkaian hasil yang relevan dengan kueri dan beragam, sehingga menghindari redundansi. Meskipun penelusuran kesamaan vektor standar (misalnya, penelusuran yang menggunakan metode k-nearest neighbor) dapat menampilkan banyak item serupa, MMR memberikan serangkaian hasil teratas yang lebih bervariasi. Hal ini berguna jika Anda memiliki data yang berpotensi tumpang-tindih atau duplikat di penyimpanan vektor.

Misalnya, dalam aplikasi e-commerce, jika pengguna menelusuri "tomat merah", penelusuran kemiripan vektor dapat menampilkan beberapa listingan jenis tomat merah segar yang sama. Penelusuran MMR akan bertujuan untuk menampilkan kumpulan hasil yang lebih beragam, seperti "tomat merah segar", "tomat merah cincang kalengan", "tomat ceri organik", dan bahkan "resep salad tomat".

Sebelum membaca halaman ini, Anda harus memahami konsep berikut:

  • Relevansi: Ukuran seberapa dekat kecocokan dokumen dengan kueri.
  • Keragaman: Ukuran seberapa berbeda suatu dokumen dari dokumen yang sudah dipilih dalam set hasil.
  • Pengganda Lambda: Faktor antara 0 dan 1 yang menyeimbangkan relevansi dan keberagaman. Nilai yang mendekati 1 memprioritaskan relevansi, sementara nilai yang mendekati 0 memprioritaskan keragaman.

Class BigtableVectorStore untuk LangChain menerapkan MMR sebagai algoritma pemeringkatan ulang. Algoritma ini pertama-tama mengambil sekumpulan dokumen yang lebih besar yang relevan dengan kueri, dan memilih dokumen yang cocok dengan kueri dengan cara yang seimbang untuk relevansi dan keragaman.

Sebelum memulai

Panduan ini menggunakan Vertex AI sebagai layanan penyematan. Pastikan Anda telah mengaktifkan Vertex AI API di project Anda.

Mengaktifkan Vertex AI API

Peran yang diperlukan

Untuk menggunakan Bigtable dengan LangChain, Anda memerlukan peran IAM berikut:

Menyiapkan lingkungan Anda

  1. Instal paket LangChain yang diperlukan:

    pip install --upgrade --quiet langchain-google-bigtable langchain-google-vertexai
    
  2. Lakukan autentikasi ke Google Cloud dengan akun pengguna Anda.

    gcloud auth application-default login
    
  3. Tetapkan project ID, ID instance Bigtable, dan ID tabel Anda:

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

Lakukan inisialisasi layanan penyematan dan buat tabel

Untuk menggunakan penyimpanan vektor Bigtable, Anda harus menyediakan embedding yang dibuat oleh model AI. Dalam panduan ini, Anda akan menggunakan model embedding teks gemini-embedding-004 di 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

Buat instance BigtableVectorStore

Buat instance penyimpanan dengan meneruskan layanan penyematan dan ID tabel 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.")

Isi penyimpanan vektor

Dalam panduan ini, kita menggunakan contoh skenario layanan e-commerce fiktif tempat pengguna ingin menelusuri item yang terkait dengan tomat merah. Pertama, kita perlu menambahkan beberapa produk dan deskripsi terkait tomat ke penyimpanan vektor.

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

Toko tersebut berisi banyak produk terkait tomat, tetapi pengguna hanya ingin menelusuri penawaran yang terkait dengan "tomat merah". Untuk mendapatkan beragam hasil, gunakan teknik MMR untuk melakukan penelusuran.

Metode utama yang digunakan adalah max_marginal_relevance_search yang menggunakan argumen berikut:

  • query (str): Teks penelusuran.
  • k (int): Jumlah akhir hasil penelusuran.
  • fetch_k (int): Jumlah awal produk serupa yang akan diambil sebelum menerapkan algoritma MMR. Sebaiknya angka ini lebih besar daripada parameter k.
  • lambda_mult (float): Parameter penyesuaian keragaman. Gunakan 0.0 untuk keragaman maksimum, 1.0 untuk relevansi maksimum.
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}")

Nilai lambda_mult yang berbeda akan menghasilkan kumpulan hasil yang berbeda, menyeimbangkan kesamaan dengan "tomat merah" dengan keunikan produk yang ditampilkan.

Menggunakan MMR dengan retriever

Untuk menggunakan penelusuran MMR, Anda juga dapat mengonfigurasi pengambil LangChain. Pengambil menyediakan antarmuka seragam yang memungkinkan Anda mengintegrasikan metode penelusuran khusus, seperti MMR, langsung ke rantai dan aplikasi Anda dengan lancar.

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

Langkah berikutnya