El RAG deja de calificarse a ojo.
Un banco de pruebas que puntúa el RAG contra un dataset de casos «verdad de campo», usa jueces LLM para medir fidelidad y relevancia, compara cada versión con la anterior y bloquea las regresiones con una puerta de calidad. Cuando tocas algo, obtienes un número que dice si mejoró o empeoró — no una opinión. Tercer artefacto de la ruta Data Science → AI Engineering.
Se evalúa una vez, se testea mil
Construir un RAG es fácil; saber si funciona y detectar cuándo una versión nueva empeora es lo que separa un sistema de un prototipo. El harness convierte esa pregunta en un pipeline con dos velocidades de coste: solo el primer paso gasta dinero — los otros dos leen su salida ya guardada, así que la puerta puede correr en cada cambio gratis.
Una sola definición de regresión
El informe que se lee y la puerta que bloquea comparten la misma lógica: el test de
calidad importa y reutiliza el comparador, no reimplementa su propio criterio. Así es
imposible que el informe diga «todo bien» mientras el test dice «roto». Una definición, dos caras: un
informe legible y un exit code que un pipeline entiende.
import comparar # la MISMA lógica que produce el informe
def test_ninguna_alucinacion_nueva(diff):
# responder algo AUSENTE del corpus = alucinación.
# es la métrica que distingue a este RAG (sabe callarse),
# por eso tiene su propio assert dedicado.
alucinaciones = [r for r in diff["regresiones"] if "FALSO POSITIVO" in r]
assert not alucinaciones
La caza, paso a paso
No es una demo de juguete: al correr sobre el RAG en producción, el harness cazó un falso positivo real y guió su corrección. Este es el replay de aquella caza, tal y como quedó en la bitácora.
# dataset_eval.json · un caso «golden» etiquetado a mano
{ "id": "T1",
"pregunta": "irse de casa",
"esperado": "AUSENTE" # el corpus NO lo contiene:
# la respuesta correcta es callar }
Las trampas son preguntas que el corpus no sabe responder. Un RAG honesto debe decir «no guardo ese recuerdo» — y esa honestidad también se mide, con casos dedicados.
# evaluar.py · el RAG responde con el umbral de entonces (0,40)
T1 "irse de casa" ....... sim 0.421 ≥ 0.40 → banda "posible"
respondida ✗ (esperado: AUSENTE)
→ FALSO POSITIVO
El prompt no llegó a alucinar: fue el umbral, blando, el que dejó pasar lo que no debía. Sin la trampa en el dataset, nadie lo habría visto — las medias seguían con buena cara.
$ HARNESS_CAND=resultados_u040.json pytest -v
test_ninguna_alucinacion_nueva ........... FAILED
E AssertionError: Alucinación nueva:
E · T1 FALSO POSITIVO — "irse de casa" (AUSENTE) a sim 0.421
bloquea La decisión rota manda sobre las medias. Aunque todos los promedios subieran, un falso positivo nuevo cierra la puerta — por eso ese assert tiene nombre propio.
# candidato: umbral 0.40 → 0.43, sin tocar el motor
decisión ............ 86 % → 100 %
regresiones ......... 0
===== 6 passed in 0.12s ===== # puerta verde → desplegado a Cloud Run
cazada y corregida El harness no solo mide: encontró un fallo real y guió su corrección. La sonda del Artefacto 2 navega hoy con ese 0,43 — son la misma historia, contada desde las dos orillas.
Cinco piezas, una red de seguridad
gpt-4o, superior al generador para evitar auto-preferencia) puntúan faithfulness y relevancia; temperatura 0, salida JSON forzada.
pytest. Verde si nada empeoró, rojo si algo cayó. No gasta API: solo lee dos JSON.
Los criterios, cumplidos
Herramienta interna, no un servicio. El harness no se despliega: se integra. Su valor es proteger a los otros artefactos — ya guió una corrección del RAG del Artefacto 2 que sí está en producción, y su filosofía es la semilla de la puerta CI del Artefacto 5.
Prompt engineering sin evaluación es superstición. Un harness convierte «creo que mejoró» en «mejoró un 14 %, sin regresiones» — y eso es lo que distingue: no construir el RAG, sino saber demostrar que funciona.