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étrica | Target | Real | Técnica usada |
|---|---|---|---|
| Latency P95 | <3,000ms | ~2,500ms | Hybrid 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étrica | Target | Real | Técnica usada |
|---|---|---|---|
| Latency P95 | <2,000ms | ~1,800ms | Pre-filtering reduce search space |
| Precision@5 | >80% | ~83% | Metadata filtering + recency |
| Privacy violations | 0 | 0 | Workspace-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étrica | Target | Real | Técnica usada |
|---|---|---|---|
| Latency P95 | <3,000ms | ~2,800ms | Parallel 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/5 | Hybrid 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étrica | Target | Real | Técnica usada |
|---|---|---|---|
| Latency P95 | <1,500ms | ~1,200ms | Hybrid 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/5 | Direct 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étrica | Target | Real | Técnica usada |
|---|---|---|---|
| Plugin selection accuracy | >95% | ~96% | GPT-4 function calling |
| Latency P95 | <4,000ms | ~3,500ms | Parallel 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
| Company | Primary Use | Chunking | Retrieval | Re-ranking | Special Feature |
|---|---|---|---|---|---|
| Perplexity | Web search | Semantic | Hybrid (BM25 + embeddings) | ✅ Cross-encoder | Query expansion |
| Notion AI | Private docs | Fixed (page-based) | Semantic | ❌ (metadata filter suficiente) | Time-weighted ranking |
| GitHub Copilot | Code Q&A | Structural (functions) | Multi-source (docs+code) | ✅ Code relevance | Low temperature |
| Stripe | Technical docs | Recursive | Hybrid (BM25 + embeddings) | ✅ Section priority | Query classification |
| ChatGPT Plugins | External APIs | N/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
- Perplexity Architecture - Blog oficial de arquitectura
- Notion AI Technical Deep Dive - Cómo funciona Notion AI
- GitHub Copilot Explained - Guía oficial
- Stripe Developer Tools - Blog de Stripe sobre docs
- ChatGPT Plugins Architecture - Documentación oficial
- RAG in Production (LangChain) - Casos reales de LangChain
Creado: Febrero 6, 2026
Versión: 1.0