Embeddings
Un ordenador no puede entender texto ni relación semántica o significado entre palabras. Solo puede entender números. Esto lo resolvemos mediante el uso de embeddings.
Un embedding es la representación de texto (en forma de números) en un espacio vectorial. Esto permite a los modelos de IA comparar y operar sobre el significado de las palabras.
flowchart TD
A["perro"] --> B
B --> C["[-0.003, 0.043, ..., -0.01]"]
N1["(texto que queremos convertir)"]:::note --> A
N2["(vectores con contenido semántico)"]:::note --> C
classDef note fill:none,stroke:none,color:#777;
Los vectores de cada palabra o documento capturan el significado semántico del texto.
- perro estará cerca de mascota
- contrato estará lejos de playa
Vector vs SQL databases
El problema con las BBDD típicas es que solo buscan matches exactos. Si yo busco por coche solo me sacará las entradas que contengan coche.
En cambio, como las BBDD vectoriales pueden interpretar la semántica de las palabras mediante los vectores, si busco por coche puede sacarme valores como sedán, SUV, Land Rover, etc.
Las BBDD vectoriales son muy buenas cuando necesitamos buscar items similares por proximidad uno respecto al otro. Un ejemplo de uso es buscar películas parecidas (Netflix). Otro ejemplo son los recomendadores de items parecidos en tiendas online (Amazon).
Como ejecutar una búsqueda (query) mediante vectores
Necesitamos:
- Una BBDD Vectorial (CosmosDB)
- Un modelo para transformar los embeddings (text-embedding-3-large)
El flujo completo es el siguiente:
- Usar un embedding model para crear embeddings del contenido que queremos indexar
- Insertar el texto original y los vectores del contenido en una BBDD vectorial
- Cuando queramos ejecutar una query usar el mismo embedding model de antes con la query a buscar. Con el embedding resultante buscamos vectores similares en la BBDD y sacamos el texto original de original_text
Introducir vectores en CosmosDB
Para poder buscar necesitamos rellenar antes la BBDD con contenido. Lo mantenemos simple. Metemos
- un ID a mano
- el texto original
- los vectores resultado de hacer el embedding sobre el texto original
El pseudocódigo se ve así y se ejecuta de uno en uno
def main():
text = "A shiba walks alone in the park"
# this sends the text to the model text-embedding-3-large
vectors = createEmbeddingsForText(text)
item = {
"id": "1",
"original_text": text,
"vectors": vectors
}
uploadToCosmosDB(item)
ejemplos de los datos que guardo
{
"id": "1",
"original_text": "A shiba walks alone in the park",
"vectors": [-0.003, 0.043, ..., -0.001]
}
{
"id": "2",
"original_text": "A dog sleeps on the bed",
"vectors": [0.021, ..., 0.071]
}
{
"id": "3",
"original_text": "A wild bear hunts in the mountain",
"vectors": // some vectors
}
{
"id": "4",
"original_text": "Two boats colide in the ocean",
"vectors": // some vectors
}
{
"id": "5",
"original_text": "A car travels during the night",
"vectors": // some vectors
}
Ejecutar una búsqueda
Ahora si realizo una búsqueda, puedo buscar por proximidad semántica y no solo por matches exactos como en una BBDD tradicional.
pseudocódigo
def main():
text_to_search = "inu"
# it needs to be the same model as before
vectors = createEmbeddingsForText(text)
# we search for the top 3 results
results = queryCosmosDB(vectors)
Aunque inu no se encuentra en la BBDD como tal, vemos que el hit más fuerte es el que contiene shiba. El segundo más fuerte (aunque bastante distanciado) es el que contiene dog.
text: 'A shiba walks alone in the park', cosine_distance: 0.57116
text: 'A dog sleeps on the bed', cosine_distance: 0.28378
text: 'A wild bear hunts in the mountain', cosine_distance: 0.21090
Si por el contrario busco vehicle ahora los hits más fuertes son los que contienen medios de transporte
text: 'A car travels during the night', cosine_distance: 0.37720
text: 'Two boats colide in the ocean', cosine_distance: 0.23041
text: 'A shiba walks alone in the park', cosine_distance: 0.15880
Reference(s)
Using Embeddings to Find Similar Texts with Azure OpenAI and Cosmos DB | by Shubham Agarwal | Medium