Generación de JSON estructurado con Qwen2.5-7B y vLLM

Introdcución a la necesidad de salidas estructuradas

En el desarrollo de aplicaciones con modelos de lenguaje grandes (LLM), las respuestas en texto libre pueden ser complicadas de procesar de manera automática. Para integrar estas salidas en sistemas como asistentes virtuales o servicios de API, es esencial utilizar formatos estandarizados como JSON, que faciliten el análisis y la manipulación de datos.

El modelo Qwen2.5-7B-Instruct ha demostrado capacidades avanzadas en la generación de estructuras JSON precisas. Al combinarlo con el framework de inferencia vLLM, es posible desplegar el modelo de manera eficiente, obteniendo salidas JSON consistentes y con baja latencia.

Componentes tecnológicos clave

Qwen2.5-7B: un modelo con soporte nativo para estructuras

Qwen2.5-7B-Instruct es una variante de 7 mil millones de parámetros optimizada para seguir instrucciones. Entre sus características destacan:

  • Entrenamiento con aproximadamente 18 billones de tokens, cubriendo un amplio conocimiento.
  • Compatibilidad con contextos de hasta 128K tokens y salidas de hasta 8K tokens.
  • Mejoras en la comprensión y generación de datos estructurados, especialmente en formatos JSON.

vLLM: motor de inferencia de alto rendimiento

vLLM es un framework open source diseñado para la inferencia de LLMs, que utiliza técnicas como PagedAttention para optimizar el manejo de memoria. Sus ventajas incluyen:

  • Aumento del throughput en un factor de 14 a 24 veces comparado con HuggingFace Transformmers.
  • Soporte para lotes continuos (Continuous Batching) y decodificación guiada (Guided Decoding).
  • Integración nativa con la funcionalidad guided_json desde la versión 0.7.0.

Preparación del entorno e instalación

Requisitos de hardware

  • GPU: Al menos una NVIDIA A100 o 4090 con 24 GB de VRAM o más.
  • Memoria del sistema: Recomendado 64 GB o superior.
  • Sistema operativo: Linux, como Ubuntu 20.04 o CentOS 7.

Descarga del modelo

El modelo Qwen2.5-7B-Instruct se puede obtener de repositorios como ModelScope o Hugging Face. Por ejemplo, usando git:

git clone https://huggingface.co/Qwen/Qwen2.5-7B-Instruct

Asegúrese de que el directorio contenga archivos como config.json y los pesos del modelo en formato safetensors.

Configuración del entorno Python

Cree un entorno virtual con Conda y instale las dependencais necesarias:

conda create -n mi-ambiente python=3.10
conda activate mi-ambiente
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
pip install vllm

Para verificar la instalación de vLLM, ejecute un script simple que importe la librería y muestre su versión.

Métodos para la generación de JSON estructurado

Enfoque basado en prompts (menos robusto)

Esta técnica depende de instrucciones detalladas en el prompt para que el modelo genere JSON. Aunque es sencilla, no garantiza la corrección sintáctica o la completitud de los campos.

Ejemplo de código adaptado:

from vllm import LLM, SamplingParams

# Ruta al modelo descargado
ubicacion_modelo = "/ruta/a/Qwen2.5-7B-Instruct"

# Inicializar el motor de inferencia
motor = LLM(model=ubicacion_modelo, dtype="float16", max_model_len=32768)

# Prompt con instrucciones claras
consulta = """
Extraiga la información del siguiente texto y devuélvala en formato JSON:
"María tiene 30 años, reside en Madrid y trabaja como ingeniera."

Formato esperado:
{
  "nombre": "nombre_completo",
  "edad": "años",
  "ciudad": "ubicacion",
  "profesion": "trabajo"
}
"""

# Parámetros de muestreo
parametros = SamplingParams(temperature=0.1, top_p=0.9, max_tokens=512)

# Ejecutar inferencia
resultados = motor.generate(consulta, parametros)
salida_cruda = resultados[0].outputs[0].text.strip()
print(salida_cruda)

