# RAG & Knowledge Management - Guía Completa Técnica

## Introducción y Fundamentos

### ¿Qué es RAG (Retrieval Augmented Generation)?
- **Definición**: Sistema que combina búsqueda de información relevante con generación de respuestas por IA
- **Ventaja**: Permite a la IA acceder a conocimiento específico y actualizado sin reentrenamiento
- **Aplicaciones**: Chatbots empresariales, sistemas de soporte, análisis de documentos, knowledge bases

### Arquitectura RAG Completa
```
Document Ingestion → Text Processing → Embedding Generation → 
Vector Storage → Query Processing → Semantic Search → 
Context Injection → LLM Generation → Response Delivery
```

### RAG Tradicional vs RAG Semántico

#### RAG Tradicional (Método Básico):
```
Limitaciones:
- Chunking simple por tamaño (1000 caracteres)
- Metadatos mínimos (solo ID de documento)
- Sin estructura jerárquica
- Contexto limitado entre chunks
```

#### RAG Semántico (Método Avanzado):
```
Ventajas:
- Chunking inteligente por contenido semántico
- Metadatos ricos (sección, subsección, contexto)
- Estructura jerárquica preservada
- Mayor precisión en retrieval
```

## Implementación RAG Tradicional

### Arquitectura Básica en n8n

#### Data Ingestion Pipeline:
```json
Workflow: RAG_Traditional_Upload
1. Google Drive Watch → 2. Download File → 3. Extract PDF Text → 
4. Simple Chunking → 5. Generate Embeddings → 6. Store in Vector DB
```

#### Configuración de Chunking Tradicional:

**PDF Text Extraction**:
```json
{
  "method": "POST",
  "url": "https://api.pdfshift.io/v3/convert/pdf",
  "headers": {
    "Authorization": "Basic {{base64_api_key}}"
  },
  "body": {
    "source": "{{$json.file_url}}",
    "format": "text"
  }
}
```

**Simple Text Chunking**:
```javascript
// Code node para chunking básico
const chunkText = (text, chunkSize = 1000, overlap = 100) => {
  const chunks = [];
  let start = 0;
  
  while (start < text.length) {
    const end = Math.min(start + chunkSize, text.length);
    const chunk = text.slice(start, end);
    
    chunks.push({
      content: chunk,
      metadata: {
        document_id: $json.document_id,
        chunk_index: chunks.length,
        start_pos: start,
        end_pos: end
      }
    });
    
    start += chunkSize - overlap;
  }
  
  return chunks.map(chunk => ({json: chunk}));
};
```

#### Embedding Generation:

**OpenAI Embeddings**:
```json
{
  "method": "POST",
  "url": "https://api.openai.com/v1/embeddings",
  "headers": {
    "Authorization": "Bearer {{openai_api_key}}"
  },
  "body": {
    "model": "text-embedding-3-small", // Más barato que 3-large
    "input": "{{$json.chunk_content}}",
    "encoding_format": "float"
  }
}
```

#### Vector Storage (Supabase):

