M0 — El mapa y el vocabulario
Outcome del módulo: entender por qué medir va antes que optimizar, y salir de aquí sabiendo qué es cada término técnico que aparece en el resto del curso, sin dar nada por sabido. Este módulo es tu diccionario: vuelve a él cuando una sigla te frene.
Por qué este curso existe
Montar un RAG con un tutorial es fácil. Saber si tu RAG es bueno, cuánto cuesta, dónde se rompe y por qué elegiste cada pieza, eso es lo que separa a un desarrollador que “hizo un RAG” de uno que sabe operar un sistema de recuperación. La diferencia no es escribir más código, es poder responder con números y con el porqué. Este curso toma un RAG real, scholar-rag, y lo excava hasta la roca, un concepto a la vez.
La regla que ordena todo el curso:
No puedes profundizar en lo que no puedes medir. Primero el instrumento de medición, después la optimización.
Por eso el Módulo 1 es evaluación, antes que cualquier truco de mejora. Sin medir, “lo mejoré” es una opinión.
flowchart LR
A[Pregunta del usuario] --> B[Embedding de la pregunta]
B --> C[Retrieval: buscar chunks relevantes]
C --> D[Grade: filtrar lo que no sirve]
D --> E[Generate: el LLM responde con ese contexto]
E --> F[Respuesta con citas]
C -.mides.-> M1[recall, precision]
E -.mides.-> M2[faithfulness, costo, latencia]
Todo el curso vive en ese diagrama: cada etapa tiene conceptos que entender y métricas que medir.
El vocabulario, desde cero
Cada término trae tres cosas: qué es (en palabras llanas), por qué importa y dónde aparece en scholar-rag. No necesitas memorizarlos hoy, solo saber que existen y volver cuando los encuentres.
Recuperación (retrieval)
Embedding. Un vector de números (por ejemplo 384 o 768 valores) que representa el “significado” de un texto. Textos parecidos en significado quedan cerca en ese espacio de números. Es cómo una máquina compara sentido sin entender palabras.
Por qué importa: es la base de la búsqueda semántica; buscas por significado, no por palabras exactas.
En scholar-rag: services/embeddings.py convierte cada chunk de tesis y cada pregunta en un vector.
Chunk / chunking. Un documento largo (una tesis de 200 páginas) se parte en pedazos manejables llamados chunks. Chunking es la estrategia de cómo partirlo: por tamaño fijo, por párrafos, por significado.
Por qué importa: si el chunk es muy grande, mezcla temas y confunde; si es muy chico, pierde contexto. El tamaño del chunk cambia cuánto encuentra el sistema.
En scholar-rag: corpus.py:16 parte en trozos de 1000 caracteres con 150 de solape, un valor fijo que aún no está justificado con datos.
Búsqueda vectorial (vector search). Dado el vector de la pregunta, encuentra los chunks cuyos vectores están más cerca (por distancia coseno, normalmente). Por qué importa: es el corazón del RAG, pero por sí sola falla con términos exactos (códigos, nombres, números).
Búsqueda léxica / full-text. Búsqueda por palabras literales, como un buscador clásico. En Postgres se hace con tsvector y ts_rank.
Por qué importa: atrapa lo que la vectorial pierde: coincidencias exactas de términos.
En scholar-rag: usa websearch_to_tsquery('spanish', …) para el corpus en español.
Hybrid search (búsqueda híbrida). Combinar la vectorial (significado) con la léxica (palabras exactas) y fusionar sus resultados. Casi siempre gana a cualquiera sola.
En scholar-rag: retrieval_repository.py:hybrid_search hace las dos y las une.
RRF (Reciprocal Rank Fusion). La receta para fusionar dos listas de resultados sin tener que comparar sus puntajes (que están en escalas distintas). A cada documento le da un puntaje de 1 / (k + posición) en cada lista y los suma. k suele ser 60.
Por qué importa: es una forma simple y robusta de combinar la búsqueda vectorial y la léxica; que estén en unidades diferentes deja de ser problema, solo importa la posición en cada ranking.
En scholar-rag: el parámetro rrf_k=60 está ahí; parte del curso es entender por qué ese número y si mueve algo cambiarlo.
Reranking / cross-encoder. Un segundo paso que reordena los resultados con un modelo más caro pero más preciso, que mira pregunta y chunk juntos (a diferencia del embedding, que los mira por separado — a eso se le llama bi-encoder). Por qué importa: sube mucho la precisión del top-k a costa de latencia; se usa cuando la calidad importa más que los milisegundos.
Indexado (hacer la búsqueda rápida)
ANN (Approximate Nearest Neighbors). Búsqueda de vecinos más cercanos aproximada. Buscar el vector exacto más cercano entre millones es lento (hay que compararlos todos, O(n)); ANN sacrifica un poco de exactitud por muchísima velocidad. Por qué importa: sin un índice ANN, cada búsqueda recorre todo el corpus. Es la diferencia entre milisegundos y segundos. En scholar-rag: hoy no se ve un índice ANN, así que probablemente hace ese recorrido completo. Medirlo y arreglarlo es uno de los mayores saltos del curso.
HNSW (Hierarchical Navigable Small World). Un tipo de índice ANN que arma un grafo en capas por el que “salta” hasta la zona correcta del espacio de vectores. Muy rápido y preciso, usa más memoria y tarda más en construirse. Parámetros: m (conexiones por nodo), ef_construction (esfuerzo al construir), ef_search (esfuerzo al consultar; más = más recall, más lento).
Por qué importa: es hoy el índice por defecto para la mayoría de casos de RAG.
IVFFlat (Inverted File Flat). Otro índice ANN: agrupa los vectores en lists celdas y, al consultar, solo mira unas pocas (probes). Más liviano en memoria y rápido de construir que HNSW, pero suele dar menos recall.
Por qué importa: es la alternativa a HNSW; elegir entre ambos es un trade-off clásico que debes saber defender.
pgvector. La extensión de Postgres que guarda vectores y sabe hacer búsqueda por distancia (<=> para coseno) e índices HNSW/IVFFlat.
En scholar-rag: es donde viven los embeddings de los chunks.
Métricas (saber si es bueno)
recall@k. De todos los documentos relevantes que existían, qué fracción apareció en los primeros k resultados. Fórmula: |relevantes ∩ top-k| / |relevantes|.
Por qué importa: mide si el retrieval trae lo que hace falta. Si el chunk correcto no está en el top-k, el LLM no tiene con qué responder bien.
precision@k. De los k resultados que trajiste, qué fracción era de verdad relevante.
Por qué importa: mide el ruido. Traer basura relevante-parecida gasta espacio de contexto y confunde al LLM.
MRR (Mean Reciprocal Rank). Promedio de 1 / (posición del primer resultado relevante). Premia que lo bueno aparezca arriba.
Por qué importa: en RAG, que el chunk correcto sea el #1 y no el #8 cambia mucho la respuesta.
nDCG (normalized Discounted Cumulative Gain). Métrica de ranking que valora tanto que los relevantes estén presentes como que estén bien ordenados (los más relevantes primero), normalizada de 0 a 1. Por qué importa: es la métrica de ranking más completa; cuando quieras comparar dos retrievals en serio, es la que usan los papers.
faithfulness (fidelidad). Qué fracción de las afirmaciones de la respuesta están de verdad soportadas por el contexto recuperado. Mide alucinación: una respuesta faithful no inventa. Por qué importa: es la métrica que prueba que tu RAG no se inventa cosas. La más importante de la etapa de generación.
groundedness (anclaje). Muy cercana a faithfulness: que cada afirmación esté “anclada” en una fuente citable. A veces se usan como sinónimos.
RAGAS. Una librería que calcula estas métricas de RAG (faithfulness, answer relevance, context recall…) usando un LLM como juez. Por qué importa: es el atajo estándar; conviene entender las métricas a mano primero y usar RAGAS después.
Ground truth / dataset gold. El conjunto de preguntas con su respuesta o su documento correcto anotado a mano, contra el cual mides. Sin él no hay métrica posible. Por qué importa: es el instrumento. Construirlo (aunque sean 50 preguntas) es el primer trabajo real de profundidad.
Sistemas (que sea rápido, barato y aguante)
Latencia p50 / p95 / p99. Percentiles del tiempo de respuesta. p50 es la mediana (la mitad de las peticiones tarda menos); p99 es “el 1% peor”. Se miden por separado porque el promedio esconde los picos. Por qué importa: los usuarios sienten el p99, no el promedio. “Tarda 200ms en promedio pero el p99 es 4s” es un sistema que se siente lento y roto a ratos.
Profiling. Medir dónde se va el tiempo (o la memoria) dentro de tu código, en vez de adivinar. Herramientas: cProfile, py-spy, timers por etapa.
Por qué importa: la regla de oro de rendimiento es “mide, no adivines”. El cuello casi nunca está donde crees.
Event loop. El motor de asyncio en Python: un solo hilo que va atendiendo muchas tareas, saltando a otra cuando una espera I/O (red, disco, base de datos).
Por qué importa: es por qué un backend async atiende miles de conexiones sin miles de hilos. Pero si le metes trabajo pesado de CPU, lo bloqueas y todo se congela.
GIL (Global Interpreter Lock). El candado de CPython que deja ejecutar bytecode de Python a un solo hilo a la vez. Por qué importa: por eso el trabajo I/O-bound (esperar la BD, la API) escala con async, pero el trabajo CPU-bound (generar embeddings localmente con FastEmbed) bloquea el event loop y hay que sacarlo a otro proceso o thread.
Connection pool (pool de conexiones). Un conjunto de conexiones a la base de datos ya abiertas y reutilizables, en vez de abrir una nueva por petición (caro).
Por qué importa: el tamaño del pool (pool_size=20 en scholar-rag) define cuántas queries concurrentes soportas antes de que empiecen a hacer cola.
En scholar-rag: repositories/db.py con asyncpg.
Backpressure (contrapresión). Qué hace el sistema cuando llega más carga de la que aguanta: encolar, rechazar rápido, o degradarse. Un sistema maduro lo maneja a propósito. Por qué importa: sin backpressure, un pico de tráfico no te ralentiza, te tumba.
Timeout / retry / backoff. Cortar una llamada que tarda demasiado (timeout), reintentarla si falló (retry), y esperar cada vez más entre intentos (backoff exponencial) para no golpear un servicio caído. Por qué importa: toda llamada a un tercero (el LLM, la BD) puede colgar o fallar. Asumir que siempre responde bien es el error de junior más común.
Fijar
Nota atómica:
- Front: ¿por qué “medir antes de optimizar” y no al revés?
- Back: porque sin una métrica (recall, faithfulness, p99) cualquier cambio es una opinión sobre si mejoró; con el instrumento de medición, cada cambio se prueba con un número antes/después. El eval harness es el instrumento, por eso va primero.
Feynman: “Profundizar en un RAG es como afinar un carro con el tablero prendido. Sin velocímetro ni medidor de gasolina, ‘lo mejoré’ es una corazonada. Primero pones los instrumentos, después tocas el motor.”
Aplicar
No escribas código todavía. Recorre scholar-rag con este glosario al lado y ubica, en el código real, dónde vive cada concepto: el embedding (services/embeddings.py), el chunking (corpus.py), la búsqueda híbrida y el RRF (retrieval_repository.py), el pool (repositories/db.py), el grafo (services/rag_graph.py). Anota qué término del glosario todavía no entiendes del todo: esos son los que el resto del curso te va a aclarar.
Siguiente: M1 — Evaluación, donde construyes el instrumento que hace posible todo lo demás.