SEXTANTEcursos técnicos de IA
métodobackward-design
árbitroel dato
Entrar
N1 · Error analysis/L4

De fallos a dataset etiquetado

Objetivo de maestría

construirás un dataset de evaluación con etiquetas binarias claras, split y casos +/− balanceados, tratándolo como un activo de ingeniería versionado. Sin él, los niveles siguientes no tienen contra qué medir.


1.4.1La taxonomía que no era un dataset

Acabas el axial coding de Aurora. Tienes la taxonomía priorizada delante: el fallo nº1 es "recupera la política equivocada", presente en el 31% de las trazas. Lo llevas a la reunión con el equipo de N2, que va a montar el LLM-as-judge.

La pregunta llega rápido: "vale, ¿y dónde están los ejemplos etiquetados que usaré para validar el juez?".

Abres tu hoja. Tienes categorías, conteos y porcentajes. Tienes "31%". No tienes, para cada traza, una marca que diga este caso falló el criterio o este caso lo pasó.

Una taxonomía con conteos es un resumen: te dice cuántas veces ocurre cada fallo. No es un dataset: el equipo de N2 no puede validar un juez contra un porcentaje. Necesita casos individuales, cada uno con su veredicto.

Te falta convertir cada traza en un caso con etiqueta. Eso es esta lección.


1.4.2Qué vas a poder hacer

Al terminar sabrás:

  • Definir un criterio de evaluación binario (pass/fail) a partir de un modo de fallo de la taxonomía.
  • Etiquetar trazas contra ese criterio y separar el dataset en conjuntos de desarrollo y held-out (split).
  • Justificar por qué necesitas casos que pasan y casos que fallan, balanceados.
  • Tratar el dataset como un activo versionado que crece a lo largo del curso, no como una hoja desechable.

Necesitas saber antes:

  • La taxonomía priorizada de N1·L3: categorías, conteos y el fallo nº1.
  • Python a nivel de leer funciones, diccionarios y listas.
  • Manejo básico de pandas (cargar un DataFrame, filtrar filas). La API exacta está en la referencia del nivel.

Esta lección no construye el juez ni mide nada todavía. Produce el material contra el que N2 medirá. Sin dataset etiquetado, validar un juez es imposible: no tendrías verdad de referencia.


1.4.3Recupera

Antes de seguir, responde mentalmente. No mires lo de abajo hasta tener tu respuesta.

  1. De N1·L3, ¿cuál es el fallo nº1 de Aurora y cómo lo priorizaste?
  2. ¿Por qué priorizaste por frecuencia y por impacto, no solo por frecuencia?
  3. Imagina que tienes que decirle a otra persona si una respuesta de Aurora "está bien". ¿Le das una nota del 1 al 5, o un pass/fail? ¿Cuál de las dos dará menos discusiones entre dos personas distintas?

La pregunta 3 es el gancho de hoy. La nota 1-5 obliga a discutir si algo es un 3 o un 4. El pass/fail obliga a una sola pregunta: ¿cumple el criterio o no? Esa diferencia, que ahora parece menor, decide si tu dataset es consistente o ruidoso.


1.4.4El concepto: el dataset como activo de ingeniería

Empecemos por lo concreto —una etiqueta— y subamos hasta la idea de activo versionado.

La etiqueta binaria gana a la escala numérica

Tienes el fallo nº1: "recupera la política equivocada". Para convertirlo en dato, defines un criterio: una pregunta de sí/no sobre una traza. Aquí: ¿la política citada corresponde al producto o tema de la consulta?

La respuesta es binaria: pass o fail. No "calidad 3,5". Una etiqueta binaria es un veredicto de pass/fail respecto a un criterio concreto, no una nota en una escala.

¿Por qué binaria y no una escala 1-5? Porque dos personas distintas etiquetan igual con más frecuencia.

Shankar lo formula así: las métricas binarias son más fáciles de alinear y de juzgar de forma consistente por humanos que las escalas numéricas. (Traducción de: "binary metrics are easier to align… and easier for humans to consistently judge" — Shreya Shankar, "AI Engineering Flywheel", jul 2024.)

