Módulo 1: RAG Pipeline Completo (Architecture Overview)

Casos de Uso Reales de RAG en Producción

Descripción de la cápsula

RAG no es teórico. Empresas como Perplexity, Notion AI, ChatGPT Plugins, GitHub Copilot, y Stripe Documentation usan RAG en producción todos los días. Esta cápsula analiza arquitecturas reales: qué técnicas usan, por qué tomaron esas decisiones, qué trade-offs aceptaron, y qué puedes aprender para tu propio sistema.

Ver casos reales te da contexto crítico. Cuando aprendas re-ranking en Módulo 4, entenderás que Perplexity lo usa porque precision >90% es crítica para búsqueda web. Cuando aprendas hybrid search en Módulo 5, entenderás que Stripe lo usa porque queries contienen API names exactos que semantic search falla.

Esta cápsula desglosa 5 arquitecturas reales: (1) Qué problema resuelven, (2) Qué componentes RAG usan, (3) Decisiones técnicas específicas, (4) Métricas de éxito, (5) Lecciones aplicables a tu caso.


🌐 Caso 1: Perplexity AI (Search Engine)

Problema:

Búsqueda web conversacional con fuentes citadas. Usuario pregunta "¿Qué pasó con SVB bank?", Perplexity busca en web, genera respuesta grounded, y cita fuentes.

Arquitectura RAG:

User Query
    ↓
Query Optimization (expansion + rewriting)
    ↓
Hybrid Retrieval (Web search + Vector search)
    ↓
Re-ranking (Top-100 → Top-5)
    ↓
LLM Generation (GPT-4 con citations)
    ↓
Response + Sources

Componentes específicos:

1. Query Optimization:

# Perplexity expande queries para aumentar recall
user_query = "¿Qué pasó con SVB bank?"

# Expansion:
expanded_queries = [
    "Silicon Valley Bank collapse 2023",
    "SVB bank failure causes",
    "What happened to Silicon Valley Bank"
]

# Rewriting (para claridad):
rewritten = "Silicon Valley Bank collapse March 2023 timeline and causes"

Por qué: Queries de usuario son ambiguas ("SVB" no es obvio). Expansion aumenta recall (encontrar más resultados), rewriting clarifica intent.


2. Hybrid Retrieval:

# Perplexity combina keyword search (BM25) + semantic search

# Keyword search (rápido, exacto)
keyword_results = search_web_bm25(query)  # Top-50

# Semantic search (context-aware)
semantic_results = search_web_embeddings(query)  # Top-50

# Merge con reciprocal rank fusion
merged = reciprocal_rank_fusion(keyword_results, semantic_results)  # Top-100

Por qué: Web search necesita ambos: keywords para nombres propios ("SVB"), semantic para conceptos ("collapse", "bank failure").

Técnica: Módulo 5 enseña hybrid search en detalle.


3. Re-ranking:

# Perplexity re-rankea top-100 → top-5 con cross-encoder

from sentence_transformers import CrossEncoder

model = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-12-v2')

# Re-rankear top-100
scores = model.predict([
    (user_query, doc['text']) for doc in merged[:100]
])

# Seleccionar top-5
top_5_indices = np.argsort(scores)[::-1][:5]
final_docs = [merged[i] for i in top_5_indices]

Por qué: Precision >90% crítica para búsqueda. Re-ranking elimina falsos positivos.

Trade-off: +200ms latency, pero vale la pena.

Técnica: Módulo 4 enseña re-ranking.


4. LLM Generation con Citations:

# Perplexity genera respuesta con fuentes numeradas

context = "\n\n".join([
    f"[{i+1}] {doc['text']}\nFuente: {doc['url']}"
    for i, doc in enumerate(final_docs)
])

prompt = f"""
Usa el siguiente contexto para responder la pregunta. Cita las fuentes con [1], [2], etc.

Contexto:
{context}

Pregunta: {user_query}

Respuesta con citations:
"""

response = openai.ChatCompletion.create(
    model="gpt-4-turbo",
    messages=[
        {"role": "system", "content": "Eres un motor de búsqueda conversacional. Siempre cita fuentes."},
        {"role": "user", "content": prompt}
    ]
)

answer = response.choices[0].message.content

# Output: "Silicon Valley Bank (SVB) colapsó el 10 de marzo de 2023 [1] debido a una crisis de liquidez [2]..."

Por qué: Citations aumentan trustworthiness. Usuario puede verificar información.


