DEV Community

Cover image for Cómo usar la OpenAI Batch API
Roobia
Roobia

Posted on • Originally published at apidog.com

Cómo usar la OpenAI Batch API

Al final de esta guía podrás usar la API de Lotes de OpenAI para ejecutar miles de solicitudes como un único trabajo asíncrono y recuperar los resultados con un 50% de descuento. Prepararás un archivo JSONL, lo cargarás, crearás un lote, sondearás su estado y descargarás la salida. También verás cómo probar cada paso en Apidog antes de llevarlo a producción. Si tu caso es interactivo, usa la ruta síncrona y prueba la API de ChatGPT con Apidog.

Prueba Apidog hoy

Qué es la API de Lotes y cuándo usarla

La API de Lotes es un flujo asíncrono para ejecutar muchas llamadas a modelos cuando puedes tolerar latencia. En vez de enviar una solicitud HTTP por prompt, empaquetas todas las solicitudes en un archivo JSONL, lo subes como un único trabajo y sondeas hasta que termine.

OpenAI ejecuta el lote fuera del flujo síncrono normal y devuelve los resultados en un archivo de salida.

Úsala cuando tu carga sea offline y masiva:

  • Clasificar o etiquetar un backlog de registros.
  • Generar embeddings para un corpus completo.
  • Crear contenido en volumen, como descripciones de productos, resúmenes o traducciones.
  • Ejecutar evaluaciones o comparaciones de modelos sobre datasets completos.

Los beneficios principales son:

  • 50% de descuento en tokens de entrada y salida frente a la API síncrona.
  • Mayor rendimiento operativo, porque los trabajos por lotes usan un pool de límites de tasa separado y no compiten con tu tráfico en vivo.

La desventaja es la latencia: OpenAI se compromete a completar el trabajo dentro de una ventana de 24 horas. Muchos lotes terminan antes, pero debes diseñar el sistema asumiendo el peor caso.

No uses Batch API para flujos donde un usuario espera una respuesta inmediata, como chat, autocompletado o agentes en vivo. Si estás generando muchas configuraciones de modelos o agentes, el procesamiento por lotes encaja bien con esa carga; puedes ver también el tutorial sobre generación de más de 100 configuraciones de agentes con procesamiento por lotes.

Qué necesitas antes de empezar

El flujo usa dos recursos principales:

  • /v1/files
  • /v1/batches

Y se divide en cuatro pasos:

Paso Endpoint Qué sucede
1. Cargar POST /v1/files Envías tu archivo .jsonl con purpose: "batch" y recibes un ID de archivo
2. Crear POST /v1/batches Envías el ID del archivo, el endpoint destino y la ventana de finalización
3. Sondear GET /v1/batches/{id} Consultas el status hasta que sea completed
4. Recuperar GET /v1/files/{id}/content Descargas los resultados usando output_file_id

Para seguir la guía necesitas:

  • Una clave de API de OpenAI exportada como OPENAI_API_KEY.
  • Un archivo JSONL con las solicitudes.
  • Una herramienta para ejecutar e inspeccionar llamadas HTTP, como Apidog o curl.

Cada paso devuelve un objeto JSON sobre el que puedes hacer aserciones, lo que facilita probar el ciclo completo antes de automatizarlo.

Paso 1: construir y cargar el archivo JSONL

La entrada del lote es un archivo JSONL. Cada línea representa una solicitud autocontenida.

Cada línea debe incluir:

  • custom_id: identificador único definido por ti.
  • method: normalmente POST.
  • url: endpoint destino, por ejemplo /v1/chat/completions.
  • body: parámetros reales de la solicitud.

Ejemplo de requests.jsonl:

