Publicado el 5 min de lectura

Evalúa campos extraídos por IA con precisión y recall de coincidencia exacta

En esta página

Un asistente de IA convierte solicitudes de mantenimiento en identificadores de activos y fechas límite. El JSON se puede analizar, pero un identificador es incorrecto, una fecha es inventada y otra solicitud queda sin respuesta. ¿Qué parte de la extracción es realmente correcta?

Construye un evaluador local que separe las predicciones incorrectas de los datos omitidos y cuente los registros completamente correctos. Usa la biblioteca estándar de Python, ejemplos sintéticos y ninguna cuenta de modelos. Si recibes JSON sin procesar del modelo, primero rechaza el JSON ambiguo; una sintaxis válida no demuestra que la extracción sea precisa.

Una lupa compara los campos extraídos de solicitudes de mantenimiento con tarjetas de referencia; las coincidencias aparecen en verde azulado y una fecha incorrecta, en ámbar.

1. Fija la referencia y las reglas de coincidencia

Empieza con tres mensajes de origen, conservados sin cambios como datos de prueba:

  • r1: “Inspect pump A7 by 2026-11-10.”
  • r2: “Inspect fan B2; no due date provided.”
  • r3: “Inspect valve C9 by 2026-11-12.”

Pide al extractor exactamente dos campos por registro: asset, con solo el identificador del activo, y due, con una fecha en formato ISO o el valor JSON null si no existe. En Python, representa null con None. Una persona revisa las fuentes y escribe GOLD independientemente de las predicciones. No permitas que el modelo modifique su propia clave de respuestas.

Usa coincidencias exactas de cadenas, distinguiendo mayúsculas y minúsculas. Los espacios y el formato de fecha importan; los valores repetidos en registros distintos siguen siendo datos diferentes. Este ejemplo admite un valor por campo, no partidas repetidas de facturas ni entidades anidadas. Conserva los identificadores incluso cuando falle la extracción, con ambos campos en None.

2. Cuenta datos, no celdas vacías

Representa cada dato no vacío como (record_id, field, value):

  • Verdadero positivo (TP): un dato predicho coincide con la referencia.
  • Falso positivo (FP): un dato predicho no tiene coincidencia en la referencia.
  • Falso negativo (FN): un dato de referencia no tiene una predicción coincidente.

Un valor incorrecto genera tanto un FP como un FN. Predecir una fecha inexistente genera solo un FP. Estas distinciones siguen las definiciones de evaluación de extracción de Google Document AI; nuestro evaluador es una implementación pequeña de coincidencia exacta, no una reproducción de ese servicio.

La precisión es TP / (TP + FP); la exhaustividad, o recall, es TP / (TP + FN). F1 es 2*TP / (2*TP + FP + FN). Son las definiciones estándar de precisión, recall y puntuación F. Para entender mejor la diferencia, consulta recall frente a precisión.

3. Ejecuta el evaluador local

Guarda esto como evaluate_extraction.py y usa Python 3.10 o posterior. CANDIDATE contiene predicciones escritas a mano con errores deliberados, no resultados medidos de un modelo. El comprobador rechaza identificadores ausentes, campos inesperados y tipos de valores inválidos en lugar de excluirlos silenciosamente.

FIELDS = ("asset", "due")
GOLD = {
    "r1": {"asset": "A7", "due": "2026-11-10"},
    "r2": {"asset": "B2", "due": None},
    "r3": {"asset": "C9", "due": "2026-11-12"},
}
CANDIDATE = {
    "r1": {"asset": "A7", "due": "2026-11-10"},
    "r2": {"asset": "B3", "due": "2026-11-11"},
    "r3": {"asset": None, "due": None},
}


def facts(rows):
    if not isinstance(rows, dict) or set(rows) != set(GOLD):
        raise ValueError("record IDs must match gold")
    result = set()
    for record_id, row in rows.items():
        if not isinstance(row, dict) or set(row) != set(FIELDS):
            raise ValueError("each record needs asset and due")
        for field, value in row.items():
            if value is not None:
                if not isinstance(value, str) or not value.strip():
                    raise ValueError("values must be nonempty strings or None")
                result.add((record_id, field, value))
    return result


