OpenAI의 Batch API를 사용하면 여러 요청을 묶어 비동기로 전송하고 24시간 이내에 결과를 받을 수 있습니다. 비용은 동기 요청보다 50% 낮으며, 훨씬 높은 요청 한도가 별도로 적용됩니다. 즉시 응답이 필요하지 않은 작업에 적합합니다. 자세한 내용은 API 레퍼런스에서도 확인할 수 있습니다.
개요
OpenAI 플랫폼을 사용할 때 동기 요청을 보내야 하는 경우도 있지만, 즉시 응답을 받을 필요가 없거나 요청 한도 때문에 짧은 시간에 많은 쿼리를 실행하기 어려운 경우도 많습니다. 다음과 같은 작업에는 배치 처리가 유용합니다.
- 평가 실행
- 대규모 데이터셋 분류
- 콘텐츠 레포지토리 임베딩
Batch API의 엔드포인트를 사용하면 여러 요청을 파일 하나에 모아 배치 작업을 시작할 수 있습니다. 요청이 실행되는 동안 배치 상태를 조회하고, 배치가 완료되면 결과를 한꺼번에 가져올 수 있습니다.
표준 엔드포인트를 직접 호출할 때와 비교하면 Batch API에는 다음과 같은 이점이 있습니다.
- 비용 절감: 동기 API보다 비용이 50% 낮습니다.
- 더 높은 요청 한도: 동기 API보다 요청 한도가 훨씬 높습니다.
- 빠른 처리: 각 배치는 24시간 이내에 완료되며, 더 일찍 끝나는 경우도 많습니다.
시작하기
1. 배치 파일 준비하기
먼저 .jsonl 파일을 만들고 각 줄에 API 요청 하나의 세부 정보를 작성하세요. 현재 사용할 수 있는 엔드포인트는 다음과 같습니다.
/v1/responses(Responses API)/v1/chat/completions(Chat Completions API)/v1/embeddings(Embeddings API)/v1/completions(Completions API)/v1/moderations(모더레이션 가이드)/v1/images/generations(Images API)/v1/images/edits(Images API)
입력 파일의 각 줄에서 body 필드에 지정하는 매개변수는 해당 엔드포인트를 직접 호출할 때와 같습니다. 각 요청에는 고유한 custom_id 값이 있어야 합니다. 배치가 완료되면 이 값으로 각 요청의 결과를 식별할 수 있습니다. 다음은 요청 두 개가 들어 있는 입력 파일의 예입니다. 한 입력 파일에 담는 요청은 모두 같은 모델을 사용해야 합니다.
/v1/moderations를 호출할 때는 모든 요청 본문에 input 필드를 포함하세요. 배치에서 omni-moderation-latest를 사용하면 일반 텍스트 또는 텍스트나 이미지 입력을 담은 콘텐츠 배열을 전달할 수 있습니다. 배치 워커는 동기 모더레이션 엔드포인트와 마찬가지로 stream=true로 설정한 요청을 거부합니다.
{"custom_id": "request-1", "method": "POST", "url": "/v1/responses", "body": {"model": "gpt-6-luna", "input": "Reply with the word blue.", "reasoning": {"effort": "none"}, "max_output_tokens": 64}}
{"custom_id": "request-2", "method": "POST", "url": "/v1/responses", "body": {"model": "gpt-6-luna", "input": "Reply with the word green.", "reasoning": {"effort": "none"}, "max_output_tokens": 64}}
모더레이션 입력 예시
텍스트만 포함하는 요청
{
"custom_id": "moderation-text-1",
"method": "POST",
"url": "/v1/moderations",
"body": {
"model": "omni-moderation-latest",
"input": "This is a harmless test sentence."
}
}
텍스트와 이미지를 함께 입력하는 요청
{
"custom_id": "moderation-mm-1",
"method": "POST",
"url": "/v1/moderations",
"body": {
"model": "omni-moderation-latest",
"input": [
{
"type": "text",
"text": "Describe this image"
},
{
"type": "image_url",
"image_url": {
"url": "https://api.nga.gov/iiif/a2e6da57-3cd1-4235-b20e-95dcaefed6c8/full/!800,800/0/default.jpg"
}
}
]
}
}
특히 멀티 모달 모더레이션 요청에서는 base64 데이터를 직접 넣기보다 image_url로 원격 파일을 참조하세요. 이렇게 하면 .jsonl 파일 크기를 배치 업로드 한도인 200 MB보다 훨씬 작게 유지할 수 있습니다.
2. 배치 입력 파일 업로드하기
파인튜닝 API와 마찬가지로, 배치를 시작할 때 입력 파일을 참조하려면 먼저 파일을 업로드해야 합니다. .jsonl 파일을 Files API로 업로드하세요.
import fs from "fs";
import OpenAI from "openai";
const openai = new OpenAI();
const file = await openai.files.create({
file: fs.createReadStream("fixtures/batchinput.jsonl"),
purpose: "batch",
});
console.log(file);3. 배치 생성하기
입력 파일을 업로드하면 해당 File 객체의 ID로 배치를 생성할 수 있습니다. 이 예시에서는 파일 ID가 file-abc123이라고 가정합니다. 현재 완료 기한은 24h로만 설정할 수 있습니다. 선택적 매개변수인 metadata로 사용자 지정 메타데이터를 추가할 수도 있습니다.
import OpenAI from "openai";
const openai = new OpenAI();
const batch = await openai.batches.create({
input_file_id: "file-abc123",
endpoint: "/v1/responses",
completion_window: "24h",
});
console.log(batch);이 요청은 배치의 메타데이터가 담긴 Batch 객체를 반환합니다.
{
"id": "batch_abc123",
"object": "batch",
"endpoint": "/v1/responses",
"errors": null,
"input_file_id": "file-abc123",
"completion_window": "24h",
"status": "validating",
"output_file_id": null,
"error_file_id": null,
"created_at": 1714508499,
"in_progress_at": null,
"expires_at": 1714536634,
"completed_at": null,
"failed_at": null,
"expired_at": null,
"request_counts": {
"total": 0,
"completed": 0,
"failed": 0
},
"metadata": null
}
4. 배치 상태 확인하기
배치 상태는 언제든지 조회할 수 있습니다. 이 요청도 Batch 객체를 반환합니다.
import OpenAI from "openai";
const openai = new OpenAI();
const batch = await openai.batches.retrieve("batch_abc123");
console.log(batch);Batch 객체의 상태는 다음 중 하나입니다.
| 상태 | 설명 |
|---|---|
validating |
배치를 시작하기 전에 입력 파일을 검증하는 중입니다. |
failed |
입력 파일이 검증을 통과하지 못했습니다. |
in_progress |
입력 파일이 검증을 통과했고 배치가 실행 중입니다. |
finalizing |
배치 실행이 끝나 결과를 준비하는 중입니다. |
completed |
배치가 완료되어 결과를 가져올 수 있습니다. |
expired |
24시간 이내에 배치가 완료되지 않았습니다. |
cancelling |
배치를 취소하는 중입니다. 최대 10분이 걸릴 수 있습니다. |
cancelled |
배치가 취소되었습니다. |
5. 결과 가져오기
배치가 완료되면 Files API에 Batch 객체의 output_file_id 값을 전달해 결과를 다운로드하고 로컬 파일에 저장할 수 있습니다. 이 예시에서는 batch_output.jsonl에 저장합니다.
import OpenAI from "openai";
const openai = new OpenAI();
const fileResponse = await openai.files.content("file-xyz123");
const fileContents = await fileResponse.text();
console.log(fileContents);출력 .jsonl 파일에는 입력 파일에서 처리에 성공한 요청마다 응답이 한 줄씩 기록됩니다. 배치에서 실패한 요청의 오류 정보는 별도의 오류 파일에 기록됩니다. 이 파일은 배치의 error_file_id로 찾을 수 있습니다.
출력 파일의 줄 순서는 입력 파일의 줄 순서와 다를 수 있습니다. 결과를 처리할 때는 줄 순서에 의존하지 말고 출력 파일의 각 줄에 있는 custom_id 필드를 사용해 입력 요청과 출력 결과를 연결하세요.
다음 출력 예시는 ID로 요청과 결과를 연결하는 방법과 생성된 텍스트를 보여 주기 위해 일부 내용만 표시합니다. 각 메시지의 output_text 내용은 response.body.output에서 읽으세요.
{"id": "batch_req_2", "custom_id": "request-2", "response": {"status_code": 200, "request_id": "req_2", "body": {"id": "resp_2", "object": "response", "status": "completed", "output": [{"type": "message", "role": "assistant", "content": [{"type": "output_text", "text": "green"}]}]}}, "error": null}
{"id": "batch_req_1", "custom_id": "request-1", "response": {"status_code": 200, "request_id": "req_1", "body": {"id": "resp_1", "object": "response", "status": "completed", "output": [{"type": "message", "role": "assistant", "content": [{"type": "output_text", "text": "blue"}]}]}}, "error": null}
출력 파일은 배치가 완료된 후 30일이 지나면 자동으로 삭제됩니다.
6. 배치 취소하기
필요하면 실행 중인 배치를 취소할 수 있습니다. 취소를 요청하면 배치 상태가 cancelling으로 바뀝니다. 이미 처리 중인 요청이 완료될 때까지 최대 10분이 걸릴 수 있으며, 이후 상태가 cancelled로 바뀝니다.
import OpenAI from "openai";
const openai = new OpenAI();
const batch = await openai.batches.cancel("batch_abc123");
console.log(batch);7. 전체 배치 목록 가져오기
언제든지 자신의 전체 배치 목록을 조회할 수 있습니다. 배치가 많다면 limit 및 after 매개변수를 사용해 결과를 페이지 단위로 가져오세요.
import OpenAI from "openai";
const openai = new OpenAI();
const list = await openai.batches.list();
for await (const batch of list) {
console.log(batch);
}지원 모델
대부분의 모델은 Batch API를 지원합니다. 사용하려는 모델의 지원 여부는 모델 레퍼런스에서 확인하세요. GPT-6 Sol과 Luna는 Standard, Flex, Batch 처리에서 EU 데이터 레지던시를 지원합니다. 자세한 내용은 데이터 레지던시 지원 대상을 참고하세요.
GPT Image 2.5에서는 gpt-image-2.5-flare와 gpt-image-2.5-sunburst로 이미지 생성 및 편집을 배치 처리할 수 있습니다. 두 모델의 2026-09-08 스냅샷도 지원합니다. /v1/images/generations 또는 /v1/images/edits를 사용하세요. 배치 요금은 이미지 생성 요금에서 확인할 수 있습니다.
요청 한도
Batch API에는 기존 모델별 요청 한도와 별도로 다음 세 가지 한도가 적용됩니다.
- 배치당 한도: 한 배치에 최대 50,000개의 요청을 포함할 수 있으며, 배치 입력 파일의 최대 크기는 200 MB입니다.
/v1/embeddings배치에서는 모든 요청에 포함된 임베딩 입력을 합쳐 최대 50,000개까지 처리할 수 있습니다. - 모델별 대기열의 프롬프트 토큰 한도: 배치 처리를 위해 대기열에 넣을 수 있는 프롬프트 토큰 수에는 모델별 상한이 있습니다. 각 모델의 한도는 플랫폼 설정 페이지에서 확인하세요.
- 배치 생성 한도: 시간당 최대 2,000개의 배치를 생성할 수 있습니다. 더 많은 요청을 제출해야 한다면 배치당 요청 수를 늘리세요.
현재 Batch API에는 출력 토큰 한도가 없습니다. Batch API에는 별도의 요청 한도가 적용되므로 배치에서 사용한 토큰은 모델별 표준 요청 한도에서 차감되지 않습니다. 따라서 API로 더 많은 요청을 보내고 더 많은 토큰을 처리할 수 있습니다.
배치 만료
기한 내에 완료되지 않은 배치는 expired 상태로 바뀝니다. 완료되지 않은 요청은 취소되며, 완료된 요청의 응답은 배치 출력 파일에서 가져올 수 있습니다. 완료된 요청에서 사용한 토큰에는 요금이 부과됩니다.
만료된 요청은 아래 메시지와 함께 오류 파일에 기록됩니다. custom_id를 사용하면 만료된 요청의 데이터를 찾을 수 있습니다.
{"id": "batch_req_123", "custom_id": "request-3", "response": null, "error": {"code": "batch_expired", "message": "This request could not be executed before the completion window expired."}}
{"id": "batch_req_123", "custom_id": "request-7", "response": null, "error": {"code": "batch_expired", "message": "This request could not be executed before the completion window expired."}}