Significado como coordenadas: de los embeddings a las bases de datos vectoriales y RAG
Los embeddings, la similitud coseno, las bases de datos vectoriales y el ciclo RAG explicados en cuatro frases cortas sobre perros, gatos y París, para aumentar los clics en búsquedas semánticas.
Fuentes: Meaning as Coordinates: Semantic Search, Vector Databases, and RAG
Un cuadro de búsqueda que no muestra resultados para “un buen animal de compañía para una persona activa”, a pesar de que la base de conocimientos está llena de consejos sobre perros, demuestra exactamente dónde falla la coincidencia de palabras clave. Solucionarlo implica tratar el significado como una posición en el espacio. Esa idea sustenta la búsqueda semántica, las bases de datos vectoriales y la generación mejorada por recuperación de información, y un pequeño ejemplo es suficiente para comprender todo ello.
El ejemplo utilizado en todo el texto
Imagínese una base de conocimientos en miniatura formada por cuatro oraciones:
1. Dogs are loyal and need daily walks and exercise
2. Cats are independent pets that groom themselves
3. Golden retrievers are friendly family dogs
4. The capital of France is Paris
Un usuario pregunta:
"What's a good pet for an active person who exercises a lot?"
La pregunta nunca contiene las palabras “perro” ni “caminar”. Una búsqueda simple por palabras clave no daría ningún resultado útil. Sin embargo, una máquina aún puede ofrecer la respuesta correcta, porque compara dónde se encuentran los textos en un espacio de significado y no qué palabras comparten.
Significado similar, puntos cercanos
Un vector es simplemente una fila de números que codifica el significado de un texto. Dado que los significados similares generan vectores similares, encontrar textos relacionados se convierte en encontrar puntos cercanos. Esto transforma un problema lingüístico en uno geométrico, que es la base de las búsquedas modernas, de las recomendaciones y de RAG, la técnica que permite a un modelo de lenguaje consultar una biblioteca externa para dejar de inventar cosas.
Cuando el significado es un conjunto de coordenadas, trabajar con el significado implica trabajar con la distancia y la dirección, algo que las computadoras hacen excepcionalmente bien.
Embebidos para pasajes completos
Los vectores a nivel de palabra no son suficientes para buscar documentos. Se necesita un vector por oración, párrafo o página. Los modelos Transformer pueden generar uno: al introducir un fragmento de texto, se obtiene un vector, generalmente llamado embedding, que resume su significado.
"Dogs need daily walks" ──► [ 0.91, 0.08, -0.30, ... ] (e.g. 384 numbers)
"The capital is Paris" ──► [-0.05, 0.62, 0.44, ... ]
Un embedding de oración comprime un pasaje en una lista de números de longitud fija. Dos textos sobre el mismo tema generan listas similares, mientras que los textos no relacionados producen listas muy diferentes. Cada número por sí solo no significa nada para una persona. Lo importante es cómo se relacionan entre sí, y nadie los lee directamente; solo se comparan.
La imagen a tener en mente
Imagínese cada texto como un punto en el espacio. Los textos con significados similares se encuentran cerca unos de otros, mientras que los no relacionados están muy separados.
(a simplified 2-D "meaning space")
dog walks • • golden retriever ← the "dogs" neighborhood
\ /
(pets)
cat grooming • • Paris ← far away, different topic
En ese mapa simplificado, las dos oraciones sobre perros se agrupan juntas, la oración sobre el gato está cerca de ellas porque también trata sobre una mascota, y la oración sobre París se encuentra en una región completamente distinta. Los espacios de embedding reales tienen cientos de dimensiones, pero la intuición es idéntica: los significados relacionados se corresponden con puntos cercanos. Todo lo que sigue es una forma de encontrar los puntos más cercanos.
Búsqueda por palabras clave frente a búsqueda semántica
La búsqueda por palabras clave compara palabras. Al buscar “ejercicio”, se ignorará un documento que hable de “caminatas diarias”, ya que no comparten ninguna palabra. Es rápida pero literal, y no captura el significado.
La búsqueda semántica compara significados. La consulta se convierte en un vector, y se devuelven los vectores de los documentos más cercanos a él, independientemente de las palabras que utilicen. Aquí está el ranking generado para el ejemplo, utilizando las puntuaciones de similitud reales:
Query: "a good pet for an active person who exercises"
0.999 ############################# Golden retrievers are friendly family dogs
0.995 ############################# Dogs are loyal and need daily walks and exercise
0.398 ########### Cats are independent pets that groom themselves
0.059 # The capital of France is Paris
La consulta no comparte palabras clave con las oraciones sobre perros, pero ambas obtienen la puntuación más alta, alrededor de 1.0. La oración sobre gatos queda en el medio porque sigue siendo una mascota, mientras que la oración sobre París está cerca de cero. La búsqueda por palabras clave no habría devuelto ningún resultado. Por eso la búsqueda semántica parece inteligente: reconoce que una persona activa que hace ejercicio y un perro que necesita paseos diarios se refieren más o menos a lo mismo. La diferencia entre la búsqueda por palabras clave y la búsqueda semántica es la diferencia entre no encontrar resultados y obtener la respuesta que realmente se buscaba.
Medir la cercanía con similitud coseno
La herramienta habitual para medir cuán cercanos están dos vectores es la similitud coseno. Esta mide el ángulo entre dos flechas e ignora su longitud.
- Las flechas que apuntan en la misma dirección dan una similitud cercana a 1, lo que significa un significado muy similar.
- Las flechas en ángulo recto dan una similitud cercana a 0, lo que significa que no están relacionadas.
- Las flechas que apuntan en direcciones opuestas indican una similitud cercana a -1, lo que significa un significado opuesto.
Un ángulo pequeño entre la consulta y un documento sobre perros se ve así:
^ query
│ /
│/ small angle → cosine ≈ 1 (similar)
└──────► dog doc
Y un ángulo amplio del documento de París:
^ query
│
└──────► Paris doc big angle → cosine ≈ 0 (unrelated)
Se utiliza el ángulo en lugar de la longitud para que los textos largos y cortos se comparen de manera justa. Los cálculos caben en una sola línea: se multiplican los vectores entre sí y luego se normalizan.
import numpy as np
def cosine(a, b):
return a @ b / (np.linalg.norm(a) * np.linalg.norm(b))
Esa pequeña función está detrás de cada puntuación en la clasificación anterior. Las puntuaciones van de -1 a 1, y un valor cercano a 1 indica que los dos textos significan lo mismo.
Bases de datos vectoriales para búsquedas a gran escala
El ejemplo incluye cuatro documentos. Los sistemas reales albergan millones o miles de millones de ellos, como cada ticket de soporte, página de producto o párrafo de la documentación de la empresa. Comparar una consulta con mil millones de vectores uno por uno en cada búsqueda es demasiado lento.
Existen bases de datos vectoriales para esto. Son almacenes diseñados para hacer una tarea de manera eficiente: tomar un vector de consulta y devolver rápidamente los vectores almacenados más cercanos. Se basan en búsquedas de vecino más cercano aproximadas, un conjunto de índices inteligentes que encuentran las coincidencias casi más cercanas omitiendo la mayoría de las comparaciones. Se sacrifica un poco de precisión a cambio de una gran mejora en la velocidad.
documents ─► embed ─► [ vector database ]
│ stores millions of vectors
│ + a smart index (ANN)
query ─► embed ─────────► │
▼
top-k nearest matches (in milliseconds)
Los documentos pasan por el modelo de incrustación una sola vez y se guardan junto con un índice. Cuando llega una pregunta, también se incrusta, y la base de datos responde al instante con los k elementos que mejor se ajustan, sin importar cuántos vectores almacene. Entre los productos en este campo se encuentran FAISS, Pinecone, Weaviate, Chroma y Milvus, además de pgvector, una extensión que integra la búsqueda vectorial en PostgreSQL convencional. Los detalles varían, pero todos ellos almacenan incrustaciones y encuentran elementos similares rápidamente. En resumen, una base de datos vectorial es un motor de búsqueda para el significado.
Qué errores cometen los modelos de lenguaje sencillo
Los modelos de lenguaje grandes son impresionantes, pero por sí solos presentan tres debilidades persistentes:
- Alucinaciones. Cuando no están seguros, generan respuestas fluidas, seguras y erróneas.
- Límite de conocimiento. Solo conoce lo que había en los datos de entrenamiento, congelados en una fecha anterior.
- Sin conocimiento de sus datos. Los documentos internos, las notas privadas y la reunión de la semana pasada son desconocidos para el modelo.
You: "What's our refund policy?"
Plain LLM: "Typically, refunds are offered within 30 days..." ← a guess, not YOUR policy
Al preguntarle sobre la política de reembolsos, un modelo básico responde de memoria con una suposición plausible, y no con la política real de la empresa. Esto resulta arriesgado para cualquier información factual o privada. Lo necesario es proporcionar los datos correctos justo cuando el modelo responde, sin necesidad de reentrenamiento, y RAG hace exactamente eso.
Generación mejorada por recuperación de información
RAG combina todo lo anterior en un único proceso. En lugar de pedirle al modelo que responda de memoria, primero se recuperan los documentos relevantes mediante búsqueda semántica, y luego se le pide al modelo que responda basándose en ellos. El nombre es descriptivo: la recuperación busca el texto relevante, “mejorado” significa añadirlo al prompt, y la generación permite que el modelo escriba la respuesta.
1. Question ─► embed ─► search the vector DB ─► top relevant chunks
│
2. Build a prompt: "Using ONLY the context below, answer the question.
Context: [retrieved chunks]
Question: [user's question]"
│
3. LLM generates an answer grounded in the retrieved text ─► with sources
Ejecutando el ejemplo con él:
Question: "What's a good pet for an active person?"
→ retrieves docs 1 & 3 (the dog sentences, from Figure 3)
→ prompt: "Using this context: [Dogs need daily walks and exercise;
Golden retrievers are friendly family dogs] — answer the question."
→ LLM: "A dog — especially a golden retriever — is a great fit, since
they need daily walks and exercise. (Source: docs 1, 3)"
La respuesta ahora está fundamentada. Se basa en documentos reales que controla el propietario, y puede indicar de dónde proviene cada hecho. Hay muchas menos respuestas inventadas que logran pasar desapercibidas. RAG es una búsqueda semántica combinada con un modelo de lenguaje: se recuperan los hechos adecuados y luego el modelo redacta la respuesta.
El proceso práctico y su principal trampa
RAG tiene dos fases. La configuración se realiza una sola vez, mientras que las consultas se realizan cada vez que alguien hace una pregunta.
── SETUP (once) ── ── QUERY (every question) ──
documents user question
│ split into chunks │ embed
│ embed each chunk │ search vector DB
│ store in vector DB │ get top-k chunks
▼ │ build prompt with chunks
[ vector database ] ◄───── search ──────┤ send to LLM
▼
grounded answer
Los documentos se dividen en fragmentos, se incrustan y se almacenan una sola vez. Cada pregunta se incrusta, se compara con el almacenamiento, y los mejores fragmentos se envían al modelo para que genere la respuesta final.
El problema radica en la división en fragmentos, es decir, en cómo se dividen los documentos antes de incrustarlos. Los fragmentos demasiado grandes mezclan varios temas en un único vector, lo que genera coincidencias poco precisas. Los fragmentos demasiado pequeños pierden el contexto, y la respuesta puede quedar incompleta. Elegir el tamaño adecuado de los fragmentos es una de las decisiones más importantes en un sistema RAG funcional, y sirve como recordatorio de que la preparación de datos, aunque no sea tan llamativa, influye en todo lo que sucede posteriormente.
Lo mismo en código
La parte de recuperación de RAG, que consiste en una búsqueda semántica básica, solo requiere unas pocas líneas de código en NumPy. Recibe los vectores de algunos documentos además de uno para la consulta y ordena los documentos según la similitud coseno:
import numpy as np
def cosine(a, b):
return a @ b / (np.linalg.norm(a) * np.linalg.norm(b))def search(query_vec, doc_vecs, docs, k=2):
scores = [(cosine(query_vec, v), d) for v, d in zip(doc_vecs, docs)]
return sorted(scores, reverse=True)[:k] # top-k most similar
Al alimentar los cuatro vectores de mascotas y de París, junto con la consulta de persona activa, se devuelven primero los dos documentos relacionados con perros, siguiendo el ranking mostrado anteriormente. Eso es búsqueda semántica en unas pocas líneas de código.
Un proyecto real no crea los vectores manualmente. En su lugar, utiliza un modelo de embedding y un almacén de vectores, y el código se parece más o menos a esto:
# Illustrative real-world usage (libraries download a model, so not run here)
from sentence_transformers import SentenceTransformer
import chromadb
model = SentenceTransformer("all-MiniLM-L6-v2") # turns text into vectors
db = chromadb.Client().create_collection("pets")db.add(documents=my_docs, embeddings=model.encode(my_docs).tolist(),
ids=[str(i) for i in range(len(my_docs))])q = "a good pet for an active person"
hits = db.query(query_embeddings=model.encode([q]).tolist(), n_results=2)
# hits now holds the top-2 most semantically similar documents
Las bibliotecas se encargan de la mayor parte del trabajo, pero en esencia realizan la misma búsqueda de similitud por coseno. La búsqueda semántica consiste en unas pocas líneas de cálculos matemáticos con vectores, y las herramientas reales integran esa idea con velocidad y escala.
Todo el proceso
El texto comienza como caracteres y tokens, luego se convierte en embeddings, después adquiere contexto mediante la atención dentro de un transformador, y finalmente se transforma en un mapa de conocimiento buscable que hace que los modelos de lenguaje sean precisos y útiles.
raw text
→ characters / tokens / embeddings [article 1: From Characters to Meaning]
→ attention turns them into context-aware
vectors inside a transformer [article 2: Attention, Explained Simply]
→ those vectors become coordinates we can
store, search, and retrieve [article 3: this one]
→ semantic search (find by meaning)
→ vector databases (search at scale)
→ RAG (ground an LLM in real data)
El hilo conductor de todo esto es una idea que se va desarrollando: el significado es un punto en el espacio. Primero se aplica a las palabras, luego a las oraciones en contexto, y finalmente a bibliotecas completas de documentos que pueden buscarse y analizarse.
Hay otra distinción que vale la pena tener en cuenta. RAG permite que un modelo acceda al conocimiento sin cambiar al modelo en sí, como si se le entregaran notas para leer en el momento de responder. El ajuste fino es un enfoque diferente, en el que los pesos internos del modelo se modifican mediante entrenamiento con ejemplos. RAG proporciona conocimiento para leer, mientras que el ajuste fino cambia la naturaleza del modelo. Saber cuál utilizar es una habilidad práctica por sí misma.
Leer más
- Notas prácticas: Los límites de la búsqueda vectorial en RAG — Similitud coseno y el — Guía práctica de Notas prácticas: Los límites de la búsqueda vectorial en RAG — Similitud coseno y el: contratos, verificaciones y espacios para código listo para usar para los equipos que implementan este patrón.
- Notas prácticas: Bases de datos vectoriales para RAG en producción: Indexación, búsqueda híbrida — Guía práctica de Notas prácticas: Bases de datos vectoriales para RAG en producción: Indexación, búsqueda híbrida: contratos, verificaciones y espacios para código listo para usar para los equipos que implementan este patrón.