Módulo 3: Query Optimization

Cápsula 07: Decision framework — qué técnica de query optimization elegir

Descripción de la cápsula

Cubrimos las cuatro técnicas principales de query optimization en este módulo: expansion (cápsula 03), rewriting (04), decomposition (05), HyDE (06). Cada una con sus trade-offs, casos de uso, modos de falla. Esta cápsula es la consolidación operativa: decision framework para elegir la técnica correcta dado un escenario, benchmarks lado a lado, y patrones de combinación cuando una sola técnica no alcanza.

Es la cápsula que vas a consultar cada vez que diagnostiques que tu sistema RAG necesita query optimization. Te ahorra releer las 4 cápsulas previas para decidir.

Al finalizar esta cápsula serás capaz de:

  • ✅ Comparar las cuatro técnicas sobre seis dimensiones (recall, precision, latencia, costo, complejidad, dominio)
  • ✅ Aplicar un flowchart de decisión para elegir técnica en menos de 10 minutos
  • ✅ Diseñar pipelines híbridos que combinan dos o más técnicas en cascada
  • ✅ Calcular el TCO mensual de cada opción para un volumen dado
  • ✅ Identificar las tres anti-patrones más comunes al combinar técnicas
  • ✅ Diferenciar cuándo el problema requiere query optimization vs cuándo es problema de retrieval o re-ranking

Tiempo estimado: 25-30 minutos


Benchmark consolidado de las 4 técnicas

Calidad

TécnicaRecall@50 (típico)Precision@5 (típico)Best for
Sin optimization (baseline)57-65%75-82%MVP donde todo funciona OK
Query Expansion72-80% (+15-20pts)78-82% (+1-2pts)Queries ambiguas, recall crítico
Query Rewriting60-65% (+3-5pts)86-90% (+8-12pts)Queries incompletas o keyword-style
Query Decomposition65-72% (+8-15pts)83-87% (+5-10pts)Queries complejas (comparativas, multi-paso)
HyDE75-82% (+18-25pts)80-84% (+3-5pts)Queries abiertas, dominios técnicos

Costo y latencia

TécnicaLatencia extraCosto por query (gpt-4o-mini)LLM callsRetrieval calls
Sin optimization0 ms$001
Query Expansion+650-850 ms$0.0010-0.001215 (paralelo)
Query Rewriting+400-700 ms$0.0006-0.000811
Query Decomposition+900-1200 ms$0.0018-0.00221 (decision) + 1 (synthesis)3-5 (paralelo)
HyDE+700-900 ms$0.0012-0.00171 (generation)1

Complejidad operativa

TécnicaSetup timeMantenimientoRiesgos
Expansion4-6 hrsBajo (prompt estable)Expansiones que cambian intención
Rewriting4-8 hrsBajoRewrites incorrectos en queries factuales
Decomposition8-12 hrsMedio (más complejo)Sub-queries no independientes
HyDE6-8 hrsMedioDocs hipotéticos que alucinan

Decision framework

                          ¿Cuál es el problema dominante?
                                     │
        ┌────────────────────────────┼────────────────────────────┐
        │                            │                            │
        ▼                            ▼                            ▼
   RECALL bajo                PRECISION baja              QUERIES COMPLEJAS
        │                            │                            │
        ▼                            ▼                            ▼
┌────────────────┐         ┌────────────────┐         ┌────────────────────┐
│ ¿Queries cortas │         │ ¿Queries       │         │ ¿Multi-aspecto,    │
│ y ambiguas?     │         │ keyword-style  │         │ comparativas o     │
│                 │         │ o incompletas? │         │ multi-paso?        │
└───────┬────────┘         └───────┬────────┘         └─────────┬──────────┘
        │                          │                            │
   ┌────┴────┐                  ┌──┴──┐                  ┌──────┴──────┐
   │ SÍ      │ NO                │ SÍ  │ NO                │ SÍ          │ NO
   ▼         ▼                  ▼     ▼                  ▼              ▼
┌──────┐  ┌──────┐          ┌──────┐ │            ┌──────────────┐  │
│Expan-│  │HyDE  │          │Rewri-│ │            │Decomposition │  │
│sion  │  │      │          │ting  │ │            │              │  │
└──────┘  └──────┘          └──────┘ │            └──────────────┘  │
                                     │                                │
                                     ▼                                ▼
                          ┌──────────────────────┐         ┌──────────────────┐
                          │ ¿Latencia <500ms?    │         │ Considerar:      │
                          │  └─ Sí: skip optim.  │         │ - Re-ranking      │
                          │  └─ No: HyDE         │         │ - Hybrid search   │
                          └──────────────────────┘         │ - Metadata filter │
                                                           └──────────────────┘

