Salidas estructuradas en LLMs de producción
JSON mode garantiza texto parseable, no campos correctos. Las salidas estructuradas en producción necesitan contratos de esquema, validación en servidor, bucles de reparación con reintentos acotados y conjuntos de eval que puntúen forma y semántica — no solo sintaxis válida.
El pipeline de extracción devolvió JSON válido. El parser de facturas lo aceptó. Finanzas concilió contra un nombre de proveedor que nunca apareció en el documento — el modelo inventó una cadena plausible dentro de un objeto perfectamente tipado. Las salidas estructuradas en LLMs de producción fallan en dos capas: la sintaxis pasa mientras la semántica deriva, y los equipos descubren la brecha solo cuando los sistemas downstream tratan el JSON parseado como verdad absoluta. JSON mode y la generación guiada por esquema reducen errores de formato. No reemplazan validación, observabilidad ni la disciplina de eval que define qué significa "extracción correcta" antes de que llegue el tráfico.
Los modelos de lenguaje grandes emiten texto. Los sistemas de producción necesitan objetos — campos tipados, valores enumerados, registros anidados, arrays con restricciones de cardinalidad. La brecha entre generación de tokens y contratos de aplicación es donde se originan la mayoría de incidentes de integración con IA. Tratar al modelo como serializador sin frontera de validación es la misma categoría de error que confiar en validación de formularios del lado del cliente para montos de pago.
JSON mode vs schema contracts: what each layer actually guarantees
Las funciones del proveedor caen en un espectro de laxo a estricto:
| Mechanism | Guarantees | Does not guarantee |
|---|---|---|
| Instrucción en prompt ("devuelve solo JSON") | Nada exigible | JSON válido, claves correctas, tipos correctos |
| JSON mode | Objeto/array JSON sintácticamente válido | Cumplimiento de esquema, campos requeridos, valores enum |
| JSON Schema / restricción de formato de respuesta | La salida coincide con la forma del esquema declarado en la capa API | Corrección de negocio, valores de campo alucinados |
| Decodificación restringida (gramática, guiada por esquema) | El flujo de tokens no puede violar la gramática | Precisión semántica de campos string |
| Validación post-parse (Zod, Pydantic, AJV) | La aplicación rechaza payloads inválidos | El modelo produce salida válida al primer intento |
JSON mode resuelve el problema de comas finales y fences de markdown. No resuelve que el modelo rellene confidence: 0.99 en una suposición o mapee "status": "approved" cuando el texto fuente dice rechazado. Los contratos de esquema en la capa API reducen el espacio de tokens — propiedades requeridas, restricciones de tipo, pertenencia a enum — lo que mejora materialmente la presencia de campos y la corrección de tipos. Los contratos de esquema aún permiten strings incorrectos en campos tipados como string.
JSON válido es una preocupación de transporte. Extracción correcta es una preocupación de producto. Solo validación y evals las separan.
La arquitectura de producción trata el soporte de esquema del proveedor como la primera puerta, no la última. El contrato durable vive en código de aplicación:
import { z } from "zod";
const InvoiceExtraction = z.object({
vendor_name: z.string().min(1).max(200),
invoice_number: z.string().regex(/^[A-Z0-9-]{4,32}$/),
total_cents: z.number().int().positive(),
line_items: z.array(
z.object({
description: z.string(),
quantity: z.number().positive(),
unit_price_cents: z.number().int().nonnegative(),
})
).min(1),
currency: z.enum(["USD", "EUR", "GBP"]),
});
type InvoiceExtraction = z.infer<typeof InvoiceExtraction>;Los fallos de parse, desajustes de tipo y violaciones de reglas de negocio surgen aquí — con mensajes de error aptos para bucles de reparación y logging apto para dashboards.
Where schema contracts belong in the request path
Un flujo típico de producción:
User input → prompt assembly → LLM call (schema mode) → raw JSON parse
→ schema validation → business rules → persist / downstream API
↓ fail ↓ fail
repair loop (bounded) human review queue
Prompt assembly incluye ejemplos, definiciones de campos y manejo explícito de null ("usar null cuando falte, nunca inventar"). LLM call usa el modo más estricto soportado — response schema, tool schema o restricción de gramática — alineado con la capacidad del proveedor. Validation corre en servidor independientemente de las promesas del proveedor; los proveedores cambian comportamiento entre versiones de modelo.
Business rules se sitúan sobre validación de esquema: total_cents debe igualar la suma de line items dentro de tolerancia de redondeo; invoice_number no debe duplicar un registro existente salvo que se marque como revisión. El esquema valida forma; las reglas de negocio validan significado.
Los equipos que debaten fine-tuning como último recurso para extracción suelen tener brechas de prompt y esquema corregibles primero. Fine-tuning en tareas con formato estable puede ayudar a escala — pero solo después de que la infraestructura de eval demuestre que el modo de fallo restante es comportamiento del modelo, no validación faltante o prompts débiles.
Repair loops: bounded recovery when the model misses the contract
El cumplimiento de esquema en primer pase en producción rara vez alcanza el 100%. Los bucles de reparación reintentan con feedback estructurado:
MAX_REPAIR_ATTEMPTS = 2
def extract_invoice(document_text: str) -> InvoiceExtraction:
messages = build_initial_messages(document_text)
for attempt in range(MAX_REPAIR_ATTEMPTS + 1):
raw = call_llm(messages, response_schema=INVOICE_SCHEMA)
try:
parsed = json.loads(raw)
validated = InvoiceExtraction.model_validate(parsed)
validate_business_rules(validated, document_text)
return validated
except (json.JSONDecodeError, ValidationError, BusinessRuleError) as exc:
if attempt >= MAX_REPAIR_ATTEMPTS:
raise ExtractionFailed(str(exc)) from exc
messages.append({"role": "assistant", "content": raw})
messages.append({
"role": "user",
"content": f"Validation failed: {format_errors(exc)}. "
f"Return corrected JSON matching the schema. "
f"Do not invent fields not supported by the source.",
})
raise ExtractionFailed("unreachable")Los bucles de reparación efectivos comparten propiedades:
Bounded attempts. Tres intentos con feedback superan bucles de reintento infinitos que queman presupuestos de latencia y amplifican costo en inputs patológicos.
Error messages the model can act on. "Validation failed at line_items[2].quantity: expected positive number, got 0" supera a "invalid schema".
Assistant turn preservation. Incluir la salida fallida en contexto da al modelo un objetivo de diff; omitirla fuerza regeneración completa desde cero.
Escalation path. Tras fallo acotado, enrutar a revisión humana, heurística de respaldo o extracción degradada de un solo campo — nunca paso silencioso de objetos parciales.
Metrics per attempt. Rastrear tasa de éxito en primer pase, tasa de éxito tras reparación y tasa de fallo terminal por separado. Una tasa de reparación creciente con tasa de primer pase plana señala deriva de prompt o esquema, no degradación del modelo.
Los bucles de reparación añaden latencia. Para rutas síncronas orientadas al usuario, acotar timeout total incluyendo reparaciones. Para pipelines async, las reparaciones son aceptables si se monitorea la profundidad de cola.
Streaming, partial JSON, and parser hardening
El streaming de salida estructurada mejora la latencia percibida pero complica el parse. Los flujos de tokens pueden entregar JSON incompleto hasta el chunk final. Estrategias:
Buffer-until-complete. Lo más simple: acumular tokens, parsear una vez al final del stream. Pierde UX incremental pero evita bugs de parse parcial.
Incremental parsers. Librerías de reparación JSON y parsers de stream conscientes del esquema emiten objetos parciales conforme se completan campos — útil para indicadores de progreso en UI. Requieren fuzz testing en límites de chunks.
Never execute on partial state. Efectos secundarios downstream — escrituras en base de datos, inicio de pagos — deben esperar objetos completos validados. Vista previa parcial en UI está bien; persistencia parcial no.
Incluso con JSON mode, el stripping defensivo de fences markdown maneja regresiones del proveedor sin tumbar el pipeline.
Evals for structured output: shape is necessary, semantics is sufficient
La calidad de salida estructurada requiere dimensiones de eval más allá del éxito de JSON.parse:
| Eval dimension | Example check | Why it matters |
|---|---|---|
| Schema pass rate | Valida contra Zod/AJV | Detecta fallos de tipo y enum |
| Field presence | Campos requeridos no nulos cuando la fuente contiene datos | Detecta el tradeoff omisión vs invención |
| Hallucination rate | Campos string coinciden con spans fuente o solapamiento NER | Detecta valores plausibles pero incorrectos |
| Numeric accuracy | Montos parseados dentro de tolerancia de verdad etiquetada | Detecta errores de orden de magnitud |
| Repair rate | Primer pase vs pase post-reparación | Señala salud de prompt/esquema |
| Latency p99 | End-to-end incluyendo reparaciones | Señala viabilidad en producción |
El marco de evals de producto IA aplica directamente: los dueños de producto definen qué significa extracción correcta por campo — cuándo null es aceptable, cuándo se permite inferencia, cuándo revisión humana es obligatoria. Ingeniería implementa validadores; producto posee el conjunto etiquetado y umbrales de aprobación.
Las pruebas de regresión para salidas estructuradas corren en cada cambio de prompt, actualización de modelo y revisión de esquema. Una actualización de modelo que mejora calidad de prosa mientras degrada adherencia a enum es una regresión silenciosa común — solo un conjunto de eval con casos específicos de enum la detecta antes del deploy.
Observability and failure taxonomy in production
Registrar fallos de salida estructurada con taxonomía, no 500s genéricos:
extraction_outcome: success | schema_fail | business_rule_fail | repair_success | terminal_fail
schema_violation_path: $.line_items[0].quantity
repair_attempt: 1
model_version: gpt-4.x-2025-04-14
latency_ms: 1840
Los dashboards segmentan por versión de modelo, tipo de documento y ruta de violación. Alertar sobre tasa de fallo terminal y aumentos de tasa de reparación. Muestrear payloads fallidos en cola de revisión para ampliar el conjunto de eval. Almacenar salida cruda del modelo junto a objetos validados para replay de auditoría.
How should teams ship structured LLM outputs?
Decisiones de implementación que sobreviven actualizaciones de modelo y crecimiento de tráfico.
When is JSON mode enough?
JSON mode basta para herramientas internas de bajo riesgo donde un humano siempre revisa la salida, los esquemas son planos y el reintento ante fallo de parse es manual. Es insuficiente para escrituras downstream automatizadas, campos financieros o pipelines de alto volumen sin validación.
Should validation run client-side or server-side?
Siempre en servidor. Las comprobaciones de esquema del lado del cliente mejoran UX en flujos interactivos; la frontera autoritativa es el servidor antes de persistir. Nunca confiar en salida LLM validada en navegador para mutaciones.
How many repair attempts are reasonable?
Dos reparaciones tras el intento inicial (tres generaciones totales) es un default común de producción para tareas de extracción. Ajustar contra SLO de latencia y costo por documento. Registrar fallos terminales para expansión de eval.
Does streaming require a different validation strategy?
Sí. Separar streaming de visualización de validación de commit. Hacer commit solo tras pasar validación de objeto completo. Documentar el comportamiento de UX cuando el stream completa pero la validación falla — mostrar error, ofrecer reintento, nunca guardado parcial.
A common argument runs the other way
La postura opuesta sostiene que esquemas estrictos y bucles de reparación añaden complejidad innecesaria — los modelos frontier con JSON mode son lo bastante fiables para parsear una vez y seguir.
La fiabilidad depende de la tarea y de la cola. El JSON en caso mediano de modelos frontier actuales luce excelente en demos. El tráfico de producción incluye PDFs escaneados, tablas ambiguas, encabezados multilingües e inputs adversariales. La tasa de paso de esquema en un conjunto demo de 50 ejemplos no predice comportamiento p99 en diez mil facturas diarias. Los bucles de reparación y validación cuestan milisegundos y centavos; IDs de proveedor alucinados cuestan horas de reconciliación y riesgo de auditoría. La complejidad es proporcional al costo de equivocarse — por eso los pipelines automatizados nunca omiten la capa de validación aunque el modelo "casi siempre funcione".
Key takeaways
- JSON mode garantiza sintaxis parseable, no campos correctos ni significado de negocio.
- Contratos de esquema en la capa API más validación en servidor forman la frontera durable de producción.
- Bucles de reparación con intentos acotados y feedback de error accionable recuperan fallos de formato sin reintento infinito.
- Reglas de negocio sobre validación de esquema detectan extracciones semánticamente válidas pero factualmente incorrectas.
- Los conjuntos de eval deben puntuar precisión a nivel de campo y alucinación — no solo tasa de paso de esquema.
- Hacer stream para UX; validar y hacer commit solo en objetos completos y validados.
- Taxonomía de observabilidad (ruta de esquema, intento de reparación, versión de modelo) convierte fallos en mejoras de eval.
Conclusion
Las salidas estructuradas convierten modelos de lenguaje en componentes que los sistemas downstream pueden consumir — pero solo cuando las garantías de sintaxis se superponen con validación, reparación acotada y corrección definida por eval. JSON mode y funciones de esquema del proveedor reducen la tasa de fallo en primer pase; no eliminan la obligación de rechazar objetos malos antes de que lleguen a la base de datos.
El checklist de producción: response schema habilitado, validador en servidor definido, bucle de reparación acotado, reglas de negocio documentadas, conjunto de eval cubre forma y semántica, salida cruda registrada para auditoría. Los ítems faltantes mapean a categorías de incidente — campos inventados, coerción silenciosa de tipos, tormentas de reintento sin límite — que la arquitectura de salida estructurada existe para prevenir.