3 min de lectura

RAG Enterprise en Java: de la teoria a produccion

RAG Enterprise en Java: de la teoria a produccion

RAG (Retrieval Augmented Generation) permite a los LLMs responder preguntas usando tus propios datos. Aprende a implementar soluciones enterprise-grade en Java.

¿Por qué RAG?

Los LLMs tienen limitaciones importantes:

  • Conocimiento estático: No conocen tus datos internos
  • Alucinaciones: Inventan información cuando no saben
  • Sin actualizaciones: Su conocimiento tiene fecha de corte

RAG resuelve estos problemas conectando el LLM a tu base de conocimiento.

Arquitectura RAG

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│   Usuario    │────▶│   Retriever  │────▶│ Vector Store │
└──────────────┘     └──────────────┘     └──────────────┘
       │                    │
       │                    ▼
       │            ┌──────────────┐
       │            │  Documentos  │
       │            │  relevantes  │
       │            └──────────────┘
       │                    │
       ▼                    ▼
┌──────────────────────────────────┐
│              LLM                  │
│   (pregunta + contexto)          │
└──────────────────────────────────┘


        ┌──────────────┐
        │   Respuesta  │
        │  fundamentada│
        └──────────────┘

Stack tecnológico

  • LangChain4j: Framework de IA para Java
  • PostgreSQL + pgvector: Vector store escalable
  • Quarkus: Framework cloud-native
  • Ollama: Modelos locales (privacidad)

Configuración de pgvector

-- Habilitar extensión
CREATE EXTENSION vector;

-- Tabla de embeddings
CREATE TABLE document_embeddings (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    content TEXT NOT NULL,
    metadata JSONB,
    embedding vector(1536),
    created_at TIMESTAMP DEFAULT NOW()
);

-- Índice para búsqueda eficiente
CREATE INDEX ON document_embeddings
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);

Implementación con LangChain4j

Configuración del EmbeddingStore

@ApplicationScoped
public class VectorStoreConfig {

    @ConfigProperty(name = "pgvector.host")
    String host;

    @ConfigProperty(name = "pgvector.database")
    String database;

    @Produces
    @ApplicationScoped
    EmbeddingStore<TextSegment> embeddingStore() {
        return PgVectorEmbeddingStore.builder()
            .host(host)
            .port(5432)
            .database(database)
            .user("app")
            .password("secret")
            .table("document_embeddings")
            .dimension(1536)
            .build();
    }
}

Ingesta de documentos

@ApplicationScoped
public class DocumentIngestionService {

    @Inject
    EmbeddingStore<TextSegment> store;

    @Inject
    EmbeddingModel embeddingModel;

    public void ingest(Path documentPath) {
        // 1. Cargar documento
        Document document = FileSystemDocumentLoader.loadDocument(
            documentPath,
            new ApachePdfBoxDocumentParser()
        );

        // 2. Dividir en chunks
        DocumentSplitter splitter = DocumentSplitters.recursive(
            500,   // max chunk size
            50     // overlap
        );
        List<TextSegment> segments = splitter.split(document);

        // 3. Generar embeddings
        List<Embedding> embeddings = embeddingModel.embedAll(segments).content();

        // 4. Almacenar
        store.addAll(embeddings, segments);
    }
}

Servicio RAG

@ApplicationScoped
public class RagService {

    private final Assistant assistant;

    @Inject
    public RagService(
        ChatLanguageModel model,
        EmbeddingStore<TextSegment> store,
        EmbeddingModel embeddingModel
    ) {
        ContentRetriever retriever = EmbeddingStoreContentRetriever.builder()
            .embeddingStore(store)
            .embeddingModel(embeddingModel)
            .maxResults(5)
            .minScore(0.7)
            .build();

        this.assistant = AiServices.builder(Assistant.class)
            .chatLanguageModel(model)
            .contentRetriever(retriever)
            .build();
    }

    public String query(String question) {
        return assistant.answer(question);
    }

    interface Assistant {
        @SystemMessage("""
            Eres un asistente experto. Responde SOLO basándote en el contexto proporcionado.
            Si no encuentras la información, di "No tengo información sobre eso".
            Cita las fuentes cuando sea posible.
            """)
        String answer(@UserMessage String question);
    }
}

Mejoras para producción

1. Chunking inteligente

DocumentSplitter splitter = DocumentSplitters.recursive(
    500,
    50,
    new OpenAiTokenizer("gpt-4")  // Cuenta tokens reales
);

2. Metadata enriquecida

TextSegment segment = TextSegment.from(
    content,
    Metadata.from("source", "manual-v2.pdf")
        .add("page", "15")
        .add("section", "Configuración")
);

3. Reranking

ContentRetriever retriever = EmbeddingStoreContentRetriever.builder()
    .embeddingStore(store)
    .embeddingModel(embeddingModel)
    .maxResults(20)  // Traer más
    .build();

// Reranker reduce a los más relevantes
Reranker reranker = CohereReranker.builder()
    .apiKey(cohereApiKey)
    .build();

4. Caché semántico

@ApplicationScoped
public class SemanticCache {

    private final EmbeddingStore<TextSegment> cacheStore;
    private final EmbeddingModel embeddingModel;

    public Optional<String> get(String query) {
        Embedding queryEmbedding = embeddingModel.embed(query).content();
        List<EmbeddingMatch<TextSegment>> matches =
            cacheStore.findRelevant(queryEmbedding, 1, 0.95);

        return matches.isEmpty()
            ? Optional.empty()
            : Optional.of(matches.get(0).embedded().metadata().get("response"));
    }
}

API REST

@Path("/api/rag")
@Produces(MediaType.APPLICATION_JSON)
public class RagResource {

    @Inject
    RagService ragService;

    @POST
    @Path("/query")
    public Response query(QueryRequest request) {
        String answer = ragService.query(request.question());

        return Response.ok(new QueryResponse(
            request.question(),
            answer,
            Instant.now()
        )).build();
    }

    @POST
    @Path("/ingest")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response ingest(@MultipartForm FileUpload upload) {
        ragService.ingest(upload.filePath());
        return Response.accepted().build();
    }
}

Conclusión

RAG transforma los LLMs de curiosidades a herramientas empresariales reales. Con Java, pgvector y LangChain4j, puedes construir sistemas robustos que respetan la privacidad de tus datos y escalan con tu organización.

¿Te gustó? ¡Compártelo!

Comentarios (0)

Cargando...