Aplicado a casos reales

CasoTécnica recomendadaRazón
Chatbot SaaS con queries cortas ("auth issue", "deploy fail")ExpansionQueries ambiguas, recall es problema
Soporte técnico con chat history disponibleRewriting con contextoQueries incompletas que el chat completa
Plataforma de papers académicosHyDE + rerankQueries abiertas, dominio con doc style predecible
Asistente de DevOps ("deploy fastapi+postgres+aws")DecompositionQueries multi-aspecto explícitas
Buscador de productos e-commerce ("nike air max barato")Rewriting estructuralKeyword-style, transformar a natural language
Sistema legal con queries específicasSin optimizationLas queries de abogados ya son específicas

Patrones híbridos

A veces una técnica sola no resuelve el problema. Tres patrones probados:

Patrón 1: Rewriting → Expansion (cascada)

Para queries que están mal formuladas Y son ambiguas (ej: keyword-style + corta).

def rewrite_then_expand(query: str) -> list[str]:
    """Rewrite primero, después expandir el rewrite."""
    # Paso 1: convertir a natural language
    rewritten = rewrite_structural(query).rewritten

    # Paso 2: si sigue siendo ambigua, expandir
    if len(rewritten.split()) <= 6:
        expansion = expand_query(rewritten, num_expansions=4)
        return [rewritten] + expansion.queries

    return [rewritten]

Caso de uso: "k8s pod fail" (keyword + ambigua):

  1. Rewriting → "Why is my Kubernetes pod failing?"
  2. Expansion → 4 queries cubriendo distintas razones de fallo

Patrón 2: HyDE + Decomposition

Para queries abiertas Y multi-aspecto (ej: research questions complejas).

def hyde_with_decomposition(query: str, top_k: int = 8):
    """Si la query es decomponible, descompone primero, después HyDE para cada sub."""
    decomp = decompose_query(query)

    if not decomp.is_decomposable:
        # Query simple → HyDE directo
        return hyde_search(query, top_k)

    # Query compleja → HyDE para cada sub-query
    all_results = []
    for sub_q in decomp.sub_queries:
        hyde_doc = generate_hypothetical_document(sub_q)
        results = collection.query(query_texts=[hyde_doc], n_results=10)
        all_results.append(results['ids'][0])

    # Fusionar con RRF
    fused = reciprocal_rank_fusion(all_results)
    top_ids = [doc_id for doc_id, _ in fused[:top_k]]
    return collection.get(ids=top_ids)

Caso de uso: "Compare transformer architectures and recommend the best for time-series forecasting":

  1. Decomposition → 3 sub-queries
  2. HyDE para cada sub-query → encontrar papers específicos
  3. Fusion → top-K final

Patrón 3: Adaptive (LLM clasifica y elige)

El LLM decide qué técnica aplicar por query:

def adaptive_query_optimization(query: str, chat_history: list = None):
    """LLM clasifica la query y aplica la técnica óptima."""

    # Clasificación con LLM
    classification = classify_query_type(query, chat_history)

    if classification == "well_formed":
        return query  # skip optimization

    elif classification == "ambiguous":
        expansion = expand_query(query, num_expansions=4)
        return [query] + expansion.queries

    elif classification == "incomplete":
        if chat_history:
            return [rewrite_with_context(query, chat_history).rewritten]
        else:
            return [rewrite_structural(query).rewritten]

    elif classification == "complex":
        decomp = decompose_query(query)
        if decomp.is_decomposable:
            return decomp.sub_queries
        return [query]

    elif classification == "open_research":
        # HyDE encaja bien para research questions
        return ["use_hyde"]  # signal para usar HyDE en lugar de query directa

    else:
        return [query]

Trade-off: más costo (LLM call extra para clasificación) pero mejor selección. Útil cuando tu tráfico tiene mezcla amplia de tipos de query.


Calculando TCO mensual

Para decidir entre opciones, calcula el costo mensual concreto:

# tco_query_optimization.py
QUERIES_PER_DAY = 10_000
DAYS_PER_MONTH = 30

