Qué es un embedding: el significado hecho geometría
Un embedding es la traducción de un fragmento de texto a un vector denso de cientos de números, colocado en un espacio donde la cercanía geométrica aproxima la cercanía de sentido. Qué hace exactamente el modelo que los produce, por qué ninguna de esas dimensiones tiene nombre, cómo la similitud del coseno mide parecido semántico ignorando la magnitud, en qué se diferencia buscar por significado de buscar por coincidencia literal, y por qué ninguna base de datos convencional puede responder en milisegundos la pregunta que un índice vectorial responde de serie.
Cada almacén que has aprendido hasta aquí responde preguntas de identidad. KV te devuelve el valor de una clave exacta, D1 filtra las filas que cumplen un predicado, R2 te entrega el objeto que nombraste. Todos comparten un supuesto invisible —que sabes describir lo que buscas mediante una condición literal— y ese supuesto se derrumba en cuanto la pregunta es “dame lo que hable de lo mismo que esto”. Un embedding es la pieza que rompe ese muro: convierte un texto en un punto de un espacio de cientos de dimensiones, situado de tal modo que las cosas con sentido parecido caen cerca unas de otras. A partir de ahí, buscar por significado deja de ser un problema de lingüística y pasa a ser uno de geometría.
- Definir un embedding como un vector denso que codifica el significado de un fragmento.
- Entender por qué la proximidad geométrica aproxima la proximidad semántica.
- Distinguir la búsqueda por coincidencia literal de la búsqueda por similitud.
- Situar Vectorize como el almacén que hace viable esa búsqueda a escala.
Del texto a un punto en el espacio
Un modelo de embeddings es una función determinista que toma un fragmento de texto y devuelve una lista fija de números en coma flotante. Si el modelo declara 768 dimensiones, cualquier entrada —una palabra suelta o un párrafo entero— sale convertida en exactamente 768 valores. El vector se llama denso porque casi todas sus posiciones cargan información, a diferencia de las representaciones dispersas clásicas, donde la inmensa mayoría de las casillas eran ceros y cada casilla correspondía a una palabra concreta del vocabulario.
// el modelo convierte texto en un vector denso de 768 numeros
const { data } = await env.AI.run("@cf/google/embeddinggemma-300m", {
text: ["El gato duerme sobre el tejado"],
});
const vector = data[0]; // 768 valores en coma flotante
El campo text acepta un array porque embeber es una operación que se amortiza en lote: pasarle treinta fragmentos de golpe cuesta mucho menos que treinta llamadas sueltas, y por eso toda canalización de indexación seria agrupa antes de invocar. La respuesta llega en data con un vector por cada entrada y en el mismo orden en que los mandaste, correspondencia que conviene no perder si vas a construir identificadores a partir de la posición.
// embeber en lote: un vector por entrada, en el mismo orden
const { data } = await env.AI.run("@cf/google/embeddinggemma-300m", {
text: fragmentos, // un array de cadenas
});
console.log(data.length === fragmentos.length); // true
Hay un límite silencioso que conviene conocer desde el principio. Cada modelo admite un máximo de tokens de entrada y lo que sobra se descarta sin avisar: si le entregas un documento de veinte páginas a un modelo que acepta unos cientos de tokens, obtendrás un vector perfectamente válido que solo representa el principio. Ese truncado invisible es una de las causas más frecuentes de sistemas que recuperan mal sin dar ninguna señal de error, y la razón de que la siguiente decisión —cómo trocear— pese tanto.
Lo desconcertante, y lo decisivo, es que ninguna de esas 768 posiciones tiene nombre. No existe una dimensión “trata de animales” y otra “tono formal”: el modelo aprendió durante su entrenamiento un sistema de coordenadas propio y distribuido, donde el sentido no reside en ejes aislados sino en la posición conjunta de todos ellos. Por eso un embedding es opaco a la inspección humana y transparente a la comparación. No puedes leerlo, pero puedes medir distancias con él, y esa asimetría es justo lo que lo hace útil.
Esa geografía aprendida tiene una propiedad que sorprende la primera vez y que a ti, trabajando en español, te importa especialmente. Los modelos multilingües sitúan una frase y su traducción prácticamente en el mismo punto, porque durante el entrenamiento aprendieron que expresan el mismo contenido. La consecuencia práctica es notable: con el modelo adecuado puedes preguntar en español y recuperar documentos escritos en inglés sin traducir nada por el camino, algo sencillamente inalcanzable para cualquier buscador basado en palabras. Y a la inversa, un modelo entrenado solo en inglés colocará tu corpus en español en una región empobrecida de su espacio, con resultados mediocres que ningún ajuste posterior arregla.
De ahí se sigue una consecuencia que conviene fijar antes que ninguna otra: el espacio pertenece al modelo. Dos modelos distintos producen dos geografías incompatibles aunque ambos declaren 768 dimensiones, porque cada uno colocó los conceptos donde su entrenamiento decidió. Comparar el vector de un modelo con el de otro no arroja un resultado malo, arroja un resultado sin sentido, como medir la distancia entre una coordenada de Madrid y una latitud marciana.
La similitud es un ángulo
Si el significado es una posición, el parecido es una distancia, y hay más de una forma de medirla. La que domina en texto es la similitud del coseno: mide el ángulo entre dos vectores e ignora por completo su longitud. Esa indiferencia a la magnitud no es un capricho, es lo que quieres cuando comparas un fragmento largo con uno corto y te interesa la dirección del significado, no cuánta tinta se gastó en expresarlo.
| Métrica | Qué mide | Cuándo encaja |
|---|---|---|
cosine |
El ángulo entre dos vectores, indiferente a su longitud | Texto y modelos normalizados: el valor por defecto sensato |
euclidean |
La distancia en línea recta entre los dos puntos | Espacios donde la magnitud del vector sí porta información |
dot-product |
La proyección de uno sobre otro, sensible a la magnitud | Modelos entrenados con ese objetivo, típicos en recomendadores |
La elección no es libre: cada modelo se entrenó optimizando una de estas funciones, y usar otra degrada los resultados sin producir ningún error visible. Lo veremos con detalle al crear el índice, porque esa decisión queda congelada para siempre.
El cálculo no tiene ningún misterio y merece la pena escribirlo una vez a mano, aunque en producción nunca lo hagas tú. Es el producto escalar de los dos vectores dividido por el producto de sus longitudes, y ese denominador es exactamente lo que anula el efecto de la magnitud.
// la similitud del coseno, escrita a mano una sola vez en la vida
function coseno(a: number[], b: number[]): number {
let punto = 0, normaA = 0, normaB = 0;
for (let i = 0; i < a.length; i++) {
punto += a[i] * b[i];
normaA += a[i] * a[i];
normaB += b[i] * b[i];
}
return punto / (Math.sqrt(normaA) * Math.sqrt(normaB));
}
Muchos modelos entregan sus vectores ya normalizados a longitud unitaria, y ese detalle tiene una consecuencia práctica curiosa: cuando ambas longitudes valen uno, el denominador desaparece y el coseno se reduce al producto escalar. Por eso, con esos modelos, cosine y dot-product ordenan los resultados exactamente igual y la discusión sobre cuál elegir se vuelve puramente formal.
El resultado de comparar dos vectores es un escalar al que llamamos score. Con cosine, ese número se mueve en un rango donde el máximo indica dirección idéntica y los valores intermedios indican parecido decreciente. Interpretarlo exige recordar de dónde sale: es la afinidad geométrica que el modelo aprendió, no un porcentaje de verdad ni una medida de relevancia calibrada para tu dominio.
flowchart LR T[texto de origen] --> M[modelo de embeddings] M --> V[vector denso] V --> I[indice vectorial] Q[consulta del usuario] --> M2[el mismo modelo] M2 --> QV[vector de consulta] QV --> I I --> R[los k vecinos mas cercanos] style M fill:#89b4fa,color:#11111b style I fill:#cba6f7,color:#11111b
Hay un matiz sobre esa simetría que separa a quien entiende el mecanismo de quien lo repite. Documento y consulta no se parecen en nada como textos: uno es un párrafo declarativo y la otra una pregunta breve, con otro registro y otra longitud. Que un modelo de embeddings los coloque cerca cuando tratan del mismo tema no es evidente, es precisamente lo que aprendió a hacer durante su entrenamiento, y por eso su calidad se mide sobre pares de pregunta y pasaje relevante. Elegir un modelo para recuperación es elegir uno entrenado para tender ese puente entre dos formas de decir muy distintas.
Fíjate en la simetría del diagrama, porque es la regla de oro de todo el nivel: el mismo modelo tiene que embeber los documentos y las consultas. En el momento en que indexas con un modelo y preguntas con otro, la geometría se rompe y los resultados dejan de significar nada, aunque el sistema siga devolviendo números con toda la apariencia de normalidad.
Por qué tu base de datos de siempre no sirve
Podrías pensar que esto se resuelve con una tabla y un poco de SQL. Guarda el vector como un blob en D1, recórrelos todos, calcula el coseno contra cada uno y ordena. Con mil documentos funciona; con un millón, cada consulta obliga a leer un millón de filas y hacer un millón de productos escalares de 768 términos. El coste crece linealmente con el corpus, y es exactamente el patrón que una base relacional no puede indexar, porque sus índices —árboles B, tablas hash— presuponen un orden total sobre una clave y en un espacio de 768 dimensiones no existe tal orden.
Búsqueda literal
Casa cadenas o tokens. Encuentra “coche” cuando escribes “coche” y no encuentra nada cuando escribes “automóvil”, por muy sinónimos que sean.
Búsqueda por similitud
Compara posiciones en el espacio del modelo. Encuentra el párrafo sobre automóviles cuando preguntas por coches, porque ambos viven en la misma vecindad.
El coste de la fuerza bruta
Comparar contra todo el corpus crece linealmente con su tamaño. Con millones de vectores de 768 componentes, cada consulta se vuelve un recorrido completo imposible de servir en el edge.
El vecino aproximado
Un índice especializado organiza el espacio para visitar solo una fracción de los candidatos, sacrificando algún vecino legítimo a cambio de órdenes de magnitud en latencia.
La solución del sector es, por tanto, renunciar a la exactitud a cambio de velocidad. Las estructuras que lo consiguen agrupan vectores próximos y construyen atajos entre regiones del espacio, de modo que una consulta desciende hacia la vecindad correcta saltando y no recorriendo. Se llaman aproximadas porque ese descenso puede dejarse algún vecino legítimo por el camino, y ese trato —una pizca de recall a cambio de varios órdenes de magnitud en latencia— es lo que hace viable la búsqueda semántica en producción.
Nada de esto convierte la búsqueda literal en una reliquia, y conviene decirlo antes de que el entusiasmo haga estragos. Hay consultas donde la coincidencia exacta es justamente lo que el usuario quiere: un código de producto, un identificador de incidencia, un nombre propio poco frecuente. La similitud semántica es mala en esos casos precisamente porque generaliza, y devolverá cosas parecidas cuando lo que hacía falta era esa y no otra. Los sistemas maduros combinan ambos mundos —una búsqueda por palabras y otra por vectores, fusionando después sus resultados—, y saber cuándo tu problema pide una, otra o las dos es parte del criterio que este nivel pretende darte.
Conviene detenerse un segundo en lo que significa aceptar una respuesta aproximada, porque rompe una expectativa profundamente arraigada. Una consulta de SQL con un índice devuelve exactamente las filas que cumplen el predicado, siempre, y esa exactitud es innegociable. Una consulta vectorial devuelve los que casi con toda seguridad son los más parecidos, y admitir ese “casi” es la condición de entrada a este territorio. No es una debilidad de la implementación, es la única forma conocida de que la pregunta sea respondible en el tiempo que tienes.
Merece la pena ver la alternativa para apreciar lo que se te está dando hecho. Montar esto por tu cuenta significa elegir una estructura de índice, ajustar sus parámetros de construcción y de búsqueda, dimensionar la memoria que ocupa —los índices de este tipo suelen vivir en RAM—, decidir cómo se reconstruye tras una caída y cómo se replica para no tener un punto único de fallo. Es un proyecto de infraestructura completo, con su propio equipo si el corpus crece.
Vectorize es la implementación de esa idea dentro de la plataforma. Es una base de datos vectorial gestionada, accesible desde un Worker mediante un binding como cualquier otro almacén, que en 2026 admite índices de hasta 10 millones de vectores con un máximo de 1536 dimensiones en precisión de 32 bits. No la operas, no la escalas y no eliges su algoritmo: declaras el índice, insertas vectores y consultas por proximidad.
La ventaja de tener la base vectorial dentro de la plataforma no es solo administrativa. Un sistema de recuperación encadena dos viajes por consulta —embeber la pregunta y buscar sus vecinos— y con servicios externos ambos cruzan internet desde el edge. Con Workers AI y Vectorize los dos ocurren detrás de un binding, sin cadenas de conexión, sin claves que rotar y sin salir de la red de Cloudflare. Esa cercanía es lo que permite que una búsqueda semántica quepa dentro del presupuesto de latencia de una petición web.
Con eso queda dibujado el mapa del nivel. Sabes qué es un embedding, por qué la similitud es geometría y qué estructura hace falta para buscar vecinos sin recorrer el corpus entero. Lo que viene a continuación son las cuatro decisiones prácticas que convierten esa idea en un sistema: cómo se declara el índice, cómo se escriben y se consultan los vectores, cómo se acota la búsqueda antes de comparar y cómo se mantiene todo ello sincronizado y medido.
Un embedding no guarda tu texto: guarda una proyección de su significado de la que no se puede reconstruir el original. Por eso el flujo real nunca es “buscar y devolver el vector”, sino “buscar, obtener identificadores y recuperar el contenido de verdad” desde D1, R2 o KV. Interiorizar que el índice vectorial es un directorio de punteros semánticos, y no el almacén de tus documentos, te evitará la mitad de los errores de diseño de este nivel.
Durante medio siglo, enseñar a una máquina a reconocer que dos textos hablan de lo mismo fue el problema abierto por excelencia del procesamiento del lenguaje, y todos los ataques clásicos compartían el mismo techo: eran simbólicos. Contaban palabras, pesaban su rareza con TF-IDF, expandían consultas con tesauros escritos a mano, construían ontologías con miles de relaciones curadas por lingüistas. Funcionaban razonablemente mientras el usuario acertara con las palabras exactas y se hundían en cuanto aparecía una paráfrasis, un sinónimo no previsto o una manera oblicua de decir lo mismo, porque el significado se había codificado como una relación discreta entre símbolos y la lengua real no se deja discretizar. El embedding cambia el sustrato entero de la representación: en lugar de declarar qué palabras se parecen, deja que un modelo aprenda una geometría en la que el parecido es una consecuencia emergente de la posición. Y con ese único movimiento, un problema que era de lógica simbólica —imposible de completar, imposible de mantener— se transforma en un problema de álgebra lineal, donde comparar significados es multiplicar vectores y buscar los más relacionados es encontrar vecinos. Esa traducción es la que abre la puerta a todo lo que viene después: la recuperación aumentada, los agentes con memoria, la búsqueda que entiende la intención en lugar de las letras. Pero trae consigo una disciplina nueva que hay que aceptar con los ojos abiertos. El espacio no es tuyo, es del modelo, y con él heredas sus sesgos, sus lagunas y sus límites de contexto. La similitud que mide no es la verdad, es la afinidad que ese modelo concreto aprendió de sus datos concretos. Y como toda representación comprimida, es lossy por construcción: descarta información para ganar comparabilidad. Quien trabaja con embeddings sin recordar estas tres cosas acaba tratando un score como si fuera una certeza, y ahí empiezan los sistemas que recuperan documentos plausibles y equivocados con una confianza impecable.
- Genera con Workers AI el embedding de tres frases: dos que signifiquen casi lo mismo con palabras distintas y una ajena. Comprueba la longitud del vector y verifica que coincide con las dimensiones del modelo.
- Calcula a mano la similitud del coseno entre los tres pares posibles y comprueba que el orden que obtienes coincide con tu intuición sobre el sentido.
- Explica con tus palabras por qué comparar vectores generados por dos modelos distintos no produce un resultado peor, sino un resultado sin significado.
- Estima el coste de una búsqueda por fuerza bruta sobre un millón de vectores de 768 dimensiones y razona qué renuncia hace un índice aproximado para evitarlo.