{"custom_id": "req-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4.1-mini", "messages": [{"role": "user", "content": "Classify the sentiment of: 'shipping was slow but the product is great'"}]}}
{"custom_id": "req-2", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4.1-mini", "messages": [{"role": "user", "content": "Classify the sentiment of: 'returned it the same day'"}]}}
Enter fullscreen mode Exit fullscreen mode

El custom_id debe ser único dentro del archivo. Los resultados no se devuelven necesariamente en el mismo orden que las entradas, así que este campo es la clave para asociar cada respuesta con su solicitud original.

Un lote puede contener hasta 50.000 solicitudes y el archivo puede tener hasta 200 MB.

Carga el archivo con purpose="batch":

curl https://api.openai.com/v1/files \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -F purpose="batch" \
  -F file="@requests.jsonl"
Enter fullscreen mode Exit fullscreen mode

La respuesta incluirá un id de archivo, por ejemplo:

{
  "id": "file-abc123",
  "object": "file",
  "purpose": "batch"
}
Enter fullscreen mode Exit fullscreen mode

Guarda ese valor. Lo usarás como input_file_id en el siguiente paso.

Paso 2: crear el lote

Con el archivo cargado, crea el trabajo por lotes.

Debes enviar:

  • input_file_id: ID devuelto por /v1/files.
  • endpoint: endpoint que ejecutarán las líneas del JSONL.
  • completion_window: actualmente acepta "24h".
  • metadata: opcional, útil para identificar el trabajo.
curl https://api.openai.com/v1/batches \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "input_file_id": "file-abc123",
    "endpoint": "/v1/chat/completions",
    "completion_window": "24h",
    "metadata": {
      "job": "sentiment-backfill"
    }
  }'
Enter fullscreen mode Exit fullscreen mode

El valor de endpoint debe coincidir con la url usada dentro de cada línea JSONL.

Endpoints admitidos incluyen:

  • /v1/chat/completions
  • /v1/responses
  • /v1/embeddings
  • /v1/completions
  • /v1/moderations

El objeto metadata puede contener hasta 16 pares clave-valor. Úsalo para etiquetar lotes por feature, cliente, dataset o job interno.

La respuesta será un objeto de lote:

{
  "id": "batch_abc123",
  "object": "batch",
  "endpoint": "/v1/chat/completions",
  "input_file_id": "file-abc123",
  "completion_window": "24h",
  "status": "validating",
  "output_file_id": null,
  "error_file_id": null,
  "request_counts": {
    "total": 0,
    "completed": 0,
    "failed": 0
  },
  "created_at": 1733452800,
  "metadata": {
    "job": "sentiment-backfill"
  }
}
Enter fullscreen mode Exit fullscreen mode

Guarda el id del lote, por ejemplo batch_abc123.

Paso 3: sondear el estado del lote

Un lote nuevo normalmente comienza en validating. Luego avanza por varios estados hasta terminar o fallar.

Consulta el estado con:

curl https://api.openai.com/v1/batches/batch_abc123 \
  -H "Authorization: Bearer $OPENAI_API_KEY"
Enter fullscreen mode Exit fullscreen mode

Estados relevantes:

Estado Significado
validating El archivo de entrada se está verificando antes de ejecutar
in_progress Las solicitudes están siendo procesadas
finalizing La ejecución terminó y se está preparando el archivo de salida
completed El lote terminó y los resultados están listos
failed Falló la validación; no se ejecutó nada
expired La ventana de 24 horas se cerró antes de completar todas las solicitudes
cancelling / cancelled Solicitaste la cancelación del lote

Mientras el lote está en in_progress, revisa request_counts:

{
  "request_counts": {
    "total": 50000,
    "completed": 42000,
    "failed": 12
  }
}
Enter fullscreen mode Exit fullscreen mode

No hay webhook que esperar en este flujo. El patrón recomendado es sondear con un intervalo razonable, por ejemplo cada pocos minutos, no cada segundo.

Ejemplo simple de sondeo en Bash:

BATCH_ID="batch_abc123"