La analogía: una escala 1-5 es como puntuar un examen "por buena impresión"; el binario es una rúbrica con casillas. Límite de la analogía: el binario fuerza a colapsar matices reales en dos cajas. Esa es su debilidad y, a la vez, la razón de su consistencia.

Es común sentir que el binario "pierde información". Es cierto que pierde matiz. La diferencia clave: lo que ganas es un criterio que dos anotadores aplican igual, y eso es lo que hace medible un dataset.

Anatomía de un caso

Cada caso de tu dataset tiene tres piezas:

  • Input: la traza o la consulta del cliente (qué entró al agente).
  • Etiqueta binaria: pass o fail respecto al criterio definido.
  • Nota (opcional): una línea de por qué, heredada del open coding.

Un caso de Aurora se ve así, en estructura:

text
1caso_017
2├─ input:    "¿puedo devolver estas zapatillas que no me quedan?"
3├─ traza:    consultar_politica(tema="devoluciones") -> chunk "electronica-04"
4├─ criterio: ¿la política citada corresponde al producto de la consulta?
5├─ label:    fail        ← citó política de electrónica para calzado
6└─ nota:     "RAG recuperó devoluciones-electrónica, no calzado"

El split: no validar con los mismos casos que ajustas

Aquí entra una idea prestada del machine learning clásico. Un split es la partición del dataset en conjuntos separados: uno para desarrollar (afinar el criterio, el prompt del juez, el umbral) y otro held-out —apartado— que solo tocas para validar al final.

En evals lo llamamos conjunto de desarrollo (dev) y conjunto de prueba (test). El de prueba se queda intacto: no lo miras mientras ajustas.

¿Por qué? Porque si afinas el juez de N2 sobre los mismos casos con los que luego dices "el juez acierta el 90%", te engañas a ti mismo. El juez habrá memorizado esos casos concretos. Es el equivalente a estudiar el examen con las respuestas delante: el resultado no predice nada.

La analogía falla en un punto: en evals los conjuntos suelen ser pequeños, y no entrenas pesos. Pero la lógica del held-out se mantiene: separas lo que ajustas de lo que valida.

Casos +/− balanceados: el evaluador necesita ver la frontera

Tienes que incluir casos que fallan el criterio (negativos del comportamiento deseado) y casos que lo pasan (positivos). No solo los fallos.

Suena contraintuitivo: si analizas fallos, ¿para qué guardar casos que funcionan? Porque un evaluador —humano o juez— que solo ve fallos no aprende dónde está la frontera. Si todo es fail, marcar fail siempre da 100% de acierto y cero información. Necesitas los dos lados para saber si el evaluador distingue uno de otro.

Balanceados significa que tienes una cantidad razonable de cada clase, no 38 fallos y 1 acierto. Con una sola clase, las métricas de acierto se vuelven mentirosas.

El dataset como activo que crece

Última subida al nivel abstracto. Este dataset no es una hoja que tiras tras la reunión. Es un activo de ingeniería versionado: un artefacto que guardas, versionas y haces crecer a lo largo del curso.

Lo reutilizan los niveles siguientes: N2 lo usa para validar su LLM-as-judge contra tus etiquetas humanas; N4 lo versiona en un gate de CI; N5 le añade casos desde producción. Cada vuelta del flywheel lo engorda.

No necesitas que sea enorme para empezar. Anthropic lo dice directo. En su texto: "20-50 simple tasks drawn from real failures is a great start" (Anthropic, "Demystifying evals for AI agents", 9 ene 2026). Es decir: empezar con 20-50 tareas extraídas de fallos reales basta. En fases tempranas, el efecto de un cambio es grande, así que muestras pequeñas ya dan señal. Empiezas con decenas de casos reales, no con miles.


1.4.5Míralo funcionar: de trazas a dataset etiquetado

Vamos a construir, paso a paso, un mini-dataset del fallo nº1 de Aurora. Toma 6 trazas de ese fallo más 4 que lo pasan. El código usa pandas, ya instalado en tu entorno del curso.

Lee primero el bloque entero. Después analizamos cada decisión.