# Costos por query (gpt-4o-mini, mayo 2026)
COST_BY_TECHNIQUE = {
    "no_optimization": 0,
    "rewriting": 0.0007,
    "expansion": 0.0011,
    "decomposition": 0.0020,
    "hyde": 0.0015,
    "adaptive": 0.0010,  # average dependiendo de mix
}

# Latencia extra
LATENCY_BY_TECHNIQUE = {
    "no_optimization": 0,
    "rewriting": 500,
    "expansion": 750,
    "decomposition": 1100,
    "hyde": 800,
    "adaptive": 700,
}

# Mejora típica de recall
RECALL_IMPROVEMENT_BY_TECHNIQUE = {
    "no_optimization": 0,
    "rewriting": 4,
    "expansion": 17,
    "decomposition": 12,
    "hyde": 22,
    "adaptive": 18,
}


def calculate_tco_and_impact(technique: str, baseline_recall: float = 0.65):
    monthly_queries = QUERIES_PER_DAY * DAYS_PER_MONTH

    cost_monthly = monthly_queries * COST_BY_TECHNIQUE[technique]
    new_recall = baseline_recall + RECALL_IMPROVEMENT_BY_TECHNIQUE[technique] / 100
    latency = LATENCY_BY_TECHNIQUE[technique]

    return {
        "technique": technique,
        "monthly_cost_usd": round(cost_monthly, 2),
        "expected_recall": f"{new_recall:.0%}",
        "extra_latency_ms": latency,
    }


for tech in COST_BY_TECHNIQUE.keys():
    result = calculate_tco_and_impact(tech)
    print(f"\n{tech.upper()}:")
    for k, v in result.items():
        print(f"  {k}: {v}")

Output (10K queries/día):

NO_OPTIMIZATION:
  monthly_cost_usd: 0.00
  expected_recall: 65%
  extra_latency_ms: 0

REWRITING:
  monthly_cost_usd: 210.00
  expected_recall: 69%
  extra_latency_ms: 500

EXPANSION:
  monthly_cost_usd: 330.00
  expected_recall: 82%
  extra_latency_ms: 750

DECOMPOSITION:
  monthly_cost_usd: 600.00
  expected_recall: 77%
  extra_latency_ms: 1100

HYDE:
  monthly_cost_usd: 450.00
  expected_recall: 87%
  extra_latency_ms: 800

ADAPTIVE:
  monthly_cost_usd: 300.00
  expected_recall: 83%
  extra_latency_ms: 700

Lectura:

  • HyDE da el mejor recall (+22pts) por $450/mes — buena opción si recall es crítico.
  • Expansion da +17pts por $330/mes — sweet spot precio/calidad.
  • Decomposition es caro y solo justifica si tienes muchas queries complejas.
  • Adaptive da casi el mismo resultado que HyDE/Expansion mezclados, a menor costo — pero requiere más complejidad operativa.

Anti-patrones al combinar técnicas

Anti-patrón 1: aplicar todas las técnicas

El error: "agreguemos rewriting + expansion + HyDE para máxima calidad".

Síntoma: latencia +2 segundos, costo 4x, mejora marginal sobre la mejor técnica individual.

Por qué pasa: las técnicas atacan problemas distintos. Si tu problema dominante es recall (HyDE lo resuelve), agregar rewriting solo agrega latencia sin beneficio.

Cómo prevenir: diagnosticar primero (cápsula 02), aplicar la técnica que ataca el problema dominante. Combinar solo cuando hay evidencia de problemas múltiples.

Anti-patrón 2: combinar sin medir

El error: asumes que dos técnicas combinadas suman mejoras. Rewriting +5% + Expansion +15% = +20% combinado.

Realidad: las técnicas tienen overlap. Combinadas dan típicamente +18% (no +20%) por interacción. A veces combinarlas EMPEORA: una técnica "rompe" lo que la otra arregla.

Cómo prevenir: A/B test cada combinación contra cada técnica individual sobre eval set. Si la combinación no mejora >5% sobre la mejor individual, no vale la complejidad extra.

Anti-patrón 3: optimization donde el problema no es la query

El error: baja precision/recall → asumes problema de query → agregas 4 técnicas de optimization.

