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.
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: normalmentePOST. -
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'"}]}}
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"
La respuesta incluirá un id de archivo, por ejemplo:
{
"id": "file-abc123",
"object": "file",
"purpose": "batch"
}
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"
}
}'
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"
}
}
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"
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
}
}
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
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"
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
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"}}]}}}
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
metadatapara 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,urlobody. - El
endpointdel lote puede no coincidir con laurlde 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:
- Validar la estructura JSONL antes de subirla
Comprueba localmente que cada línea tenga:
custom_idmethodurlbodybody.model-
messageso 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.
- 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.
- Crear el lote y validar la respuesta
Ejecuta POST /v1/batches usando {{input_file_id}}.
Verifica que:
-
statusseavalidating. -
endpointcoincida con el endpoint enviado. -
input_file_idsea el archivo correcto. -
completion_windowsea24h.
- Sondear hasta finalizar
Ejecuta GET /v1/batches/{id} y revisa status.
Cuando sea completed, extrae output_file_id.
- 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.
- 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
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
urlde cada línea JSONL. - En el campo
endpointal 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:
- Crear un archivo JSONL con tus solicitudes.
- Subirlo a
/v1/filesconpurpose=batch. - Crear el lote en
/v1/batches. - Sondear
GET /v1/batches/{id}hasta que termine. - Descargar
output_file_id. - 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)