Métricas de Perplexity:

MétricaTargetRealTécnica usada
Latency P95<3,000ms~2,500msHybrid search (fast), Re-ranking (optimized)
Precision@5>90%~92%Re-ranking con cross-encoder
Recall@100>70%~75%Query expansion + hybrid
Faithfulness>95%~96%Citations obligatorias en prompt

Lecciones aplicables:

Query optimization importa: Expansion aumenta recall +20-30%
Hybrid search para web: Keywords + semantic juntos superan ambos solos
Re-ranking vale la pena: +200ms latency → +25% precision
Citations aumentan trust: Usuarios validan información


📝 Caso 2: Notion AI (Document Q&A)

Problema:

Usuario pregunta sobre su workspace de Notion (ej: "¿Qué decidimos en el meeting de Q4 strategy?"). Notion AI busca en docs privados del workspace y responde.

Arquitectura RAG:

User Query
    ↓
Metadata Filtering (workspace_id, date_range)
    ↓
Semantic Search (embeddings)
    ↓
Context Ranking (recent docs prioritized)
    ↓
LLM Generation (GPT-4)
    ↓
Response + Page Links

Componentes específicos:

1. Metadata Filtering:

# Notion AI filtra por workspace y date range ANTES de semantic search

user_query = "¿Qué decidimos en Q4 strategy meeting?"
workspace_id = "user123_workspace"

# Extraer metadata de query
metadata_filter = {
    "workspace_id": workspace_id,
    "page_type": "meeting_notes",
    "date_range": ("2023-10-01", "2023-12-31"),  # Q4 2023
    "tags": ["strategy", "meeting"]
}

# Buscar solo en subset relevante
results = collection.query(
    query_embeddings=[query_embedding],
    n_results=10,
    where=metadata_filter  # Pre-filtering
)

Por qué: Workspace privado tiene 50,000+ páginas. Sin filtering, semantic search devuelve docs irrelevantes de otros proyectos. Metadata filtering reduce search space 95%.

Técnica: Módulo 6 enseña metadata filtering.


2. Context Ranking:

# Notion AI prioriza documentos recientes (relevance decay)

def time_weighted_score(doc, query_embedding):
    """Combina similarity score con recency"""
    
    # Similarity score (0-1)
    similarity = cosine_similarity(query_embedding, doc['embedding'])
    
    # Time decay (documentos recientes pesan más)
    days_ago = (datetime.now() - doc['created_at']).days
    recency_weight = 1 / (1 + days_ago / 30)  # Decay over 30 days
    
    # Combined score
    final_score = 0.7 * similarity + 0.3 * recency_weight
    
    return final_score

# Re-rankear por time-weighted score
docs_ranked = sorted(docs, key=lambda d: time_weighted_score(d, query_embedding), reverse=True)
top_k = docs_ranked[:5]

Por qué: En workspaces, documentos recientes suelen ser más relevantes. Meeting notes de hace 2 años son menos útiles que de hace 2 semanas.


3. Privacy Constraints:

# Notion AI NUNCA cruza workspaces

# Embeddings son workspace-scoped
collection_name = f"workspace_{workspace_id}"
collection = client.get_collection(collection_name)

# Queries solo buscan en collection del usuario
results = collection.query(...)  # Scope limitado

# LLM context SOLO tiene docs del workspace
# Zero-shot learning: LLM no tiene datos de otros usuarios

Por qué: Privacidad crítica. Notion no puede filtrar respuestas de un workspace a otro.


Métricas de Notion AI:

MétricaTargetRealTécnica usada
Latency P95<2,000ms~1,800msPre-filtering reduce search space
Precision@5>80%~83%Metadata filtering + recency
Privacy violations00Workspace-scoped collections
Faithfulness>90%~91%Solo cita docs del workspace

Lecciones aplicables:

Metadata filtering es crítico: Reduce search space 10-100x
Recency importa en docs: Time-weighted ranking mejora relevancia +15%
Privacy by design: Collections separadas para multi-tenant
Context ranking adicional: Semantic search no es suficiente, custom ranking ayuda


🧑‍💻 Caso 3: GitHub Copilot Chat (Code Q&A)

Problema:

Developer pregunta "How do I parse JSON in Python?" o "What does this function do?". Copilot busca en docs de Python + código del proyecto + contexto del archivo actual.

Arquitectura RAG:

User Query + Code Context
    ↓
Hybrid Retrieval (Code search + Docs search)
    ↓
