Structured Outputs
Las salidas estructuradas limitan la respuesta de un modelo de IA a un esquema, como JSON Schema, durante la decodificación, para que las aplicaciones puedan analizar cada respuesta de forma fiable.
Las salidas estructuradas son respuestas de modelos limitadas a un formato predefinido, normalmente un esquema JSON que especifica las claves obligatorias, sus tipos y los valores permitidos, para que el software pueda analizar cada respuesta sin tener que limpiarla. Un modelo de lenguaje grande (LLM) al que se pide amablemente que responda en JSON suele hacerlo, pero aun así puede añadir una frase en prosa, escribir mal una clave o detenerse a mitad de un objeto, y cualquiera de estas cosas rompe el programa que lee la respuesta. Las salidas estructuradas eliminan ese riesgo mediante la decodificación restringida: en cada paso de la generación, el motor de inferencia solo permite los tokens que mantienen la salida conforme al esquema. Cuando OpenAI añadió esta función a su API en agosto de 2024, informó de que gpt-4o-2024-08-06 con salidas estructuradas obtuvo un 100 % en su evaluación de seguimiento de esquemas JSON complejos, frente a menos del 40 % de GPT-4 (gpt-4-0613) sin esta función.
Modo JSON frente a salidas estructuradas#
Las API de los proveedores ofrecen dos niveles de garantía. El modo JSON, que OpenAI introdujo en noviembre de 2023, solo garantiza que la respuesta sea JSON sintácticamente válido, así que aún puede haber claves ausentes o mal escritas. Las salidas estructuradas garantizan que la respuesta se ajuste al esquema proporcionado. En la API Structured Outputs de OpenAI, los desarrolladores definen el esquema como un modelo de Pydantic en Python o un objeto de Zod en JavaScript, y las negativas aparecen en un campo aparte en lugar de romper el formato. Las salidas estructuradas de Claude, de Anthropic, compilan cada esquema en una gramática, lo que añade latencia la primera vez que se usa un esquema, y almacenan en caché la gramática compilada durante 24 horas. Ambos proveedores solo admiten un subconjunto de JSON Schema; por ejemplo, el de Anthropic no admite esquemas recursivos ni límites numéricos como minimum.
Cómo funciona la decodificación restringida#
En cada paso, un LLM produce una puntuación, o logit, para cada token de su vocabulario, y la decodificación elige entre los valores de la distribución softmax resultante. La decodificación restringida fija primero en menos infinito la puntuación de cada token que rompería el formato, de modo que nunca se pueda elegir. Brandon Willard y Rémi Louf mostraron cómo hacerlo de forma eficiente en Generación guiada eficiente para modelos de lenguaje grandes: una expresión regular o un esquema JSON se compila en una máquina de estados finitos, y un índice creado una sola vez sobre el vocabulario enumera los tokens válidos para cada estado, de manera que cada paso solo requiere una consulta. Su biblioteca de código abierto Outlines implementa el método, y los motores de servicio, como vLLM, ofrecen generación guiada por gramáticas para modelos abiertos.
El ejemplo siguiente aplica la idea manualmente a GPT-2 de Hugging Face Transformers. El código escribe el texto fijo del esquema —las llaves, las claves y las comillas—, y en cada valor el modelo solo puede elegir entre los tokens permitidos por el esquema:
import json
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("gpt2")
model = AutoModelForCausalLM.from_pretrained("gpt2")
prompt = "Review: The battery died after two days and support never replied.\nJSON:"
# Decodificación codiciosa sin restricciones: nada obliga a que la respuesta se ajuste a un esquema
ids = tokenizer(prompt, return_tensors="pt").input_ids
free = model.generate(ids, max_new_tokens=16, do_sample=False, pad_token_id=tokenizer.eos_token_id)
print("free:", repr(tokenizer.decode(free[0, ids.shape[1] :])))
def choose(text, options):
"""Return the option GPT-2 scores highest after text, with every other token masked out."""
logits = model(tokenizer(text, return_tensors="pt").input_ids).logits[0, -1]
allowed = torch.tensor([tokenizer.encode(option)[0] for option in options])
masked = torch.full_like(logits, float("-inf"))
masked[allowed] = logits[allowed]
return tokenizer.decode(masked.argmax())
# Decodificación restringida: el esquema escribe las claves y el modelo solo puede elegir valores permitidos
with torch.no_grad():
text = prompt + ' {"sentiment": "'
text += choose(text, ["positive", "negative"]) + '", "stars": '
text += choose(text, ["1", "2", "3", "4", "5"]) + "}"
print("constrained:", json.loads(text[len(prompt) :]))Imprime free: ' The battery died after two days and support never replied.\n\nJSON: The' y constrained: {'sentiment': 'positive', 'stars': 1}. Si se deja a su aire, GPT-2 repite la reseña en lugar de escribir JSON, mientras que la versión restringida siempre se puede analizar. El resultado analizado también muestra los límites de esta técnica: el modelo de 124 millones de parámetros valoró como positiva una batería agotada y un servicio de asistencia que no respondía, y le dio una estrella. El esquema fijó el formato, pero los valores incluidos siguieron dependiendo del criterio del propio modelo.
Usos y contrapartidas#
- Extracción de datos: Extracción de nombres, fechas, totales y partidas de facturas, contratos o correos electrónicos directamente a filas de bases de datos.
- Llamada a funciones: Una llamada a una herramienta es una salida estructurada cuyo esquema corresponde a los parámetros de la herramienta. El uso estricto de herramientas en las API de OpenAI y Anthropic aplica la misma garantía a los argumentos de las herramientas.
- Flujos de trabajo agénticos: Decisiones de encaminamiento como valores de enumeración y resultados intermedios que se pasan entre los pasos de una cadena de prompts como objetos tipados.
- Modelos de visión y lenguaje: Detecciones devueltas como listas de etiquetas y coordenadas de cajas que el código de dibujo o evaluación puede utilizar directamente.
La anotación inteligente guiada por clases de Ultralytics Platform depende de este último tipo de salida. Pide a modelos de visión de proveedores como OpenAI, Anthropic y Google que detecten las clases de un conjunto de datos y añade cada objeto devuelto como un cuadro delimitador editable, por lo que cada respuesta debe indicar una clase y proporcionar coordenadas en un formato que el código pueda analizar. Estos modelos no devuelven puntuaciones de confianza, así que Platform oculta los ajustes de confianza e IoU mientras se selecciona uno. La clasificación de VLM compara la precisión con la que estos modelos detectan objetos en conjuntos de datos del mundo real y ordena los cuadros de cada modelo según el orden en que los enumera.
Los formatos estrictos pueden reducir la precisión en tareas de razonamiento. En ¿Dejarme hablar libremente?, Zhi Rui Tam y sus colegas observaron un descenso significativo del razonamiento de los LLM ante las restricciones de formato, y comprobaron que las restricciones más estrictas provocaban descensos mayores. La API de OpenAI genera las claves en el orden en que aparecen en el esquema, así que una solución habitual es colocar un campo de razonamiento de texto libre antes del campo de respuesta, para que el modelo redacte su cadena de pensamiento antes de comprometerse con la respuesta restringida.