La salida podría ser un JSON válido, pero no está garantizado. Por ejemplo:

{
  "nombre": "María",
  "edad": 30,
  "ciudad": "Madrid",
  "profesion": "ingeniera"
}

Enfoque con esquema JSON guiado (recomendado para producción)

Utilizando la función guided_json de vLLM, se puede forzar al modelo a producir JSON que cumpla con un esquema definido. Esto asegura la validez estructural de la salida.

Pasos clave:

  1. Definir un esquema JSON que especifique los campos y sus tipos.
  2. Pasar el esquema como parámetro en la configuración de muestreo.

Ejemplo de implementación modificada:

import json
from vllm import LLM, SamplingParams

# Ruta del modelo
ruta_modelo = "/ruta/a/Qwen2.5-7B-Instruct"

# Iniciar LLM con decodificación guiada activada
motor_inferencia = LLM(
    model=ruta_modelo,
    dtype="float16",
    swap_space=8,
    gpu_memory_utilization=0.9,
    decoding_config={"guided_decoding_backend": "outlines"}
)

# Esquema JSON deseado
esquema = {
    "type": "object",
    "properties": {
        "nombre_persona": {"type": "string"},
        "edad_persona": {"type": "integer"},
        "ubicacion_persona": {"type": "string"},
        "ocupacion_persona": {"type": "string"}
    },
    "required": ["nombre_persona", "edad_persona"]
}

# Entrada del usuario
texto_entrada = "Carlos, de 45 años, vive en Barcelona y es arquitecto."

# Crear prompt con referencia al esquema
instruccion = f"""
Analice el texto siguiente y extraiga los datos según el esquema proporcionado.
Texto: {texto_entrada}
Genere únicamente JSON válido.
"""

# Configurar parámetros con esquema guiado
params = SamplingParams(
    temperature=0.2,
    top_p=0.95,
    max_tokens=256,
    guided_json=esquema
)

# Generar salida
salidas = motor_inferencia.generate(instruccion, params)
texto_json = salidas[0].outputs[0].text.strip()

try:
    datos = json.loads(texto_json)
    print("JSON parseado correctamente:")
    print(json.dumps(datos, indent=2, ensure_ascii=False))
except json.JSONDecodeError as error:
    print(f"Error en el parseo: {error}")

Este método produce salidas consistentes, como:

{
  "nombre_persona": "Carlos",
  "edad_persona": 45,
  "ubicacion_persona": "Barcelona",
  "ocupacion_persona": "arquitecto"
}

Técnicas avanzadas y optimizaciones

Manejo de estructuras JSON complejas

Para datos jerárquicos, como listas de objetos, amplíe el esquema incluyendo arreglos. Por ejemplo, un esquema para múltiples empleados podría definir un campo de tipo array con objetos internos que requieran campos como nombre y departamento.

Ajustes de rendimiento

  • Use tensor_parallel_size para aprovechar múltiples GPUs.
  • Ajuste gpu_memory_utilization a valores entre 0.8 y 0.9 para evitar errores de memoria.
  • Habilite enforce_eager=False para mejorar el throughput mediante CUDA Graphs.

Solución de problemas comunes

  • Error de guided_json no soportado: actualice vLLM a la versión 0.7.0 o superior.
  • Salida no es JSON: verifique que guided_decoding_backend='outlines' esté configurado.
  • Desbordamiento de memoria: reduzca el tamaño del lote o active la offload a CPU.

Casos de uso prácticos

Parseo de logs estructurados

Convertir líneas de log no estructuradas, como "ERROR [fecha] evento usuario=123", en JSON con campos dedicados para nivel, timestamp, evento e identificador de usuario.

Automatización de formularios web

Interpretar solicitudes de usuario en lenguaje natural, como "quiero reservar un vuelo de Madrid a París mañana", y generar JSON con campos para origen, destino y fecha.

Etiquetas: Qwen2.5 vLLM json generación estructurada LLM

Publicado el 6-3 21:47