Re-ranking (Code relevance)
    ↓
Code-Aware LLM (GPT-4)
    ↓
Response + Code Snippets

Componentes específicos:

1. Code-Specific Chunking:

# GitHub Copilot chunka código por funciones/clases (no fixed-size)

# Naive fixed-size (BAD para código):
chunks_fixed = [code[i:i+500] for i in range(0, len(code), 500)]
# Problema: Corta en medio de función

# Code-aware chunking (GOOD):
import ast

def chunk_by_functions(python_code: str) -> list[str]:
    """Divide código por funciones/clases"""
    
    tree = ast.parse(python_code)
    chunks = []
    
    for node in ast.walk(tree):
        if isinstance(node, (ast.FunctionDef, ast.ClassDef)):
            chunk = ast.get_source_segment(python_code, node)
            chunks.append(chunk)
    
    return chunks

# Output: Cada chunk es una función completa
chunks = chunk_by_functions(python_code)

Por qué: Código debe respetar estructura (funciones, clases). Fixed-size rompe contexto.

Técnica: Módulo 2 enseña chunking strategies, incluyendo structural.


2. Hybrid Retrieval (Code + Docs):

# Copilot busca en múltiples sources simultáneamente

query = "How do I parse JSON in Python?"

# Source 1: Python documentation
docs_results = search_docs(
    query=query,
    collection="python_stdlib_docs"
)

# Source 2: Project code (user's repo)
code_results = search_code(
    query=query,
    collection=f"repo_{repo_id}_code"
)

# Source 3: Open source examples (GitHub public repos)
examples_results = search_examples(
    query=query,
    collection="github_public_python"
)

# Merge: Docs primero, luego code del proyecto, luego ejemplos
merged = docs_results[:3] + code_results[:2] + examples_results[:2]

Por qué: Developers necesitan docs (conceptos) + code examples (implementación) juntos.


3. Code-Aware LLM:

# Copilot usa GPT-4 con system prompt específico para código

system_prompt = """
Eres un asistente experto en programación.

Reglas:
1. Provee code snippets funcionales (no pseudocódigo)
2. Explica qué hace el código
3. Incluye imports necesarios
4. Menciona edge cases o errores comunes
5. Si hay múltiples formas, muestra la más simple primero
"""

user_prompt = f"""
Contexto (de documentación y código del usuario):
{merged_context}

Pregunta: {query}

Respuesta con código:
"""

response = openai.ChatCompletion.create(
    model="gpt-4",
    messages=[
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": user_prompt}
    ],
    temperature=0.2  # Baja temperatura para código (determinístico)
)

Por qué: Código requiere precisión alta. Temperature baja evita hallucinations en syntax.


Métricas de GitHub Copilot:

MétricaTargetRealTécnica usada
Latency P95<3,000ms~2,800msParallel retrieval (docs + code)
Code correctness>85%~87%Low temperature, code-aware prompts
Precision@5>75%~78%Code-specific chunking
User satisfaction>4.0/5~4.2/5Hybrid retrieval (docs + examples)

Lecciones aplicables:

Domain-specific chunking: Código necesita chunking por funciones, no fixed-size
Multi-source retrieval: Docs + code + examples juntos > solos
Low temperature para código: Temperature 0.2 reduce hallucinations en syntax
Code-aware prompts: System prompt específico mejora correctness +15%


💳 Caso 4: Stripe Documentation Search

Problema:

Developer busca en Stripe docs: "How to create a subscription with trial period". Docs tienen 5,000+ páginas (API reference, guides, examples).

Arquitectura RAG:

User Query
    ↓
Query Classification (API vs Guide vs Example)
    ↓
Hybrid Search (Keyword + Semantic)
    ↓
Metadata Filtering (language, API version)
    ↓
Section Re-ranking (API ref prioritized)
    ↓
Response + Direct Links

Componentes específicos:

1. Query Classification:

# Stripe clasifica query para buscar en sección correcta

user_query = "How to create a subscription with trial?"

# Clasificar query
query_type = classify_query(user_query)
# Output: "API" (no "guide" o "example")

# Buscar en sección específica
if query_type == "API":
    search_collection = "stripe_api_reference"
elif query_type == "guide":
    search_collection = "stripe_guides"
else:
    search_collection = "stripe_examples"

results = collection[search_collection].query(...)

Por qué: API reference tiene syntax exacta. Guides tienen conceptos. Classification aumenta precision +25%.