**Database Schema**:
```sql
-- Crear tabla de vectores
CREATE TABLE knowledge_chunks (
  id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
  content TEXT NOT NULL,
  embedding VECTOR(1536), -- text-embedding-3-small dimension
  metadata JSONB DEFAULT '{}',
  document_id TEXT,
  chunk_index INTEGER,
  created_at TIMESTAMP DEFAULT NOW()
);

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

**Insert Vector Data**:
```json
{
  "method": "POST",
  "url": "https://your-project.supabase.co/rest/v1/knowledge_chunks",
  "headers": {
    "apikey": "{{supabase_anon_key}}",
    "Authorization": "Bearer {{supabase_anon_key}}",
    "Content-Type": "application/json"
  },
  "body": {
    "content": "{{$json.chunk_content}}",
    "embedding": {{$json.embedding_vector}},
    "metadata": {{$json.chunk_metadata}},
    "document_id": "{{$json.document_id}}",
    "chunk_index": {{$json.chunk_index}}
  }
}
```

## RAG Semántico Avanzado

### Análisis Estructural con GPT-4

#### Prompt para Análisis de Estructura:
```json
{
  "model": "gpt-4o", // Recomendado por su eficiencia y costo
  "messages": [
    {
      "role": "system",
      "content": "Eres un experto en análisis documental. Tu tarea es crear un resumen jerárquico estructurado de documentos."
    },
    {
      "role": "user",
      "content": "Analiza este documento y devuelve un resumen jerárquico en JSON de su estructura. Por cada bloque identifica:\n\n- título: título principal del documento\n- secciones: array con cada sección principal\n  - título: título de la sección\n  - start: posición de inicio en el texto (número de carácter)\n  - end: posición final en el texto\n  - subsecciones: array con subsecciones (mismo formato)\n\nEl JSON debe arrancar por el primer carácter y cubrir todo el texto.\n\nTexto del documento:\n{{$json.document_text}}"
    }
  ],
  "max_tokens": 4000,
  "temperature": 0.1
}
```

#### Respuesta Esperada:
```json
{
  "título": "Desempeño Exportador de España - Claves del Éxito",
  "secciones": [
    {
      "título": "Resumen Ejecutivo",
      "start": 0,
      "end": 1250,
      "subsecciones": []
    },
    {
      "título": "Introducción",
      "start": 1251,
      "end": 3400,
      "subsecciones": [
        {
          "título": "Contexto Económico",
          "start": 1251,
          "end": 2100
        },
        {
          "título": "Objetivos del Estudio", 
          "start": 2101,
          "end": 3400
        }
      ]
    }
  ]
}
```

### Semantic Chunking Implementation

#### Código de Chunking Semántico:
```javascript
// Code node para semantic chunking
const semanticChunker = (documentText, structureAnalysis) => {
  const chunks = [];
  
  // Función para procesar secciones recursivamente
  const processSection = (section, parentContext = "") => {
    const sectionText = documentText.slice(section.start, section.end);
    const fullContext = parentContext ? `${parentContext} > ${section.título}` : section.título;
    
    // Si la sección tiene subsecciones, procesarlas por separado
    if (section.subsecciones && section.subsecciones.length > 0) {
      section.subsecciones.forEach(subsection => {
        processSection(subsection, fullContext);
      });
    } else {
      // Crear chunk para sección sin subsecciones
      chunks.push({
        content: sectionText,
        metadata: {
          document_title: structureAnalysis.título,
          section_hierarchy: fullContext,
          section_title: section.título,
          start_position: section.start,
          end_position: section.end,
          content_type: "section",
          chunk_size: sectionText.length
        }
      });
    }
  };
  
  // Procesar todas las secciones
  structureAnalysis.secciones.forEach(section => {
    processSection(section);
  });
  
  return chunks.map(chunk => ({json: chunk}));
};
```

#### Enhanced Metadata Structure:
```json
{
  "document_id": "doc_12345",
  "document_title": "Desempeño Exportador de España",
  "section_hierarchy": "Introducción > Contexto Económico",
  "section_title": "Contexto Económico",
  "content_type": "section",
  "start_position": 1251,
  "end_position": 2100,
  "chunk_size": 849,
  "semantic_tags": ["economía", "exportación", "contexto"],
  "processing_date": "2026-02-18T10:30:00Z"
}
```

### Advanced Vector Storage

#### Enhanced Database Schema:
```sql
CREATE TABLE semantic_knowledge (
  id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
  content TEXT NOT NULL,
  embedding VECTOR(1536),
  document_id TEXT NOT NULL,
  document_title TEXT,
  section_hierarchy TEXT,
  section_title TEXT,
  content_type TEXT DEFAULT 'section',
  start_position INTEGER,
  end_position INTEGER,
  chunk_size INTEGER,
  semantic_tags TEXT[],
  metadata JSONB DEFAULT '{}',
  created_at TIMESTAMP DEFAULT NOW(),
  updated_at TIMESTAMP DEFAULT NOW()
);

-- Índices optimizados
CREATE INDEX idx_semantic_embedding ON semantic_knowledge 
USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);

CREATE INDEX idx_semantic_hierarchy ON semantic_knowledge 
USING gin(to_tsvector('spanish', section_hierarchy));

CREATE INDEX idx_semantic_tags ON semantic_knowledge 
USING gin(semantic_tags);