Paso 1 — Definir el criterio binario

Antes de etiquetar, escribe el criterio como una pregunta de sí/no. Si no puedes responderla con pass/fail sin dudar, todavía no es binarizable.

text
1Criterio C1-policy:
2  "¿La política citada en la respuesta corresponde al producto o tema de la consulta?"
3  pass = la política recuperada es la del tema correcto
4  fail = recuperó/citó una política de otro producto o tema

Paso 2 — Cargar las trazas y etiquetar

python
1import pandas as pd
2
3# Cada traza es un dict; en tu caso vienen del export de Langfuse del C0.
4# Aquí las construimos a mano para el ejemplo (6 que fallan, 4 que pasan).
5trazas = [
6    {"trace_id": "t01", "user_query": "¿puedo devolver estas zapatillas?",
7     "politica_citada": "devoluciones-electronica", "tema_consulta": "calzado"},
8    {"trace_id": "t02", "user_query": "¿cuánto tarda el reembolso de un móvil?",
9     "politica_citada": "envios-general", "tema_consulta": "reembolso-electronica"},
10    {"trace_id": "t03", "user_query": "garantía de esta batidora",
11     "politica_citada": "garantia-electrodomesticos", "tema_consulta": "electrodomesticos"},
12    {"trace_id": "t04", "user_query": "devolver un abrigo sin etiqueta",
13     "politica_citada": "devoluciones-electronica", "tema_consulta": "ropa"},
14    {"trace_id": "t05", "user_query": "¿hacéis envíos a Canarias?",
15     "politica_citada": "envios-peninsula", "tema_consulta": "envios-canarias"},
16    {"trace_id": "t06", "user_query": "cambiar talla de unas botas",
17     "politica_citada": "garantia-electrodomesticos", "tema_consulta": "calzado"},
18    {"trace_id": "t07", "user_query": "devolver un libro defectuoso",
19     "politica_citada": "devoluciones-libros", "tema_consulta": "libros"},
20    {"trace_id": "t08", "user_query": "garantía de un portátil",
21     "politica_citada": "garantia-electronica", "tema_consulta": "electronica"},
22    {"trace_id": "t09", "user_query": "plazo de envío a península",
23     "politica_citada": "envios-peninsula", "tema_consulta": "envios-peninsula"},
24    {"trace_id": "t10", "user_query": "reembolso de un electrodoméstico",
25     "politica_citada": "reembolsos-electrodomesticos", "tema_consulta": "electrodomesticos"},
26]
27
28df = pd.DataFrame(data=trazas)
29
30# Etiqueta humana: pass si la política casa con el tema, fail si no.
31# Lo hacemos a mano porque la etiqueta es un juicio humano, no una regla automática.
32etiquetas = ["fail", "fail", "pass", "fail", "fail", "fail",
33             "pass", "pass", "pass", "pass"]
34df["label"] = etiquetas
35
36print(df["label"].value_counts())
37# fail    6
38# pass    4

Paso 3 — Verificar el balance +/−

python
1# value_counts devuelve el conteo por clase, ordenado por frecuencia.
2print(df["label"].value_counts(normalize=True))
3# fail    0.6
4# pass    0.4

El balance es 6 a 4. No es perfecto, pero ninguna clase domina. Un dataset 9 a 1 te daría un evaluador que marca siempre la clase mayoritaria y "acierta" el 90% sin saber nada.

Paso 4 — Split: separar dev de test

python
1# Mezcla reproducible (semilla fija) y corta: ~70% dev, ~30% test.
2df_mezclado = df.sample(frac=1, random_state=42).reset_index(drop=True)
3
4corte = int(len(df_mezclado) * 0.7)
5df_dev  = df_mezclado.iloc[:corte]
6df_test = df_mezclado.iloc[corte:]
7
8print(len(df_dev), len(df_test))   # 7 3

Con random_state=42 el split es reproducible: cualquiera que ejecute esto obtiene la misma partición. Eso es parte de tratar el dataset como activo de ingeniería.

Paso 5 — Exportar el dataset versionado