while true; do
  STATUS=$(curl -s https://api.openai.com/v1/batches/$BATCH_ID \
    -H "Authorization: Bearer $OPENAI_API_KEY" | jq -r '.status')

  echo "Estado actual: $STATUS"

  if [ "$STATUS" = "completed" ] || [ "$STATUS" = "failed" ] || [ "$STATUS" = "expired" ] || [ "$STATUS" = "cancelled" ]; then
    break
  fi

  sleep 180
done
Enter fullscreen mode Exit fullscreen mode

Si enviaste un lote por error, puedes cancelarlo:

curl -X POST https://api.openai.com/v1/batches/batch_abc123/cancel \
  -H "Authorization: Bearer $OPENAI_API_KEY"
Enter fullscreen mode Exit fullscreen mode

Paso 4: recuperar la salida

Cuando status sea completed, el objeto del lote incluirá un output_file_id.

Descarga el archivo de resultados con la API de Archivos:

curl https://api.openai.com/v1/files/file-output456/content \
  -H "Authorization: Bearer $OPENAI_API_KEY" > results.jsonl
Enter fullscreen mode Exit fullscreen mode

La salida también es JSONL: una línea por solicitud procesada. Cada línea contiene el custom_id original y un objeto response con el código de estado y el cuerpo.

Ejemplo conceptual:

{"custom_id":"req-1","response":{"status_code":200,"body":{"choices":[{"message":{"content":"Positive with minor negative feedback"}}]}}}
{"custom_id":"req-2","response":{"status_code":200,"body":{"choices":[{"message":{"content":"Negative"}}]}}}
Enter fullscreen mode Exit fullscreen mode

No asumas que el orden de salida coincide con el orden de entrada. Siempre cruza datos usando custom_id.

También revisa error_file_id. Si algunas solicitudes fallaron, sus detalles estarán en ese archivo.

Ten en cuenta costo, latencia y límites

La regla principal es simple: ahorras un 50% en tokens, pero aceptas una ventana de respuesta de hasta 24 horas.

Esto funciona bien para:

  • Backfills.
  • Jobs nocturnos.
  • Procesamiento batch de datasets.
  • Evaluaciones offline.
  • Generación masiva no interactiva.

No funciona bien para:

  • UX en tiempo real.
  • Chat.
  • Agentes interactivos.
  • Autocompletado.
  • Flujos críticos donde el usuario espera una respuesta inmediata.

Notas prácticas:

  • El descuento aplica a tokens de entrada y salida en los modelos compatibles.
  • La ventana de 24 horas es un máximo, no un objetivo.
  • Si un lote queda expired, las solicitudes completadas se devuelven y se facturan; las restantes no.
  • Los lotes usan un límite de tokens en cola separado, así que no deberían consumir los límites de tasa de tu tráfico síncrono.
  • Si ya estás lidiando con límites de tasa, revisa la guía sobre límites de tasa de la API de GPT y cómo probarlos.
  • Aunque los tokens cuesten la mitad, el volumen puede crecer rápido. Usa metadata para atribuir gasto por trabajo o feature. Este manual de atribución de costos para OpenAI cubre ese enfoque.

Cómo probarlo en Apidog

La API de Lotes tiene más puntos de fallo que una llamada síncrona simple:

  • El archivo JSONL puede estar mal formado.
  • Una línea puede no incluir custom_id, method, url o body.
  • El endpoint del lote puede no coincidir con la url de las líneas.
  • La validación puede fallar antes de ejecutar.
  • La salida puede llegar horas después.
  • Los errores pueden quedar separados en error_file_id.

Por eso conviene probar el ciclo completo antes de automatizarlo.

Apidog es una plataforma de API para ejecutar solicitudes, encadenarlas y realizar aserciones sobre respuestas. No es un SDK de OpenAI; úsalo para probar y simular los endpoints del flujo.

Una configuración práctica sería:

  1. Validar la estructura JSONL antes de subirla

Comprueba localmente que cada línea tenga:

  • custom_id
  • method
  • url
  • body
  • body.model
  • messages o los campos requeridos por el endpoint destino

Detectar un campo faltante antes de subir el archivo evita esperar a que falle la validación del lote.

  1. Ejecutar la carga multipart