-- Función de búsqueda híbrida
CREATE OR REPLACE FUNCTION hybrid_search(
  query_embedding VECTOR(1536),
  search_text TEXT DEFAULT '',
  match_threshold FLOAT DEFAULT 0.8,
  match_count INTEGER DEFAULT 10
)
RETURNS TABLE (
  id UUID,
  content TEXT,
  similarity FLOAT,
  section_hierarchy TEXT,
  metadata JSONB
) AS $$
BEGIN
  RETURN QUERY
  SELECT 
    sk.id,
    sk.content,
    1 - (sk.embedding <=> query_embedding) AS similarity,
    sk.section_hierarchy,
    sk.metadata
  FROM semantic_knowledge sk
  WHERE 
    (search_text = '' OR sk.section_hierarchy ILIKE '%' || search_text || '%')
    AND (1 - (sk.embedding <=> query_embedding)) > match_threshold
  ORDER BY similarity DESC
  LIMIT match_count;
END;
$$ LANGUAGE plpgsql;
```

## Query Processing & Retrieval

### Intelligent Query Analysis

#### Query Intent Classification:
```json
{
  "model": "gpt-4o-mini",
  "messages": [
    {
      "role": "system",
      "content": "Clasifica la intención de búsqueda en: FACTUAL (hechos específicos), ANALYTICAL (análisis/comparación), PROCEDURAL (cómo hacer algo), CONCEPTUAL (explicaciones). También extrae keywords clave."
    },
    {
      "role": "user",
      "content": "Consulta del usuario: {{$json.user_query}}\n\nDevuelve JSON: {\"intent\": \"TIPO\", \"keywords\": [\"palabra1\", \"palabra2\"], \"complexity\": \"low/medium/high\"}"
    }
  ],
  "max_tokens": 150
}
```

#### Query Expansion:
```json
{
  "model": "gpt-4o-mini", 
  "messages": [
    {
      "role": "system",
      "content": "Expande consultas para mejorar búsqueda semántica. Genera sinónimos, términos relacionados y variaciones conceptuales."
    },
    {
      "role": "user",
      "content": "Consulta original: {{$json.user_query}}\nIntención: {{$json.query_intent}}\n\nGenera 3-5 variaciones de la consulta para búsqueda semántica:"
    }
  ]
}
```

### Hybrid Search Implementation

#### Multi-Stage Retrieval:
```javascript
// Code node para búsqueda híbrida avanzada
const performHybridSearch = async (userQuery, queryAnalysis) => {
  const results = [];
  
  // Stage 1: Vector similarity search
  const queryEmbedding = await generateEmbedding(userQuery);
  const vectorResults = await fetch('/api/vector-search', {
    method: 'POST',
    body: JSON.stringify({
      embedding: queryEmbedding,
      threshold: 0.7,
      limit: 20
    })
  });
  
  // Stage 2: Keyword-based search
  const keywordResults = await fetch('/api/keyword-search', {
    method: 'POST',
    body: JSON.stringify({
      keywords: queryAnalysis.keywords,
      sections: queryAnalysis.target_sections || []
    })
  });
  
  // Stage 3: Merge and re-rank
  const combinedResults = mergeResults(
    await vectorResults.json(),
    await keywordResults.json()
  );
  
  // Stage 4: Context-aware filtering
  const filteredResults = await contextualFilter(combinedResults, queryAnalysis);
  
  // Stage 5: Final re-ranking with LLM
  const finalResults = await llmRerank(filteredResults, userQuery);
  
  return finalResults.slice(0, 5); // Top 5 results
};
```

#### Result Re-ranking:
```json
{
  "model": "gpt-4o-mini",
  "messages": [
    {
      "role": "system", 
      "content": "Re-ordena resultados de búsqueda por relevancia específica a la consulta. Considera contexto, especificidad y utilidad."
    },
    {
      "role": "user",
      "content": "Consulta: {{$json.user_query}}\n\nResultados encontrados:\n{{$json.search_results}}\n\nDevuelve array de IDs ordenados por relevancia: [\"id1\", \"id2\", \"id3\"]"
    }
  ]
}
```

## Response Generation

### Context Injection

#### Advanced Context Assembly:
```javascript
// Code node para ensamblar contexto
const assembleContext = (searchResults, queryAnalysis) => {
  const context = {
    primary_sources: [],
    supporting_sources: [],
    hierarchical_context: {},
    confidence_scores: []
  };
  
  // Agrupar por jerarquía de secciones
  const hierarchyGroups = {};
  searchResults.forEach(result => {
    const hierarchy = result.metadata.section_hierarchy;
    if (!hierarchyGroups[hierarchy]) {
      hierarchyGroups[hierarchy] = [];
    }
    hierarchyGroups[hierarchy].push(result);
  });
  
  // Seleccionar fuentes primarias (alta relevancia)
  context.primary_sources = searchResults
    .filter(r => r.similarity > 0.85)
    .slice(0, 3)
    .map(r => ({
      content: r.content,
      source: r.metadata.section_hierarchy,
      confidence: r.similarity
    }));
  
  // Fuentes de apoyo (relevancia media)
  context.supporting_sources = searchResults
    .filter(r => r.similarity >= 0.7 && r.similarity <= 0.85)
    .slice(0, 2)
    .map(r => ({
      content: r.content.slice(0, 200) + "...", // Resumen
      source: r.metadata.section_hierarchy,
      confidence: r.similarity
    }));
  
  return context;
};
```

#### Dynamic Prompt Generation:
```json
{
  "model": "gpt-4",
  "messages": [
    {
      "role": "system",
      "content": "Eres un experto analista que proporciona respuestas precisas basadas en documentación específica. Usa SOLO la información proporcionada. Si no tienes información suficiente, dilo claramente."
    },
    {
      "role": "user",
      "content": "Consulta: {{$json.user_query}}\n\nFUENTES PRIMARIAS:\n{{#each context.primary_sources}}\n[Fuente: {{source}} | Confianza: {{confidence}}]\n{{content}}\n\n{{/each}}\n\nFUENTES DE APOYO:\n{{#each context.supporting_sources}}\n[Fuente: {{source}}]\n{{content}}\n\n{{/each}}\n\nProporciona una respuesta completa citando las fuentes utilizadas."
    }
  ],
  "max_tokens": 1500,
  "temperature": 0.2
}
```

### Response Quality Control

#### Answer Validation:
```json
{
  "model": "gpt-4o-mini",
  "messages": [
    {
      "role": "system",
      "content": "Evalúa la calidad de respuestas RAG. Verifica: precisión factual, cobertura de la consulta, uso apropiado de fuentes, claridad."
    },
    {
      "role": "user",
      "content": "Consulta original: {{$json.user_query}}\nRespuesta generada: {{$json.generated_answer}}\nFuentes utilizadas: {{$json.sources_used}}\n\nEvalúa (1-10) y sugiere mejoras si score < 7:"
    }
  ]
}
```

#### Source Attribution:
```javascript
// Code node para atribución de fuentes
const addSourceAttribution = (answer, sources) => {
  let attributedAnswer = answer;
  
  sources.forEach((source, index) => {
    const sourceId = `[${index + 1}]`;
    const attribution = `\n\n**Fuente ${index + 1}**: ${source.section_hierarchy}`;
    
    // Buscar referencias en el texto y agregar citas
    const relevantSentences = answer.match(/[^.!?]+[.!?]/g) || [];
    relevantSentences.forEach(sentence => {
      if (source.keywords.some(keyword => 
        sentence.toLowerCase().includes(keyword.toLowerCase())
      )) {
        attributedAnswer = attributedAnswer.replace(
          sentence, 
          sentence + ` ${sourceId}`
        );
      }
    });
  });
  
  // Agregar lista de fuentes al final
  const sourcesList = sources.map((source, index) => 
    `[${index + 1}] ${source.section_hierarchy} (Confianza: ${(source.confidence * 100).toFixed(1)}%)`
  ).join('\n');
  
  return `${attributedAnswer}\n\n**Fuentes consultadas:**\n${sourcesList}`;
};
```

## Multimodal RAG

### Image + Text Processing

#### Image Analysis Integration:
```json
{
  "model": "gpt-4-vision-preview",
  "messages": [
    {
      "role": "system",
      "content": "Analiza imágenes y extrae información textual relevante. Describe contenido, texto visible, gráficos, diagramas."
    },
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "Analiza esta imagen y extrae toda la información relevante:"
        },
        {
          "type": "image_url",
          "image_url": {
            "url": "{{$json.image_url}}"
          }
        }
      ]
    }
  ],
  "max_tokens": 1000
}
```

#### Combined Vector Storage:
```sql
CREATE TABLE multimodal_knowledge (
  id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
  content_type TEXT CHECK (content_type IN ('text', 'image', 'combined')),
  text_content TEXT,
  image_url TEXT,
  image_description TEXT,
  text_embedding VECTOR(1536),
  image_embedding VECTOR(1024), -- Different dimension for image embeddings
  combined_metadata JSONB,
  document_id TEXT,
  created_at TIMESTAMP DEFAULT NOW()
);