Realidad: muchas veces el problema es:

  • Chunking inadecuado (M02) — chunks demasiado grandes/pequeños
  • Embeddings débiles (M07) — modelo desalineado al dominio
  • Falta re-ranking (M04) — top-5 tiene falsos positivos
  • Falta hybrid search (M05) — queries con keywords exactos
  • Corpus incompleto — la respuesta no está en los documentos

Cómo prevenir: diagnosticar dónde está el problema antes de invertir en query optimization. Si el problema es de re-ranking, agregar HyDE no ayuda.

def diagnose_pipeline_bottleneck(eval_set):
    """Identifica cuál componente del pipeline es el cuello de botella."""
    issues = {"missing_data": 0, "retrieval": 0, "reranking": 0, "query": 0}

    for item in eval_set:
        # ¿La info correcta existe en algún chunk del corpus?
        in_corpus = check_corpus(item["expected_text"])
        if not in_corpus:
            issues["missing_data"] += 1
            continue

        # ¿Cosine encuentra el doc correcto en top-50?
        results = collection.query(query_texts=[item["query"]], n_results=50)
        if not any(item["expected_id"] in id_ for id_ in results['ids'][0]):
            issues["retrieval"] += 1
            continue

        # ¿Re-rank encuentra el doc correcto en top-5?
        reranked = cross_encoder_rerank(item["query"], results['documents'][0], top_k=5)
        if not any(item["expected_id"] in r.original_index for r in reranked):
            issues["reranking"] += 1
            continue

        # Si llegamos hasta acá, el doc está en top-5 con rerank — problema query era el menor
        issues["query"] += 1

    print("Bottleneck diagnosis:")
    for issue, count in issues.items():
        print(f"  {issue}: {count}/{len(eval_set)}")

Si "retrieval" es alto, query optimization ayuda. Si "reranking" es alto, agregar/mejorar reranker. Si "missing_data" es alto, expandir corpus — ninguna técnica de query lo resuelve.


Trampas y errores comunes

Trampa 1: aplicar query optimization sin diagnóstico previo

Cubierta arriba. Diagnosticar primero.

Trampa 2: copiar técnica de un blog sin medir

El error: ves que "HyDE da +25% recall" en un blog, lo aplicas. Tu mejora real es +5%.

Cómo prevenir: los benchmarks de blogs son sobre datasets/dominios específicos. Medir sobre tu eval set antes de comprometerse.

Trampa 3: optimization que rompe queries simples

El error: activas expansion para todas las queries. Queries simples como "Stripe API documentation" se expanden a 5 versiones, cada una más vaga que la original. Recall sube en queries complejas pero baja en simples.

Cómo prevenir: skip dinámico (visto en cápsulas 03, 04, 05, 06). Queries bien formuladas no necesitan optimization.

Trampa 4: caché de optimization sin invalidar al cambiar prompt

El error: cacheas resultados de query expansion. Cambias el prompt del LLM. Las queries cacheadas siguen usando expansions del prompt viejo.

Cómo prevenir: versioning del prompt en la cache key:

PROMPT_VERSION = "v3"

def cache_key(query: str) -> str:
    return f"{PROMPT_VERSION}:{hashlib.md5(query.encode()).hexdigest()}"

Trampa 5: medir solo recall sin precision

El error: activas HyDE, recall sube 20%, deployas.

Síntoma: precision cae 5% (HyDE encontró docs tangenciales). El LLM downstream se confunde con contexto extra. Quality empeora.

Cómo prevenir: medir precision Y recall juntos. Si la combinación no mejora ambas, hay algo mal.

Trampa 6: optimization sin re-ranking

El error: activas expansion + HyDE pero no tienes re-ranking. Los resultados fusionados pasan directo al LLM.

Síntoma: el LLM recibe 10 docs medianamente relevantes en lugar de 5 muy relevantes. Calidad de respuesta es peor que sin optimization.

Cómo prevenir: query optimization + re-ranking trabajan juntos. Optimization mejora retrieval, re-ranking refina los candidatos. Sin re-ranking, optimization puede degradar calidad.


Ejercicio aplicado

Escenario: eres AI Engineer en una plataforma de educación corporativa. Sistema RAG sirve preguntas de empleados sobre cursos de tecnología.

Datos:

  • 50K cursos chunkeados, en español
  • 20K queries/día
  • Pipeline actual: cosine + cross-encoder rerank

Análisis del log:

