DEV Community

Maru EU
Maru EU

Posted on • Edited on

Construyendo cosas... Día 1: Bot de nutrición deportiva con RAG

Acabo de terminar un proyecto en el que creé un nutricionista bot en Telegram usando RAG (Retrieval Augmented Generation) con Claude 3.5 Haiku. Quería compartir lo que aprendí en el camino, especialmente sobre cómo armar un sistema de IA que sea útil, seguro y escalable.

El Proyecto: Bot Nutricionista en Telegram

Básicamente, creé un bot que:

  • Recopila datos del usuario (peso, altura, objetivo deportivo)
  • Calcula calorías y macronutrientes personalizados
  • Responde preguntas sobre nutrición usando una base de conocimiento
  • Genera planes semanales y recomienda suplementos
  • Mantiene todo seguro con guardrails contra prompt injection

Suena simple, pero bajo el capó hay bastante arquitectura interesante.


Stack Tecnológico

LLM y APIs

  • Claude 3.5 Haiku (Anthropic) - Elegí Haiku por rapidez y costo, no perdía capacidades
  • Anthropic SDK - Para llamadas a la API

Vector Store y Búsqueda

  • FAISS - Para almacenar 990 chunks de documentos (guías de nutrición)
  • Sentence-Transformers (HuggingFace) - Embeddings multilingües en español
  • CrossEncoder - Reranking de resultados para mejorar relevancia

Framework y Backend

  • LangChain - Orquestación del pipeline RAG
  • Flask - Servidor para el webhook de Telegram
  • SQLite - Base de datos con 6 tablas para perfiles y conversaciones

Infraestructura

  • Docker - Containerización
  • ngrok - Para exponer el servidor local a Telegram

Lo Que Aprendí (y lo más interesante)

1. RAG No Es Solo Embeddings + LLM

Al principio pensé: "Recupero chunks, los mando al modelo y listo". Spoiler: no listo.

El problema: recuperar no es lo mismo que encontrar lo realmente relevante. FAISS es rápido pero aproximado - usa búsqueda por similitud coseno en vectores, que es como buscar con los ojos cerrados.

La solución: Reranking con CrossEncoder

Flujo naive:
Query → Embedding → FAISS (búsqueda k-NN) → Top 3 chunks → LLM

Flujo mejorado:
Query → Embedding → FAISS (búsqueda k-NN) → Top 9 candidatos → CrossEncoder 
→ Reranking por relevancia real → Top 3 chunks → LLM
Enter fullscreen mode Exit fullscreen mode

El CrossEncoder (mmarco-mMiniLMv2-L12-H384-v1) evalúa cada pareja (query, documento) de forma conjunta. Sí, es más lento, pero los resultados mejoraron un 169% en "Context Precision".

Metrics que lo prueban (evaluación RAGas):

  • Context Precision: 28% → 77% 📈
  • Answer Relevancy: 40% → 85% 📈
  • Faithfulness: 39% → 67% 📈

2. Embeddings Multilingües Son Críticos

Usé paraphrase-multilingual-MiniLM-L12-v2 porque mi base de conocimiento y usuarios son en español. El modelo por defecto en muchos tutoriales es inglés.

La diferencia es brutal. Cuando pedí "¿cuánta proteína necesito?" con embeddings en inglés, recuperaba documentos sobre tipos de prótidos en química. Con multilingüe, recuperaba guías de proteína para atletas.

Lección: No ignores la dimensión lingüística de tu proyecto. Los modelos tienen sesgo hacia los datos en los que fueron entrenados.

3. Guardrails No Son Paranoia, Son Arquitectura

Implementé 3 capas de validación:

Capa 1 - Entrada (pre-LLM)

# Detectar prompt injection
if detect_prompt_injection(user_message):
    return "No puedo procesar esa solicitud"

# Detectar off-topic
if is_off_topic(user_message):
    return "Eso está fuera de mi dominio de nutrición"
Enter fullscreen mode Exit fullscreen mode

Capa 2 - System Prompt Reforzado
El system prompt de Claude incluye 6 reglas explícitas: solo nutrición, sin revelar info técnica, resistencia a jailbreaks, etc.

Capa 3 - Salida (post-LLM)

# Filtrar respuesta para no exponer info sensible
if contains_sensitive_patterns(llm_response):
    return generic_safe_response()
Enter fullscreen mode Exit fullscreen mode

¿Por qué 3 capas? Porque cada capa falla de forma diferente:

  • La inyección de prompts puede pasar el filtro de entrada (lenguaje creativo)
  • El LLM puede "olvidar" el system prompt (alucinaciones)
  • La respuesta puede contener accidentalmente una ruta de archivo o SQL query

Redundancia = resilencia.

4. El Costo Real de los Modelos en Producción

Comparé dos estrategias:

Opción A: Fine-tuning en GPU

  • Fine-tuning: $5-20 (barato ✓)
  • Servir 24/7 en A100: $641/mes
  • Total: ~$650/mes

Opción B: Claude Haiku API

  • 100 queries/día (nuestro caso)
  • Costo mensual: ~$4.80

Diferencia: 135x más barato con API.

Además, fine-tuning hubiera requiere MLOps, versionado de modelos, pipeline de datos. Para un MVP, la complejidad operativa no vale la pena.

Cuándo sí haría fine-tuning: 50k+ queries/día, latencia crítica (<100ms), datos propietarios que no pueden salir de la infraestructura.

5. Las Herramientas Son Mejor Que Embeddings Especializados

En lugar de usar embeddings específicos para "cálculo de macros" u "búsqueda de recetas", creé 5 herramientas especializadas que el agente invoca según la conversación:

tools = {
    "calcular_macros_objetivo": formula_cientifica(),
    "buscar_recetas_por_deporte": json_lookup(),
    "generar_menu_diario": rule_based(),
    "recomendar_suplementos": calculo_personalizado(),
    "calcular_ajuste_revision": analisis_progreso()
}
Enter fullscreen mode Exit fullscreen mode

El LLM decide cuál usar. Es más interpretable (sé exactamente qué hace cada tool) y auditable (puedo verificar los cálculos).

Ejemplo:

User: "Recomendame suplementos para crossfit"
↓
Agent decide: invoke_tool("recomendar_suplementos", deporte="crossfit")
↓
Tool devuelve JSON con dosis personalizadas (peso, edad, objetivo)
↓
Agent formatea respuesta natural
Enter fullscreen mode Exit fullscreen mode

Sin tools, todo sería "preguntale al LLM y espera a ver qué responde". Con tools, tengo garantías.

6. SQLite Escala Mejor de Lo Que Pensaba

Diseñé 6 tablas:

  • users - Info básica
  • user_profiles - Perfil nutricional
  • conversation_history - Chats
  • weekly_schedules - Planes
  • user_revisions - Seguimiento de progreso
  • onboarding_progress - Estado temporal

Para producción a escala, obvio usaría PostgreSQL. Pero para un bot con 100 usuarios activos, SQLite es simple, suficiente y sin overhead operativo. El archivo .db cabe en un commit de Git.


Resultados de Evaluación

Corrí evaluación formal con RAGas (framework para evaluar RAG):

Métrica Sin Mejoras Con Mejoras Delta
Context Precision 28.7% 77.3% +169.7%
Context Recall 25.7% 68.3% +166.0%
Answer Relevancy 39.7% 84.8% +113.4%
Faithfulness 39.1% 67.1% +71.5%

Qué cambió: Pasé de embeddings en inglés sin reranking → embeddings multilingüe + CrossEncoder.

Eso prueba que los detalles de implementación importan. No es "RAG genérico", es RAG bien hecho.


3 Aprendizajes Clave Para Tu Próximo Proyecto RAG

  1. Reranking es tuya mejor amiga: Los embeddings recuperan candidatos rápido, pero el reranking elige los correctos. No lo saltes.

  2. Herramientas > Más contexto en el prompt: En lugar de meter toda la lógica de negocio en el prompt o en RAG, crea tools que el LLM invoque. Es más mantenible.

  3. Validación en 3 capas no es paranoia: Input → LLM → Output. Cada capa debe validar. Los guardrails son arquitectura, no un addon.


Stack Mínimo para un RAG Serio

Si empezas hoy un proyecto RAG, aquí está la receta:

LLM: Claude (Anthropic) o GPT-4o
Vector Store: FAISS (local) o Pinecone (cloud)
Embeddings: Sentence-Transformers multilingües
Reranking: CrossEncoder (mismo repo que embeddings)
Framework: LangChain (abstracción decente)
DB: SQLite o PostgreSQL según escala
Backend: FastAPI (mejor que Flask para producción)
Enter fullscreen mode Exit fullscreen mode

Código y Docs

Todo el proyecto está en GitHub con documentación completa:
hands-on-coding-llm-aiengineering

Incluye:

  • Arquitectura detallada
  • Scripts para actualizar la knowledge base
  • Evaluación RAGas con código
  • Docker para deployar en 2 comandos

Final

Este proyecto me enseñó que hacer un chatbot "que funciona" es fácil. Hacer uno que funciona bien requiere diseño:

  • Recuperación semántica correcta (RAG + reranking)
  • Herramientas para lógica determinista
  • Guardrails en múltiples capas
  • Evaluación formal de resultados

Espero que la experiencia sea útil si estás explorando RAG. Los números (Context Precision +169%) hablan solos.


¿Preguntas o sugerencias? Déjalas en los comentarios, estaré encantada de ayudarte

RAG #AI #LLM #Claude #Python #Telegram

Top comments (0)