-- Función de búsqueda multimodal
CREATE OR REPLACE FUNCTION multimodal_search(
  query_text_embedding VECTOR(1536),
  query_image_embedding VECTOR(1024) DEFAULT NULL,
  content_types TEXT[] DEFAULT ARRAY['text', 'image', 'combined']
)
RETURNS TABLE (
  id UUID,
  content_type TEXT,
  text_content TEXT,
  image_description TEXT,
  similarity_score FLOAT
) AS $$
BEGIN
  RETURN QUERY
  SELECT 
    mk.id,
    mk.content_type,
    mk.text_content,
    mk.image_description,
    CASE 
      WHEN query_image_embedding IS NULL THEN
        1 - (mk.text_embedding <=> query_text_embedding)
      ELSE
        (1 - (mk.text_embedding <=> query_text_embedding) + 
         1 - (mk.image_embedding <=> query_image_embedding)) / 2
    END AS similarity_score
  FROM multimodal_knowledge mk
  WHERE mk.content_type = ANY(content_types)
  ORDER BY similarity_score DESC
  LIMIT 10;
END;
$$ LANGUAGE plpgsql;
```

### Document Type Handling

#### PDF with Images:
```javascript
// Code node para procesamiento de PDFs con imágenes
const processPDFWithImages = async (pdfFile) => {
  // Extraer imágenes del PDF
  const images = await extractImagesFromPDF(pdfFile);
  
  // Procesar cada imagen con GPT-4V
  const imageAnalyses = await Promise.all(
    images.map(async (image, index) => {
      const analysis = await analyzeImage(image.data);
      return {
        page: image.page,
        index: index,
        description: analysis.description,
        extracted_text: analysis.text,
        embedding: await generateImageEmbedding(image.data)
      };
    })
  );
  
  // Extraer texto del PDF
  const textContent = await extractPDFText(pdfFile);
  
  // Combinar información
  const combinedContent = {
    text_content: textContent,
    images: imageAnalyses,
    combined_description: await generateCombinedDescription(textContent, imageAnalyses)
  };
  
  return combinedContent;
};
```

## Interactive RAG Systems

### Conversational Memory

#### Session Context Management:
```javascript
// Code node para gestión de contexto conversacional
class ConversationMemory {
  constructor(sessionId) {
    this.sessionId = sessionId;
    this.shortTermMemory = []; // Últimas 5 interacciones
    this.longTermMemory = {}; // Temas y contextos importantes
    this.entityMemory = {}; // Entidades mencionadas
  }
  
