Búsqueda semántica en PostgreSQL con pgvector y Node.js, sin necesidad de LLM
Búsqueda semántica en PostgreSQL con pgvector y Node.js, sin LLM: embeddings de MiniLM, chunks, un índice IVFFlat, operadores de distancia y cómo leer las puntuaciones.
Fuentes: Talk to Your Database Like a Human — No LLM Required: Semantic Search with Node.js + PostgreSQL
Una base de datos puede responder a preguntas formuladas en inglés corriente sin necesidad de ningún modelo de lenguaje en el proceso. Lo que lo hace posible es la búsqueda vectorial. Con Node.js, PostgreSQL y la extensión pgvector, se puede crear un sistema que haga coincidencias basadas en la intención en lugar de en palabras clave, y el único modelo utilizado es un pequeño modelo de embedding que convierte el texto en números.
Las bases de datos relacionales siempre han sido excelentes para almacenar y recuperar datos, siempre y cuando se formule la pregunta exacta. Las coincidencias exactas, los filtros y las consultas estructuradas son poderosos pero limitados. Las bases de datos vectoriales parecen abordar un problema diferente: buscar contenido no estructurado según su significado, y no según las palabras que contiene.
Cuatro términos que vale la pena aclarar
Token. Es la pieza de texto más pequeña con la que trabaja un modelo. Los tokens no siempre son palabras completas. Un token puede ser una palabra entera como “hello”, un fragmento (por lo que “unbelievable” podría convertirse en “un”, “believ” y “able”), un único carácter como “!”, o un poco de puntuación o espacio en blanco. Una frase como “ChatGPT es genial” podría dividirse en “Chat”, “G”, “PT”, “es” y “genial”.
Chunk. Es una porción pequeña y autónoma de un documento más grande, generalmente unas pocas oraciones o un párrafo. Incluir todo el documento de una sola vez no funciona bien, por lo que primero se divide en chunks. El uso de chunks acelera el procesamiento, mejora la precisión de la búsqueda y mantiene los resultados relevantes para la consulta.
Embedding. Un sustituto numérico de un texto, imagen o audio que captura su significado. Un modelo de aprendizaje automático, como MiniLM, lo genera. Puedes considerar un embedding como la idea que subyace a los datos.
Vector. La forma en que se almacena realmente un embedding: un arreglo de números.
[0.2, -0.5, 0.9, ...]
Esa es la estructura que se mantiene en memoria y en PostgreSQL una vez instalada una extensión como pgvector.
En resumen, la idea es la siguiente: las palabras, oraciones o imágenes se convierten en embeddings. Las cosas con significados similares terminan con vectores que se encuentran cerca unos de otros, mientras que las cosas no relacionadas quedan más separadas. Una cadena como “Hello world” se transforma en una larga lista de números flotantes:
// "Hello world" turns into this embedding:
const embedding = [0.01, -0.42, 0.15, ..., 0.99]; // ← this is a vector
Y esa lista se guarda junto al texto original:
INSERT INTO documents (content, embedding)
VALUES ('Hello world', embedding);
Por qué una base de datos relacional no es suficiente
Un RDBMS tradicional funciona con tablas, filas y columnas. Maneja solicitudes como “todos los tickets con estado OPEN” o “usuarios creados después de 2024” sin esfuerzo. Sin embargo, las aplicaciones modernas también tratan con documentos, conversaciones, imágenes y audio. La búsqueda por coincidencia exacta no sirve de mucho con estos tipos de datos.
Una base de datos vectorial almacena embeddings junto con los datos y encuentra elementos por similitud y contexto. Así, en lugar de solicitar documentos que contengan la palabra “error”, se pueden buscar documentos sobre problemas de autenticación, y se obtendrán incluso cuando “error” nunca aparezca. La comparación es una distancia matemática entre vectores, no una coincidencia de texto.
El flujo habitual es el siguiente:
- Llega el contenido en bruto: documentos, tickets o cualquier otra cosa.
- Un modelo de embedding lo convierte en vectores.
- Los vectores se almacenan, por ejemplo, en PostgreSQL con pgvector.
- Un índice de vecino más cercano aproximado (ANN) acelera las búsquedas.
- La consulta del usuario también se convierte en un vector.
- La base de datos devuelve los vectores más cercanos a ella, es decir, los de significado más similar.
Esto permite:
- Búsqueda semántica, basada en el significado de una consulta y no solo en sus palabras exactas.
- Memoria a largo plazo para un LLM, al conservar interacciones, documentos o hechos anteriores que el modelo puede recordar aunque no estuvieran en sus datos de entrenamiento.
- Recomendaciones, al encontrar elementos o comportamientos que se parecen entre sí en el espacio de embedding.
- Búsqueda de similitud en texto, imágenes, audio o video.
PostgreSQL como almacén de vectores
No es necesario adoptar una nueva base de datos para todo esto. Con pgvector, PostgreSQL puede almacenar embeddings directamente, ejecutar consultas de similitud y utilizar índices como IVFFlat para mantener una alta velocidad. La base de datos que ya utiliza simplemente adquiere una nueva capacidad: pasar de almacenar datos a poder comparar su significado. La búsqueda deja de centrarse en la coincidencia de palabras y comienza a centrarse en la coincidencia de significados.
Configuración paso a paso
1. Instale PostgreSQL e active pgvector. Instale PostgreSQL desde la página oficial de descargas, conéctese y active la extensión:
CREATE EXTENSION IF NOT EXISTS vector;
2. Cree la tabla de documentos. Esta contiene el texto en bruto y su representación vectorial. El 384 mencionado en la definición corresponde al tamaño de salida del modelo all-MiniLM-L6-v2.
-- Note: 384 is the embedding size output by all-MiniLM-L6-v2
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
content TEXT,
embedding VECTOR(384)
);
3. Agregar un índice vectorial. Para mantener eficiente la búsqueda de similitud, utilice un índice de vecino más cercano aproximado:
CREATE INDEX documents_embedding_idx
ON documents
USING ivfflat (embedding vector_l2_ops)
WITH (lists = 100);
Esto selecciona IVFFlat para búsquedas aproximadas rápidas, mide con la distancia L2 (euclidiana) y divide los vectores en 100 clústeres.
4. Alinear el operador de consulta con el índice. El operador de su consulta debe coincidir con la clase de operadores con la que construyó el índice. pgvector ofrece varios operadores, cada uno emparejado con su propia clase. El ejemplo aquí utiliza <#> y configura vector_l2_ops. Tenga en cuenta que en la documentación de pgvector la distancia L2 normalmente se representa con <->, mientras que <#> corresponde al producto interno negativo, así que verifique que su consulta e índice estén alineados.
5. Ejecutar el proyecto. Un ejemplo funcional completo se encuentra en un repositorio de GitHub llamado vectorgarquer/vectorized-database-embeddings. Clónelo o cree una rama a partir de él, y luego instale las dependencias necesarias:
npm install
Copie .env.example a un archivo .env en la raíz del proyecto y complete los detalles de conexión a PostgreSQL. Luego, inícielo:
npm start
6. Observe cómo realiza la búsqueda. Una vez en marcha, el programa se conecta, inserta los embeddings y ejecuta búsquedas semánticas sin necesidad de más entrada. A partir de ahí puedes proporcionarle tus propios datos y consultas. La búsqueda de ejemplo es “¿Qué significa la IA generativa?”, y los resultados que encuentra en la base de datos se muestran de esta manera:
Search Results:
[1] Distance: -0.7562
n be represented in another modality such as text.
2.2 A Model-, System-, and Application-Level View
of Generative AI
2.2.1 Model-Level View
A generative AI model is a type of machine learning
architecture that uses AI algorithms to create novel data
instances, drawing upon the patterns and relationships
observed in the training data. A generative AI model is of
critically central yet incomplete nature, as it requires fur-
ther fine-tuning to specific tasks thro
[2] Distance: -0.7562
n be represented in another modality such as text.
2.2 A Model-, System-, and Application-Level View
of Generative AI
2.2.1 Model-Level View
A generative AI model is a type of machine learning
architecture that uses AI algorithms to create novel data
instances, drawing upon the patterns and relationships
observed in the training data. A generative AI model is of
critically central yet incomplete nature, as it requires fur-
ther fine-tuning to specific tasks thro
[3] Distance: -0.7562
n be represented in another modality such as text.
2.2 A Model-, System-, and Application-Level View
of Generative AI
2.2.1 Model-Level View
A generative AI model is a type of machine learning
architecture that uses AI algorithms to create novel data
instances, drawing upon the patterns and relationships
observed in the training data. A generative AI model is of
critically central yet incomplete nature, as it requires fur-
ther fine-tuning to specific tasks thro
[4] Distance: -0.7562
n be represented in another modality such as text.
2.2 A Model-, System-, and Application-Level View
of Generative AI
2.2.1 Model-Level View
A generative AI model is a type of machine learning
architecture that uses AI algorithms to create novel data
instances, drawing upon the patterns and relationships
observed in the training data. A generative AI model is of
critically central yet incomplete nature, as it requires fur-
ther fine-tuning to specific tasks thro
[5] Distance: -0.7094
assistants, personalized education and service, and digital
art. As such, generative AI has substantial implications for
BISE practitioners and scholars as an interdisciplinary
research community. In our Catchword article, we offered
a conceptualization of the principles of generative AI along
a model-, system-, and application-level view as well as a
social-technical view and described limitations of current
generative AI. Ultimately, we provided an impactful
rese
Leer la salida
Después de ejecutarlo, se obtiene una lista con este formato:
Search Results:
[1] Distance: -0.7562
...
[5] Distance: -0.7094
...
La distancia indica cuán cerca está un fragmento almacenado del embedding de la consulta. Tanto el fragmento como la consulta se convierten en vectores, y PostgreSQL con pgvector mide cuán lejos están entre sí. La regla es sencilla: cuanto menor sea la distancia, más similar será el contenido.
Los valores son negativos, como por ejemplo:
-0.7562
Eso se debe a que el operador <#> devuelve un valor negado para que un ordenamiento ordinario coloque primero las filas más cercanas. En la práctica, un número más negativo indica una coincidencia más cercana y relevante, mientras que un número más cercano a cero indica una coincidencia menos fuerte.
Al observar la clasificación, los resultados del 1 al 4 comparten la misma puntuación de -0.7562, por lo que son igualmente relevantes para la consulta. El resultado 5 tiene una puntuación de -0.7094, lo cual sigue siendo relevante pero con menos similitud.
También podrías notar varios resultados con texto casi idéntico. Eso es esperado. El documento de origen se dividió en fragmentos; los fragmentos adyacentes se superponen o repiten contenido similar, y cada uno tiene su propio embedding.
Qué muestra el resultado
Aunque no había un LLM en el momento de la consulta, el sistema seguía comprendiendo el significado y no solo las palabras clave, recuperaba el texto que se ajustaba al contexto y lo clasificaba según la similitud vectorial. Los fragmentos devueltos estaban relacionados con modelos de IA generativa, una visión a nivel de modelo y arquitecturas de aprendizaje automático, por lo que la búsqueda funcionaba claramente a nivel de conceptos en lugar de palabras exactas.
El resultado es un motor de búsqueda semántica que funciona dentro de PostgreSQL. No se necesita ningún LLM para realizar consultas, no existe una base de datos vectorial separada, y los embeddings junto con pgvector se encargan de todo el trabajo.
Leer más
- Cache Semántico para Agentes de LLM con Redis: Reduce Costos y Tiempos de Respuesta — Cómo el cache semántico disminuye los gastos y la latencia en los LLM: embeddings, umbrales, Redis y RedisVL, ajuste de precisión y almacenamiento temporal de subpreguntas dentro de los flujos de trabajo de los agentes.
- Por qué los Agentes de Análisis de IA Necesitan una Capa Semántica en Lugar de SQL Bruto — La conversión de texto a SQL en tablas de almacén brutas crea métricas arbitrarias e ignora las reglas de acceso. Descubra cómo una capa semántica como Cube, junto con MCP, proporciona a los agentes un significado empresarial estructurado.