Realizar una búsqueda de máxima relevancia marginal con LangChain en Bigtable
En esta página se describe cómo realizar una búsqueda de máxima relevancia marginal (MMR) mediante la integración de BigtableVectorStore para LangChain en Bigtable y Vertex AI como servicio de inserción.
MMR es una técnica de búsqueda que se usa en la recuperación de información para devolver un conjunto de resultados que sean relevantes para la consulta y diversos, evitando la redundancia. Aunque la búsqueda de similitud de vectores estándar (por ejemplo, una búsqueda que utiliza el método de los k vecinos más cercanos) puede devolver muchos elementos similares, MMR proporciona un conjunto más variado de resultados principales. Esto resulta útil cuando tienes datos potencialmente superpuestos o duplicados en tu almacén de vectores.
Por ejemplo, en una aplicación de comercio electrónico, si un usuario busca "tomates rojos", una búsqueda de similitud vectorial puede devolver varias fichas del mismo tipo de tomate rojo fresco. Una búsqueda de MMR devolvería un conjunto más diverso, como "tomates rojos frescos", "tomates rojos troceados en conserva", "tomates cherry ecológicos" y quizás incluso "receta de ensalada de tomate".
Antes de leer esta página, es importante que conozcas los siguientes conceptos:
- Relevancia: medida del grado de coincidencia del documento con la consulta.
- Diversidad: medida de lo diferente que es un documento de los documentos ya seleccionados en el conjunto de resultados.
- Multiplicador lambda: factor entre 0 y 1 que equilibra la relevancia y la diversidad. Un valor más cercano a 1 prioriza la relevancia, mientras que un valor más cercano a 0 prioriza la diversidad.
La clase BigtableVectorStore de LangChain implementa MMR como algoritmo de reordenación.
Este algoritmo primero obtiene un conjunto más amplio de documentos relevantes para la consulta y selecciona los documentos que coinciden con la consulta de forma equilibrada en cuanto a relevancia y diversidad.
Antes de empezar
En esta guía se usa Vertex AI como servicio de inserciones. Asegúrate de que la API Vertex AI esté habilitada en tu proyecto.
Roles obligatorios
Para usar Bigtable con LangChain, necesitas los siguientes roles de gestión de identidades y accesos:
- Usuario de Bigtable
(
roles/bigtable.user) en la instancia de Bigtable. - Si vas a inicializar la tabla, también necesitas el rol Bigtable
Administrator
(
roles/bigtable.admin).
Configurar un entorno
Instala los paquetes de LangChain necesarios:
pip install --upgrade --quiet langchain-google-bigtable langchain-google-vertexaiAutentícate en Google Cloud con tu cuenta de usuario.
gcloud auth application-default loginDefine el ID de tu proyecto, el ID de instancia de Bigtable y el ID de tabla:
PROJECT_ID = "your-project-id" INSTANCE_ID = "your-instance-id" TABLE_ID = "your-table-id"
Inicializar el servicio de inserción y crear una tabla
Para usar el almacén de vectores de Bigtable, debes proporcionar las inserciones generadas por un modelo de IA. En esta guía, usarás el modelo de inserción de texto gemini-embedding-004 enVertex 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
Instanciar BigtableVectorStore
Crea la instancia de almacén transfiriendo el servicio de inserción y los identificadores de tabla de 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.")
Rellenar el almacén de vectores
En esta guía, usamos un ejemplo de un servicio de comercio electrónico ficticio en el que los usuarios quieren buscar artículos relacionados con tomates rojos. Primero, tenemos que añadir algunos productos y descripciones relacionados con el tomate al almacén de vectores.
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.")
Realizar una búsqueda de MMR
La tienda contiene muchos productos relacionados con los tomates, pero los usuarios solo quieren buscar ofertas asociadas a los "tomates rojos". Para obtener un conjunto diverso de resultados, usa la técnica de MMR para realizar la búsqueda.
El método clave que debe usar es max_marginal_relevance_search, que toma los siguientes argumentos:
query(str): el texto de búsqueda.k(int): número final de resultados de búsqueda.fetch_k(int): número inicial de productos similares que se recuperarán antes de aplicar el algoritmo MMR. Recomendamos que este número sea mayor que el parámetrok.lambda_mult(float): parámetro de ajuste de la diversidad. Usa0.0para maximizar la diversidad y1.0para maximizar la relevancia.
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}")
Los diferentes valores de lambda_mult dan lugar a conjuntos de resultados distintos, lo que equilibra la similitud con "tomates rojos" con la singularidad de los productos mostrados.
Usar MMR con un retriever
Para usar la búsqueda de MMR, también puedes configurar un retriever de LangChain. El buscador proporciona una interfaz uniforme que te permite integrar fácilmente métodos de búsqueda especializados, como MMR, directamente en tus cadenas y aplicaciones.
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}")
Siguientes pasos
- Consulta otros tipos de búsqueda y opciones de filtrado disponibles en
BigtableVectorStore. - Consulta más información sobre LangChain en Bigtable.