  async addInteraction(query, response, sources) {
    const interaction = {
      timestamp: new Date().toISOString(),
      query: query,
      response: response,
      sources: sources,
      entities: await extractEntities(query + " " + response)
    };
    
    // Añadir a memoria a corto plazo
    this.shortTermMemory.push(interaction);
    if (this.shortTermMemory.length > 5) {
      this.shortTermMemory.shift();
    }
    
    // Actualizar entidades
    interaction.entities.forEach(entity => {
      if (!this.entityMemory[entity.text]) {
        this.entityMemory[entity.text] = {
          type: entity.type,
          mentioned_times: 0,
          first_mention: interaction.timestamp
        };
      }
      this.entityMemory[entity.text].mentioned_times++;
    });
    
    await this.persistMemory();
  }
  
  getContextForQuery(newQuery) {
    const relevantHistory = this.shortTermMemory.filter(interaction =>
      this.calculateQuerySimilarity(newQuery, interaction.query) > 0.7
    );
    
    const relevantEntities = Object.entries(this.entityMemory)
      .filter(([entity, data]) => newQuery.toLowerCase().includes(entity.toLowerCase()))
      .map(([entity, data]) => ({ entity, ...data }));
    
    return {
      previous_interactions: relevantHistory,
      relevant_entities: relevantEntities,
      session_context: this.longTermMemory
    };
  }
}
```

#### Follow-up Question Handling:
```json
{
  "model": "gpt-4o",
  "messages": [
    {
      "role": "system",
      "content": "Gestiona consultas de seguimiento en conversaciones RAG. Considera el contexto previo y reformula consultas ambiguas."
    },
    {
      "role": "user",
      "content": "Historial de conversación:\n{{$json.conversation_history}}\n\nNueva consulta: {{$json.current_query}}\n\nSi la consulta es ambigua o se refiere a información previa, reformúlala como una consulta independiente completa. Si es clara, devuélvela tal como está."
    }
  ]
}
```

### Real-time Updates

#### Dynamic Knowledge Base:
```javascript
// Code node para actualizaciones en tiempo real
const updateKnowledgeBase = async (newDocument) => {
  // 1. Procesar documento nuevo
  const processedDoc = await processDocument(newDocument);
  
  // 2. Detectar conflictos con información existente
  const conflicts = await detectConflicts(processedDoc);
  
  // 3. Actualizar embeddings existentes si es necesario
  if (conflicts.length > 0) {
    await resolveConflicts(conflicts, processedDoc);
  }
  
  // 4. Añadir nueva información
  await storeProcessedDocument(processedDoc);
  
  // 5. Invalidar cache de consultas relacionadas
  await invalidateRelatedCache(processedDoc.topics);
  
  // 6. Notificar cambios a sistemas dependientes
  await notifySystemsOfUpdate({
    document_id: processedDoc.id,
    topics_affected: processedDoc.topics,
    update_type: 'new_document'
  });
};
```

## Performance Optimization

### Caching Strategies

#### Multi-Level Caching:
```javascript
// Code node para sistema de cache multicapa
class RAGCache {
  constructor() {
    this.l1Cache = new Map(); // Consultas exactas (TTL: 1 hora)
    this.l2Cache = new Map(); // Consultas similares (TTL: 6 horas)  
    this.l3Cache = new Map(); // Embeddings pre-computados (TTL: 24 horas)
  }
  
