🎯 Introducción
En el mundo de los sistemas RAG (Retrieval-Augmented Generation), la vectorización es el proceso crítico que convierte texto no estructurado en representaciones numéricas que las máquinas pueden entender y comparar. Después de haber procesado y estructurado nuestros datos legales en el post anterior, ahora necesitamos transformarlos en embeddings que permitan búsquedas semánticas precisas.
Este post documenta nuestra exploración exhaustiva de 11 modelos de embedding diferentes para encontrar el óptimo para nuestro sistema RAG de consultas sobre la ley laboral paraguaya. No se trata solo de elegir el modelo más rápido o el más preciso, sino de encontrar el balance perfecto entre calidad, velocidad y recursos computacionales.
🔍 El Desafío
¿Por Qué Vectorización es Crítica?
Los sistemas RAG dependen de la capacidad de encontrar información relevante basándose en el significado semántico de las consultas, no en coincidencias exactas de palabras. Para esto necesitamos:
- Representaciones vectoriales que capturen el significado semántico
- Modelos de embedding optimizados para español y contenido legal
- Velocidad de búsqueda que permita respuestas en tiempo real
- Calidad de resultados que encuentre la información más relevante
Nuestro Dataset de Prueba
- 413 artículos del Código del Trabajo paraguayo
- 29 artículos seleccionados representativos de 8 capítulos diferentes
- 16 consultas semánticas generadas con GPT-4o-mini
- Datos reales con metadatos enriquecidos (libro, título, capítulo, artículo)
⚡ La Solución: Evaluación Sistemática de Modelos
Arquitectura de Evaluación
📊 DATASET DE PRUEBA
├── 29 artículos legales estructurados
├── 16 consultas semánticas específicas
└── Metadatos enriquecidos por artículo
🔬 EVALUACIÓN DE MODELOS
├── 11 modelos de embedding diferentes
├── Métricas de rendimiento (velocidad)
├── Métricas de calidad (similitud)
└── Integración con Qdrant vector database
📈 ANÁLISIS COMPARATIVO
├── Normalización de puntuaciones
├── Sistema de pesos configurables
├── Ranking final basado en criterios
└── Recomendaciones específicas por caso de uso
Modelos Evaluados
Modelo | Dimensiones | Especialización | Descripción |
---|---|---|---|
multilingual-e5-small | 384 | Multilingüe · Rápido | Modelo ligero y eficiente |
paraphrase-multilingual-MiniLM-L12-v2 | 384 | Multilingüe · Ligero | Balanceado para múltiples idiomas |
sentence_similarity_spanish_es | 768 | Español · Optimizado | Especializado en español |
jina-embeddings-v2-base-es | 768 | Español · Última generación | Modelo de nueva generación |
multilingual-e5-base | 768 | Multilingüe · Robusto | Versión base más robusta |
gte-multilingual-base | 768 | Multilingüe · Generalista | Modelo general de alta calidad |
paraphrase-multilingual-mpnet-base-v2 | 768 | Multilingüe · MPNet | Alta precisión con MPNet |
distiluse-base-multilingual-cased-v2 | 512 | Multilingüe · Compacto | Versión compacta balanceada |
LaBSE | 768 | Multilingüe · Confiable | Amplio soporte multilingüe |
snowflake-arctic-embed-l-v2.0 | 1024 | Multilingüe · Large | Modelo grande de alto rendimiento |
bge-m3-korean | 1024 | Multilingüe · BGE | Optimizado para múltiples idiomas |
🛠️ Implementación Técnica
1. Configuración del Entorno
# Importaciones necesarias
import os
import time
import json
import re
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import string
import seaborn as sns
from itables import init_notebook_mode, show
from typing import List, Dict, Any, Tuple
from pathlib import Path
from dotenv import load_dotenv
# OpenAI para generación de consultas
from openai import OpenAI
# Qdrant y modelos de embedding
from qdrant_client import QdrantClient
from qdrant_client.http.models import Distance, VectorParams, PointStruct
from sentence_transformers import SentenceTransformer
# Configuración de visualizaciones
plt.style.use('seaborn-v0_8')
sns.set_palette("husl")
init_notebook_mode(all_interactive=True)
print("Librerías importadas exitosamente")
2. Carga de Variables de Entorno
def load_env_from_parent(levels_up=1, env_filename=".env"):
"""
Carga un archivo .env ubicado varios niveles arriba de este script.
"""
# Obtener ruta actual de trabajo
current_path = Path.cwd()
# Subir 'levels_up' niveles
env_path = current_path
for _ in range(levels_up):
env_path = env_path.parent
env_path = env_path / env_filename
if env_path.exists():
load_dotenv(dotenv_path=env_path)
print(f"Variables de entorno cargadas desde: {env_path}")
else:
print(f"Archivo {env_filename} no encontrado en: {env_path}")
# Cargar variables de entorno
load_env_from_parent()
# Configuración de conexión a Qdrant
QDRANT_URL = os.getenv('QDRANT_URL')
QDRANT_API_KEY = os.getenv('QDRANT_API_KEY')
print(f"Conectando a Qdrant en: {QDRANT_URL}")
3. Configuración de Modelos de Embedding
Configuramos un diccionario con 11 modelos de embedding a evaluar. Cada modelo incluye:
- name: Nombre completo del modelo en HuggingFace
- description: Características principales
- dimension: Dimensiones del vector de salida
Ejemplo de configuración:
MODELS_TO_TEST = dict()
# Modelo 1: Ligero y rápido (384 dimensiones)
MODELS_TO_TEST['multilingual-e5-small'] = dict(
name='intfloat/multilingual-e5-small',
description='Multilingüe · Small · Rápido',
dimension=384
)
# Modelo 2: Español optimizado (768 dimensiones)
MODELS_TO_TEST['sentence_similarity_spanish_es'] = dict(
name='hiiamsid/sentence_similarity_spanish_es',
description='Español · Optimizado · Preciso',
dimension=768
)
# ... 9 modelos más ...
Total configurado: 11 modelos de embedding
💡 Lista completa: Ver variable
MODELS_TO_TEST
en el notebook con los 11 modelos
4. Carga de Datos Legales
# Cargar datos reales de la ley laboral paraguaya
def load_labor_law_data(json_path="../data/processed/codigo_trabajo_articulos.json"):
"""Cargar y procesar los datos reales de la ley laboral"""
try:
with open(json_path, 'r', encoding='utf-8') as f:
law_data = json.load(f)
print(f"Datos cargados exitosamente desde: {json_path}")
print(f"Metadatos de la ley: {law_data['meta']}")
print(f"Total de artículos: {len(law_data['articulos'])}")
return law_data
except Exception as e:
print(f"Error cargando datos: {e}")
return None
# Cargar datos reales
law_data = load_labor_law_data()
5. Selección de Artículos y Generación de Consultas
Para crear un dataset de prueba representativo, implementamos dos funciones clave:
Función 1: select_representative_articles()
- Agrupa artículos por capítulo
- Selecciona 1-4 artículos por capítulo de los primeros 8 capítulos
- Formatea el texto como:
"capítulo: artículo"
- Resultado: 29 artículos representativos
Función 2: generate_semantic_questions()
- Usa GPT-4o-mini para generar 2 preguntas por capítulo
- Cada pregunta apunta a artículos específicos del capítulo
- Prompt estructurado que solicita formato JSON
- Resultado: 16 consultas semánticas de prueba
Ejemplos de consultas generadas:
1. "¿Cuál es el objetivo principal del código en relación con las relaciones laborales?"
→ Apunta al Artículo 1 (Objeto y aplicación del código)
2. "¿Qué tipos de trabajadores están sujetos a las disposiciones de este código?"
→ Apunta al Artículo 2 (Objeto y aplicación del código)
3. "¿Qué debe prevalecer en caso de dudas sobre la interpretación de normas?"
→ Apunta al Artículo 1 (Del trabajo y sus garantías)
Dataset final:
- ✅ 29 textos legales seleccionados
- ✅ 16 consultas de prueba
- ✅ 8 capítulos representados
💡 Código completo: Ver
notebooks/02_vectorstore_embedding_exploration.ipynb
secciones “Selecting Sample Articles” y “Generate Semantic Questions”
6. Clase Evaluadora de Modelos
Creamos una clase EmbeddingModelEvaluator
que encapsula toda la lógica de evaluación:
Métodos principales:
-
connect_qdrant()
– Establece conexión con Qdrant vector database -
load_model_and_measure_time(model_name)
– Carga el modelo y mide el tiempo
model = SentenceTransformer(model_name, trust_remote_code=True)
load_time = time.time() - start_time
-
create_embeddings_and_measure_time(model, texts)
– Genera embeddings y mide rendimiento
embeddings = model.encode(texts, convert_to_tensor=False)
embedding_time = time.time() - start_time
Métricas capturadas:
- ⏱️ Tiempo de carga del modelo
- ⏱️ Tiempo de generación de embeddings
- 📊 Dimensiones de los vectores
- 🎯 Calidad de similitud semántica
💡 Código completo: Ver clase
EmbeddingModelEvaluator
ennotebooks/02_vectorstore_embedding_exploration.ipynb
7. Evaluación de Calidad de Búsqueda
Implementamos dos funciones para medir la calidad de los modelos:
Función 1: calculate_cosine_similarity()
- Calcula la similitud coseno entre dos embeddings
- Fórmula:
dot_product / (norm1 * norm2)
- Rango: 0.0 (sin similitud) a 1.0 (idénticos)
Función 2: evaluate_search_quality()
- Para cada consulta:
- Genera embedding de la consulta
- Calcula similitud con todos los textos
- Ordena por similitud descendente
- Mide tiempo de búsqueda
- Retorna:
- Similitud promedio del mejor resultado
- Tiempo promedio de búsqueda
- Resultados detallados por consulta
Ejemplo de flujo:
# 1. Generar embedding de consulta
query_embedding = model.encode(["¿Cuáles son los derechos del trabajador?"])
# 2. Calcular similitudes
for text_embedding in text_embeddings:
similarity = calculate_cosine_similarity(query_embedding, text_embedding)
# 3. Ordenar y retornar top resultados
similarities.sort(key=lambda x: x[2], reverse=True)
💡 Código completo: Ver funciones de evaluación en
notebooks/02_vectorstore_embedding_exploration.ipynb
8. Evaluación Completa de Modelos
El proceso de evaluación itera sobre los 11 modelos configurados:
Flujo de evaluación por modelo:
for model_key, model_config in MODELS_TO_TEST.items():
# 1. Cargar modelo y medir tiempo
model, load_time = evaluator.load_model_and_measure_time(model_config['name'])
# 2. Generar embeddings y medir tiempo
embeddings, embedding_time = evaluator.create_embeddings_and_measure_time(
model, SAMPLE_LEGAL_TEXTS
)
# 3. Almacenar resultados con todas las métricas
model_performance[model_key] = create_performance_dict(
model_config, load_time, embedding_time, embeddings, model
)
Métricas capturadas por modelo:
- ⏱️ Tiempo de carga del modelo
- ⏱️ Tiempo de generación de embeddings (29 artículos)
- 📊 Dimensiones de los vectores
- 🎯 Embeddings generados para búsquedas
Resultado: 11 modelos evaluados con métricas completas de rendimiento
💡 Código completo: Ver sección “Model Loading and Evaluation” en el notebook
9. Evaluación de Calidad de Búsqueda
Para cada modelo evaluado, medimos la calidad de búsqueda:
for model_key, model_data in model_performance.items():
# Evaluar calidad con las 16 consultas de prueba
quality_results = evaluate_search_quality(
model_data, SAMPLE_LEGAL_TEXTS, SAMPLE_QUERIES
)
# Almacenar resultados
search_quality_results[model_key] = quality_results
Métricas obtenidas por modelo:
- 📊 Similitud promedio del mejor resultado
- ⏱️ Tiempo promedio de búsqueda
- 🎯 Resultados detallados por cada consulta
💡 Código completo: Ver sección “Search Quality Evaluation” en el notebook
10. Análisis Comparativo Completo
El análisis final combina todas las métricas en un sistema de puntuación ponderada:
Paso 1: Consolidar datos en DataFrames
- DataFrame de rendimiento: tiempos de carga, embedding y velocidad
- DataFrame de calidad: similitud promedio y tiempo de búsqueda
- Merge de ambos para análisis completo
Paso 2: Normalización de scores (0-1)
def normalize_score(series, higher_is_better=True):
if higher_is_better:
return (series - series.min()) / (series.max() - series.min())
else:
return (series.max() - series) / (series.max() - series.min())
Paso 3: Sistema de pesos configurables
- 🎯 Calidad de búsqueda: 50% (lo más importante para RAG)
- ⚡ Velocidad de búsqueda: 35% (experiencia de usuario)
- 🔄 Velocidad de embedding: 10% (procesamiento batch)
- 📥 Velocidad de carga: 5% (se hace una vez)
Paso 4: Cálculo de score final
score_final = (
score_calidad * 0.5 +
score_velocidad_busqueda * 0.35 +
score_velocidad_embedding * 0.1 +
score_velocidad_carga * 0.05
)
Resultado: Ranking ordenado de modelos por score final
💡 Código completo: Ver sección “Comprehensive Comparative Analysis” en el notebook
📊 Resultados de la Evaluación
Métricas de Rendimiento
Modelo | Carga (s) | Embedding (s) | Total (s) | Velocidad (textos/s) |
---|---|---|---|---|
sentence_similarity_spanish_es | 2.71 | 4.96 | 7.67 | 5.85 |
paraphrase-multilingual-MiniLM-L12-v2 | 3.71 | 0.90 | 4.61 | 32.22 |
jina-embeddings-v2-base-es | 19.18 | 8.28 | 27.46 | 3.50 |
distiluse-base-multilingual-cased-v2 | 4.85 | 1.67 | 6.52 | 17.37 |
multilingual-e5-base | 6.12 | 4.67 | 10.79 | 6.21 |
paraphrase-multilingual-mpnet-base-v2 | 8.45 | 3.89 | 12.34 | 7.46 |
multilingual-e5-small | 3.89 | 1.82 | 5.71 | 15.93 |
bge-m3-korean | 15.67 | 16.08 | 31.75 | 1.80 |
LaBSE | 7.23 | 4.56 | 11.79 | 6.36 |
snowflake-arctic-embed-l-v2.0 | 12.34 | 9.87 | 22.21 | 2.94 |
gte-multilingual-base | 5.67 | 4.95 | 10.62 | 5.86 |
Métricas de Calidad
Modelo | Similitud Promedio | Tiempo Búsqueda (s) | Consultas/segundo |
---|---|---|---|
multilingual-e5-small | 0.901 | 0.1596 | 6.27 |
multilingual-e5-base | 0.876 | 0.5625 | 1.78 |
gte-multilingual-base | 0.821 | 0.0580 | 17.24 |
paraphrase-multilingual-mpnet-base-v2 | 0.784 | 0.7120 | 1.40 |
paraphrase-multilingual-MiniLM-L12-v2 | 0.783 | 0.2105 | 4.75 |
jina-embeddings-v2-base-es | 0.723 | 0.0607 | 16.47 |
bge-m3-korean | 0.697 | 1.8040 | 0.55 |
snowflake-arctic-embed-l-v2.0 | 0.696 | 1.3093 | 0.76 |
sentence_similarity_spanish_es | 0.663 | 0.5597 | 1.79 |
LaBSE | 0.582 | 0.5851 | 1.71 |
distiluse-base-multilingual-cased-v2 | 0.495 | 0.2950 | 3.39 |
Análisis por Dimensiones
Dimensiones | Similitud Promedio | Tiempo Búsqueda (s) | Score Final |
---|---|---|---|
384 | 0.842 | 0.185 | 0.896 |
512 | 0.495 | 0.295 | 0.438 |
768 | 0.741 | 0.423 | 0.695 |
1024 | 0.697 | 1.557 | 0.346 |
🏆 Ranking Final de Modelos
Sistema de Puntuación Ponderada
Criterio | Peso | Descripción |
---|---|---|
Calidad de Búsqueda | 50% | Similitud promedio en consultas legales |
Velocidad de Búsqueda | 35% | Tiempo de respuesta para usuarios |
Velocidad de Embedding | 10% | Procesamiento de documentos batch |
Velocidad de Carga | 5% | Tiempo de inicialización del modelo |
Top 5 Modelos Recomendados
Pos | Score Final | Calidad | Modelo | Dimensiones |
---|---|---|---|---|
🥇 | 0.969 | 0.901 | multilingual-e5-small | 384 |
🥈 | 0.836 | 0.821 | gte-multilingual-base | 768 |
🥉 | 0.831 | 0.876 | multilingual-e5-base | 768 |
4️⃣ | 0.823 | 0.783 | paraphrase-multilingual-MiniLM-L12-v2 | 384 |
5️⃣ | 0.750 | 0.723 | jina-embeddings-v2-base-es | 768 |
🎯 Recomendaciones Específicas por Caso de Uso
🏆 MEJOR MODELO GENERAL: multilingual-e5-small
Características:
- Score Final: 0.969 (mejor balance general)
- Similitud Promedio: 0.901 (excelente calidad)
- Dimensiones: 384 (eficiente)
- Velocidad: 6.27 consultas/segundo
Recomendado para:
- ✅ Sistemas RAG de producción
- ✅ Aplicaciones que requieren alta precisión
- ✅ Entornos con recursos limitados
- ✅ Consultas legales complejas
⚡ MÁS RÁPIDO PARA BÚSQUEDAS: gte-multilingual-base
Características:
- Tiempo de Búsqueda: 0.0580s (más rápido)
- Consultas/segundo: 17.24
- Similitud Promedio: 0.821 (buena calidad)
- Dimensiones: 768
Recomendado para:
- ✅ Aplicaciones en tiempo real
- ✅ Sistemas con alta carga de consultas
- ✅ APIs que requieren respuesta rápida
- ✅ Búsquedas interactivas
🚀 MÁS RÁPIDO PARA EMBEDDINGS: paraphrase-multilingual-MiniLM-L12-v2
Características:
- Tiempo de Embedding: 0.90s (más rápido)
- Velocidad: 32.22 textos/segundo
- Similitud Promedio: 0.783 (buena calidad)
- Dimensiones: 384
Recomendado para:
- ✅ Procesamiento batch masivo
- ✅ Carga inicial de grandes volúmenes
- ✅ Sistemas de indexación
- ✅ Migración de datos
🔧 Integración con Qdrant
Configuración de Colección
def create_qdrant_collection(client, collection_name, vector_size):
if client.collection_exists(collection_name):
client.delete_collection(collection_name)
client.create_collection(
collection_name=collection_name,
vectors_config=VectorParams(
size=vector_size,
distance=Distance.COSINE
),
timeout=60
)
print(f"Colección '{collection_name}' creada")
Inserción de Documentos con Metadatos
La función insert_documents_qdrant_collection()
inserta los embeddings en Qdrant con metadatos enriquecidos:
Proceso:
-
Crear payload para cada documento con:
- Texto del artículo
- Longitud del texto
- Fuente (código_trabajo_paraguay)
- Metadatos legales: libro, título, capítulo, número de artículo
-
Crear PointStruct con:
- ID único
- Vector (embedding)
- Payload con metadatos
-
Inserción en lote usando
client.upsert()
Estructura del payload:
point = PointStruct(
id=i,
vector=embedding.tolist(),
payload=payload_with_metadata
)
💡 Código completo: Ver función
insert_documents_qdrant_collection()
en el notebook
Búsqueda Semántica
def search_qdrant_collection(client: QdrantClient, collection_name: str,
query_embedding: np.ndarray, limit: int = 3):
"""Probar búsqueda en Qdrant"""
try:
results = client.query_points(
collection_name=collection_name,
query=query_embedding,
limit=limit
).points
return results
except Exception as e:
print(f"Error en búsqueda de '{collection_name}': {e}")
return None
Ejemplo de Resultados de Búsqueda
Consulta: '¿Cuál es el objetivo principal del código en relación con las relaciones laborales?'
Resultados de búsqueda en Qdrant:
================================================================================
1. ✅ Similitud: 0.915
📝 este código tiene por objeto establecer normas para regular las relaciones entre los trabajadores y empleadores, concern...
📖 Libro: libro primero
📚 Título: titulo primero
📂 Capítulo: capitulo i - del objeto y aplicación del código
📜 Artículo Nº: 1
2. ✅ Similitud: 0.866
📝 los reglamentos de fábricas o talleres, contratos individuales y colectivos de trabajo que establezcan derechos o benefi...
📖 Libro: libro primero
📚 Título: titulo primero
📂 Capítulo: capitulo i - del objeto y aplicación del código
📜 Artículo Nº: 4
3. ✅ Similitud: 0.865
📝 se entiende por trabajo, a los fines de este código, toda actividad humana, consciente y voluntaria, prestada en forma d...
📖 Libro: libro primero
📚 Título: titulo primero
📂 Capítulo: capitulo ii - del trabajo y sus garantías
📜 Artículo Nº: 8
🚀 Implementación en Casos de Uso Reales
Para Desarrolladores:
“Necesito implementar búsqueda semántica en mi aplicación legal”
Solución: Pipeline completo con multilingual-e5-small
# Configuración recomendada
model = SentenceTransformer('intfloat/multilingual-e5-small')
embeddings = model.encode(legal_texts)
# Integración directa con Qdrant
Para Científicos de Datos:
“Necesito evaluar diferentes modelos de embedding para mi dataset”
Solución: Framework de evaluación sistemática
# Evaluación automatizada
evaluator = EmbeddingModelEvaluator(qdrant_url, api_key)
results = evaluator.evaluate_all_models(models_to_test)
# Análisis comparativo con métricas normalizadas
Para DevOps:
“Necesito optimizar el rendimiento del sistema RAG en producción”
Solución: Modelo optimizado para velocidad y recursos
# Configuración para producción
model = SentenceTransformer('Alibaba-NLP/gte-multilingual-base')
# 17.24 consultas/segundo con 0.821 de similitud
Para Organizaciones:
“Necesito un sistema RAG escalable para múltiples países”
Solución: Modelo multilingüe robusto
# Configuración multilingüe
model = SentenceTransformer('intfloat/multilingual-e5-base')
# Balance óptimo calidad/velocidad para escala
💡 Lecciones Aprendidas
1. Dimensiones vs Rendimiento
- 384 dimensiones: Mejor balance velocidad/calidad para aplicaciones RAG
- 768 dimensiones: Mayor calidad pero menor velocidad
- 1024 dimensiones: Calidad similar pero significativamente más lento
2. Velocidad de Búsqueda es Crítica
- La velocidad de búsqueda (35% del score) es más importante que la velocidad de embedding (10%)
- Los usuarios esperan respuestas en tiempo real
- La diferencia entre 0.06s y 1.8s es perceptible para el usuario
3. Calidad de Similitud es Fundamental
- La similitud promedio (50% del score) es el factor más importante
- Un modelo con 0.90 de similitud vs 0.50 marca la diferencia en precisión
- La calidad de resultados impacta directamente en la confianza del usuario
4. Modelos Especializados vs Generales
- Los modelos especializados en español no siempre superan a los multilingües
- Los modelos multilingües modernos (E5, GTE) ofrecen excelente rendimiento
- La especialización debe balancearse con la versatilidad
🎯 Impacto y Beneficios del Sistema
Métricas de Éxito
- 0.901 similitud promedio con multilingual-e5-small
- 6.27 consultas/segundo en tiempo real
- 29 artículos procesados y vectorizados
- 16 consultas de prueba con resultados precisos
- 11 modelos evaluados sistemáticamente
Beneficios Técnicos
- Búsqueda semántica precisa en contenido legal
- Integración robusta con Qdrant vector database
- Metadatos enriquecidos para filtrado avanzado
- Escalabilidad para grandes volúmenes de datos
- Flexibilidad para diferentes casos de uso
Beneficios de Negocio
- Respuestas más relevantes a consultas legales
- Tiempo de respuesta optimizado para usuarios
- Escalabilidad para múltiples países y leyes
- Reducción de costos computacionales
- Mejora en experiencia del usuario final
🔧 Tecnologías Utilizadas
- Python 3.13 con sentence-transformers
- Qdrant para base de datos vectorial
- OpenAI GPT-4o-mini para generación de consultas
- NumPy/Pandas para análisis de datos
- Matplotlib/Seaborn para visualizaciones
- Docker para containerización
- Phoenix/OpenTelemetry para observabilidad
📈 Próximos Pasos e Implementación
Implementación en Producción
- Configurar multilingual-e5-small como modelo principal
- Implementar pipeline de vectorización con metadatos enriquecidos
- Configurar Qdrant con dimensiones 384 y distancia coseno
- Implementar sistema de monitoreo de calidad de embeddings
- Optimizar para escala con procesamiento batch
Optimizaciones Adicionales
- Caching de embeddings para consultas frecuentes
- Compresión de vectores para reducir almacenamiento
- Fine-tuning del modelo con datos legales específicos
- A/B testing de diferentes modelos en producción
Monitoreo Continuo
- Métricas de calidad de búsquedas en tiempo real
- Latencia de respuesta por consulta
- Uso de recursos computacionales
- Feedback de usuarios sobre relevancia de resultados
📋 Resumen Ejecutivo
Modelo Recomendado
intfloat/multilingual-e5-small
- Score Final: 0.969 (mejor balance general)
- Similitud Promedio: 0.901 (excelente calidad)
- Dimensiones: 384 (eficiente)
- Velocidad: 6.27 consultas/segundo
Criterios de Selección
- Calidad de Búsqueda (50%): Similitud promedio en consultas legales
- Velocidad de Búsqueda (35%): Tiempo de respuesta para usuarios
- Velocidad de Embedding (10%): Procesamiento de documentos batch
- Velocidad de Carga (5%): Tiempo de inicialización del modelo
Resultados Clave
- ✅ 11 modelos evaluados sistemáticamente
- ✅ 29 artículos procesados y vectorizados
- ✅ 16 consultas de prueba con resultados precisos
- ✅ Sistema de puntuación ponderada implementado
🔗 Recursos y Enlaces
Repositorio del Proyecto
- GitHub: lus-laboris-py – Sistema completo de procesamiento de datos legales con observabilidad