← Ingeniería con IA ETAPA 08 · 30 MIN

Construye una función sobre un modelo de lenguaje

Trata un modelo como una dependencia poco confiable: valida lo que devuelve, mídelo con un conjunto de evaluación y limita lo que puede costar cada llamada.

Abrir en el laboratorio ↗

AL TERMINAR, PODRÁS

  • Tratar la salida de un modelo como una entrada no confiable y validar su estructura
  • Construir un conjunto de evaluación que detecte regresiones cuando cambian el prompt o el modelo
  • Limitar el costo y la latencia de una llamada al modelo, y planear qué pasa cuando falla
La llamada se limita antes del modelo y se comprueba después. La salida que no pasa la validación toma la alternativa en lugar de llegar al resto del sistema, y el conjunto de evaluación mide cada cambio.

Descripción del diagrama: Mensaje de error → Límites; Límites → Modelo; Modelo → Validar; Validar → Usarla (válida); Validar → Alternativa (inválida); Conjunto de evaluación → Modelo (mide)

El modelo es una dependencia poco confiable

Supón que Relay le pide a un modelo de lenguaje que lea el mensaje de error de un trabajo fallido y devuelva una categoría (network, data o code), si tiene sentido reintentar y un resumen de una línea.

El modelo devuelve texto probable, no texto comprobado. El perfil de IA generativa del NIST llama confabulación (confabulation) al contenido falso dicho con seguridad; el modelo también puede romper el formato que pediste, y la misma entrada puede dar respuestas distintas. Diseña para eso, como lo harías con un servicio externo inestable cuyas respuestas son sugerencias.

Pide JSON con un conjunto fijo de campos; algunas API de modelos pueden obligar a que la salida siga un esquema, pero valídala de todos modos: campos obligatorios, tipos, valores de una lista cerrada y largos. Cuando la validación falla, reintenta una vez o recurre a una alternativa, por ejemplo la categoría unknown y una persona que lo lea. Nunca pases la salida del modelo a una terminal, a eval, a un string de SQL o a una página web sin escaparla: el consejo de OWASP sobre el manejo inadecuado de la salida es tratar al modelo como a cualquier otro usuario.

El texto de la entrada puede traer instrucciones, y estas pueden llegar a la salida.

Python
import json

CATEGORIES = {"network", "data", "code"}

def parse_triage(text):
    try:
        data = json.loads(text)
    except ValueError:
        return None
    if not isinstance(data, dict) or data.get("category") not in CATEGORIES:
        return None
    if not isinstance(data.get("retry"), bool):
        return None
    summary = data.get("summary")
    if not isinstance(summary, str) or not 0 < len(summary) <= 200:
        return None
    return {"category": data["category"], "retry": data["retry"], "summary": summary}

Evalúa antes y después de cada cambio

Un prompt que funcionó con tres ejemplos se probó por encima, no se evaluó.

El perfil del NIST advierte contra juzgar un sistema generativo a partir de evaluaciones estrechas y anecdóticas. Construye en su lugar un conjunto de evaluación: entradas que se parezcan al tráfico real, cada una con su resultado esperado, incluidos casos difíciles y hostiles, como un mensaje de error que contiene instrucciones, un mensaje vacío y uno muy largo. Califica con código siempre que puedas: la categoría coincide, el formato es válido.

Deja la revisión humana o una rúbrica escrita para el texto libre, como el resumen. Ejecuta el conjunto completo con cada cambio del prompt, del modelo o de la versión del proveedor, como ejecutas una suite de regresión, y compara la tasa de aciertos por categoría y la lista de casos que fallan, no un solo número global. Como las respuestas varían, ejecuta cada caso varias veces y da un caso por bueno solo cuando todas las ejecuciones pasan.

Guarda aparte una parte del conjunto y nunca ajustes el prompt contra ella, y vuelve a ejecutar el conjunto con regularidad, porque el comportamiento de un modelo alojado por otro puede cambiar con el tiempo.

Limita el costo y la espera

Cada llamada cuesta dinero y tiempo, y ambos crecen con el texto que envías y el que vuelve.

Sin límites, un usuario, o un atacante, puede disparar la factura o volver lento el servicio para todos; OWASP llama a esto consumo sin límites (unbounded consumption). Limita el tamaño de la entrada y el largo de la salida, pon un timeout a cada llamada y dale a cada usuario un límite de frecuencia y una cuota. Guarda en caché la respuesta para entradas idénticas cuando la misma pregunta se repite a menudo.

Saca las llamadas lentas del camino de la petición: Relay puede clasificar una falla en el worker, después de registrar el trabajo, en lugar de mientras un cliente espera. Decide qué pasa cuando el modelo está caído o es demasiado lento, y prefiere una respuesta degradada a un trabajo fallido: la categoría unknown, enviada a una persona. Registra los tokens y la latencia de cada llamada para seguir el costo y la velocidad en el tiempo.

Un modelo más pequeño y barato puede bastar; el conjunto de evaluación es la forma de saberlo.

ERROR FRECUENTE

Publicar un cambio de prompt porque unos pocos ejemplos se veían mejor. Sin un conjunto de evaluación, nadie sabe qué casos rompió.

INTÉNTALO TÚ

Escribe doce casos de evaluación para la clasificación de fallas de Relay: cuatro comunes, cuatro difíciles y cuatro hostiles, uno de ellos con instrucciones dentro del mensaje de error. Para cada uno, escribe la categoría esperada y si tiene sentido reintentar.

COMPROBACIÓN DE RECUERDO / APLICA LA IDEA

Decide en el laboratorio.

El checkpoint de dos preguntas, tus notas y tu progreso guardado están en el laboratorio. Gratis y sin cuenta.

Abrir en el laboratorio ↗

CONÉCTALO CON RELAY

Agrega al worker de Relay la clasificación de fallas: llama a un modelo con un timeout y un límite de tamaño, valida el JSON con parse_triage, recurre a unknown y registra los tokens y la latencia. Escribe un conjunto de evaluación de al menos veinte casos y ejecútalo en CI cada vez que cambien el prompt o el modelo.