  async getCachedResponse(query) {
    // L1: Consulta exacta
    const exactMatch = this.l1Cache.get(query);
    if (exactMatch && !this.isExpired(exactMatch)) {
      return exactMatch.response;
    }
    
    // L2: Consultas similares
    const queryEmbedding = await generateEmbedding(query);
    for (const [cachedQuery, data] of this.l2Cache.entries()) {
      const similarity = calculateSimilarity(queryEmbedding, data.embedding);
      if (similarity > 0.95 && !this.isExpired(data)) {
        return data.response;
      }
    }
    
    return null; // Cache miss
  }
  
  setCachedResponse(query, response, sources) {
    const embedding = await generateEmbedding(query);
    const cacheEntry = {
      response: response,
      sources: sources,
      embedding: embedding,
      timestamp: Date.now(),
      access_count: 1
    };
    
    this.l1Cache.set(query, cacheEntry);
    this.l2Cache.set(query, cacheEntry);
  }
}
```

### Vector Database Optimization

#### Index Optimization:
```sql
-- Optimización de índices para diferentes patrones de consulta
CREATE INDEX CONCURRENTLY idx_embedding_hnsw 
ON knowledge_chunks USING hnsw (embedding vector_cosine_ops) 
WITH (m = 16, ef_construction = 64);

-- Particionamiento por fecha para documentos temporales
CREATE TABLE knowledge_chunks_2024 
PARTITION OF knowledge_chunks FOR VALUES 
FROM ('2024-01-01') TO ('2025-01-01');

-- Índice compuesto para consultas filtradas
CREATE INDEX idx_metadata_search 
ON knowledge_chunks USING gin ((metadata->'tags'), (metadata->'category'));

-- Función optimizada para búsquedas frecuentes
CREATE OR REPLACE FUNCTION fast_semantic_search(
  query_embedding VECTOR(1536),
  category_filter TEXT DEFAULT NULL,
  limit_results INTEGER DEFAULT 5
)
RETURNS TABLE (content TEXT, similarity FLOAT, metadata JSONB)
LANGUAGE sql STABLE PARALLEL SAFE AS $$
  SELECT 
    content,
    1 - (embedding <=> query_embedding) AS similarity,
    metadata
  FROM knowledge_chunks
  WHERE 
    (category_filter IS NULL OR metadata->>'category' = category_filter)
    AND (embedding <=> query_embedding) < 0.3
  ORDER BY embedding <=> query_embedding
  LIMIT limit_results;
