RAG en Quarkus: un asistente que responde sobre tus documentos

En el artículo anterior creamos un asistente de IA que responde preguntas generales. Pero, ¿qué pasa si quieres que responda sobre tus propios documentos? Por ejemplo, un manual de tu empresa, una guía técnica o las políticas internas.

Eso es exactamente lo que hace RAG (Retrieval-Augmented Generation). Y con LangChain4j y Quarkus, implementarlo es sorprendentemente simple.

Para demostrarlo, crearemos un asistente que responde preguntas sobre una receta de cocina. Algo cotidiano que todos entendemos.


¿Qué es RAG?

RAG combina dos técnicas:

  1. Retrieval (Recuperación): busca fragmentos relevantes en tus documentos
  2. Augmented Generation (Generación aumentada): el modelo responde usando esos fragmentos como contexto

En otras palabras, busca en tus documentos y responde basándose en lo que encuentra.


¿Cómo funciona?

Cuando cargas documentos, el sistema:

  1. Los divide en fragmentos pequeños
  2. Convierte cada fragmento en un «embedding» (representación numérica)
  3. Los almacena en una base de datos vectorial

Cuando preguntas algo:

  1. Tu pregunta se convierte en embedding
  2. Se buscan los fragmentos más similares
  3. Se envían al modelo junto con tu pregunta
  4. El modelo responde usando ese contexto

Quarkus con easy-rag hace todo esto automáticamente.


Requisitos

  • Java 17 ó 21 (soportadas por Quarkus)
  • Maven 3.9 o superior
  • Podman o Docker funcionando
  • Quarkus CLI

¿No cumples todos los requisitos? Revisa Entorno de desarrollo ideal para Quarkus donde explicamos cómo instalar todo fácilmente.

Si usas Podman, te sugerimos revisar Usando Podman con Quarkus: la configuración esencial


Crear el proyecto

quarkus create app io.quarkiverso:rag-documentos \
  --extension=rest,langchain4j-ollama,langchain4j-easy-rag,smallrye-openapi \
  --no-code

Esto incluye:

  • REST: para exponer el endpoint
  • LangChain4j Ollama: el modelo de IA
  • Easy RAG: ingesta y búsqueda de documentos simplificada
  • SmallRye OpenAPI: Swagger UI para probar sin curl

Entra al proyecto:

cd rag-documentos

Agregar el documento

Crea la carpeta donde pondrás tus documentos:

mkdir -p src/main/resources/documentos

Crea un archivo de ejemplo src/main/resources/documentos/receta-tortilla.txt:

RECETA: TORTILLA ESPAÑOLA

Ingredientes (4 personas):
- 6 huevos grandes
- 4 patatas medianas (aproximadamente 500g)
- 1 cebolla mediana (opcional, pero recomendada)
- Aceite de oliva virgen extra
- Sal al gusto

Preparación:

1. Pela las patatas y córtalas en rodajas finas de 2-3 mm. 
   Si usas cebolla, córtala en juliana fina.

2. Calienta abundante aceite en una sartén honda a fuego medio.
   Añade las patatas y la cebolla. Cocina durante 20-25 minutos
   removiendo ocasionalmente. Deben quedar tiernas, no crujientes.

3. Escurre las patatas reservando el aceite. Sazona con sal.

4. Bate los huevos en un bol grande con una pizca de sal.
   Añade las patatas escurridas y mezcla bien.

5. En una sartén antiadherente de 24cm, calienta una cucharada 
   del aceite reservado. Vierte la mezcla y cocina a fuego 
   medio-bajo durante 4-5 minutos hasta que cuaje por debajo.

6. Dale la vuelta usando un plato. Cocina el otro lado 
   3-4 minutos más. El centro puede quedar jugoso.

Tiempo total: 35-40 minutos
Calorías aproximadas: 250 por porción
Dificultad: Media

Variantes:
- Sin cebolla: algunos puristas la prefieren así
- Con pimientos: añade pimiento rojo en el paso 2
- Versión express: usa patatas ya cocidas para reducir a 15 minutos

Consejos:
- El secreto está en cocinar las patatas a fuego lento
- Usa una sartén antiadherente de buen tamaño
- Para darle la vuelta, usa un plato más grande que la sartén

Puedes agregar tus propios documentos: manuales, FAQs, guías técnicas. Easy RAG soporta .txt y .pdf.


Crear el servicio de IA

Crea el archivo src/main/java/io/quarkiverso/AsistenteDocumentos.java:

package io.quarkiverso;