python
1# index=False evita escribir el índice de pandas como una columna extra.
2df_dev.to_csv("dataset_c1_dev.csv", index=False)
3df_test.to_csv("dataset_c1_test.csv", index=False)

Estos archivos son el primer commit de tu activo. En N4 vivirán en el repo y los versionará el CI.

Ahora la pregunta de auto-explicación. Respóndela antes de leer la línea siguiente: ¿por qué incluiste 4 casos que pasan, si tu análisis era sobre el fallo nº1?

Porque sin casos pass, ni un humano ni el juez de N2 pueden demostrar que distinguen el fallo de su ausencia. Con solo fallos, "marcar fail siempre" parece perfecto y no mide nada. Los pass definen la otra orilla de la frontera.


1.4.6Hazlo tú

Ejercicio 1 — andamiaje parcial

El criterio ya está dado: "¿el agente llamó a buscar_pedido antes de afirmar el estado de un pedido?" (pass = sí lo llamó; fail = afirmó el estado sin llamarlo).

Aquí tienes el primer caso resuelto como modelo. Etiqueta los otros tres.

text
1caso A → traza: buscar_pedido("AUR-9920") -> "en reparto"; respuesta: "tu pedido va en reparto"
2         label: pass   (consultó antes de afirmar)   ← RESUELTO
3
4caso B → traza: (sin tool calls); respuesta: "tu pedido ya fue entregado"
5         label: ______
6
7caso C → traza: buscar_pedido("AUR-3311") -> "retenido en aduana"; respuesta: "está retenido en aduana"
8         label: ______
9
10caso D → traza: consultar_politica("envios"); respuesta: "tu pedido llegó ayer"
11         label: ______

Ejercicio 2 — autónomo

Tienes el segundo fallo de la taxonomía de Aurora: "escala a humano sin intentar resolver". Trabaja sobre él de cero:

  1. Escribe el criterio binario como una pregunta de sí/no.
  2. Decide qué cuenta como pass y qué como fail.
  3. Bosqueja 6 casos: piensa cuántos deben fallar y cuántos pasar, y justifica el balance que elegiste.
  4. Di cómo los repartirías en dev/test y por qué el test se queda intacto.

Antes de seguir, una pregunta de interrogación elaborativa. Respóndela tú primero: ¿por qué un criterio como "¿la respuesta es de buena calidad?" no sirve como etiqueta binaria, mientras que "¿citó la política del tema correcto?" sí?

Porque "buena calidad" no tiene una frontera única: dos personas la cruzan en sitios distintos, así que las etiquetas no concuerdan. "¿Citó la política del tema correcto?" tiene una respuesta verificable contra la traza. Un criterio binarizable apunta a un hecho observable, no a una impresión.


1.4.7Comprueba

Sin pistas. Aquí tienes un mini-dataset que un compañero preparó para el fallo nº1 de Aurora. Tiene dos defectos. Encuéntralos y propón la corrección de cada uno.

text
1Criterio: "¿la respuesta del agente es satisfactoria para el cliente?"
2
3caso 1 → fail
4caso 2 → fail
5caso 3 → fail
6caso 4 → fail
7caso 5 → fail
8
9(split: todo el set se usa para afinar el prompt del juez)
Ver la respuesta razonada

Defecto 1 — el criterio no es binarizable. "¿Es satisfactoria para el cliente?" no apunta a un hecho observable; apunta a una impresión. Dos anotadores la cruzarán en sitios distintos y las etiquetas no concordarán. Corrección: reescribir el criterio como una pregunta verificable contra la traza, p. ej. "¿la política citada corresponde al tema de la consulta? pass/fail".

Defecto 2 — cero casos positivos. Las cinco etiquetas son fail. Un evaluador que marque fail siempre "acierta" el 100% sin distinguir nada; el dataset no puede validar a nadie. Corrección: añadir casos pass —respuestas que sí citan la política correcta— hasta un balance razonable (p. ej. 5 fail / 4 pass).

(Defecto extra, si lo viste: no hay split. Usar el set entero para afinar el prompt del juez impide validar sin fuga. Separa un test held-out que no se toca al ajustar.)


