1. Descripción general
En diferentes industrias, la búsqueda contextual es una funcionalidad fundamental que forma el núcleo de sus aplicaciones. La generación de aumento de recuperación ha sido un impulsor clave de esta evolución tecnológica crucial desde hace bastante tiempo con sus mecanismos de recuperación potenciados por IA generativa. Los modelos generativos, con sus grandes ventanas de contexto y su impresionante calidad de salida, están transformando la IA. La RAG proporciona una forma sistemática de incorporar contexto en las aplicaciones y los agentes de IA, basándolos en bases de datos estructuradas o información de varios medios. Estos datos contextuales son fundamentales para la claridad de la verdad y la precisión de los resultados, pero ¿qué tan precisos son esos resultados? ¿Tu empresa depende en gran medida de la precisión de estas coincidencias contextuales y la relevancia? Entonces, este proyecto te encantará.
El secreto de la búsqueda de vectores no es solo crearla, sino saber si tus coincidencias de vectores son realmente buenas. Todos hemos estado allí, mirando fijamente una lista de resultados y preguntándonos: "¿Funciona esto?". Veamos cómo evaluar la calidad de tus coincidencias de vectores. Te preguntarás: "¿Qué cambió en la RAG?". Todo! Durante años, la generación mejorada por recuperación (RAG) fue un objetivo prometedor, pero difícil de alcanzar. Por último, tenemos las herramientas para compilar aplicaciones de RAG con el rendimiento y la confiabilidad necesarios para las tareas críticas.
Ahora ya tenemos los conocimientos básicos de 3 aspectos:
- Qué significa la búsqueda contextual para tu agente y cómo lograrla con la Búsqueda de vectores.
- También analizamos en detalle cómo obtener la Búsqueda de vectores dentro del alcance de tus datos, es decir, dentro de tu base de datos (si aún no lo sabías, todas las bases de datos de Google Cloud admiten esta función).
- Fuimos un paso más allá que el resto del mundo para contarte cómo lograr una función de RAG de búsqueda de vectores liviana con alto rendimiento y calidad con la función de búsqueda de vectores de AlloyDB potenciada por el índice ScaNN.
Si no has revisado esos experimentos de RAG básicos, intermedios y ligeramente avanzados, te recomendamos que los leas aquí, aquí y aquí en el orden indicado.
La Búsqueda de patentes ayuda al usuario a encontrar patentes contextualmente relevantes para su texto de búsqueda. Ya creamos una versión de esta función en el pasado. Ahora la compilaremos con funciones de RAG nuevas y avanzadas que permiten una búsqueda contextual controlada por calidad para esa aplicación. ¡Comencemos!
En la siguiente imagen, se muestra el flujo general de lo que sucede en esta aplicación.~
Objetivo
Permite que un usuario busque patentes en función de una descripción textual con un rendimiento y una calidad mejorados, a la vez que puede evaluar la calidad de las coincidencias generadas con las funciones de RAG más recientes de AlloyDB.
Qué compilarás
Como parte de este lab, aprenderás a hacer lo siguiente:
- Crea una instancia de AlloyDB y carga el conjunto de datos públicos de Patents
- Crea un índice de metadatos y un índice de ScaNN
- Implementa la Búsqueda de vectores avanzada en AlloyDB con el método de filtrado intercalado de ScaNN
- Implementa la función de evaluación de recuperación
- Evalúa la respuesta de la consulta
Requisitos
2. Antes de comenzar
Crea un proyecto
- En la página del selector de proyectos de la consola de Google Cloud, selecciona o crea un proyecto de Google Cloud.
- Asegúrate de que la facturación esté habilitada para tu proyecto de Cloud. Obtén información para verificar si la facturación está habilitada en un proyecto .
- Usarás Cloud Shell, un entorno de línea de comandos que se ejecuta en Google Cloud. Haz clic en Activar Cloud Shell en la parte superior de la consola de Google Cloud.
- Una vez que te conectes a Cloud Shell, verifica que ya te hayas autenticado y que el proyecto esté configurado con tu ID con el siguiente comando:
gcloud auth list
- En Cloud Shell, ejecuta el siguiente comando para confirmar que el comando gcloud conoce tu proyecto.
gcloud config list project
- Si tu proyecto no está configurado, usa el siguiente comando para hacerlo:
gcloud config set project <YOUR_PROJECT_ID>
- Habilita las API necesarias. Puedes usar un comando gcloud en la terminal de Cloud Shell:
gcloud services enable alloydb.googleapis.com compute.googleapis.com cloudresourcemanager.googleapis.com servicenetworking.googleapis.com run.googleapis.com cloudbuild.googleapis.com cloudfunctions.googleapis.com aiplatform.googleapis.com
La alternativa al comando gcloud es buscar cada producto en la consola o usar este vínculo.
Consulta la documentación para ver los comandos y el uso de gcloud.
3. Configuración de la base de datos
En este lab, usaremos AlloyDB como la base de datos para los datos de patentes. Usa clústeres para contener todos los recursos, como bases de datos y registros. Cada clúster tiene una instancia principal que proporciona un punto de acceso a los datos. Las tablas contendrán los datos reales.
Crear un clúster, una instancia y una tabla de AlloyDB en los que se cargará el conjunto de datos de patentes
Crea un clúster y una instancia
- Navega a la página de AlloyDB en Cloud Console. Una forma sencilla de encontrar la mayoría de las páginas en la consola de Cloud es buscarlas con la barra de búsqueda de la consola.
- Selecciona CREATE CLUSTER en esa página:
- Verás una pantalla como la siguiente. Crea un clúster y una instancia con los siguientes valores (asegúrate de que los valores coincidan en caso de que estés clonando el código de la aplicación desde el repositorio):
- cluster id: "
vector-cluster
" - contrasena: "
alloydb
" - PostgreSQL 15 o la versión más reciente recomendada
- Región: "
us-central1
" - Redes: "
default
"
- Cuando selecciones la red predeterminada, verás una pantalla como la que se muestra a continuación.
Selecciona CONFIGURAR CONEXIÓN.
- Allí, selecciona "Usar un rango de IP asignado automáticamente" y haz clic en Continuar. Después de revisar la información, selecciona CREAR CONEXIÓN.
- Una vez que se configure la red, podrás continuar con la creación del clúster. Haz clic en CREATE CLUSTER para completar la configuración del clúster, como se muestra a continuación:
Asegúrate de cambiar el ID de la instancia (que puedes encontrar en el momento de la configuración del clúster o la instancia) a
vector-instance
. Si no puedes cambiarlo, recuerda usar el ID de tu instancia en todas las referencias futuras.
Ten en cuenta que la creación del clúster tardará alrededor de 10 minutos. Una vez que se realice correctamente, deberías ver una pantalla que muestre la descripción general del clúster que acabas de crear.
4. Transferencia de datos
Ahora es el momento de agregar una tabla con los datos de la tienda. Navega a AlloyDB, selecciona el clúster principal y, luego, AlloyDB Studio:
Es posible que debas esperar a que se termine de crear la instancia. Una vez que lo hagas, accede a AlloyDB con las credenciales que creaste cuando creaste el clúster. Usa los siguientes datos para autenticarte en PostgreSQL:
- Nombre de usuario : "
postgres
" - Base de datos : "
postgres
" - Contraseña : "
alloydb
"
Una vez que te hayas autenticado correctamente en AlloyDB Studio, los comandos SQL se ingresarán en el editor. Puedes agregar varias ventanas del editor con el signo más que se encuentra a la derecha de la última ventana.
Ingresarás comandos para AlloyDB en las ventanas del editor, con las opciones Ejecutar, Formatear y Borrar según sea necesario.
Habilita las extensiones
Para compilar esta app, usaremos las extensiones pgvector
y google_ml_integration
. La extensión pgvector te permite almacenar y buscar embeddings de vectores. La extensión google_ml_integration proporciona funciones que usas para acceder a los extremos de predicción de Vertex AI y obtener predicciones en SQL. Para habilitar estas extensiones, ejecuta los siguientes DDL:
CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;
CREATE EXTENSION IF NOT EXISTS vector;
Si quieres verificar las extensiones que se habilitaron en tu base de datos, ejecuta este comando SQL:
select extname, extversion from pg_extension;
Crear una tabla
Puedes crear una tabla con la siguiente sentencia DDL en AlloyDB Studio:
CREATE TABLE patents_data ( id VARCHAR(25), type VARCHAR(25), number VARCHAR(20), country VARCHAR(2), date VARCHAR(20), abstract VARCHAR(300000), title VARCHAR(100000), kind VARCHAR(5), num_claims BIGINT, filename VARCHAR(100), withdrawn BIGINT, abstract_embeddings vector(768)) ;
La columna abstract_embeddings permitirá el almacenamiento de los valores vectoriales del texto.
Otorgar permiso
Ejecuta la siguiente sentencia para otorgar la ejecución en la función "embedding":
GRANT EXECUTE ON FUNCTION embedding TO postgres;
Otorga el rol de usuario de Vertex AI a la cuenta de servicio de AlloyDB
En la consola de IAM de Google Cloud, otorga a la cuenta de servicio de AlloyDB (que se ve de la siguiente manera: service-<<PROJECT_NUMBER>>@gcp-sa-alloydb.iam.gserviceaccount.com) acceso al rol "Usuario de Vertex AI". PROJECT_NUMBER tendrá el número de tu proyecto.
Como alternativa, puedes ejecutar el siguiente comando desde la terminal de Cloud Shell:
PROJECT_ID=$(gcloud config get-value project)
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" \
--role="roles/aiplatform.user"
Carga datos de patentes en la base de datos
Los conjuntos de datos públicos de Google Patents en BigQuery se usarán como nuestro conjunto de datos. Usaremos AlloyDB Studio para ejecutar nuestras consultas. Los datos se obtienen de este archivo insert_scripts.sql
y lo ejecutaremos para cargar los datos de patentes.
- En la consola de Google Cloud, abre la página AlloyDB.
- Selecciona el clúster que acabas de crear y haz clic en la instancia.
- En el menú de navegación de AlloyDB, haz clic en AlloyDB Studio. Accede con tus credenciales.
- Para abrir una pestaña nueva, haz clic en el ícono Nueva pestaña que se encuentra a la derecha.
- Copia la sentencia de consulta
insert
de la secuencia de comandosinsert_scripts.sql
mencionada anteriormente en el editor. Puedes copiar entre 10 y 50 instrucciones de inserción para una demostración rápida de este caso de uso. - Haz clic en Ejecutar. Los resultados de tu consulta aparecen en la tabla Resultados.
Nota: Es posible que notes que la secuencia de comandos de inserción tiene muchos datos. Esto se debe a que incluimos incorporaciones en las secuencias de comandos de inserción. Haz clic en "Ver sin procesar" en caso de que tengas problemas para cargar el archivo en GitHub. Esto se hace para ahorrarte el problema (en los próximos pasos) de generar más de unas pocas incorporaciones (digamos, de 20 a 25 como máximo) en caso de que uses una cuenta de facturación de crédito de prueba para Google Cloud.
5. Crea incorporaciones para datos de patentes
Primero, probemos la función de incorporación ejecutando la siguiente consulta de muestra:
SELECT embedding('text-embedding-005', 'AlloyDB is a managed, cloud-hosted SQL database service.');
Se debería mostrar el vector de incorporaciones, que parece un array de números de punto flotante, para el texto de muestra en la consulta. Se ve de la siguiente manera:
Actualiza el campo de vector abstract_embeddings
Ejecuta la siguiente DML para actualizar los resúmenes de patentes en la tabla con las incorporaciones correspondientes solo si no insertaste los datos de abstract_embeddings como parte de la secuencia de comandos de inserción:
UPDATE patents_data set abstract_embeddings = embedding( 'text-embedding-005', abstract);
Es posible que tengas problemas para generar más de unas pocas incorporaciones (por ejemplo, entre 20 y 25 como máximo) si usas una cuenta de facturación de crédito de prueba para Google Cloud. Por lo tanto, ya incluí las incorporaciones en las secuencias de comandos de inserción y deberías tenerlas cargadas en tu tabla si completaste el paso "Carga datos de patentes en la base de datos".
6. Realiza RAG avanzado con las nuevas funciones de AlloyDB
Ahora que la tabla, los datos y los embeddings están listos, realicemos la Búsqueda de vectores en tiempo real para el texto de búsqueda del usuario. Para probarlo, ejecuta la siguiente consulta:
SELECT id || ' - ' || title as title FROM patents_data ORDER BY abstract_embeddings <=> embedding('text-embedding-005', 'Sentiment Analysis')::vector LIMIT 10;
En esta consulta,
- El texto que buscó el usuario es "Análisis de opiniones".
- Lo convertimos en incorporaciones en el método embedding() con el modelo text-embedding-005.
- "<=>" representa el uso del método de distancia SIMILARITY_COSINE.
- Convertimos el resultado del método de incorporación en un tipo de vector para que sea compatible con los vectores almacenados en la base de datos.
- LIMIT 10 representa que seleccionamos las 10 coincidencias más cercanas del texto de búsqueda.
AlloyDB lleva el RAG de búsqueda vectorial al siguiente nivel:
Se introdujeron muchos elementos. Dos de las más centradas en los desarrolladores son las siguientes:
- Filtrado intercalado
- Evaluador de recuperación
Filtrado intercalado
Anteriormente, como desarrollador, debías realizar la consulta de Búsqueda de vectores y lidiar con el filtrado y la recuperación. El optimizador de consultas de AlloyDB toma decisiones sobre cómo ejecutar una consulta con filtros. El filtrado intercalado es una nueva técnica de optimización de consultas que permite que el optimizador de consultas de AlloyDB evalúe las condiciones de filtrado de metadatos y la búsqueda de vectores en paralelo, aprovechando los índices de vectores y los índices de las columnas de metadatos. Esto aumentó el rendimiento de la recuperación, lo que permite a los desarrolladores aprovechar lo que AlloyDB tiene para ofrecer de forma predeterminada.
El filtrado intercalado es mejor para los casos con selectividad media. A medida que AlloyDB busca en el índice de vectores, solo calcula las distancias de los vectores que coinciden con las condiciones de filtrado de metadatos (los filtros funcionales en una consulta que suelen controlarse en la cláusula WHERE). Esto mejora enormemente el rendimiento de estas consultas y complementa las ventajas del filtro posterior o previo.
- Instala o actualiza la extensión pgvector
CREATE EXTENSION IF NOT EXISTS vector WITH VERSION '0.8.0.google-3';
Si la extensión pgvector ya está instalada, actualízala a la versión 0.8.0.google-3 o una posterior para obtener capacidades de evaluador de recuperación.
ALTER EXTENSION vector UPDATE TO '0.8.0.google-3';
Este paso solo debe ejecutarse si tu extensión vectorial es <0.8.0.google-3>.
Nota importante: Si el recuento de filas es inferior a 100, no necesitarás crear el índice ScaNN, ya que no se aplicará a menos filas. En ese caso, omite los siguientes pasos.
- Para crear índices ScaNN, instala la extensión alloydb_scann.
CREATE EXTENSION IF NOT EXISTS alloydb_scann;
- Primero, ejecuta la consulta de búsqueda de vectores sin el índice y sin el filtro intercalado habilitado:
SELECT id || ' - ' || title as title FROM patents_data
WHERE num_claims >= 15
ORDER BY abstract_embeddings <=> embedding('text-embedding-005', 'Sentiment Analysis')::vector LIMIT 10;
El resultado debería ser similar al siguiente:
- Ejecuta Explain Analyze en él: (sin índice ni filtrado intercalado)
El tiempo de ejecución es de 2.4 ms
- Creemos un índice normal en el campo num_claims para poder filtrar por él:
CREATE INDEX idx_patents_data_num_claims ON patents_data (num_claims);
- Creemos el índice ScaNN para nuestra aplicación de búsqueda de patentes. Ejecuta el siguiente comando desde AlloyDB Studio:
CREATE INDEX patent_index ON patents_data
USING scann (abstract_embeddings cosine)
WITH (num_leaves=32);
Nota importante: (num_leaves=32)
se aplica a nuestro conjunto de datos total con más de 1,000 filas. Si el recuento de filas es inferior a 100, no necesitarás crear un índice, ya que no se aplicará a menos filas.
- Establece el filtrado intercalado habilitado en el índice ScaNN:
SET scann.enable_inline_filtering = on
- Ahora, ejecutemos la misma consulta con el filtro y Vector Search:
SELECT id || ' - ' || title as title FROM patents_data
WHERE num_claims >= 15
ORDER BY abstract_embeddings <=> embedding('text-embedding-005', 'Sentiment Analysis')::vector LIMIT 10;
Como puedes ver, el tiempo de ejecución se reduce significativamente para la misma Búsqueda de vectores. El índice ScaNN con filtrado intercalado en la Búsqueda de vectores lo hizo posible.
A continuación, evaluemos la recuperación de esta Búsqueda de vectores habilitada para ScaNN.
Evaluador de recuperación
La recuperación en la búsqueda de similitudes es el porcentaje de instancias relevantes que se recuperaron de una búsqueda, es decir, la cantidad de verdaderos positivos. Esta es la métrica más común que se usa para medir la calidad de la búsqueda. Una fuente de pérdida de recuperación proviene de la diferencia entre la búsqueda de vecino más cercano aproximado, o aNN, y la búsqueda de vecino más cercano k (exacto), o kNN. Los índices vectoriales, como ScaNN de AlloyDB, implementan algoritmos de ANN, lo que te permite acelerar la búsqueda vectorial en grandes conjuntos de datos a cambio de una pequeña compensación en la recuperación. Ahora, AlloyDB te permite medir esta compensación directamente en la base de datos para consultas individuales y asegurarte de que sea estable con el tiempo. Puedes actualizar los parámetros de consulta y de índice en función de esta información para obtener mejores resultados y rendimiento.
¿Cuál es la lógica detrás de la recuperación de los resultados de la búsqueda?
En el contexto de la búsqueda vectorial, la recuperación se refiere al porcentaje de vectores que muestra el índice y que son vecinos más cercanos reales. Por ejemplo, si una consulta de vecino más cercano a los 20 vecinos más cercanos muestra 19 de los vecinos más cercanos de “verdad fundamental”, la recuperación será 19/20x100 = 95%. La recuperación es la métrica que se usa para la calidad de la búsqueda y se define como el porcentaje de los resultados que se muestran y que están objetivamente más cerca de los vectores de consulta.
Puedes encontrar la recuperación de una consulta vectorial en un índice vectorial para una configuración determinada con la función evaluate_query_recall. Esta función te permite ajustar los parámetros para lograr los resultados de recuperación de consultas vectoriales que deseas.
Nota importante:
Si tienes un error de permiso denegado en el índice de HNSW en los siguientes pasos, omite por ahora toda esta sección de evaluación de recuperación. En este momento, podría deberse a restricciones de acceso, ya que se acaba de lanzar cuando se documenta este codelab.
- Establece la marca Enable Index Scan en el índice ScaNN y el índice de HNSW:
SET scann.enable_indexscan = on
SET hnsw.enable_index_scan = on
- Ejecuta la siguiente consulta en AlloyDB Studio:
SELECT
*
FROM
evaluate_query_recall($$
SELECT
id || ' - ' || title AS title,
abstract
FROM
patents_data
where num_claims >= 15
ORDER BY
abstract_embeddings <=> embedding('text-embedding-005',
'sentiment analysis')::vector
LIMIT 25 $$,
'{"scann.num_leaves_to_search":1, "scann.pre_reordering_num_neighbors":10}',
ARRAY['scann']);
La función evaluate_query_recall toma la consulta como parámetro y muestra su recuperación. Estoy usando la misma consulta que usé para verificar el rendimiento como la consulta de entrada de la función. Agregué SCaNN como el método de indexación. Para obtener más opciones de parámetros, consulta la documentación.
El recuerdo de esta consulta de búsqueda de vectores que hemos estado usando:
Veo que el valor de RECALL es 70%. Ahora puedo usar esta información para cambiar los parámetros de índice, los métodos y los parámetros de consulta, y mejorar mi recuperación para esta Búsqueda vectorial.
7. Pruébala con parámetros de consulta y de índice modificados
Ahora, probemos la consulta modificando los parámetros de consulta en función del recuerdo recibido.
- Modifiqué la cantidad de filas en el conjunto de resultados a 7 (antes eran 25) y veo una mejora en la RECALL, es decir, un 86%.
Esto significa que, en tiempo real, puedo variar la cantidad de coincidencias que ven mis usuarios para mejorar la relevancia de las coincidencias de acuerdo con el contexto de búsqueda de los usuarios.
- Volvamos a intentarlo modificando los parámetros del índice:
Para esta prueba, usaré la función de distancia de similitud "L2 Distance" en lugar de "Cosine". También cambiaré el límite de la consulta a 10 para mostrar si hay una mejora en la calidad de los resultados de la búsqueda, incluso con un aumento en el recuento de conjuntos de resultados de la búsqueda.
[ANTES] Consulta que usa la función de distancia de similitud de coseno:
SELECT
*
FROM
evaluate_query_recall($$
SELECT
id || ' - ' || title AS title,
abstract
FROM
patents_data
where num_claims >= 15
ORDER BY
abstract_embeddings <=> embedding('text-embedding-005',
'sentiment analysis')::vector
LIMIT 10 $$,
'{"scann.num_leaves_to_search":1, "scann.pre_reordering_num_neighbors":10}',
ARRAY['scann']);
Nota muy importante: Te preguntarás: "¿Cómo sabemos que esta consulta usa la similitud COSINE?". Puedes identificar la función de distancia con el uso de "<=>" para representar la distancia de coseno.
Vínculo a la documentación para las funciones de distancia de la Búsqueda de vectores.
El resultado de la consulta anterior es el siguiente:
Como puedes ver, el RECALL es del 70% sin ningún cambio en nuestra lógica de indexación. ¿Recuerdas el índice de ScaNN que creamos en el paso 6 de la sección Filtrado intercalado, "patent_index
"? El mismo índice sigue siendo eficaz mientras ejecutamos la consulta anterior.
Ahora, crearemos un índice con una consulta de función de distancia diferente: Distancia L2: <->
drop index patent_index;
CREATE INDEX patent_index_L2 ON patents_data
USING scann (abstract_embeddings L2)
WITH (num_leaves=32);
La sentencia drop index solo sirve para garantizar que no haya índices innecesarios en la tabla.
Ahora, puedo ejecutar la siguiente consulta para evaluar el RECALL después de cambiar la función de distancia de mi funcionalidad de Búsqueda de vectores.
[DESPUÉS] Consulta que usa la función de distancia de similitud de coseno:
SELECT
*
FROM
evaluate_query_recall($$
SELECT
id || ' - ' || title AS title,
abstract
FROM
patents_data
where num_claims >= 15
ORDER BY
abstract_embeddings <-> embedding('text-embedding-005',
'sentiment analysis')::vector
LIMIT 10 $$,
'{"scann.num_leaves_to_search":1, "scann.pre_reordering_num_neighbors":10}',
ARRAY['scann']);
El resultado de la consulta anterior es el siguiente:
¡Qué transformación en el valor de recuperación, 90%!
Hay otros parámetros que puedes cambiar en el índice, como num_leaves, etc., según el valor de recuperación deseado y el conjunto de datos que usa tu aplicación.
8. Limpia
Sigue estos pasos para evitar que se apliquen cargos a tu cuenta de Google Cloud por los recursos que usaste en esta publicación:
- En la consola de Google Cloud, ve a la página Administrador de recursos.
- En la lista de proyectos, elige el proyecto que deseas borrar y haz clic en Borrar.
- En el diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrarlo.
- Como alternativa, puedes borrar el clúster de AlloyDB (cambia la ubicación en este hipervínculo si no elegiste us-central1 para el clúster en el momento de la configuración) que acabamos de crear para este proyecto haciendo clic en el botón BORRAR CLÚSTER.
9. Felicitaciones
¡Felicitaciones! Creaste correctamente tu consulta contextual de búsqueda de patentes con la búsqueda vectorial avanzada de AlloyDB para obtener un alto rendimiento y que sea realmente orientada al significado. Ensamblé una aplicación de agente multiherramienta controlada por calidad que usa ADK y todo el material de AlloyDB que analizamos aquí para crear un agente de búsqueda y análisis de vectores de patentes de alta calidad y rendimiento que puedes ver aquí: https://youtu.be/Y9fvVY0yZTY
Si quieres aprender a compilar ese agente, consulta este codelab.