import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import io.quarkiverse.langchain4j.RegisterAiService;

@RegisterAiService
public interface AsistenteDocumentos {

    @SystemMessage("""
        Eres un asistente que responde preguntas basándose en los documentos disponibles.
        Responde de forma concisa, en máximo 2 oraciones.
        Si la información no está en los documentos, di "No tengo esa información".
        """)
    String responder(@UserMessage String pregunta);
}

El @SystemMessage guía al modelo sobre cómo responder. Easy RAG se encarga automáticamente de buscar los fragmentos relevantes y enviarlos como contexto.


Crear el endpoint

Crea el archivo src/main/java/io/quarkiverso/AsistenteResource.java:

package io.quarkiverso;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;

@Path("/asistente")
public class AsistenteResource {

    @Inject
    AsistenteDocumentos asistente;

    @GET
    public String preguntar(@QueryParam("pregunta") String pregunta) {
        return asistente.responder(pregunta);
    }
}

Configurar Easy RAG

Edita src/main/resources/application.properties:

# Ruta a los documentos
quarkus.langchain4j.easy-rag.path=src/main/resources/documentos
# Cantidad de fragmentos a recuperar por pregunta
quarkus.langchain4j.easy-rag.max-results=3
# Tamaño máximo de cada fragmento
quarkus.langchain4j.easy-rag.max-segment-size=500

# Timeout para respuestas del modelo (útil en documentos grandes)
quarkus.langchain4j.ollama.timeout=PT60S

Con esta configuración, Easy RAG:

  • Carga todos los archivos de la carpeta documentos
  • Busca los 3 fragmentos más relevantes para cada pregunta
  • Divide documentos largos en fragmentos de 500 caracteres

💡 Para documentos grandes (PDFs extensos), puedes aumentar max-results a 5 y max-segment-size a 1000.


Ejecutar

Asegúrate que Podman o Docker esté corriendo y ejecuta:

quarkus dev

Durante el arranque verás que carga los documentos:

Ingesting documents from filesystem: src/main/resources/documentos

Probar con Swagger UI

Abre el navegador en http://localhost:8080/q/swagger-ui

Expande el endpoint GET /asistente, haz clic en el botón «Try it out», escribe tu pregunta y ejecuta. Verás la respuesta debajo en Response body.

Prueba estas preguntas:

PreguntaRespuesta esperada
¿Cuántos huevos lleva?6 huevos grandes
¿Cuánto tiempo tarda?35-40 minutos
¿Se puede hacer sin cebolla?Sí, algunos puristas la prefieren así
¿Cuántas calorías tiene?250 por porción aproximadamente
¿Cuál es el secreto?Cocinar las patatas a fuego lento
¿Cómo hacerla más rápido?Usar patatas ya cocidas, reduce a 15 minutos

Ahora prueba algo que no está en el documento:

PreguntaRespuesta mínima esperada
¿Cómo hacer paella?No tengo esa información
¿Cuántos limones lleva?No tengo esa información

💡 Tip: RAG funciona mejor cuando la pregunta está semánticamente cerca del contenido. «¿Cuántos huevos?» conecta perfectamente con «6 huevos grandes» en la receta.


Sobre el rendimiento

La primera pregunta tarda más porque Ollama carga el modelo en memoria (~3GB). Las siguientes preguntas son más rápidas.

Factores que afectan la velocidad:

  • CPU vs GPU: con GPU NVIDIA es mucho más rápido
  • Tamaño del modelollama3.2 es equilibrado; tinyllama es más rápido pero menos preciso
  • Cantidad de contexto: más fragmentos = más tiempo de procesamiento

Agregar más documentos

Simplemente agrega más archivos a src/main/resources/documentos/. Easy RAG soporta .txt y .pdf.

Puedes agregar manuales técnicos, guías de tu empresa, documentación de proyectos o cualquier contenido que quieras consultar. Reinicia la aplicación para que cargue los nuevos documentos.


¿Qué pasó detrás?

Con solo tres líneas de configuración, Easy RAG:

  1. Cargó el documento y lo dividió en fragmentos
  2. Calculó embeddings y los almacenó en memoria
  3. Al preguntar, buscó los fragmentos más relevantes
  4. Envió esos fragmentos como contexto al modelo
  5. El modelo respondió basándose en ese contexto

Próximos pasos

  • Agrega documentos reales: manuales, políticas, FAQs de tu empresa
  • Experimenta con max-results y max-segment-size

Código fuente: github.com/quarkiverso/rag-documentos