Feedback formativo:

  • Si encontraste los dos defectos y supiste corregirlos: dominas el criterio central de la lección —binarizable + balanceado—. Es exactamente lo que la dimensión 4 del checkpoint C1 evalúa. En N2 reutilizarás este dataset para validar el juez.
  • Si solo viste el criterio ambiguo: acertaste lo más difícil, pero te faltó el balance. Vuelve al §1.4.4: un dataset de una sola clase hace que cualquier evaluador "acierte" sin saber nada. Siguiente paso: cuenta las clases de cualquier dataset que veas, siempre.
  • Si solo viste la falta de casos positivos: captaste el balance, que mucha gente olvida. La brecha está en el criterio: "satisfactoria" no es un hecho verificable contra la traza. Releer §1.4.4, "la etiqueta binaria gana a la escala", cierra esa brecha.

1.4.8Conecta

Vuelve a la reunión con el equipo de N2.

Si llegas con dataset_c1_dev.csv y dataset_c1_test.csv —criterio binario explícito, balance +/−, split reproducible—, la pregunta "¿dónde están los ejemplos etiquetados?" ya tiene respuesta. El "31%" se ha vuelto un conjunto de casos individuales con veredicto humano.

Eso es lo que vas a defender en el checkpoint C1. La dimensión 4 de su rúbrica pide exactamente esto: etiquetas binarias claras, split y casos +/− balanceados. Hoy produjiste el material que la satisface.

Y este dataset no muere aquí. Es el activo que recorre el resto del curso:

  • N2 valida su LLM-as-judge contra tus etiquetas: ¿el juez concuerda con el humano?
  • N4 lo versiona en CI y bloquea el merge si una regresión rompe casos que antes pasaban.
  • N5 le añade casos nuevos desde producción, cerrando el flywheel.

¿Dónde lo aplicarías en tu trabajo? Piensa en cualquier sistema LLM que hayas tocado. Si tuvieras que validar mañana un evaluador automático, ¿tienes 20-50 casos reales etiquetados con un criterio binario? Si la respuesta es "no", ese es tu siguiente entregable.

Queda un cabo suelto. Quizá tu dataset apenas tenga ejemplos de un caso raro —pocas trazas reales de "devolución frágil enviada a Canarias"—. En N1·L5 verás cuándo (y cuándo no) generar esos ejemplos de forma sintética, sin contaminar la señal.


1.4.9Reflexiona

Tómate dos minutos. Estas preguntas consolidan más que releer.

  • Con tus palabras: ¿por qué una etiqueta binaria es más fácil de juzgar de forma consistente que una nota 1-5?
  • ¿Por qué un dataset con solo casos fail no puede validar a un evaluador?
  • ¿Qué sigue sin estar claro? Anótalo. Si es "cómo lleno los huecos de un caso raro que casi no aparece en mis trazas", es la pregunta correcta —la responde L5—.

Referencia rápida

  • Etiqueta binaria: veredicto pass/fail respecto a un criterio concreto. Más fácil de alinear y de juzgar de forma consistente entre humanos que una escala 1-5 (Shankar, "AI Engineering Flywheel", 2024).
  • Criterio binarizable: una pregunta de sí/no sobre un hecho observable en la traza ("¿citó la política del tema correcto?"), no una impresión ("¿es satisfactoria?").
  • Anatomía del caso: input (traza/consulta) + etiqueta binaria + nota opcional.
  • Split: partición en dev (afinas aquí) y test held-out (solo validas al final). Evita engañarte ajustando y validando sobre los mismos casos.
  • Casos +/− balanceados: incluye fallos y aciertos, sin que una clase domine. Sin las dos clases, las métricas de acierto mienten.
  • Activo versionado: el dataset se guarda, versiona y crece; lo reutilizan N2 (validar juez), N4 (gate CI) y N5 (flywheel). "20-50 tareas de fallos reales es un gran comienzo" (Anthropic, 9 ene 2026).
  • No usar nunca: "el 85% de proyectos IA fallan (Gartner)" ni "el 80% (McKinsey)" — cifras sin fuente primaria trazable.