Práctica: Creación de un Pipeline Básico de Embeddings

Lectura
30 min~5 min lectura

Concepto clave

En el corazón de cualquier sistema RAG (Retrieval Augmented Generation) se encuentra el proceso de embeddings. Imagina que tienes una biblioteca con miles de libros y necesitas encontrar rápidamente aquellos que hablan sobre "inteligencia artificial en medicina". En lugar de leer cada título, usas un sistema que convierte cada libro en una "huella digital" numérica única que captura su esencia temática. Los embeddings hacen precisamente eso: transforman texto (o imágenes, audio) en vectores numéricos densos en un espacio multidimensional donde la distancia entre vectores refleja similitud semántica.

En términos técnicos, un embedding es una representación vectorial de alta dimensión (típicamente 384 a 1536 dimensiones) generada por modelos como BERT, GPT o sentence-transformers. La magia ocurre cuando documentos similares en significado tienen vectores cercanos en este espacio. Por ejemplo, "perro" y "canino" tendrán vectores muy próximos, mientras que "perro" y "algoritmo" estarán distantes. Esta propiedad es fundamental para la recuperación eficiente en bases de datos vectoriales como Chroma, Pinecone o pgvector.

"Los embeddings convierten el problema de búsqueda semántica en un problema de búsqueda de vecinos más cercanos en un espacio vectorial."

Cómo funciona en la práctica

Vamos a construir un pipeline básico de embeddings para un sistema RAG. Supongamos que queremos indexar documentos técnicos sobre bases de datos. El proceso tiene cuatro etapas claras:

  1. Preprocesamiento de texto: Dividir documentos largos en fragmentos (chunks) manejables, típicamente de 500-1000 tokens. Esto mejora la precisión de recuperación.
  2. Generación de embeddings: Usar un modelo preentrenado (ej: all-MiniLM-L6-v2) para convertir cada chunk en un vector.
  3. Almacenamiento vectorial: Insertar los vectores en una base de datos vectorial junto con metadatos (fuente, posición, etc.).
  4. Consulta y recuperación: Cuando llega una pregunta, generar su embedding y buscar los chunks más similares.

Veamos un ejemplo concreto con datos. Supongamos estos tres chunks de documentos:

IDTextoDimensión del embedding
1ChromaDB es una base de datos vectorial open-source optimizada para embeddings.384
2Pinecone ofrece bases de datos vectoriales gestionadas en la nube con alta escalabilidad.384
3PostgreSQL con pgvector añade capacidades vectoriales a bases de datos relacionales tradicionales.384

Al generar embeddings, cada fila se convierte en un vector como [0.23, -0.45, 0.87, ...] (384 valores). En la base de datos vectorial, podemos consultar con "¿Qué opciones hay para bases de datos vectoriales?" y recuperar los chunks 1 y 2 como más relevantes.

Caso de estudio

Una empresa de e-learning quiere implementar un asistente que responda preguntas sobre su catálogo de 10,000 cursos. El equipo de ingeniería de datos implementó este pipeline:

  1. Extracción: Convertir descripciones de cursos (PDFs, HTML) a texto plano.
  2. Chunking: Dividir cada descripción en párrafos de ~200 palabras usando separadores naturales.
  3. Embedding: Usar el modelo "all-mpnet-base-v2" (768 dimensiones) para generar vectores.
  4. Indexación: Almacenar en Pinecone con metadatos: categoría, nivel, duración.

Cuando un usuario pregunta "¿Tienen cursos avanzados de Python para ciencia de datos?", el sistema:

  • Genera el embedding de la pregunta
  • Busca los 5 cursos más similares en Pinecone
  • Pasa esos contextos a un LLM para generar una respuesta natural

Resultado: Reducción del 70% en tiempo de búsqueda manual y respuestas un 40% más precisas que búsqueda por palabras clave.

Errores comunes

1. Chunks demasiado grandes o pequeños: Fragmentos muy grandes pierden especificidad; muy pequeños pierden contexto. Solución: Experimentar con tamaños entre 256-1024 tokens según el dominio.

2. Inconsistencia dimensional: Usar diferentes modelos de embedding para indexar y consultar genera resultados incoherentes. Solución: Estandarizar un modelo para todo el pipeline.

3. Ignorar metadatos: Almacenar solo vectores sin metadatos limita el filtrado posterior. Solución: Incluir siempre fuente, timestamp, categoría, etc.

4. No normalizar vectores: Algunas bases de datos vectoriales requieren vectores normalizados para búsquedas eficientes. Solución: Aplicar normalización L2 antes del almacenamiento.

5. Subestimar costos de inferencia: Generar embeddings para millones de documentos puede ser costoso. Solución: Planificar batch processing y considerar modelos más eficientes.

Checklist de dominio

  • Puedo explicar qué es un embedding y por qué es esencial en RAG
  • He implementado al menos un pipeline completo de chunking → embedding → almacenamiento
  • Sé cómo elegir un modelo de embedding balanceando calidad vs velocidad
  • Entiendo cómo la dimensionalidad afecta precisión y costo de almacenamiento
  • Puedo diagnosticar problemas comunes de similitud semántica
  • Conozco las diferencias clave entre Chroma, Pinecone y pgvector para este uso
  • Sé implementar filtrado por metadatos junto con búsqueda vectorial

Implementa un pipeline de embeddings para documentos técnicos

En este ejercicio, crearás un pipeline completo para procesar documentos sobre tecnologías de bases de datos. Sigue estos pasos:

  1. Prepara los datos: Crea un archivo documentos.txt con al menos 5 párrafos sobre diferentes bases de datos (ej: MongoDB, Redis, Cassandra, PostgreSQL, Elasticsearch). Cada párrafo debe tener 3-5 oraciones.
  2. Implementa el chunking: Escribe una función en Python que divida el texto en chunks de aproximadamente 100 palabras usando separadores naturales (puntos, saltos de línea).
  3. Genera embeddings: Usa la biblioteca sentence-transformers con el modelo all-MiniLM-L6-v2 para convertir cada chunk en un vector de 384 dimensiones.
  4. Almacena localmente: Crea un diccionario Python que mapee cada chunk a su embedding y metadatos (posición, número de palabras).
  5. Simula una consulta: Escribe una función que tome una pregunta como entrada, genere su embedding, y encuentre los 2 chunks más similares usando similitud coseno.
  6. Evalúa resultados: Prueba con preguntas como "¿Qué base de datos es mejor para datos no estructurados?" y verifica que los chunks recuperados sean relevantes.

Entrega: Código Python completo y salida de ejemplo con al menos una consulta.

Pistas
  • Usa nltk o split() simple para chunking si necesitas mantenerlo sencillo
  • La similitud coseno entre vectores A y B se calcula como dot(A,B)/(norm(A)*norm(B))
  • Considera usar numpy para operaciones vectoriales eficientes

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.