11 puntos por GN⁺ 2024-10-30 | 1 comentarios | Compartir por WhatsApp
  • El mensaje que atormenta a los equipos de ingeniería que intentan construir aplicaciones de IA: "los embeddings no se volvieron a sincronizar"
  • Una implementación simple de búsqueda vectorial evoluciona hacia una compleja orquesta de monitoreo, sincronización y resolución de problemas
  • Tras hablar con equipos de ingeniería que construyen sistemas de IA con bases de datos vectoriales, se descubrió la abstracción equivocada de las bases de datos vectoriales y los defectos de cómo se usan hoy

"El caso común al construir sistemas RAG"

  • Se usa Pinecone como base de datos vectorial para almacenar y recuperar embeddings
  • Como los datos de texto no encajan bien en los metadatos de Pinecone, se usa DynamoDB para manejar blobs y datos de la aplicación
  • Se necesitó OpenSearch para la búsqueda léxica
  • Ahora conectar y sincronizar 3 sistemas es una pesadilla

Al eliminar un documento fuente, hay que hacer lo siguiente:

  1. Ejecutar boto3 para quitar el registro de DynamoDB
  2. Actualizar Pinecone para confirmar que el embedding fue eliminado
  3. Hacer una solicitud POST para actualizar el índice de búsqueda léxica
  • Esto debe hacerse para cada actualización, adición o eliminación de documentos fuente
  • La gestión de configuración no solo es desordenada, sino también riesgosa
  • Incluso hay equipos que pagaron $2,000 al mes por índices que debieron haberse eliminado hace 4 meses
  • Existe el riesgo de devolver datos incorrectos o desactualizados a los usuarios

Las bases de datos vectoriales están construidas sobre una abstracción equivocada

  • Las bases de datos vectoriales tratan los embeddings como datos independientes, no como datos derivados
  • Al tratarlos como datos independientes, crean complejidad innecesaria

Una mejor forma: la abstracción de "Vectorizer"

  • Se propone la abstracción de "vectorizer", que trata los embeddings como índices de base de datos
  • Este enfoque sincroniza automáticamente los embeddings con los datos fuente, eliminando el costo de mantenimiento
  • El equivalente del comando CREATE INDEX para un vectorizer es el siguiente:
SELECT ai.create_vectorizer(
    'public.blogs'::regclass,
    embedding => ai.embedding_openai('text-embedding-3-small', 1536),
    chunking => ai.chunking_recursive_character_text_splitter('content')
);
  • Este comando genera embeddings para todas las entradas de la tabla de blogs y sigue actualizándolos cuando cambian los datos de la tabla

Problemas de las bases de datos vectoriales (y de los tipos de datos vectoriales)

  • Las bases de datos vectoriales se desarrollaron para manejar grandes volúmenes de embeddings vectoriales de texto, imágenes y datos multimodales
  • Las bases de datos de propósito general como PostgreSQL, MySQL, MongoDB y Oracle también agregaron soporte para búsqueda vectorial
  • Sin embargo, la abstracción de las capacidades de búsqueda vectorial, ya sea como sistemas independientes o añadidas a bases de datos existentes, tiene fallas fatales
  • Una vez que los embeddings se insertan en la base de datos, se rompe la conexión entre los datos no estructurados que se embeben y los propios embeddings vectoriales
  • Sin esa conexión, los embeddings se tratan erróneamente como átomos de datos independientes que el desarrollador debe administrar, y no como datos derivados
  • Al replantear los embeddings como datos derivados, queda clara la absurdidad de la abstracción actual de las bases de datos vectoriales, donde los embeddings no están conectados a los datos fuente

Los equipos de desarrollo deben administrar:

  • Pipelines ETL (extracción-carga-transformación) complejos

  • Una base de datos vectorial para embeddings, otra base de datos para metadatos y datos de la app, e índices de búsqueda léxica

  • Servicios de sincronización de datos

  • Sistemas de colas para actualizaciones y sincronización

  • Herramientas de monitoreo para detectar drift de datos y manejar límites de velocidad del servicio de embeddings, entre otros

  • Sistemas de alertas cuando la búsqueda devuelve resultados desactualizados

  • Verificaciones de validación para todos los sistemas

  • Para actualizar a un nuevo modelo de embeddings o probar otro método de chunking, hay que escribir código personalizado y coordinar cambios entre varios servicios de datos y bases de datos

  • Estas tareas ponen sobre el equipo de desarrollo la carga de garantizar que los embeddings se generen oportunamente a medida que cambian los datos fuente

  • Si no, existe el riesgo de que los embeddings se desactualicen con frecuencia y ofrezcan una peor experiencia de aplicación a los usuarios