Categoría                       %      Ejemplos
─────────────────────────────────────────────────────────────
Bien formuladas                30%      "¿qué hace useState en React?"
Keyword-style                  25%      "react useState hook"
Incompletas (chat)             20%      "cómo lo configuro?" en chat de Docker
Comparativas                   12%      "diferencias entre useState y useReducer"
Vagas                           8%      "ayuda con mi código"
Multi-paso                      5%      "cómo testeo y deployeo mi app"

Métricas:

  • Precision@5: 79%
  • Recall@5: 61%
  • Stakeholders piden recall@5 ≥ 80% sin pasar 1500ms p95.

Tu trabajo:

  1. Aplica el decision framework. ¿Qué pipeline diseñas?
  2. Calcular costo y latencia esperados.
  3. Plan de validación.
Solución

1. Pipeline propuesto: adaptive con clasificación por LLM

El tráfico es muy variado (6 categorías distintas con %s significativos cada una). Una sola técnica no encaja. Adaptive es la opción correcta.

def adaptive_pipeline(query: str, chat_history: list = None, top_k: int = 5):
    """
    Pipeline adaptativo: LLM clasifica y aplica técnica óptima.
    """
    # Clasificación con LLM (gpt-4o-mini, ~150ms)
    category = classify_query(query, chat_history)

    queries_to_search = []

    if category == "well_formed":
        # Skip optimization
        queries_to_search = [query]

    elif category == "keyword_style":
        # Rewriting estructural
        rewritten = rewrite_structural(query).rewritten
        queries_to_search = [rewritten]

    elif category == "incomplete" and chat_history:
        # Rewriting con contexto
        rewritten = rewrite_with_context(query, chat_history).rewritten
        queries_to_search = [rewritten]

    elif category == "comparative":
        # Decomposition
        decomp = decompose_query(query)
        queries_to_search = decomp.sub_queries if decomp.is_decomposable else [query]

    elif category == "vague":
        # Expansion (queries vagas → múltiples interpretaciones)
        expansion = expand_query(query, num_expansions=4)
        queries_to_search = [query] + expansion.queries

    elif category == "multi_step":
        # Decomposition
        decomp = decompose_query(query)
        queries_to_search = decomp.sub_queries if decomp.is_decomposable else [query]

    # Retrieval para todas las queries
    if len(queries_to_search) == 1:
        results = collection.query(query_texts=queries_to_search, n_results=20)
        candidates = results['documents'][0]
    else:
        # Multiple queries → paralelo + RRF
        all_rankings = parallel_retrieve(queries_to_search, top_k=15)
        fused = reciprocal_rank_fusion(all_rankings)
        top_ids = [doc_id for doc_id, _ in fused[:30]]
        candidates = collection.get(ids=top_ids)['documents']

    # Re-rank con query original
    return cross_encoder_rerank(query, candidates, top_k=top_k)

2. Cálculo de costo y latencia

Latencia ponderada:

Categoría%LatenciaPonderada
Well-formed (skip)30%400ms120ms
Keyword (rewrite)25%700ms175ms
Incomplete (rewrite ctx)20%700ms140ms
Comparative (decomp)12%1100ms132ms
Vague (expansion)8%850ms68ms
Multi-step (decomp)5%1100ms55ms
Total promedio690ms

Latencia p95 (clasificación + caso peor): ~1300ms. Dentro del límite de 1500ms.

Costo mensual:

queries_per_day = 20_000
days_per_month = 30
total_queries = queries_per_day * days_per_month  # 600K

# Cost de clasificación (todas las queries)
classification_cost_per_query = 0.00005  # gpt-4o-mini, prompt corto
classification_total = total_queries * classification_cost_per_query

# Cost de cada técnica
costs_by_technique = {
    "skip": 0,
    "rewrite": 0.0006,
    "rewrite_ctx": 0.0008,
    "decomp": 0.0018,
    "expansion": 0.0011,
}

distribution = {
    "skip": 0.30,
    "rewrite": 0.25,
    "rewrite_ctx": 0.20,
    "decomp": 0.17,  # comparative + multi-step
    "expansion": 0.08,
}

technique_total = sum(
    total_queries * pct * costs_by_technique[tech]
    for tech, pct in distribution.items()
)

monthly_cost = classification_total + technique_total
print(f"Classification cost: ${classification_total:.2f}")
print(f"Technique cost: ${technique_total:.2f}")
print(f"Total monthly: ${monthly_cost:.2f}")

Output:

Classification cost: $30.00
Technique cost: $440.40
Total monthly: $470.40

