Tag: RAG

  • Implementación de RAG en el Frontend con Angular para Chat con PDFs

    Implementación de RAG en el Frontend con Angular para Chat con PDFs

    Implementación de RAG (Retrieval-Augmented Generation) en el Frontend con Angular

    Tiempo estimado de lectura: 5 min

    • Ideas clave:
    • RAG combina recuperación semántica (vector DB) y generación (LLM); en el frontend debe evitar exponer claves y delegar embeddings/search/generation a una BFF/Edge Function.
    • Flujo: preprocesado offline → indexación (vector DB) → consulta runtime a Edge Function → streaming del LLM al frontend.
    • Angular actúa como orquestador UI: JWT al BFF, consumo de ReadableStream, y Signals para estado y streaming.
    • Seguridad multi-tenant: RLS/metadata.filter y nunca incluir keys en el bundle cliente.

    Implementación de RAG (Retrieval-Augmented Generation) en el Frontend con Angular: aquí verás un diseño pragmático y seguro para que tus usuarios “chateen” con PDFs y bases de conocimiento sin exponer claves privadas, y con una experiencia de streaming y baja latencia.

    Resumen rápido (lectores con prisa)

    RAG une un índice vectorial para recuperar contexto relevante con un LLM que genera respuestas. Úsalo cuando necesites respuestas ancladas en documentación privada. Importa porque permite precisión y control de costos. Funciona: preprocesado e indexado server-side, BFF/Edge Function para retrieval + prompt building + streaming, y frontend que consume el stream y mantiene estado con Signals.

    Implementación de RAG (Retrieval-Augmented Generation) en el Frontend con Angular — resumen arquitectónico

    RAG combina recuperación semántica (vector DB) y generación (LLM). En el frontend esto se traduce en tres responsabilidades claras:

    • Orquestar la UI y el estado reactivo.
    • Llamar a una capa segura (BFF / Edge Function) que haga embeddings, búsqueda y generación.
    • Mostrar la respuesta en streaming con Signals para una UX fluida.

    Nunca pongas claves de OpenAI, Pinecone o Supabase en el bundle. Usa BFF/Edge Functions. Patrones y herramientas: Supabase (pgvector + Edge Functions + RLS), Pinecone, OpenAI Embeddings, SSE/Streams MDN, Angular Signals.

    Paso a paso: flujo de datos y responsabilidades

    Preprocesado (server-side, offline)

    • Extrae texto del PDF (pdfminer, tika, or pdf-lib).
    • Segmenta en chunks (200–1000 tokens según modelo).
    • Calcula embeddings y guarda vectores con metadata: { documentId, chunkId, text, userId }.
    • Upsert en la vector DB (Pinecone o Supabase pgvector).

    Consulta desde Angular (runtime)

    • Usuario pregunta en la UI.
    • Angular envía la petición a la Edge Function (BFF) con el JWT del usuario.
    • La Edge Function:
      • a) crea embedding de la consulta,
      • b) hace búsqueda semántica filtrada por metadata (userId) en la vector DB,
      • c) construye prompt con los top-K chunks,
      • d) llama al LLM (streaming) y reenvía el stream al cliente.

    Presentación (cliente)

    • Angular consume el stream y muestra la respuesta en tiempo real.
    • Signals mantiene conversación, estados y métricas.

    Código práctico: servicio Angular para consumir stream RAG

    Este es el patrón cliente: Angular delega todo a una URL segura y procesa un ReadableStream en Signals.

    <!-- rag-client.service.ts -->
    import { Injectable, signal } from '@angular/core';
    
    export interface ChatMessage { role: 'user'|'assistant'; content: string; }
    
    @Injectable({ providedIn: 'root' })
    export class RagClientService {
      public convo = signal<ChatMessage[]>([]);
      public loading = signal(false);
    
      async ask(question: string, docId: string, token: string) {
        this.convo.update(c => [...c, { role: 'user', content: question }]);
        this.convo.update(c => [...c, { role: 'assistant', content: '' }]);
        this.loading.set(true);
    
        const res = await fetch(`/api/rag?doc=${docId}`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
          body: JSON.stringify({ question })
        });
    
        if (!res.body) { this.loading.set(false); throw new Error('No stream'); }
        const reader = res.body.getReader();
        const dec = new TextDecoder();
        let done = false;
    
        while (!done) {
          const { value, done: rDone } = await reader.read();
          done = rDone;
          if (value) {
            const chunk = dec.decode(value, { stream: true });
            this.append(chunk);
          }
        }
        this.loading.set(false);
      }
    
      private append(text: string) {
        this.convo.update(c => {
          const last = [...c];
          const idx = last.length - 1;
          last[idx] = { ...last[idx], content: last[idx].content + text };
          return last;
        });
      }
    }
    

    Seguridad y multi-tenant: cómo proteger datos y consultas

    • Edge Functions (Supabase / Vercel) firman y validan JWT. Angular solo envía el token del usuario.
    • En Supabase usa Row Level Security (RLS) para que la consulta vectorial devuelva solo vectores del userId (https://supabase.com/docs).
    • En Pinecone añade metadata.filter (userId) en las queries y realiza autorización en tu backend.
    • Nunca aceptes keys “hosted” en el cliente; si necesitas BYOK (Bring Your Own Key), que el usuario lo suministre y limite permisos.

    Buenas prácticas de diseño

    • Chunking y contexto: corta por sentencias y 200–500 tokens. Guarda overlap para preservar contexto.
    • Top-K + score threshold: recupera 3–8 chunks y descarta con score bajo para evitar ruido.
    • Fallback y control de costos: si la DB no devuelve contexto útil, responde con “No encontré información” en lugar de llamar al LLM.
    • Telemetría: registra latencia de retrieval vs generation, porcentaje de respuestas sin contexto.
    • UX: muestra progreso de retrieval y luego streaming del LLM; evita spinners largos.

    Resumen y criterio

    Implementación de RAG en el frontend con Angular no es “cliente habla con Pinecone”. Es dividir responsabilidades: preprocesado e indexación en backend, retrieval y prompt-building en BFF/Edge Function, y presentación + streaming en Angular. Esa separación protege claves, permite RLS/tenant isolation y ofrece una UX moderna con Signals y ReadableStreams.

    Si quieres ejemplos de Edge Functions (Supabase) o plantillas para indexado de PDF, lo siguiente es lo lógico: un script server-side que extrae texto, chunkea, crea embeddings (OpenAI) y hace upsert a la vector DB. Cuando tengas ese bloque, el frontend es trivial: JWT + fetch streaming + Signals. Implementa eso y tendrás un “chat” con tus PDFs que realmente sirve en producción.

    Para recursos citados en el artículo: Supabase (pgvector + Edge Functions + RLS), Pinecone, OpenAI Embeddings, SSE/Streams MDN, Angular Signals.

    Continúa explorando plantillas y laboratorios técnicos en Dominicode Labs para ver implementaciones prácticas y scripts de indexado que complementan este flujo.

    FAQ

    ¿Qué es RAG y cuándo debería usarlo?

    RAG (Retrieval-Augmented Generation) combina una base de conocimiento indexada en vectores para recuperar contexto relevante y un LLM para generar respuestas. Úsalo cuando necesites respuestas ancladas en documentación privada, control de factualidad y reducción de costos frente a enviar todo el prompt al LLM.

    ¿Dónde deben vivír las claves de OpenAI / Pinecone?

    Las claves deben residir en el backend (BFF o Edge Functions). Nunca las incluyas en el bundle cliente. El frontend solo envía el JWT del usuario y la Edge Function realiza llamadas a los servicios con las claves seguras.

    ¿Cómo evito fugas de datos entre tenants?

    Usa Row Level Security (RLS) en Supabase o filtros de metadata (por ejemplo userId) en Pinecone y valida JWT en la Edge Function para asegurar que las queries devuelvan solo vectores autorizados.

    ¿Qué tamaño de chunk es recomendado?

    Segmenta entre 200–1000 tokens según el modelo; una recomendación práctica es 200–500 tokens con overlap para preservar contexto y mantener relevancia.

    ¿Qué hacer si la vector DB no devuelve contexto útil?

    Implementa un fallback: responde con “No encontré información” en lugar de llamar al LLM para evitar costos y respuestas potencialmente incorrectas sin contexto.

    ¿Cómo mostrar streaming en Angular?

    Consume el ReadableStream desde fetch, lee chunks con un TextDecoder y actualiza el estado reactivo (Signals) a medida que llegan datos para una experiencia en tiempo real.

    ¿Qué telemetría es esencial?

    Registra latencia de retrieval vs generation, porcentaje de respuestas sin contexto y métricas de coste por llamada al LLM para evaluar trade-offs y optimizaciones.

  • Mejorando la Recuperación de Información con RAG Avanzado

    Mejorando la Recuperación de Información con RAG Avanzado

    RAG Avanzado: Híbrido, Jerárquico y Multi-Vector

    RAG Avanzado: Híbrido, Jerárquico y Multi-Vector. Si eso suena a demasiada ingeniería comparado con “chunk + embeddings”, es porque lo es —y la diferencia entre demo y producto está justo ahí. En producción no vale con que el LLM “suene bien”; necesitas precisión, contexto y control de coste. Este artículo explica qué técnicas añadir, por qué y cuándo.

    Tiempo estimado de lectura: 4 min

    • Ideas clave:
    • La recuperación es el 80% de una buena respuesta: combina sparse (BM25) y dense (embeddings).
    • Arquitectura jerárquica (child + parent) equilibra precisión de fragmento y contexto coherente.
    • Re-ranking con cross-encoders y compresión de contexto reducen hallucinations y coste token.

    Introducción

    La calidad de las respuestas generadas por un sistema RAG depende mayoritariamente de la recuperación. Los vectores aportan semántica; los métodos sparse (BM25) aportan exactitud. En producción necesitas precisión, contexto y control de coste; esto implica añadir capas: híbrido, jerarquía, re-ranking, rewriting y compresión de contexto.

    Resumen rápido (lectores con prisa)

    RAG avanzado combina búsquedas sparse (BM25) y dense (embeddings) para precisión y semántica. Usa indexing jerárquico child→parent para fragmentos precisos con contexto. Re-rank con cross-encoders para reducir ruido. Reescribe y descompone queries; comprime contexto antes del LLM.

    RAG Avanzado: implementación práctica

    1) Hybrid retrieval: BM25 + embeddings

    Problema: buscas “ERR-9921” y el vector devuelve “error de sistema” porque semánticamente es parecido. Solución: híbrido.

    • Sparse: BM25/Elasticsearch para coincidencias literales.
    • Dense: embeddings (OpenAI, Cohere, etc.) para intención.
    • Fusión: Reciprocal Rank Fusion (RRF) o combinación ponderada. Pinecone hybrid search

    Patrón práctico:

    • Ejecuta BM25 y vector search en paralelo.
    • Normaliza scores.
    • Fusiona con RRF.
    • Si BM25 tiene match exacto para tokens sensibles (IDs, SKUs), priorízalo.

    2) Multi-vector / Parent-Child indexación

    Dilema clásico: chunks pequeños = mejor match; chunks grandes = mejor contexto. La arquitectura jerárquica arregla ambos.

    • Indexa embeddings a nivel child (p. ej. 200 tokens).
    • Mantén parent docs grandes (p. ej. 2000 tokens) con metadata.
    • Al recuperar un child relevante, sube el parent completo al contexto.

    Implementación: LangChain ParentDocumentRetriever — LangChain ParentDocumentRetriever

    Beneficio: precisión de fragmento + contexto coherente para razonamiento.

    3) Re-ranking con cross-encoders

    Bi-encoders: rápidos, aproximados. Cross-encoders: lentos, precisos.

    Flujo:

    1. Fast retrieval → top N (50).
    2. Cross-encoder rerank en top N.
    3. Selecciona top K final para el LLM.

    Herramientas: sentence-transformers, Cohere Rerank. Costo: aumenta latencia; recompensa: reduce ruido que provoca hallucinations.

    4) Query rewriting y decomposition

    Muchos fallos vienen por queries ambiguas. No todos los problemas se arreglan en el índice.

    • Query rewrite: un LLM rápido reescribe la consulta con contexto de la sesión.
    • Multi-query: genera 3–5 variantes de la pregunta y busca por cada una.
    • Decomposition: divide preguntas complejas en sub-queries paralelas.

    Técnica HyDE (Hypothetical Document Embeddings) es útil: genera la “respuesta hipotética”, embeddea eso y busca. Idea en práctica: mejora recall sin cambiar el índice.

    5) Context compression antes del LLM

    Enviar 10 documentos de 8k tokens es suicida. Comprime:

    • Filtrado selectivo: extrae párrafos con más evidencia.
    • Summarization condensado (con cuidado: pierde citas).
    • Algoritmos de compresión semántica como LLMLingua

    Objetivo: maximizar densidad informativa dentro de la ventana del LLM.

    Criterio para decidir qué añadir (roadmap pragmático)

    No implementes todo a la vez. Sigue este orden iterativo:

    1. Naive RAG. Mide recall@5 y tasa de hallucination.
    2. Si fallan exact matches → añade Hybrid (BM25).
    3. Si falta contexto coherente → añade Parent-Child multi-vector.
    4. Si llega ruido que confunde al LLM → añade Re-ranking.
    5. Si tokens exceden la ventana → añade Context Compression.

    Mide antes y después. No hay excusas.

    Operacional: latencia, coste y caching

    • Re-ranking y cross-encoders aumentan latencia 10x en la etapa de ranking. Mitiga con caching de top-N por query fingerprint.
    • Hybrid search añade coste infra (Elasticsearch + vector DB). Mide Cost/Accuracy.
    • Batch embeddings nocturnos para contenido estático. Mantén refresh policies.
    • Telemetría: trace request → retrieval steps → rerank → LLM call. LangFuse y LangSmith ayudan a visualizar traces (LangFuse, LangSmith).

    Integración con agentes y workflows (n8n)

    Pipeline ejemplo en n8n:

    1. Node: Query Rewrite (LLM pequeño)
    2. Node: Hybrid Search (ES + Pinecone/Qdrant)
    3. Node: Rerank (Cross-Encoder)
    4. Node: Parent Expander + Context Compressor
    5. Node: LLM final (generation)
    6. Node: Post-check (schema validation / guardrails)

    Versiona prompts, registra fingerprints y alertas en drift.

    Referencias operativas

    Implementar RAG avanzado es menos glamour y más disciplina: medir, añadir la capa correcta y repetir. Hazlo así y tu sistema dejará de improvisar respuestas y empezará a dar respuestas que puedes explicarle al CTO.

    Dominicode Labs

    Si trabajas con pipelines de agentes, workflows o IA aplicada, considera explorar integraciones y experimentos prácticos en Dominicode Labs. Es una continuación lógica para prototipos operacionales y pruebas de telemetría.

    FAQ

     

    Respuesta: ¿Por qué combinar BM25 con embeddings?

    BM25 proporciona coincidencias literales útiles para IDs, SKUs y frases exactas; los embeddings capturan intención y sinónimos. El híbrido reduce falsos positivos semánticos y mejora precisión en búsquedas sensibles.

     

    Respuesta: ¿Qué ventaja tiene la indexación parent-child?

    Permite mantener chunks pequeños para alta precisión en matching mientras se conserva contexto amplio subiendo el documento parent al LLM cuando un child es relevante.

     

    Respuesta: ¿Cuándo usar cross-encoders para re-ranking?

    Úsalos cuando el top-N recuperado contenga ruido que provoca hallucinations o respuestas incorrectas. Son adecuados para reducir falsos positivos aunque aumenten latencia y coste.

     

    Respuesta: ¿Qué es HyDE y por qué usarlo?

    HyDE (Hypothetical Document Embeddings) genera una “respuesta hipotética” desde un LLM, la embeddea y busca con esa representación. Mejora recall sin tocar el índice.

     

    Respuesta: ¿Cómo mitigar la latencia al re-rankear?

    Cachea top-N por huella de consulta, ejecuta re-ranking asíncrono donde sea posible y usa cross-encoders solo en escenarios críticos o por lotes nocturnos para contenido estático.

     

    Respuesta: ¿Qué técnicas de compresión de contexto son seguras?

    Filtrado selectivo de párrafos con evidencia, resúmenes condensados con control de citas y algoritmos semánticos como LLMLingua. Ten cuidado: la compresión puede perder citas y detalles verificables.