¿Por qué evaluar tu RAG?
La pregunta que no se puede contestar a ojo
Sección titulada «La pregunta que no se puede contestar a ojo»Cambiaste el chunkSize de 800 a 1200 y le hiciste a tu RAG la pregunta que más te gusta. La respuesta cambió un poco. ¿Está mejor o peor?
Si tu respuesta honesta es “me parece que mejor” — felicitaciones, sos como el 95% de los proyectos de RAG que se ponen “en producción” sin saber si funcionan bien. Y andá despidiéndote del salario que pensaste cobrar.
Para defender una decisión técnica necesitás números reproducibles. Eso es lo que vamos a construir en este nivel.
Las dos cosas que hay que separar
Sección titulada «Las dos cosas que hay que separar»Cuando una respuesta es mala, hay dos lugares donde puede haber fallado:
- Retrieval: el retriever no trajo los chunks correctos.
- Generación: los chunks estaban bien, pero el LLM los usó mal (o no los usó).
Si las medís juntas, no podés saber qué arreglar. Por eso un eval harness decente reporta cada dimensión por separado.
Las cuatro métricas del harness
Sección titulada «Las cuatro métricas del harness»El package 06-evals (ya está en el repo desde el día 1) computa cuatro métricas en cada corrida:
| Métrica | Mide | Cuándo te avisa |
|---|---|---|
| Latency | Cuánto tarda query() end-to-end | Tu RAG es correcto pero lento |
| Retrieval@k | ¿Está el chunk correcto en los top-K? | Problema de retriever |
| Faithfulness | ¿La respuesta usa SOLO los chunks recuperados? | El LLM alucina |
| Answer relevance | ¿La respuesta responde la pregunta? | Respuesta off-topic |
Las cuatro juntas te dan un mapa: si retrieval@k está alto pero faithfulness está bajo, el LLM está inventando. Si retrieval@k está bajo, el LLM no tiene chance — no le llegaron los chunks correctos.
Por qué un harness propio y no Ragas
Sección titulada «Por qué un harness propio y no Ragas»Ragas es la librería estándar de evals para RAG. ¿Por qué no la usamos? Tres razones:
- Caja transparente vs. caja negra. Cuando un score te sale raro, querés poder leer el código que lo computó. ~200 líneas de TypeScript son más rápidas de leer que una librería con plugins, decoradores, y abstracciones de configuración.
- Cero dependencias nuevas. El harness usa el mismo Ollama que ya tenés corriendo. Sin pip, sin uv, sin Python.
- Pedagogía. Implementar los 4 evaluators a mano enseña qué mide cada uno. Después podés cambiar a Ragas si querés — ya entendés qué hace por dentro.
Tour del package 06-evals
Sección titulada «Tour del package 06-evals»packages/06-evals/├── golden/│ └── dataset.json # 12 pares Q-A curados a mano├── reports/ # generados, gitignorados└── src/ ├── index.ts # CLI: parsea args, preflight, runner, reportes ├── runner.ts # framework × pregunta loop con try/catch por celda ├── adapters.ts # importa los 4 query.fn de los packages 01-04 ├── preflight.ts # chequea Ollama + Qdrant + collections antes de correr ├── judge.ts # LLM-as-judge: faithfulness + answer-relevance ├── report.ts # renderiza markdown + json └── metrics/ ├── latency.ts ├── retrieval-overlap.ts ├── faithfulness.ts └── answer-relevance.tsEl harness fue construido pensando en comparar los 4 frameworks (Vercel AI SDK, LangChain.js, LlamaIndex.TS, Mastra) — esa comparación es el contenido del Nivel 5. Pero también podés correrlo sobre uno solo con --only, que es lo que vamos a hacer en este nivel.
El primer comando
Sección titulada «El primer comando»pnpm --filter @rag-lab/06-evals run eval -- --only vercel-ai-sdk --limit 3Lo que hace, paso a paso:
- Preflight: verifica que Ollama está corriendo, los modelos están pulleados, Qdrant arriba y la collection
rag_vercelingestada. - Carga el golden set: 12 pares Q-A curados a mano sobre el corpus.
- Corre 3 preguntas (por el
--limit 3) contra Vercel AI SDK. - Para cada respuesta computa las 4 métricas (la 3 y 4 vía LLM-as-judge — son llamadas adicionales a Ollama).
- Escribe un reporte markdown + JSON en
packages/06-evals/reports/y un summary en stdout.
Los reportes están gitignorados
Sección titulada «Los reportes están gitignorados»Por diseño. Cada corrida genera un timestamp distinto y los números varían por el LLM-as-judge. No queremos commitear esa basura — solo el código del harness y el dataset son source-truth.
Si una corrida específica te sirve para algo (ej. “antes/después” de un cambio que vas a documentar en un blog post), copiala fuera de reports/ o agregala manualmente a un permanent path.
Lo que viene
Sección titulada «Lo que viene»En el siguiente capítulo abrimos la métrica más interesante: faithfulness. Cómo se implementa con un segundo LLM call, cómo se diseña el judge prompt, y cuál es el bias que trae que el mismo modelo genere y juzgue.