Una mejor forma: dejar que la base de datos maneje la complejidad

  • Al replantear los embeddings como datos derivados, se puede dejar en manos del sistema de gestión de bases de datos la responsabilidad de generarlos y actualizarlos a medida que cambian los datos subyacentes
  • Este cambio libera a los desarrolladores de la carga de tener que mantener manualmente sincronizados los embeddings con los datos fuente
  • Esta distinción puede no ser importante para aplicaciones simples que hacen una importación única de datos para RAG
  • Pero en la mayoría de las aplicaciones reales, los datos cambian de forma continua
  • Pensemos en una plataforma de comercio electrónico que usa búsqueda semántica basada en embeddings o en una app RAG de asistencia de productos que debe mantenerse al día con la información más reciente
  • Rastrear manualmente estos cambios y regenerar embeddings no solo requiere mucho trabajo y es propenso a errores, sino que también distrae a los desarrolladores de sus objetivos principales de negocio
  • ¿Por qué desperdiciar tiempo de desarrollo en algo que el sistema de base de datos puede manejar automáticamente?

Vectorizer: embeddings vectoriales como índices

  • Una abstracción más efectiva es conceptualizar los embeddings vectoriales como un índice especial sobre los datos embebidos, no como una tabla o tipo de dato independiente
  • Los embeddings vectoriales no son un índice en el sentido tradicional
  • Más bien, funcionan como un mecanismo de indexación que recupera las partes más relevantes de los datos con base en los embeddings
  • A esta nueva abstracción, similar a un índice, la podemos llamar "vectorizer"

Beneficios principales de la abstracción vectorizer:

Sincronización automática

  • Uno de los beneficios principales del indexado en una base de datos es mantener el índice sincronizado automáticamente con los datos subyacentes
  • Cuando cambian los datos de una columna, el índice se actualiza en consecuencia
  • Al tratar los embeddings vectoriales como una forma de indexación, se puede aprovechar esa misma sincronización automática
  • El sistema garantiza que los embeddings vectoriales siempre se mantengan al día con los datos más recientes, eliminando la necesidad de actualizaciones manuales y reduciendo el riesgo de errores

Relación reforzada entre datos y embeddings

  • Cuando los vectores se almacenan de forma independiente, es fácil perder la relación con los datos originales
  • ¿Este vector se generó a partir de una actualización reciente de los datos? ¿O es un vector viejo de un modelo de embeddings anterior?
  • Estas preguntas son importantes, y la confusión aquí puede causar errores graves
  • Al vincular directamente los embeddings vectoriales con los datos como si fueran un índice, la relación queda clara y se mantiene automáticamente

Gestión de datos simplificada

  • Los desarrolladores suelen enfrentar dificultades al administrar manualmente la sincronización de datos
  • Por ejemplo, si al eliminar los datos base se olvida borrar los datos del modelo de embeddings anterior, pueden surgir inconsistencias
  • La abstracción vectorizer convierte la gestión de estas relaciones en responsabilidad del sistema, reduciendo la carga cognitiva del desarrollador y minimizando la posibilidad de errores

Vectorizer es una evolución natural de la promesa central de los DBMS

  • El concepto de vectorizer es una evolución natural de las capacidades de los sistemas modernos de gestión de bases de datos (DBMS)
  • Los DBMS actuales ya son muy buenos administrando transformaciones y sincronización de datos mediante estructuras declarativas como índices, triggers y vistas materializadas
  • La abstracción vectorizer encaja bien en este paradigma al ofrecer una nueva herramienta para manejar la tarea cada vez más importante de gestionar embeddings vectoriales
  • Al incluir esta funcionalidad directamente en el DBMS, nos acercamos más a cumplir la promesa última del sistema de base de datos
  • Administrar los datos abstrayendo la complejidad para que los usuarios puedan enfocarse en lo que mejor saben hacer: construir aplicaciones, analizar datos e impulsar innovación

Implementación de vectorizer para PostgreSQL: pgai Vectorizer

  • Motivado por la promesa de aligerar la carga de los desarrolladores, el equipo de ingeniería de IA de Timescale implementó un vectorizer para PostgreSQL
  • Se llama pgai Vectorizer y actualmente está en Early Access
  • Forma parte del proyecto pgai, cuyo objetivo es hacer que PostgreSQL sea más apto para sistemas de IA y facilitar el desarrollo de IA a los desarrolladores familiarizados con PostgreSQL
  • Para ver cómo pgai Vectorizer genera y actualiza automáticamente embeddings sobre datos en PostgreSQL, revisa el video demo