def score(rows):
    expected, actual = facts(GOLD), facts(rows)
    tp = len(expected & actual)
    fp, fn = len(actual - expected), len(expected - actual)
    precision = tp / (tp + fp) if tp + fp else None
    recall = tp / (tp + fn) if tp + fn else None
    denominator = 2 * tp + fp + fn
    f1 = 2 * tp / denominator if denominator else None
    whole = sum(rows[key] == GOLD[key] for key in GOLD)
    return tp, fp, fn, precision, recall, f1, whole


def report(name, rows):
    tp, fp, fn, precision, recall, f1, whole = score(rows)
    fmt = lambda value: "n/a" if value is None else f"{value:.3f}"
    print(f"{name}: tp={tp} fp={fp} fn={fn}")
    print(f"precision={fmt(precision)} recall={fmt(recall)} f1={fmt(f1)}")
    print(f"whole_records={whole}/{len(GOLD)}")


if __name__ == "__main__":
    report("candidate", CANDIDATE)
    report("perfect control", GOLD)
    empty = {key: dict.fromkeys(FIELDS) for key in GOLD}
    report("empty control", empty)
python3 evaluate_extraction.py

Salida esperada:

candidate: tp=2 fp=2 fn=3
precision=0.500 recall=0.400 f1=0.444
whole_records=1/3
perfect control: tp=5 fp=0 fn=0
precision=1.000 recall=1.000 f1=1.000
whole_records=3/3
empty control: tp=0 fp=0 fn=5
precision=n/a recall=0.000 f1=0.000
whole_records=0/3

4. Valida los cálculos e inspecciona los fallos

El candidato devuelve cuatro datos, pero solo dos coinciden. El B3 incorrecto aporta un FP y deja B2 como un FN. Su fecha inventada aporta otro FP. Faltan ambos datos de r3, lo que añade dos FN. Solo r1 es completamente correcto.

El control perfecto debe alcanzar 1.000 en las tres métricas. El control vacío debe tener recall cero; su precisión no está definida y se muestra como n/a, porque no predice nada. Las ausencias coincidentes no cuentan como TP, aunque la comparación de registros completos incluye todos los campos.

Estos controles prueban el evaluador, no la calidad de producción de un modelo. El comando termina correctamente incluso con predicciones deficientes; informa de mediciones en lugar de imponer un bloqueo de despliegue.

5. Resuelve problemas antes de comparar modelos

  • Omisiones inesperadas: inspecciona facts(GOLD) - facts(CANDIDATE). Comprueba la fuente antes de cambiar las etiquetas.
  • Errores solo de formato: acuerda la normalización antes de evaluar. Aplica la misma regla documentada a ambos lados; no borres diferencias significativas entre identificadores.
  • F1 global alto, fechas incorrectas: evalúa cada campo por separado e informa de su cantidad de datos de referencia. Los campos frecuentes pueden ocultar fallos en los menos habituales.
  • Resultados sorprendentemente perfectos: busca filtraciones de respuestas. Separa los ejemplos de desarrollo de un conjunto de prueba reservado.

Para ensayos reales, usa solicitudes autorizadas y anonimizadas que incluyan fechas ausentes, identificadores inusuales y entradas ilegibles. Registra las versiones del modelo y del prompt. Corrige un patrón de fallo con datos de desarrollo y usa después el mismo conjunto de prueba fijo para la comparación final. Nuestro tutorial de regresión de prompts muestra cómo seguir los cambios entre versiones.

Conclusión práctica

Comprueba los datos exactos y los registros completos antes de automatizar una extracción. Una respuesta que se puede analizar aún puede contener valores inventados; una media alta aún puede ocultar registros inutilizables.

Artículos relacionados

Últimos artículos