2. Hybrid Search (Keywords críticos):

# Stripe usa hybrid search porque queries contienen API names exactos

query = "create subscription trial_period_days parameter"

# BM25 keyword search (excelente para "subscription", "trial_period_days")
keyword_results = bm25_search(query, collection="stripe_api")

# Semantic search (excelente para conceptos como "trial")
semantic_results = semantic_search(query_embedding, collection="stripe_api")

# Reciprocal Rank Fusion (RRF)
merged = reciprocal_rank_fusion(keyword_results, semantic_results)

Por qué: API names ("trial_period_days") necesitan exact match (keyword). Conceptos ("subscription trial") necesitan semantic.

Técnica: Módulo 5 enseña hybrid search con BM25 + embeddings.


3. Metadata Filtering:

# Stripe filtra por language y API version

# User context
user_language = "python"  # De user settings
api_version = "2024-01-01"  # Latest

# Filtrar docs
results = collection.query(
    query_embeddings=[query_embedding],
    n_results=10,
    where={
        "language": user_language,
        "api_version": api_version
    }
)

# Output: Solo docs de Python API v2024

Por qué: Stripe tiene docs para 9 languages (Python, Ruby, Node, etc.). Sin filtering, devuelve Ruby code a Python developer.


Métricas de Stripe:

MétricaTargetRealTécnica usada
Latency P95<1,500ms~1,200msHybrid search (pre-indexed BM25)
Precision@3>90%~93%Query classification + hybrid
Zero-result rate<5%~3%Hybrid search (fallback to semantic)
User satisfaction>4.5/5~4.6/5Direct links + code snippets

Lecciones aplicables:

Hybrid search para technical docs: API names necesitan keywords + semantic
Query classification: Clasificar antes de buscar mejora precision +25%
Metadata filtering crítico: Language + version filtering evita confusión
Direct links en respuesta: Links directos aumentan satisfaction


🤖 Caso 5: ChatGPT Plugins (External Knowledge)

Problema:

ChatGPT no sabe info reciente (training data hasta 2023). Plugins permiten buscar en web, databases, o APIs externas.

Arquitectura RAG:

User Query
    ↓
Plugin Selection (¿Qué plugin usar?)
    ↓
Plugin API Call (Retrieval externo)
    ↓
LLM Generation (GPT-4 con context de plugin)
    ↓
Response

Componentes específicos:

1. Plugin Selection:

# ChatGPT decide qué plugin usar basándose en query

user_query = "What's the weather in SF?"

# GPT-4 analiza query y selecciona plugin
plugin_selection_prompt = f"""
Query: {user_query}

Available plugins:
1. weather_plugin: Get current weather
2. web_search_plugin: Search the web
3. calculator_plugin: Perform calculations

Which plugin(s) should be used? Respond with plugin name only.
"""

selected_plugin = gpt4.invoke(plugin_selection_prompt)
# Output: "weather_plugin"

2. Plugin API Call (RAG Retrieval):

# Plugin hace retrieval externo

# Weather plugin example
def weather_plugin(location: str) -> dict:
    """Retrieval externo de API de clima"""
    
    response = requests.get(
        f"https://api.weather.com/current?location={location}"
    )
    
    return {
        "temperature": response.json()['temp'],
        "conditions": response.json()['conditions'],
        "humidity": response.json()['humidity']
    }

# ChatGPT llama plugin
weather_data = weather_plugin("San Francisco")

# Output: {"temperature": 62, "conditions": "Cloudy", "humidity": 75}

3. LLM Generation con Plugin Context:

# ChatGPT genera respuesta usando datos del plugin

context = f"""
Weather data from plugin:
- Location: San Francisco
- Temperature: {weather_data['temperature']}°F
- Conditions: {weather_data['conditions']}
- Humidity: {weather_data['humidity']}%
"""

prompt = f"""
{context}

User query: {user_query}

Respond naturally:
"""

response = gpt4.invoke(prompt)

# Output: "The weather in San Francisco is currently 62°F and cloudy, with 75% humidity."

Métricas de ChatGPT Plugins:

MétricaTargetRealTécnica usada
Plugin selection accuracy>95%~96%GPT-4 function calling
Latency P95<4,000ms~3,500msParallel plugin calls
Faithfulness>95%~97%Direct API data (no hallucination)
Error rate<5%~4%Fallback to web search

Lecciones aplicables:

External retrieval: RAG no solo es internal docs, puede ser APIs externas
Function calling: LLMs pueden decidir qué tool/plugin usar dinámicamente
Parallel calls: Multiple plugins pueden llamarse en paralelo (-40% latency)
Direct API data: Reduce hallucinations vs scraping/parsing


📊 Comparación de Arquitecturas

CompanyPrimary UseChunkingRetrievalRe-rankingSpecial Feature
PerplexityWeb searchSemanticHybrid (BM25 + embeddings)✅ Cross-encoderQuery expansion
Notion AIPrivate docsFixed (page-based)Semantic❌ (metadata filter suficiente)Time-weighted ranking
GitHub CopilotCode Q&AStructural (functions)Multi-source (docs+code)✅ Code relevanceLow temperature
StripeTechnical docsRecursiveHybrid (BM25 + embeddings)✅ Section priorityQuery classification
ChatGPT PluginsExternal APIsN/A (API calls)External APIs❌ (direct data)Function calling

🎯 Lecciones Generales para Tu RAG

Lección 1: No hay arquitectura única

Cada caso de uso tiene requirements diferentes:

  • Web search (Perplexity): Precision crítica → Re-ranking + query expansion
  • Private docs (Notion): Privacy crítica → Metadata filtering + workspace-scoped
  • Code Q&A (Copilot): Correctness crítica → Structural chunking + low temperature
  • Technical docs (Stripe): Exact matches críticos → Hybrid search + classification
  • External data (ChatGPT): Freshness crítica → External APIs + function calling

Tu decisión: Define tus requirements primero → Selecciona técnicas después.


Lección 2: Hybrid search es común

4 de 5 casos usan hybrid search (BM25 + embeddings):

  • Perplexity, Stripe usan hybrid explícitamente
  • Copilot combina docs (semantic) + code (keyword)
  • Solo Notion usa pure semantic (porque metadata filtering suficiente)

Implicación: Módulo 5 (Hybrid Search) es crítico para production.


Lección 3: Re-ranking no siempre necesario

  • Usan re-ranking: Perplexity, Copilot, Stripe (precision >90% crítica)
  • No usan re-ranking: Notion (metadata filtering + recency suficiente), ChatGPT (API data ya es relevante)

Decisión: Re-ranking si precision >85% crítica y latency budget >500ms.


Lección 4: Metadata filtering reduce search space dramáticamente

Notion y Stripe usan metadata filtering agresivamente:

  • Notion: workspace_id + date_range → -95% search space
  • Stripe: language + api_version → -80% search space

Implicación: Módulo 6 (Metadata Filtering) es crítico para multi-tenant y large datasets.


Lección 5: Domain-specific optimizations importan

  • Código: Structural chunking, low temperature, code-aware prompts
  • Docs técnicos: Query classification, hybrid search, direct links
  • Private workspaces: Time-weighted ranking, privacy by design
  • Web search: Query expansion, citations, cross-encoder re-ranking

Implicación: Técnicas genéricas son baseline. Domain-specific optimizations dan ventaja real.


🎯 Resumen

Conceptos clave:

  • Perplexity: Query expansion + hybrid + re-ranking → Precision 92% para web search
  • Notion AI: Metadata filtering + recency ranking → Privacy + relevance en private docs
  • GitHub Copilot: Structural chunking + multi-source + low temp → Correctness 87% en código
  • Stripe: Query classification + hybrid + metadata → Precision 93% en technical docs
  • ChatGPT Plugins: External APIs + function calling → Freshness + zero hallucinations
  • Hybrid search es estándar: 4 de 5 casos usan BM25 + embeddings
  • Re-ranking si precision crítica: +200ms latency → +25% precision
  • Domain-specific optimizations: Código, docs, private, web tienen optimizations únicas

Qué sigue:

Cápsula 06 compara RAG con búsqueda tradicional (keyword search, SQL queries, grep) para entender cuándo RAG es la herramienta correcta y cuándo no.


📚 Recursos Adicionales

  1. Perplexity Architecture - Blog oficial de arquitectura
  2. Notion AI Technical Deep Dive - Cómo funciona Notion AI
  3. GitHub Copilot Explained - Guía oficial
  4. Stripe Developer Tools - Blog de Stripe sobre docs
  5. ChatGPT Plugins Architecture - Documentación oficial
  6. RAG in Production (LangChain) - Casos reales de LangChain

Creado: Febrero 6, 2026
Versión: 1.0