English · Español
Lab 04 — Arnés evaluador del tutor de gramática¶
🇪🇸 Construye un arnés evaluador (~30 prompts §A13) que ejecuta el agente del tutor de gramática contra ground-truth conocido, calcula precisión, fidelidad y coste medio de turnos/llamadas a herramientas, y emite un reporte machine-readable. Mismo formato que el A4 capstone-tracker para que ambos converjan al cierre de Fase 32.
Lee
theory/05-agent-loop-architecture.mdylab/01-tutor-end-to-end.mdantes de empezar. No consultessolutions/.
Objetivo¶
Cablea un pipeline de evaluación determinista y reproducible para el agente tutor de gramática. El arnés lee un YAML de ~30 prompts §A13 con respuestas doradas, ejecuta cada prompt a través del agente y produce un reporte estructurado. El reporte dirige el DoD de la Fase 32.
Alcance (solo §A13)¶
El conjunto de eval cubre:
- 20 verbos (12 regulares + 8 irregulares).
- 5 tiempos (infinitive, present simple, past simple, past participle, simple future).
- 3 personas (1ª sg, 2ª sg, 3ª sg).
- Prompts en inglés y español (política bilingüe, §A2).
Fuera de alcance:
- Personas plurales (1ª/2ª/3ª plural) — diferido según §A13.
- Verbos fuera de los 20 listados en §A13.
- Tiempos fuera de los 5 listados.
El arnés impone estas restricciones vía la máscara JSON-Schema sobre los tool calls del agente (referencia cruzada Fase 30 → 32).
Tareas¶
Tarea 1 — autora el conjunto de eval¶
Crea data/eval/phase-32-grammar-tutor.yaml con ~30 entradas. Esquema (por entrada):
- id: tut-01-eat-pst-3s
category: irregular_verb_correction
prompt_en: "Correct this sentence: 'He eated the apple.'"
prompt_es: "Corrige esta oración: 'Él comió la manzana.'"
gold_answer: |
{"original": "He eated the apple.",
"verb": "eat", "tense": "past simple", "person": "3rd singular",
"correct_form": "ate", "spanish": "comió"}
expected_tool_calls: ["conjugate"]
max_turns: 3
Apunta a cobertura, no a volumen:
- 8 entradas: correcciones de verbos irregulares (una por verbo irregular).
- 6 entradas: conjugaciones de verbos regulares (muestrea entre los 12).
- 5 entradas: identificación de tiempo ("¿en qué tiempo está
wrote?"). - 5 entradas: pares de traducción inglés ↔ español.
- 4 entradas: adversarias / fuera de alcance ("conjuga
swimen past simple" → esperado: el agente declina, ya queswim∉ §A13). - 2 entradas: entradas ambiguas / infraespecificadas (el agente debería pedir aclaración o rendirse con elegancia).
Tarea 2 — script del arnés¶
Crea scripts/eval_grammar_tutor.py:
def run_eval(eval_path: Path, model_ckpt: Path) -> EvalReport:
"""Load eval set, instantiate agent, run each prompt, accumulate metrics."""
El arnés debe:
- Usar el fixture autouse de semilla para que dos ejecuciones produzcan salidas idénticas (determinista).
- Cronometrar cada prompt; registrar reloj-de-pared y conteo de turnos.
- Validar la salida del agente contra
gold_answerusando un matcher estructural (no solo==): para el campo "correct_form", coincidencia exacta; para el campo "spanish", permitir sinónimos de una pequeña whitelist (p. ej.,comióyse comióambos aceptables para "ate"). - Emitir un
EvalReport:
@dataclass
class EvalReport:
n_prompts: int
correct: int # exact-match on correct_form
faithful: int # gold supported by retrieved chunks / tool outputs
declined: int # agent gave up; gold also "declined"
failed: int # agent gave up; gold expected an answer
mean_turns: float
mean_tool_calls: float
p95_latency_ms: float
by_category: dict[str, dict[str, float]]
Tarea 3 — umbrales DoD¶
Los criterios de cierre de la Fase 32, codificados en el código de salida del arnés (no-cero si algún umbral falla):
| Métrica | Umbral |
|---|---|
correct / n_prompts |
≥ 0.85 (tras LoRA fine-tune de la Fase 28) |
faithful / correct |
≥ 0.95 (sin citas alucinadas) |
mean_turns |
≤ 3.5 |
mean_tool_calls |
≤ 2.5 |
p95_latency_ms |
≤ 1500 en el i5-8250U de Borja |
declined en entradas fuera de alcance |
= 4 (coincide con los 4 prompts fuera de alcance) |
failed |
≤ 2 (permite que 2 entradas fallen sin bloquear el cierre) |
Si correct < 0.85, el reporte debería imprimir los 5 peores prompts con la respuesta real del agente y la dorada para diff visual. Esta es la entrada diagnóstica para la reflexión de la Fase 32.
Tarea 4 — log de traza JSON-line¶
Para cada prompt, emite una línea JSON a experiments/<date>-32-tutor-eval/traces.jsonl conteniendo:
{
"id": "tut-01-eat-pst-3s",
"prompt_en": "Correct this sentence: 'He eated the apple.'",
"scratchpad": [{"role": "user", "text": "..."}, {"role": "model", "action": "tool_call", ...}, ...],
"agent_output": {"correct_form": "ate", "spanish": "comió"},
"gold": {...},
"metrics": {"correct": true, "faithful": true, "turns": 2, "tool_calls": 1, "latency_ms": 437}
}
Esta traza es el log de auditoría que un profesor usa para diagnosticar fallos individuales. El subagente journal-summarizer puede digerirla más tarde.
Tarea 5 — convergencia con el capstone tracker (A4)¶
El modo examen del portal de la Fase 41 lee el mismo data/eval/phase-32-grammar-tutor.yaml. El arnés aquí y el ejecutor de examen del portal deben coincidir en las métricas — ambos consumen el mismo YAML, ambos producen formas comparables de EvalReport. Esta convergencia es el gancho §A4: el arnés es la eval offline; el portal es la eval online; ambos llegan a la misma conclusión sobre si el tutor es lo bastante bueno.
El contrato del portal está documentado en src/miniportal/BLUEPRINT.md §"Exam scoring". La salida de tu arnés debe satisfacer:
- Mismos nombres de métrica (
correct,faithful, etc.). - Mismos valores de umbral (≥ 0.85 de corrección, etc.).
- Mismo esquema JSON del log de traza.
Medidas a capturar¶
- Todos los campos del EvalReport de arriba.
- Desglose por categoría: precisión por categoría de verbo irregular, precisión de verbo regular, precisión de OOS-decline.
- Un histograma de
turnsytool_callssobre los 30 prompts. - Un scatter de latencia por prompt.
Aceptación¶
-
data/eval/phase-32-grammar-tutor.yamltiene ~30 entradas abarcando las 6 categorías anteriores. -
scripts/eval_grammar_tutor.pyse ejecuta hasta completar en la CPU de Borja en ≤ 90 s. - Re-ejecutar el arnés con la misma semilla produce un
traces.jsonlbyte-idéntico. - Los siete umbrales DoD pasan (o el arnés sale con código no-cero con un resumen claro del fallo).
- El esquema JSON-line de la traza coincide con el formato esperado por el portal.
- El conjunto de eval se publica bajo
data/eval/y es trackeado por DVC (dvc add data/eval/phase-32-grammar-tutor.yaml) para que la versión sea reproducible.
Trampas a esperar¶
- Olvidar la semilla: dos ejecuciones discrepan en un par de prompts porque el sampler de Mini-GPT no es determinista. Fija
temperature=0.0para ejecuciones de eval; si un prompt falla a T=0, esa es la señal real. - Contar OOS-declines como fallos: un prompt fuera de alcance (
"conjugate swim") que el agente correctamente declina es un ÉXITO, no un fallo. La métricadeclinedestá separada defailed. La mayoría de evaluadores las confunden — ten cuidado aquí. - Whitelist creep en sinónimos en español: tentación de meter en whitelist
corrió,corría,correríatodos paracorrió. Resiste. Añade sinónimos uno a uno conforme te encuentres falsos negativos; documenta cada adición en el YAML con un comentario. - Tamaño del log de traza: ~30 trazas × ~5 KiB cada una = 150 KiB por ejecución. No comitees las trazas; son artefactos de experimento (
.gitignoreexperiments/).
Referencias cruzadas¶
docs/phase-20-evaluation-harness/— el patrón del arnés de eval reusa la estructura de la Fase 20 para tareas de gramática.src/miniportal/BLUEPRINT.md§"Exam scoring" — el contrato con el que este arnés debe converger.docs/extension-track/X3-rlhf-dpo/lab/01-dpo-on-grammar-tutor.md— DPO usa este arnés como la señal de recompensa; las métricas aquí se convierten en el objetivo DPO.
Siguiente: con el arnés en verde, escribe PHASE_32_REPORT.md resumiendo la puntuación del agente sobre los 30 prompts y reflexiona sobre qué categorías necesitaron más qué componentes de las Fases 26-31.