Cómo funciona pgai Vectorizer

  • Se define y crea un vectorizer en SQL
  • La siguiente consulta crea un vectorizer y especifica la tabla sobre la que actúa, las columnas a vectorizar, el modelo de embeddings a usar y formato adicional sobre qué otra información incluir en los datos fuente a embebir
-- Crear un vectorizer que embebe automáticamente los datos de la tabla blogs
SELECT ai.create_vectorizer(
   'public.blogs'::regclass
   -- Usar el modelo OpenAI text-embedding-3-small
 , embedding=>ai.embedding_openai('text-embedding-3-small', 1536, api_key_name=>'OPENAI_API_KEY')
   -- Crear automáticamente un índice StreamingDiskANN cuando la tabla tenga 100k filas
 , indexing => ai.indexing_diskann(min_rows => 100000, storage_layout => 'memory_optimized'),
   -- Aplicar chunking recursivo a la columna content
 , chunking=>ai.chunking_recursive_character_text_splitter('content')
   -- Agregar metadatos de otras columnas al embedding para mejorar la búsqueda
 , formatting=>ai.formatting_python_template('Blog title: $title url: $url blog chunk: $chunk')
);
-- El vectorizer actualiza los embeddings cuando cambia la tabla fuente
-- No se necesita ninguna otra acción del usuario
  • También define una función de chunking predeterminada, ya que los textos largos deben dividirse en varios fragmentos pequeños que se ajusten al límite de tokens del modelo de embeddings

Seguimiento de cambios en los datos fuente

  • Internamente, pgai Vectorizer detecta modificaciones en la tabla fuente (inserciones, actualizaciones y eliminaciones) y genera y actualiza embeddings vectoriales de forma asíncrona
  • Se construyó pgai Vectorizer para dos tipos de despliegue: self-hosted y totalmente gestionado en Timescale Cloud
  • En la implementación hospedada en la nube de pgai Vectorizer, la generación de embeddings usa capacidades cloud de la plataforma Timescale Cloud
  • En la versión open source de pgai Vectorizer, la generación de embeddings se realiza ejecutando workers externos
  • pgai Vectorizer guarda configuración e información de catálogo junto con datos internos clave de bookkeeping dentro de la base de datos

¿Dónde se generan realmente los embeddings?

  • El proceso real de embeddings ocurre en un proceso externo fuera de la base de datos
  • Esto reduce la carga sobre el servidor de base de datos y significa que el vectorizer no afecta la capacidad de la base de datos para atender consultas de la aplicación
  • También permite escalar fácilmente el trabajo de embeddings de forma independiente de otras tareas de la base de datos
  • El proceso primero lee la base de datos para verificar si hay trabajo por hacer
  • Si lo hay, lee los datos desde la base de datos, realiza chunking y formatting, llama a proveedores de modelos de embeddings como OpenAI para generar los embeddings y vuelve a escribir los resultados en la base de datos

Personalización del proceso

  • pgai Vectorizer es flexible: se pueden especificar las reglas de chunking y formato usadas para crear embeddings
  • En particular, se pueden configurar las columnas de la tabla fuente a vectorizar y las reglas de chunking y formatting para que los datos fuente encajen dentro del límite de tokens del embedding y para que cada embedding incluya los datos relevantes
  • En la versión Early Access de pgai Vectorizer, se pueden personalizar la selección de modelos de embeddings de OpenAI, las estrategias de chunking para dividir texto en fragmentos más pequeños, las opciones de formatting para inyectar contexto adicional en cada fragmento y la configuración de indexing personalizada para creación automática de índices y ajuste de rendimiento
  • Próximamente planean hacerlo aún más flexible permitiendo que los usuarios envíen su propio código Python para personalizar completamente el chunking, los embeddings y el formatting

Por ejemplo, a continuación se muestra un vectorizer configurado para dividir recursivamente archivos fuente HTML y crear embeddings de OpenAI a partir de los datos fuente. Se puede configurar el chunking y el formatting para ajustarlos a datos de aplicaciones como código, documentación, Markdown, etc.

