<!-- Canonical: https://lucioduran.com/es/projects/structured-output-contracts
Language: es
Content-SHA256: 6e83c9d474a14e7128c94c58b3fd3296bfcc2f7ff3fdc93e163575eba69fb6ce
-->

[Proyectos](<https://lucioduran.com/es/projects>) / Structured Output Contracts

# Structured Output Contracts

Contratos JSON acotados con validación estricta, rechazos explícitos y reintentos limitados. Compara validez y exactitud con dos modelos Qwen locales y respuestas originales.

Autor: [Lucio Durán](<https://lucioduran.com/es>) · Python 3.11.13 · Licencia: [MIT](<https://github.com/lucioduran/structured-output-contracts/blob/ac8680a5b15731932da446694b8a0a5ced00d12a/LICENSE>)

Ficha publicada: 2026-10-22 · Ficha actualizada: 2026-10-22

[Repositorio](<https://github.com/lucioduran/structured-output-contracts>) · [Evidencia original](<https://raw.githubusercontent.com/lucioduran/structured-output-contracts/ac8680a5b15731932da446694b8a0a5ced00d12a/results/eval/manifest.json>) · [Release v0.1.0](<https://github.com/lucioduran/structured-output-contracts/releases/tag/v0.1.0>)

## Problema y utilidad para agentes

JSON válido puede contener una respuesta falsa. Una salida truncada, un rechazo y un error de esquema tampoco son el mismo fallo. Mezclarlos en una tasa de éxito única impide entender qué está pasando.

El proyecto implementa una frontera entre generación y consumo de datos: clasifica cada intento, limita los reintentos y conserva las respuestas inválidas para poder inspeccionarlas.

## Arquitectura

1. **Esquemas acotados.** Objetos anidados, uniones discriminadas y límites de strings y arrays dentro de un subconjunto de JSON Schema Draft 2020-12. El parser rechaza entradas inválidas sin reparación silenciosa.
2. **Política explícita.** Acepta, reconoce un rechazo explícito, reintenta o agota el presupuesto. El experimento limita cada tarea a dos intentos y usa metadatos reales de finalización.
3. **Evaluación separada.** Qwen2-0.5B-Instruct y Qwen2.5-0.5B-Instruct fijados por revisión generan localmente. La exactitud semántica se calcula aparte, sin usar etiquetas para decidir reintentos.

- [Diseño y metodología](<https://github.com/lucioduran/structured-output-contracts/blob/ac8680a5b15731932da446694b8a0a5ced00d12a/docs/design.md>)

## Qué demuestra

- Contratos con límites de estructura y tratamiento explícito de rechazo y truncamiento.
- Contabilidad por esquema de intentos, tokens, tiempo y validez separada de corrección.
- Preservación de fallos originales y replay de la política sobre trazas congeladas.

## Resultados publicados

Doce tareas reservadas por modelo, cuatro por familia de esquema. Medición CPU float32 en Intel Xeon W-3223 con cuatro hilos. Qwen2 y Qwen2.5 en la tabla son las versiones Instruct de 0,5B parámetros.

Las flechas comparan primer intento y resultado final. Validez y corrección usan todas las tareas como denominador, incluidas abstenciones esperadas. La latencia por tarea suma todos sus intentos y excluye cargar los modelos.

### Resultados por modelo y esquema

| Modelo / esquema | Válidas: inicial → final | Correctas: inicial → final | Reintentos | Mediana (s) | Máximo (s) |
| --- | --- | --- | --- | --- | --- |
| Qwen2 / bounded | 1/4 → 2/4 | 2/4 → 3/4 | 2 | 1.405 | 3.806 |
| Qwen2 / nested | 0/4 → 0/4 | 0/4 → 0/4 | 1 | 1.336 | 2.155 |
| Qwen2 / union | 0/4 → 0/4 | 1/4 → 1/4 | 0 | 0.890 | 1.010 |
| Qwen2.5 / bounded | 0/4 → 0/4 | 0/4 → 1/4 | 4 | 2.005 | 2.745 |
| Qwen2.5 / nested | 3/4 → 3/4 | 3/4 → 3/4 | 1 | 2.676 | 2.866 |
| Qwen2.5 / union | 3/4 → 3/4 | 2/4 → 2/4 | 1 | 1.607 | 3.423 |

Qwen2 terminó con 2/12 respuestas válidas y 4/12 resultados correctos, incluidas dos abstenciones correctas. Qwen2.5 obtuvo 6/12 y 6/12, con una abstención correcta. Qwen2.5 también produjo un cero inventado que pasó el esquema: validar estructura no verifica hechos.

Los 33 intentos reales incluyen 12 rechazos, siete respuestas malformadas, cuatro violaciones de esquema y dos truncamientos. Los 14 casos inyectados son controles de política separados, no muestras adicionales de modelos. [Análisis de errores](<https://github.com/lucioduran/structured-output-contracts/blob/ac8680a5b15731932da446694b8a0a5ced00d12a/docs/error-analysis.md>).

## Reproducir

El replay instala dependencias de validación, sin modelos. La reproducción neural descarga aproximadamente 1,9 GiB de snapshots públicos y usa el lock del entorno Intel macOS medido.

Ejecutá primero el bloque de replay para crear y activar el entorno. Usá directorios de salida nuevos y una medición a la vez. Las respuestas originales no se reparan ni se reemplazan.

### Revisar la evidencia guardada

```
git clone https://github.com/lucioduran/structured-output-contracts.git
cd structured-output-contracts
git checkout ac8680a5b15731932da446694b8a0a5ced00d12a
python3.11 -m venv .venv
. .venv/bin/activate
python -m pip install -r requirements-dev.txt
python -m contracts verify --output results/dev
python -m contracts verify --output results/eval
```

### Repetir la medición local

```
python -m pip install -r requirements-local.lock
python -m contracts download
OMP_NUM_THREADS=4 MKL_NUM_THREADS=4 OPENBLAS_NUM_THREADS=4 python -m contracts run --split dev --output build/reproduced-dev
OMP_NUM_THREADS=4 MKL_NUM_THREADS=4 OPENBLAS_NUM_THREADS=4 python -m contracts run --split eval --output build/reproduced-eval
python -m contracts verify --output build/reproduced-dev
python -m contracts verify --output build/reproduced-eval
python -m scripts.injected --output build/injected.json
```

## Alcance y límites

- Dos modelos pequeños de una familia y doce tareas por modelo no establecen confiabilidad de producción ni un ranking general. No hubo revisión humana independiente.
- Se evalúa JSON solicitado por prompt con validación y reintentos. No incluye decodificación restringida por gramática ni productos alojados de structured output.
- La igualdad exacta de JSON es una métrica conservadora, no una medida general de factualidad. Los límites de estructura no implementan un timeout duro ni un sandbox.
- Una observación temporal por tarea. API paga: USD 0; electricidad, hardware y tiempo de operación no medidos.

- [Function calling y contratos de salida de agentes](<https://lucioduran.com/es/blog/llm-function-calling-tool-use-patterns>)

## Fuentes y revisión

Los valores de esta ficha provienen del informe enlazado. No son una medición en vivo. El informe conserva la revisión ejecutada; la revisión consultada incluye la publicación posterior de ese informe.

- Revisión consultada: [` ac8680a5b15731932da446694b8a0a5ced00d12a `](<https://github.com/lucioduran/structured-output-contracts/commit/ac8680a5b15731932da446694b8a0a5ced00d12a>)
- Revisión registrada por el experimento: [` b73bec6fab382a96691e91a8b39af1491f53da0d `](<https://github.com/lucioduran/structured-output-contracts/commit/b73bec6fab382a96691e91a8b39af1491f53da0d>)
- Fecha del informe (UTC): 2026-10-21T22:58:44.050791+00:00
- Release publicada: [v0.1.0](<https://github.com/lucioduran/structured-output-contracts/releases/tag/v0.1.0>) · 2026-10-21T23:02:50Z

- [README y uso](<https://github.com/lucioduran/structured-output-contracts/blob/ac8680a5b15731932da446694b8a0a5ced00d12a/README.md>)
- [Evidencia original](<https://raw.githubusercontent.com/lucioduran/structured-output-contracts/ac8680a5b15731932da446694b8a0a5ced00d12a/results/eval/manifest.json>)
- [Resumen de resultados](<https://raw.githubusercontent.com/lucioduran/structured-output-contracts/ac8680a5b15731932da446694b8a0a5ced00d12a/results/eval/summary.json>)
- [Respuestas y trazas originales](<https://raw.githubusercontent.com/lucioduran/structured-output-contracts/ac8680a5b15731932da446694b8a0a5ced00d12a/results/eval/trace.jsonl>)
- [Evidencia de desarrollo](<https://raw.githubusercontent.com/lucioduran/structured-output-contracts/ac8680a5b15731932da446694b8a0a5ced00d12a/results/dev/manifest.json>)
- [Diseño y metodología](<https://github.com/lucioduran/structured-output-contracts/blob/ac8680a5b15731932da446694b8a0a5ced00d12a/docs/design.md>)
- [Análisis de errores](<https://github.com/lucioduran/structured-output-contracts/blob/ac8680a5b15731932da446694b8a0a5ced00d12a/docs/error-analysis.md>)
- [Datos y procedencia](<https://github.com/lucioduran/structured-output-contracts/blob/ac8680a5b15731932da446694b8a0a5ced00d12a/data/README.md>)
- [Configuración congelada](<https://raw.githubusercontent.com/lucioduran/structured-output-contracts/ac8680a5b15731932da446694b8a0a5ced00d12a/data/freeze.json>)
- [Modelos, revisiones y licencias](<https://github.com/lucioduran/structured-output-contracts/blob/ac8680a5b15731932da446694b8a0a5ced00d12a/docs/model-notices.md>)
- [Dependencias del entorno medido](<https://github.com/lucioduran/structured-output-contracts/blob/ac8680a5b15731932da446694b8a0a5ced00d12a/requirements-local.lock>)
- [Licencia MIT](<https://github.com/lucioduran/structured-output-contracts/blob/ac8680a5b15731932da446694b8a0a5ced00d12a/LICENSE>)
