Sistema RAG (Retrieval-Augmented Generation) especializado en el sector energético utilizando LLMs y recuperación híbrida de documentos.
- Kevin Mansilla, FaMAF-UNC
- Francisco Martiarena, FaMAF-UNC
- Descripción
- Arquitectura
- Demostración
- Stack Tecnológico
- Requisitos Previos
- Instalación y Configuración Local
- Estructura del Proyecto
- Docker
- Kubernetes
- Monitoreo
Este proyecto implementa un sistema RAG (Retrieval-Augmented Generation) especializado en responder consultas sobre el sector energético. Utiliza técnicas de recuperación híbrida, reranking y múltiples agentes para proporcionar respuestas precisas y contextualizadas.
Características principales:
- Hybrid retriever con búsqueda semántica y por palabras clave
- Reranker para mejorar la relevancia de los documentos recuperados
- Multi-agent system para verificación y mejora de respuestas
- Soporte multilingüe con traducción automática
- Base de datos para tracking de tokens consumidos
A continuación se muestran tres diagramas que sintetizan los componentes y el funcionamiento del sistema, desde el concepto base de RAG hasta el flujo completo y el subsistema de agentes que valida las respuestas.
Diagrama de referencia de un sistema RAG estándar. El usuario envía una consulta a la interfaz; el almacén de documentos se vectoriza mediante un modelo de embeddings y se persiste en un vectorstore. En tiempo de consulta, los documentos más relevantes se recuperan y se entregan como contexto al LLM, que genera la respuesta final para el usuario.
Pipeline implementado en este trabajo. La consulta del usuario pasa primero por un agente de idioma que detecta el lenguaje y aplica el prompt template adecuado. Luego se genera una multi-query para enriquecer la búsqueda, se vectoriza con el modelo de embeddings y se consulta el Vector Store aplicando filtros por país. Los documentos recuperados se filtran y ordenan con un reranker, se pasan al LLM como contexto y, finalmente, el modelo de agentes valida la salida. La respuesta final se devuelve en el idioma original detectado.
Subsistema multi-agente encargado de validar y consolidar la respuesta del LLM. La respuesta original generada por el LLM es revisada por un agente verificador que comprueba la evidencia documental. Su salida se entrega al agente de consenso, que recibe además el idioma detectado por el agente de idioma y produce la respuesta final alineada con la consulta del usuario.
A continuación se muestra una demostración del sistema funcionando con la interfaz de OpenWebUI conectada al backend RAG:
- Python 3.9.21
- FastAPI: Framework web para la API
- LangChain: Orquestación de LLMs y componentes RAG
- ChromaDB: Base de datos vectorial
- Docker: Contenedorización
- Kubernetes: Orquestación de contenedores
- Python 3.9.21
- pyenv (recomendado para gestión de versiones de Python)
- Docker y Docker Compose (para ejecución en contenedores)
- kubectl (para despliegue en Kubernetes)
Este proyecto está configurado para funcionar con Python 3.9.21.
# Instalar Python 3.9.21
pyenv install 3.9.21
# Crear el entorno virtual
pyenv virtualenv 3.9.21 env_llm_energy
# Activar el entorno
pyenv activate env_llm_energypip3 install -r requirements.txtuvicorn main:app --reload --port 8000La API estará disponible en http://localhost:8000
A continuación se detallan los archivos y directorios principales del repositorio:
| Directorio | Descripción |
|---|---|
/eval |
Scripts para evaluar los modelos LLMs en distintas tareas del sector energético |
/markdowns |
Documentos markdown utilizados como fuente de conocimiento del sistema |
| Archivo | Descripción |
|---|---|
agentes.py |
Agentes que interactúan con el LLM para realizar tareas específicas y mejorar el resultado final |
db_utils.py |
Utilidades para crear y gestionar la base de datos que almacena la cantidad de tokens usados en cada consulta |
extra.py |
Funciones auxiliares para identificar países en las preguntas y formatear los documentos fuente de manera amigable |
meta_data.py |
Funciones para añadir metadatos (país, ruta) a los archivos markdown |
vectorstore.py |
Manejo de embeddings, creación del vectorstore con ChromaDB, hybrid retriever y configuración de prompts |
templates.py |
Templates de prompts utilizados en las distintas interacciones con el LLM |
retriever.py |
Función principal retriever_agent() que maneja la consulta del usuario, detección de idioma, hybrid retriever, reranker y traducción |
query_con_agen_idioma.ipynb |
Notebook de prueba del pipeline completo con la función multi_agent_rag() que orquesta todo el proceso |
- El usuario envía una consulta a través de
retriever_agent() - Se detecta el idioma de la consulta
- El hybrid retriever busca documentos relevantes
- El reranker filtra y ordena los resultados
- Los agentes verifican y mejoran la respuesta
- La respuesta se traduce al idioma original del usuario
docker compose up -ddocker compose downdocker compose down
docker compose up -d --build# Loguearse en Docker Hub
docker login
# Construir la imagen
docker build -t kevmansilla/rag-backend:latest .
# Subir la imagen
docker push kevmansilla/rag-backend:latest# Commitear cambios
git add .
git commit -am "Descripción del cambio"
git push
# Reconstruir y subir
docker build -t kevmansilla/rag-backend:latest .
docker push kevmansilla/rag-backend:latestPara conectar el backend con OpenWebUI, ambos contenedores deben correr en la misma red de Docker.
docker network create ragnet
# Verificar que se creó correctamente
docker network lsdocker run -d \
--name rag-backend \
--network ragnet \
-p 8000:8000 \
kevmansilla/rag-backend:latestdocker run -d \
--name openwebui-ragnet \
--network ragnet \
-p 3000:8080 \
-e OPENAI_API_BASE_URL=http://rag-backend:8000/v1 \
ghcr.io/open-webui/open-webui:mainLa conexión entre OpenWebUI y el backend RAG se realiza automáticamente mediante la variable de entorno OPENAI_API_BASE_URL.
http://localhost:3000
docker logs -f rag-backenddocker compose pull rag-backend
docker compose up -d rag-backendPrimero loguearse en docker hub y crear repo llamado rag-backend
docker login
docker build -t kevmansilla/rag-backend:latest .
docker push kevmansilla/rag-backend:latest
Para hacer la conexion con openweb-ui, ambos contenedores deben correr en la misma red de docker. Para esto se puede usar docker compose. Entonces debemos crear la red llamada ragnet
docker network create ragnet
verificamos que la red fue creada con
docker network ls
Levantar el backend
docker run -d \
--name rag-backend \
--network ragnet \
-p 8000:8000 \
kevmansilla/rag-backend:latest
Levantamos openweb-ui en la misma red
docker run -d \
--name openwebui-ragnet \
--network ragnet \
-p 3000:8080 \
-e OPENAI_API_BASE_URL=http://rag-backend:8000/v1 \
ghcr.io/open-webui/open-webui:main
Esto hace la conexion entre openweb-ui y el backend del rag-llm automatico,
al agregar la variable de entorno OPENAI_API_BASE_URL con la url del backend.
Para acceder a openweb-ui, abrir en el navegador
http://localhost:3000
ver logs del backend
docker logs -f rag-backend
git add .
git commit -am "cambio X"
git push
docker build -t kevmansilla/rag-backend:latest .
docker push kevmansilla/rag-backend:latest
Luego en el server
docker compose pull rag-backend
docker compose up -d rag-backend
El despliegue se realiza utilizando el archivo deploy.yaml:
kubectl apply -f deploy.yamlAsegúrese de tener las credenciales previamente cargadas en kubeconfig.yaml.
kubectl logs -f <nombre-del-pod>kubectl exec -it <nombre-del-pod> -- bashkubectl get pods
kubectl get servicesDado que OpenWebUI ya está desplegado en Kubernetes, la conexión se realiza mediante el servicio externo:
http://rag-backend-serv:8000/v1
Para verificar el consumo de tokens del modelo:
# Entrar al contenedor
docker exec -it rag-backend-calden bash
# Dentro del contenedor
python - <<EOF
import db_utils
print("Tokens:", db_utils.get_tokens())
EOF# Entrar al pod
kubectl exec -it <nombre-del-pod> -- bash
# Dentro del pod (mismo comando que en Docker)
python - <<EOF
import db_utils
print("Tokens:", db_utils.get_tokens())
EOFEste proyecto está bajo la Licencia MIT.