$$;
```

## Monitoring & Analytics

### RAG Performance Metrics

#### Tracking Implementation:
```javascript
// Code node para métricas de RAG
const trackRAGMetrics = async (query, response, sources, userFeedback = null) => {
  const metrics = {
    timestamp: new Date().toISOString(),
    query_length: query.length,
    response_length: response.length,
    sources_count: sources.length,
    avg_source_similarity: sources.reduce((sum, s) => sum + s.similarity, 0) / sources.length,
    processing_time_ms: $json.processing_time,
    tokens_used: $json.total_tokens,
    cost_estimate: calculateCost($json.total_tokens),
    user_satisfaction: userFeedback?.rating || null,
    query_category: await classifyQuery(query),
    response_quality_score: await evaluateResponseQuality(query, response, sources)
  };
  
  // Almacenar métricas
  await saveMetrics(metrics);
  
  // Alertas automáticas
  if (metrics.avg_source_similarity < 0.6) {
    await sendAlert('Low retrieval quality detected', metrics);
  }
  
  if (metrics.response_quality_score < 7) {
    await sendAlert('Poor response quality', metrics);
  }
  
  return metrics;
};
```

#### Analytics Dashboard Data:
```javascript
// Code node para datos de dashboard
const generateRAGAnalytics = async (timeframe = '7d') => {
  const analytics = {
    // Volume metrics
    total_queries: await countQueries(timeframe),
    daily_average: await getAverageQueriesPerDay(timeframe),
    peak_hours: await getPeakUsageHours(timeframe),
    
    // Quality metrics
    average_response_quality: await getAverageResponseQuality(timeframe),
    average_retrieval_accuracy: await getAverageRetrievalAccuracy(timeframe),
    user_satisfaction_score: await getUserSatisfactionScore(timeframe),
    
    // Performance metrics
    average_response_time: await getAverageResponseTime(timeframe),
    cache_hit_rate: await getCacheHitRate(timeframe),
    cost_per_query: await getCostPerQuery(timeframe),
    
    // Content metrics
    most_queried_topics: await getMostQueriedTopics(timeframe),
    knowledge_gaps: await identifyKnowledgeGaps(timeframe),
    outdated_content_flags: await getOutdatedContentFlags(timeframe)
  };
  
  return analytics;
};
```

### Continuous Improvement

#### Automated A/B Testing:
```javascript
// Code node para A/B testing de configuraciones RAG
const ragABTest = async (query) => {
  const testVariants = [
    {
      name: 'semantic_chunking',
      config: { chunking: 'semantic', embedding_model: 'text-embedding-3-small' }
    },
    {
      name: 'hybrid_search',
      config: { chunking: 'traditional', search: 'hybrid', embedding_model: 'text-embedding-3-large' }
    }
  ];
  
  const userId = $json.user_id || 'anonymous';
  const variant = selectVariantForUser(userId, testVariants);
  
  // Aplicar configuración del variant
  const results = await processQueryWithConfig(query, variant.config);
  
  // Trackear resultado para análisis posterior
  await trackABTestResult({
    user_id: userId,
    variant: variant.name,
    query: query,
    response_quality: results.quality_score,
    user_engagement: results.engagement_metrics
  });
  
  return results;
};
```

## URLs y Recursos

### APIs Esenciales:
```
- OpenAI Embeddings: https://platform.openai.com/docs/api-reference/embeddings
- Supabase Vector: https://supabase.com/docs/guides/ai/vector-columns
- Pinecone: https://docs.pinecone.io/
- Weaviate: https://weaviate.io/developers/weaviate
- Qdrant: https://qdrant.tech/documentation/
```

### Herramientas y Libraries:
```
- LangChain: https://python.langchain.com/docs/
- LlamaIndex: https://docs.llamaindex.ai/
- ChromaDB: https://docs.trychroma.com/
- pgvector: https://github.com/pgvector/pgvector
- Sentence Transformers: https://www.sbert.net/
```

---

*Esta guía proporciona todo el conocimiento técnico necesario para implementar sistemas RAG avanzados y knowledge management que superen significativamente las implementaciones básicas tradicionales.*