REGISTRADO 2026-09-22 · REV A
Un RAG sin puerta de evals es una demo.
Un sistema de retrieval es una promesa. La puerta de evals es lo que convierte esa promesa en una afirmación que otro puede comprobar — y romper en cuanto deja de ser cierta.
El problema: un recall que nadie mide
La mayoría de proyectos RAG entregan una demo. Preguntas algo, el retriever devuelve cinco fragmentos, un modelo escribe un párrafo con seguridad y todo el mundo asiente. Nadie puede decir si el documento correcto estaba entre esos cinco fragmentos — porque nadie escribió qué significa «correcto» y nadie lo mide. La demo funciona hasta que un cambio de chunking, un nuevo embedding model u otro vector store mueve la calidad en silencio, y la única señal es una vaga sensación de que las respuestas empeoraron.
Ese es el verdadero modo de fallo: no la alucinación como pánico moral, sino un retrieval que se degrada sin que nadie mire. Una demo optimiza el camino feliz delante de una audiencia; un sistema optimiza un número contra el que puede regresar. La distancia entre ambos es una eval — y CodebaseRAG existe para cerrarla.
El set golden: convertir lo «correcto» en cuarenta pares verificables
Una eval es tan honesta como sus preguntas. El set golden es una lista pública de pares pregunta/respuesta extraídos del propio repositorio: una pregunta que un desarrollador haría de verdad, emparejada con la respuesta y con dónde vive. Contiene ≥40 pares — suficientes para detectar una regresión real, lo bastante pocos para revisar cada uno a mano y mantenerlos honestos.
No necesitas una plataforma de etiquetado. Necesitas un sitio donde escribir las preguntas y la disciplina de mantenerlas. Viven junto al código, así que un cambio en el retriever y sus expectativas actualizadas viajan en la misma revisión.
Tres entradas, parafraseadas del set público, muestran la forma:
¿De qué abstracción depende el query use case y por qué no es un tipo del vector store? Depende de un port de retriever; los adapters lo implementan, así que el core nunca importa una clase de pgvector o Qdrant.
¿Qué debería hacer CI cuando el recall@5 medio cae por debajo del suelo comprometido? Hacer fallar el build. El suelo es un número comprometido, y moverlo es una decisión explícita con gate por ADR — no una edición que pone CI en verde.
¿Puede la eval ejecutarse sin red? Sí. Los embeddings llegan a través de un port con dos adapters — Ollama en local, Anthropic cuando está alojado — así que el mismo set golden se ejecuta offline.
Los ejemplos no pretenden ser difíciles. Pretenden tener respuestas defendibles, para que una equivocada sea un test que falla y no una discusión.
La puerta de CI: qué falla y qué no
Una puerta solo es útil si falla alto y de forma predecible. Esta mide el recall@5 medio, la mean reciprocal rank y el nDCG@5 sobre el set golden, y hace fallar el build cuando el recall@5 medio cae por debajo de la baseline comprometida de 0.409.
Qué falla: cualquier cambio que empuje el recall@5 medio por debajo de 0.409. Esa es toda la regla. CI ejecuta la misma eval determinista que un portátil, así que un build en rojo apunta a un cambio en el retrieval, no a un entorno inestable.
Qué no falla también importa. Un cambio de modelo que mantiene el recall@5 en el suelo o por encima pasa aunque MRR y nDCG@5 se muevan — la puerta protege la métrica comprometida, no todos los números del panel. Un refactor que mueve código sin mover el retrieval pasa. Y la puerta no juzga la fluidez de las respuestas: esto es una eval de retrieval, y fingir que mide la calidad de generación sería la misma deshonestidad que no tener ninguna eval.
Por qué hexagonal: cambiar Qdrant no debe reescribir el core
Mides el retrieval, así que lo que mides no puede estar soldado a lo que despliegas. CodebaseRAG es hexagonal: el query use case depende de ports, y pgvector, Qdrant, Ollama y Anthropic se sientan detrás como adapters.
El test es concreto. Cambiar Qdrant por pgvector — o ejecutar totalmente en local con Ollama — no debe reescribir el core. Si cambiar un vector store obliga a editar los use cases, la eval está midiendo un accidente de la capa de almacenamiento, y cada cambio futuro reabre si las métricas siguen significando algo.
Mantener el core libre de frameworks y transportes aporta más que orden: mantiene la eval determinista, ejercitada contra adapters en memoria o respaldados por contenedores sin necesidad de red. Un suelo comprometido solo es fiable cuando el código que hay debajo no cambia de forma cada vez que cambia la infraestructura.
La baseline actual y lo que no afirma
La baseline comprometida es un recall@5 medio de 0.409 (MRR 0.231, nDCG@5 0.277) sobre un set golden de al menos cuarenta pares. Léelo como un suelo, no como un resultado. 0.409 no es SOTA y esto no es una afirmación de que el retrieval esté resuelto. Es el número que el proyecto se comprometió a defender, elegido lo bastante bajo para mantenerse estable y lo bastante alto para detectar una caída real.
Lo que el número no afirma: que el set golden sea exhaustivo, que un build en verde signifique buenas respuestas, o que el embedding model sea el mejor disponible. Subir el suelo es una decisión registrada con una justificación, nunca una métrica de vanidad pegada en un README.
Lo que sí afirma es más pequeño y más útil: en cada cambio, el repositorio puede decirte si el retrieval empeoró, y demostrarlo con un set golden público. Esa es la línea entre una demo RAG y un sistema RAG. Una demo te muestra una respuesta; un sistema te deja discrepar de ella.