-- Configuración avanzada de vectorizer
SELECT ai.create_vectorizer(
   'public.blogs'::regclass,
   destination => 'blogs_embedding_recursive',
   embedding => ai.embedding_openai('text-embedding-3-small', 1536),
   -- Aplicar chunking recursivo con configuración específica para contenido HTML
   chunking => ai.chunking_recursive_character_text_splitter(
       'content',
       chunk_size => 800,
       chunk_overlap => 400,
       -- Separadores con reconocimiento de HTML, ordenados de mayor a menor prioridad
       separator => array[
           E'

', -- dividir en secciones principales del documento
           E'

',    -- dividir en los límites de div
           E'

',
           E'

',      -- dividir en párrafos
           E'
',      -- dividir en saltos de línea
           E'
',     -- dividir en elementos de lista
           E'. ',        -- respaldo usando límites de oración
           ' '          -- último recurso: dividir por espacios
       ]
   ),
   formatting => ai.formatting_python_template('title: $title url: $url $chunk')
);

Opinión de GN⁺

  • pgai Vectorizer parece una herramienta potente e innovadora que puede simplificar enormemente la gestión de embeddings. La abstracción vectorizer reduce la carga de tener que administrarlos manualmente y garantiza que permanezcan sincronizados con los datos fuente.
  • En particular, parece muy útil al aplicar cambios como actualizar el modelo de embeddings o modificar la estrategia de chunking. En una base de datos vectorial tradicional, esos cambios pueden implicar un proceso complejo de escribir y coordinar código personalizado en varios sistemas, pero con pgai Vectorizer solo hace falta actualizar la configuración del vectorizer.
  • Además, administrar embeddings en una base de datos de propósito general como PostgreSQL puede evitar el problema de tener que orquestar varios sistemas especializados. Esto puede simplificar mucho el desarrollo de aplicaciones.
  • Un punto a considerar es que los embeddings reales se generan en un proceso externo de Python. Es una buena decisión de diseño para no afectar el rendimiento de la base de datos, pero significa que el proceso de generación de embeddings debe monitorearse y administrarse por separado.
  • En última instancia, pgai Vectorizer representa un avance importante en la forma de gestionar embeddings para aplicaciones de IA. A medida que más equipos lo adopten y den retroalimentación, es de esperarse que esta potente herramienta evolucione aún más. Integrar la gestión de embeddings en herramientas familiares como Postgres permitirá que más desarrolladores aprovechen capacidades avanzadas de IA.

1 comentarios

 
GN⁺ 2024-10-30
Opiniones en Hacker News
  • Se está sobreestimando la sobrecarga de la sincronización de datos, y la mayoría de los flujos de trabajo basados en embeddings no tienen muchas actualizaciones ni eliminaciones. Incluso en conjuntos de datos pequeños es difícil percibir los problemas de consistencia. Aun así, sigue siendo genial no tener que preocuparse por la sincronización de datos

    • La mayor desventaja de guardar embeddings en una base de datos Postgres es que la carga de trabajo es muy distinta. Los índices HNSW consumen muchos recursos y pueden causar problemas de contención. Si se mueve la base de datos, vuelven a aparecer los problemas de consistencia
    • Hay una pregunta sobre cómo interactúa con el filtrado. Se preguntan si se pueden aprovechar índices parciales y si todavía existen las limitaciones en la implementación HNSW de pgvector
  • Como empleado de Elastic, menciona que Elasticsearch agregó recientemente un tipo de dato llamado semantic_text. Este divide automáticamente el texto en chunks, calcula y almacena embeddings. Las consultas también se simplifican, lo que reduce el I/O y hace más simple el código del cliente

  • Presenta una herramienta para PostgreSQL que replantea los embeddings vectoriales como índices de base de datos. Por ahora solo soporta OpenAI, pero pronto planean agregar soporte para modelos locales y OSS. Espera comentarios y reacciones

  • Plantea dudas sobre usar FAISS como una única base de datos. Sería como un sqlite para embeddings vectoriales, permitiendo almacenar juntos los metadatos y los vectores para mantener sus relaciones

  • Se muestra positivo respecto al uso de vectores en Postgres, y plantea dudas sobre el orden del filtrado al incluir búsqueda vectorial y lógica dentro de consultas SQL. Le gusta la DX de pg_vector, pero filtrar después de la búsqueda vectorial puede afectar la velocidad

  • Menciona que guardar embeddings en bruto en una base de datos vectorial es como guardar los n-gramas en bruto del texto en una base de datos. Tiene más sentido guardar los documentos

  • Menciona que usa sqlite-vec y FTS5 en SQLite, y que le resultan muy útiles

  • Construyó un ORM de PostgreSQL en Node.js para poder escribir código que incluya campos vectoriales. Esto permite consultar datos o contenido embebido, y definir cómo almacenar como embeddings los campos de un modelo

  • Menciona que las Materialized Views son buenas

  • Menciona que las apps de IA que usan chunks basados en caracteres no han pasado de la etapa de PoC