Comparativa: ajustando TOP_K, chunk size y modelo
El payoff
Sección titulada «El payoff»Llegaste hasta acá: tenés un eval harness, un golden set, y entendés qué mide cada una de las 4 métricas. Ahora viene la parte por la cual valió la pena: cambiar parámetros y medir el impacto.
En este capítulo vas a hacer un experimento de 3 ejes, leer los números, y aprender a tomar una decisión basada en datos en vez de en intuición.
Los 3 ejes que importan
Sección titulada «Los 3 ejes que importan»Hay decenas de parámetros tuneables en un RAG. Los 3 que más impacto tienen para empezar:
| Eje | Valores típicos | Cómo se cambia | Re-ingestión |
|---|---|---|---|
| TOP_K | 2, 4, 6, 8 | flag CLI --top-k N en el harness | no |
| Chunk size / overlap | 400/50, 800/100, 1200/150 | edit en chunkDocs(...) o env var | sí |
| Modelo de embeddings | nomic-embed-text, mxbai-embed-large | env var OLLAMA_EMBED | sí |
Re-ingestión = volver a correr pnpm vercel:ingest con la nueva config. Si cambiás chunk size o modelo, los vectores viejos están con la config vieja y tenés que regenerarlos. Si solo cambiás TOP_K, no — el TOP_K se aplica en el momento de la query.
El eje 1: TOP_K (sin re-ingestión)
Sección titulada «El eje 1: TOP_K (sin re-ingestión)»Empezamos por el más fácil. Una corrida con TOP_K=2 y otra con TOP_K=8:
pnpm --filter @rag-lab/06-evals run eval -- --only vercel-ai-sdk --top-k 2pnpm --filter @rag-lab/06-evals run eval -- --only vercel-ai-sdk --top-k 8Cada una te genera un reporte separado. Comparalos. Para el corpus del curso, los números típicos:
| TOP_K | retrieval@k | faithfulness | latency_mean |
|---|---|---|---|
| 2 | 0.83 | 0.79 | 1620 ms |
| 4 (default) | 1.00 | 0.83 | 1842 ms |
| 6 | 1.00 | 0.75 | 2010 ms |
| 8 | 1.00 | 0.71 | 2180 ms |
Léelo así:
- Retrieval@k sube de 0.83 a 1.00 al pasar de 2 a 4. Después se estanca: con K=4 ya estás trayendo todos los chunks correctos.
- Faithfulness baja después de K=4. Esto sorprende al principio pero tiene una razón: con más chunks en el contexto, el LLM tiene más oportunidad de mezclar info irrelevante en su respuesta. Más contexto no siempre es mejor.
- Latency sube linealmente con K. Más chunks = más tokens en el prompt = más tiempo de generación.
Conclusión para este corpus: K=4 es sweet spot. Más allá no ganás retrieval pero perdés faithfulness y velocidad.
El eje 2: chunk size (con re-ingestión)
Sección titulada «El eje 2: chunk size (con re-ingestión)»Cambiar chunk size es más invasivo: tenés que re-embeber todo el corpus con la nueva config. Lo bueno: ingest.ts acepta los flags --chunk-size y --overlap por CLI, así que no hace falta editar código:
pnpm vercel:ingest -- --chunk-size 400 --overlap 50pnpm --filter @rag-lab/06-evals run eval -- --only vercel-ai-sdk
pnpm vercel:ingest -- --chunk-size 1200 --overlap 150pnpm --filter @rag-lab/06-evals run eval -- --only vercel-ai-sdkSin flags, los defaults son 800 / 100 (lo que vive en packages/shared/src/chunker.ts). El output del comando te imprime la config usada — útil para no confundirte entre corridas.
Probá 3 configs (400/50, 800/100, 1200/150). Para el corpus del curso:
| Chunk size / overlap | retrieval@k | faithfulness | answer_relevance |
|---|---|---|---|
| 400 / 50 | 0.92 | 0.71 | 0.65 |
| 800 / 100 (default) | 1.00 | 0.83 | 0.73 |
| 1200 / 150 | 0.96 | 0.79 | 0.72 |
Léelo así:
- 400/50 pierde retrieval@k. Chunks chicos cortan conceptos y el chunk con la respuesta no tiene la respuesta completa — el retriever lo trae pero el LLM no puede armar la respuesta.
- 800/100 gana parejo. Es el sweet spot para texto técnico en español.
- 1200/150 está casi tan bien. Para corpus con párrafos largos (PDFs académicos, libros) probablemente le ganaría a 800.
Conclusión: 800 chars es buen default y el costo de probar es bajo (5 minutos por corrida). Confirmar con tu corpus es 30 minutos bien invertidos.
El eje 3: modelo de embeddings (con re-ingestión)
Sección titulada «El eje 3: modelo de embeddings (con re-ingestión)»El más caro de probar (descargás un modelo nuevo, ~270 MB a ~700 MB) pero a veces el que más mueve la aguja.
ollama pull mxbai-embed-largeOLLAMA_EMBED=mxbai-embed-large pnpm vercel:ingestOLLAMA_EMBED=mxbai-embed-large pnpm --filter @rag-lab/06-evals run eval -- --only vercel-ai-sdkPara el corpus del curso:
| Modelo de embeddings | retrieval@k | faithfulness | latency_mean |
|---|---|---|---|
| nomic-embed-text (768d) | 1.00 | 0.83 | 1842 ms |
| mxbai-embed-large (1024d) | 1.00 | 0.85 | 2110 ms |
Léelo así:
- Retrieval@k está al techo en ambos. El corpus del curso es chico — cualquier embedder decente lo resuelve.
- Faithfulness sube 2 puntos. Marginal pero real. Los embeddings de
mxbaidiscriminan mejor → al LLM le llegan chunks más enfocados → menos ruido para alucinar. - Latency sube por la dimensión más alta. El embed call al modelo es más caro por más floats que mover.
Conclusión: para este corpus, no vale la pena el upgrade. Para un corpus de 10k chunks con queries más sofisticadas, mxbai (o BGE-M3 si querés multilingüe) puede mover la aguja 5-10 puntos.
La regla del experimento bien hecho
Sección titulada «La regla del experimento bien hecho»Cambiá UN eje por vez.Mantené todos los otros ejes constantes.Anotá los números antes de cambiar nada.Si querés comparar TOP_K=2 contra TOP_K=8 con el mismo corpus, el mismo chunk size y el mismo modelo, los reportes son directamente comparables. Si cambiás dos cosas a la vez, no podés atribuir la mejora a una u otra.
La trampa del benchmark único
Sección titulada «La trampa del benchmark único»Ahora la advertencia importante. Estos números son del corpus del curso: 4 markdowns sobre arquitecturas de software, en español, ~30 chunks. Si los reportás como “verdad sobre RAG” estás mintiendo.
Para TU corpus, los sweet spots pueden ser otros. Para corpus en inglés, los modelos cambian. Para corpus de 100k chunks, K=4 es seguramente bajo y vas a querer 8-12. Para corpus con mucho jerga técnica (códigos de funciones, IDs), los embeddings densos solos no alcanzan y vas a necesitar hybrid search (que viene en Nivel 3).
Lo que transfiere de este capítulo es la metodología:
- Definí golden set sobre TU corpus.
- Mové un eje a la vez.
- Anotá las métricas antes y después.
- Decidí basado en los números, no en la intuición.
Ese workflow se aplica igual a cualquier corpus, cualquier escala, cualquier modelo. Los valores específicos son siempre del corpus.
Cerraste Nivel 2
Sección titulada «Cerraste Nivel 2»Si llegaste hasta acá:
- Tenés un eval harness corriendo sobre tu RAG.
- Sabés leer 4 métricas: latency, retrieval@k, faithfulness, answer-relevance.
- Tenés un golden set extendible y entendés por qué se cura a mano.
- Sabés generar sintéticos y para qué sirven (y para qué no).
- Hiciste experimentos en 3 ejes y aprendiste a tomar decisiones basadas en datos.
No es poco. La mayoría de la gente que dice “tengo un RAG en prod” no llegó hasta acá.
Lo que viene
Sección titulada «Lo que viene»Tenés métricas. Sabés mejorar. Pero las técnicas que probaste hasta ahora son vanilla: dense retrieval + LLM directo. Ahora viene lo que separa un RAG de demo de uno que aguanta usuarios reales:
- Hybrid search: combinar embeddings densos con búsqueda léxica (BM25) para no fallar en términos técnicos exactos.
- Reranking: un segundo paso más fino que reordena los top-K antes de pasarlos al LLM.
- Multi-query: descomponer preguntas complejas en sub-preguntas.
- Query rewriting: limpiar y reformular preguntas ambiguas antes de buscar.
- Citations: respuestas con marcas inline a las fuentes.
Cada técnica resuelve un problema específico que vas a poder medir con el harness que ya tenés. Eso es Nivel 3.