~$470/mes en query optimization. Sostenible para producto educativo corporativo.

Recall esperado:

Categoría             %     Recall actual    Recall con técnica
──────────────────────────────────────────────────────────────────
Well-formed         30%      75%              75% (sin cambio)
Keyword             25%      55%              78% (rewriting)
Incomplete          20%      45%              82% (rewriting ctx)
Comparative         12%      58%              80% (decomposition)
Vague                8%      40%              72% (expansion)
Multi-step           5%      55%              78% (decomposition)

Recall global esperado:
0.30(0.75) + 0.25(0.78) + 0.20(0.82) + 0.12(0.80) + 0.08(0.72) + 0.05(0.78)
= 0.225 + 0.195 + 0.164 + 0.096 + 0.058 + 0.039
= 0.777 (78%) → cerca de target 80%

Si no llega a 80% con esta combinación, considerar agregar HyDE para queries vagas (subir recall en esa categoría).

3. Plan de validación

  1. Construir eval set ponderado: 100 queries reales distribuidas según las % del log (30 well-formed, 25 keyword, etc.) con ground truth.
  2. Baseline: medir recall@5 sobre el eval set con pipeline actual.
  3. Implementar adaptive_pipeline con feature flag.
  4. A/B test durante 2 semanas: 50% pipeline actual, 50% adaptive.
  5. Métricas primarias: recall@5 (target ≥80%), precision@5 (no caer >2pts), latency p95.
  6. Métricas secundarias: distribución de category classification (¿el LLM clasifica bien?), tasa de fallback al pipeline simple.
  7. Si recall ≥80% y latencia ≤1500ms p95, deployar 100%.

Plan B si recall queda en 75-79%:

  • Agregar HyDE para queries vagas (subir esa categoría de 72% a 80%+).
  • Mejorar prompt de classification (¿queries comparativas se detectan correctamente?).
  • Revisar manualmente sample de queries vagas que no llegaron — ¿son problema de query optimization o de retrieval?

Plan B si latencia >1500ms:

  • Bajar n_results del retrieval inicial.
  • Reducir paralelismo (de 5 a 3 sub-queries en decomposition).
  • Considerar cache LRU para queries comunes (reduce hit rate del classifier).

Resumen y siguiente paso

Lo que aprendiste:

  • Cuatro técnicas de query optimization, cada una para problema distinto: expansion (ambigüedad), rewriting (incompleta/keyword), decomposition (compleja), HyDE (recall máximo).
  • Decision framework basado en problema dominante (recall vs precision vs queries complejas).
  • Patrones híbridos para problemas múltiples: cascada (rewriting + expansion), paralelo (HyDE por sub-query).
  • Adaptive con LLM clasificador es la solución cuando el tráfico es muy variado.
  • TCO mensual típico para 10K queries/día: $200-600 según técnica. Despreciable para mayoría de productos.
  • Anti-patrones: aplicar todas las técnicas, combinar sin medir, optimization donde el problema no es de query.
  • Diagnosticar el cuello de botella del pipeline antes de invertir en query optimization.

Checkpoint: antes de cerrar el módulo, deberías poder:

  • Aplicar el decision framework para elegir técnica en menos de 10 minutos.
  • Diseñar pipelines híbridos que combinan dos o más técnicas justificadamente.
  • Calcular TCO mensual de query optimization para tu volumen.
  • Diagnosticar si baja precision/recall es problema de query vs retrieval vs rerank.

Siguiente cápsula: 08 — Proyecto Query Optimization Pipeline.

Cierre del módulo: vas a construir un pipeline de query optimization end-to-end con A/B testing entre dos técnicas, medición sobre eval set propio, y reporte comparativo. Es la herramienta que vas a aplicar el día 1 de cualquier proyecto RAG donde sospeches que las queries del usuario son el cuello de botella.


Recursos

  1. LangChain — Query Construction Guide — Patrones avanzados
  2. LlamaIndex — Query Pipelines — Implementaciones de referencia
  3. Pinecone — Query Optimization Series — Tutorial completo
  4. Anthropic — Contextual Retrieval — Técnica complementaria
  5. Goodhart's Law — Por qué optimizar lo que mides puede romper lo que no mides
  6. Microsoft — Query Optimization in RAG — Caso de uso con Azure

Tiempo estimado: 25-30 minutos Siguiente: 08-project-query-optimizer.md