Uso de SelfQueryRetriever con LangChain para consultar una base de datos vectorial
LangChain es bien conocido por orquestar interacciones con grandes modelos de lenguaje (LLMs). Recientemente, LangChain ha introducido una forma de realizar autoconsultas, lo que les permite consultar la “chain” o los módulos mismos utilizando una consulta de entrada del usuario. Esta publicación te mostrará cómo hacer autoconsultas en Milvus, la base de datos vectorial más popular del mundo. Al interpretar una consulta de usuario, el sistema puede refinar búsquedas dentro de almacenes vectoriales, mejorando los resultados de recuperación. Puedes encontrar el código de este ejemplo en CoLab aquí.
Configuremos las autoconsultas en Milvus con LangChain. Este proceso consta de cuatro pasos lógicos.
Configurar los aspectos básicos de LangChain y Milvus.
Obtener o crear los datos necesarios.
Informar al modelo sobre el formato de datos esperado.
Demostrar las autoconsultas y explicar cómo funcionan.
Introducción a las autoconsultas
La autoconsulta es una técnica potente utilizada en el procesamiento del lenguaje natural (NLP) y la recuperación de información. Permite que un sistema se consulte a sí mismo utilizando la consulta de entrada de un usuario, lo que habilita resultados más precisos y relevantes. En el contexto de LangChain, la autoconsulta se utiliza para recuperar información de un almacén vectorial, que es una base de datos que almacena vectores que representan documentos o puntos de datos. El recuperador de autoconsultas es un componente clave del framework LangChain, que permite la creación de consultas y recuperaciones complejas usando lenguaje natural.
Al aprovechar las autoconsultas, LangChain puede descomponer la consulta de un usuario en un formato estructurado que el almacén vectorial pueda entender. Este proceso garantiza que los documentos recuperados sean altamente relevantes para la consulta del usuario, lo que facilita encontrar la información que necesita. Ya sea que estés construyendo un modelo de IA conversacional o un motor de búsqueda, las autoconsultas pueden mejorar significativamente la precisión y relevancia de tus resultados.
Configuración de LangChain y Milvus
El primer paso es configurar las bibliotecas necesarias. Puedes instalar las bibliotecas requeridas usando pip install openai langchain milvus python-dotenv. Si has seguido mis tutoriales anteriores, ya estás familiarizado con python-dotenv, mi biblioteca preferida para manejar variables de entorno. Usamos la biblioteca OpenAI con LangChain para acceder a GPT y utilizar Milvus como nuestro almacén vectorial.
Una vez que te conectes a la clave de la API de OpenAI, importa los módulos necesarios de LangChain. Necesitamos los siguientes seis módulos:
Document: Un tipo de datos de LangChain para el almacenamiento de datos.OpenAIyOpenAIEmbeddings: Dos funcionalidades para acceder a OpenAI y sus embeddings.Milvus: Un módulo para acceder a Milvus desde LangChain.SelfQueryRetriever: Un módulo recuperador.AttributeInfo: Un módulo que define nuestra estructura de datos para LangChain.
Después de importar los módulos, establecemos la variable embeddings en la función predeterminada de OpenAI Embeddings. El paso final en el proceso de configuración es usar la biblioteca milvus para iniciar una instancia de Milvus Lite en nuestro notebook.
Ahora, echemos un vistazo a los datos.
import os
from dotenv import load_dotenv
load_dotenv()
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")
from langchain.schema import Document
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Milvus
from langchain.llms import OpenAI
from langchain.retrievers.self_query.base import SelfQueryRetriever
from langchain.chains.query_constructor.base import AttributeInfo
embeddings = OpenAIEmbeddings()
from milvus import default_server
default_server.start()
Recopilemos algunos datos. Puedes extraer tus datos, usar los datos proporcionados tal cual, o usarlos como plantilla para crear tus datos. He preparado una lista de documentos sobre películas para este ejemplo, incluyendo Jurassic Park, Toy Story, Finding Nemo, The Unbearable Weight of Massive Talent, Lord of War y Ghost Rider. Aunque no incluyo los títulos en nuestros datos, quiero que sepas a qué películas se refieren.
Almaceno cada una de estas películas como un objeto Document de LangChain. Contiene una clave page_content correspondiente a una cadena, en este caso, la descripción de la película. También incluye metadatos, como el año, la calificación y el género de la película.
docs = [
# jurassic park
Document(page_content="A bunch of scientists bring back dinosaurs and mayhem breaks loose",
metadata={"year": 1993, "rating": 7.7, "genre": "action"}),
# toy story
Document(page_content="Toys come alive and have a blast doing so",
metadata={"year": 1995, "genre": "animated", "rating": 9.3 }),
# finding nemo
Document(page_content="A dad teams up with a mentally disabled partner to break into a dentist\'s office to save his son.",
metadata={"year": 2003, "genre": "animated", "rating": 8.2 }),
# unbearable weight of massive talent
Document(page_content="Nicholas Cage plays Nicholas Cage in this movie about Nicholas Cage.",
metadata={"year": 2022, "genre": "comedy", "rating": 7.0 }),
# lord of war
Document(page_content="Nicholas Cage sells guns until he has enough money to marry his favorite model. Then he sells more guns.",
metadata={"year": 2005, "genre": "comedy", "rating": 7.6 }),
# ghost rider
Document(page_content="Nicholas Cage loses his skin and sets his skull on fire. Then he rides a motorcycle.",
metadata={"year": 2007, "genre": "action", "rating": 5.3 }),
]
Definición de metadatos de self-query y self query retriever para LangChain y Milvus
Hemos completado los dos primeros pasos del rompecabezas, y ahora es el momento del tercero.
Primero, configuremos nuestra base de datos vectorial para la ingesta. Podemos usar la implementación de Milvus de LangChain para ingerir nuestros documentos y crear una base de datos vectorial basada en nuestros documentos existentes. Este paso también es donde entra en juego la función de embeddings, usando la variable embeddings que creamos previamente. La instrucción de comparación tiene en cuenta los formatos y directrices específicos necesarios para crear condiciones de filtro que guían los procesos de recuperación de datos.
El parámetro connection_args es el único parámetro requerido para conectarse a Milvus. En este tutorial, también uso el parámetro collection_name para asignar un nombre a la colección donde almacenamos nuestros datos. Cada colección en Milvus debe tener un nombre. De forma predeterminada, LangChain usa LangChainCollection.
vector_store = Milvus.from_documents(
docs,
embedding=embeddings,
connection_args={"host": "localhost", "port": default_server.listen_port},
collection_name="movies"
)
A continuación, definamos la información de metadatos usando la funcionalidad AttributeInfo para que LangChain sepa qué esperar. Esta sección creará una lista de información de atributos para los datos. Especificaremos el nombre, la descripción y el tipo de datos de cada atributo. Aquí es donde una instrucción de condición lógica se vuelve esencial para formular comparaciones y operaciones lógicas dentro del proceso de construcción de consultas.
metadata_field_info = [
AttributeInfo(
name="genre",
description="The genre of the movie",
type="string",
),
AttributeInfo(
name="year",
description="The year the movie was released",
type="integer",
),
AttributeInfo(
name="rating",
description="A 1-10 rating for the movie",
type="float"
),
]
Las últimas dos partes describen el documento, inicializan el LLM y definen el Self-Query Retriever. Definimos el self-query retriever llamando a su método ‘from_llm’. Debemos usar este método para conectar el LLM, el almacén vectorial, la descripción del contenido del documento y la información de los campos de metadatos. En este ejemplo, también establecemos ‘verbose = True’ para habilitar la salida detallada para este self-query retriever. La cadena de consulta solo debe incluir texto relevante que coincida con el contenido del documento, asegurando que cualquier condición en los filtros esté claramente separada y no se incluya en la propia cadena de consulta.
document_content_description = "Brief summary of a movie"
llm = OpenAI(temperature=0)
retriever = SelfQueryRetriever.from_llm(
llm, vector_store, document_content_description, metadata_field_info, verbose=True
)
Resultados de self-querying
Hemos terminado la configuración del self-query retriever. Ahora, veamos cómo funciona en acción. En este ejemplo, utilicé tres descripciones de películas relacionadas con Nicholas Cage. Entonces, la pregunta que hacemos es: ¿cuáles son algunas películas sobre Nicholas Cage?
# This example only specifies a relevant query
retriever.get_relevant_documents("What are some movies about Nicholas Cage?")
Deberíamos obtener una salida como la siguiente.
langchain-query-vector-database.png
Al establecer verbose=True, podemos ver la consulta, el filtro y el límite. El LLM convierte nuestra consulta de “What are some movies about Nicholas Cage?” a “Nicholas Cage.” Al observar los resultados, podemos ver que los tres primeros resultados son todas películas en las que aparece Nicholas Cage. Sin embargo, el cuarto resultado, Finding Nemo, es irrelevante debido al parámetro configurado para recuperar cuatro resultados.
Con suerte, el recorrido por el código ha aclarado el concepto de self-querying en una base de datos vectorial. En el sitio web de LangChain, LangChain describe self-querying como un método para que un LLM se consulte a sí mismo utilizando el almacén vectorial subyacente. En otras palabras, LangChain está desarrollando una aplicación sencilla de generación aumentada por recuperación (RAG) en el marco CVP que incluye una función de self-querying.
En este tutorial, hemos explorado la función de self-query de LangChain usando Milvus como almacén vectorial subyacente. Self-querying te permite crear una aplicación RAG sencilla combinando un LLM y una base de datos vectorial. El LLM descompone la consulta en lenguaje natural en una cadena, que luego se vectoriza para realizar la consulta.
En nuestro ejemplo, generamos algunos datos de muestra relacionados con películas. Una forma de ampliar este ejemplo es recopilar tus propios datos. Al definir el self-query retriever, recuerda proporcionar las descripciones tanto para el almacén vectorial como para los metadatos.
Para comenzar y experimentar con la función de self-query de LangChain, consulta el cuaderno de colab.
Consulta del almacén vectorial con declaraciones de operaciones lógicas
Al consultar el almacén vectorial, se utilizan declaraciones de operaciones lógicas para especificar condiciones para filtrar documentos. Una declaración de operación lógica toma la forma de op(statement1, statement2, …), donde op es un operador lógico como AND, OR o NOT. Cada declaración puede ser una declaración de comparación, que toma la forma de comp(attr, val), donde comp es un comparador como EQ, LT o GT, y attr y val son el atributo y el valor que se comparan, respectivamente.
Por ejemplo, una declaración de operación lógica podría verse así: AND(EQ(language, “English”), GT(rating, 4)). Esta declaración filtraría documentos que tengan un atributo de idioma igual a “English” y un atributo de calificación mayor que 4. Al usar declaraciones de operaciones lógicas, puedes crear consultas complejas que combinen múltiples condiciones, lo que permite un filtrado más preciso de documentos en el almacén vectorial.
Manejo de la consulta del usuario
Cuando un usuario introduce una consulta, el recuperador de autoconsulta utiliza un constructor de consultas para generar una consulta estructurada. La consulta estructurada se traduce luego en consultas para el almacén vectorial, que se ejecutan en el almacén vectorial para recuperar documentos relevantes. El constructor de consultas utiliza un prompt y un analizador de salida para generar la consulta estructurada, que captura los filtros especificados por el usuario.
Por ejemplo, si un usuario introduce la consulta “Find movies with a rating greater than 4 and a runtime less than 2 hours”, el constructor de consultas podría generar una consulta estructurada como esta: AND(GT(rating, 4), LT(runtime, 120)). Esta consulta estructurada se traduciría luego en consultas para el almacén vectorial y se ejecutaría en el almacén vectorial para recuperar documentos relevantes. Al gestionar la consulta del usuario de esta manera, el recuperador de autoconsulta garantiza que los resultados se adapten a los requisitos específicos del usuario.
Mejores prácticas y conclusión
Al usar el recuperador de autoconsulta, es importante seguir las mejores prácticas para garantizar resultados precisos y relevantes. Aquí tienes algunos consejos:
Usa un lenguaje específico y conciso al introducir consultas.
Usa declaraciones de operaciones lógicas para especificar condiciones para filtrar documentos.
Usa declaraciones de comparación para comparar atributos y valores.
Usa el comparador EQ para especificar coincidencias exactas.
Usa los comparadores LT y GT para especificar consultas de rango.
Usa los operadores lógicos AND y OR para combinar condiciones.
En conclusión, el recuperador de autoconsulta es una herramienta poderosa para crear modelos de IA conversacional que pueden recuperar y procesar información de diversas fuentes. Al usar declaraciones de operaciones lógicas y declaraciones de comparación, los usuarios pueden especificar consultas complejas y recuperar documentos relevantes de un almacén vectorial. Al seguir las mejores prácticas y usar el recuperador de autoconsulta de manera eficaz, los desarrolladores pueden crear modelos de IA más precisos y relevantes que pueden manejar una amplia variedad de consultas de usuarios.
Sigue leyendo

Milvus 2.6.x Now Generally Available on Zilliz Cloud, Making Vector Search Faster, Smarter, and More Cost-Efficient for Production AI
Milvus 2.6.x is now GA on Zilliz Cloud, delivering faster vector search, smarter hybrid queries, and lower costs for production RAG and AI applications.

Vector Databases vs. Document Databases
Use a vector database for similarity search and AI-powered applications; use a document database for flexible schema and JSON-like data storage.

OpenAI o1: What Developers Need to Know
In this article, we will talk about the o1 series from a developer's perspective, exploring how these models can be implemented for sophisticated use cases.