Configura una solicitud POST /v1/files con:

  • Header Authorization: Bearer {{OPENAI_API_KEY}}
  • Campo purpose=batch
  • Archivo requests.jsonl

Captura el id devuelto en una variable, por ejemplo input_file_id.

  1. Crear el lote y validar la respuesta

Ejecuta POST /v1/batches usando {{input_file_id}}.

Verifica que:

  • status sea validating.
  • endpoint coincida con el endpoint enviado.
  • input_file_id sea el archivo correcto.
  • completion_window sea 24h.
  1. Sondear hasta finalizar

Ejecuta GET /v1/batches/{id} y revisa status.

Cuando sea completed, extrae output_file_id.

  1. Descargar resultados

Llama a GET /v1/files/{output_file_id}/content y guarda el resultado como JSONL.

Después, parsea cada línea usando custom_id.

  1. Probar rutas de error y cancelación

Envía un archivo deliberadamente incorrecto para confirmar que obtienes failed.

También prueba:

   POST /v1/batches/{batch_id}/cancel
Enter fullscreen mode Exit fullscreen mode

Así validas el manejo real de errores antes de que ocurra en producción.

Como la salida puede tardar, también puedes crear una API simulada que devuelva un lote completed y un archivo de resultados predefinido. Esto permite construir y probar la lógica de recuperación sin esperar hasta 24 horas ni gastar tokens durante el desarrollo.

Si tu equipo trabaja desde una especificación, también puedes generar una colección de pruebas desde una especificación OpenAPI y mantener los endpoints del flujo batch cubiertos en CI.

Preguntas frecuentes

¿Cuánto tarda realmente un lote?

OpenAI se compromete a completar un lote dentro de 24 horas. En la práctica, muchos trabajos terminan antes, pero debes diseñar el sistema considerando esa ventana máxima.

Si la ventana se cierra antes de que todo termine, el lote pasa a expired. Las solicitudes completadas se devuelven y facturan; las que no terminaron no se completan.

¿Cuál es el descuento real?

La API de Lotes ofrece un descuento fijo del 50% frente a los endpoints síncronos, tanto en tokens de entrada como de salida.

Si necesitas atribuir ese gasto por feature, cliente o job, puedes usar metadata y seguir una estrategia como la del manual de atribución de costos.

¿Qué endpoints puedo ejecutar en un lote?

Debes definir el destino en dos lugares:

  • En la url de cada línea JSONL.
  • En el campo endpoint al crear el lote.

Ambos valores deben coincidir.

Endpoints admitidos incluyen:

  • /v1/chat/completions
  • /v1/responses
  • /v1/embeddings
  • /v1/completions
  • /v1/moderations

También hay compatibilidad con otros endpoints, incluidos algunos de imagen y video. Consulta la documentación actual de OpenAI para confirmar la lista completa.

¿Por qué mis resultados están desordenados?

Porque el archivo de salida no conserva necesariamente el orden del archivo de entrada.

Esto es esperado. Por eso cada línea necesita un custom_id único. Usa ese valor para asociar cada respuesta con su solicitud original.

Si dos líneas comparten el mismo custom_id, no podrás distinguir sus resultados de forma fiable.

Conclusión

El flujo completo es:

  1. Crear un archivo JSONL con tus solicitudes.
  2. Subirlo a /v1/files con purpose=batch.
  3. Crear el lote en /v1/batches.
  4. Sondear GET /v1/batches/{id} hasta que termine.
  5. Descargar output_file_id.
  6. Asociar resultados con entradas usando custom_id.

A cambio de aceptar una ventana de hasta 24 horas, puedes ejecutar cargas offline a mitad de costo en tokens.

Antes de automatizarlo, ejecuta el ciclo manualmente. Descarga Apidog para validar tu archivo, probar los endpoints de carga, creación, sondeo y cancelación, y añadir aserciones sobre los objetos de lote antes de enviarlos a producción.

Top comments (0)