Batch API

Batch API

OpenAI의 Batch API를 쓰면 비동기 요청 그룹을 50% 저렴한 비용, 크게 높아진 별도의 rate limit 풀, 그리고 명확한 24시간 처리 주기로 보낼 수 있어요. 즉시 응답이 필요 없는 작업을 처리할 때 아주 적합하죠. API reference도 직접 살펴볼 수 있어요.

출처: 문서

본문

개요 (Overview)

OpenAI Platform의 일부 용도는 동기 요청을 보내야 하지만, 많은 경우 즉시 응답이 필요 없거나 rate limit 때문에 많은 쿼리를 빠르게 실행하지 못하는 상황이 있어요. 배치 처리 작업은 이런 경우에 유용해요.

  1. 평가(evaluations) 실행하기
  2. 대규모 데이터셋 분류하기
  3. 콘텐츠 저장소 임베딩하기

Batch API는 요청 집합을 단일 파일로 모으고, 배치 처리 작업을 시작해 요청을 실행하고, 실행되는 동안 배치 상태를 조회하고, 완료되면 결과를 가져오는 일련의 간단한 엔드포인트를 제공해요.

표준 엔드포인트를 직접 쓰는 것과 비교해 Batch API는:

  1. 더 나은 비용 효율: 동기 API 대비 50% 비용 할인
  2. 더 높은 rate limit: 동기 API에 비해 훨씬 많은 헤드룸
  3. 빠른 완료 시간: 각 배치는 24시간 이내(종종 더 빠르게) 완료

시작하기

1. 배치 파일 준비하기

배치는 .jsonl 파일로 시작하는데, 각 줄이 API에 보낼 개별 요청의 세부 사항을 담아요. 현재 사용 가능한 엔드포인트는:

  • /v1/responses (Responses API)
  • /v1/chat/completions (Chat Completions API)
  • /v1/embeddings (Embeddings API)
  • /v1/completions (Completions API)
  • /v1/moderations (Moderation 가이드)
  • /v1/images/generations (Images API)
  • /v1/images/edits (Images API)

주어진 입력 파일에서 각 줄의 body 필드 파라미터는 기본 엔드포인트의 파라미터와 동일해요. 각 요청은 고유한 custom_id 값을 포함해야 하고, 완료 후 결과를 참조할 때 이 값을 사용해요. 아래는 요청 2개를 담은 입력 파일 예시예요. 각 입력 파일은 단일 모델에 대한 요청만 담을 수 있다는 점 참고하세요.

/v1/moderations를 대상으로 할 때는 모든 요청 body에 input 필드를 포함하세요. Batch는 omni-moderation-latest로 텍스트 입력과 텍스트·이미지 입력을 담은 콘텐츠 배열을 모두 받아요. 동기 moderation 엔드포인트와 일치하게, Batch worker는 stream=true를 설정한 요청을 거부해요.

{"custom_id": "request-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-3.5-turbo-0125", "messages": [{"role": "system", "content": "You are a helpful assistant."},{"role": "user", "content": "Hello world!"}],"max_tokens": 1000}}
{"custom_id": "request-2", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-3.5-turbo-0125", "messages": [{"role": "system", "content": "You are an unhelpful assistant."},{"role": "user", "content": "Hello world!"}],"max_tokens": 1000}}
Moderation 입력 예시

텍스트 전용 요청:

{
  "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"
        }
      }
    ]
  }
}

특히 멀티모달 Moderations 요청의 경우, base64 blob 대신 image_url로 원격 자산을 참조하면 .jsonl 파일을 Batch 업로드 한도인 200MB 아래로 유지할 수 있어요.

2. 배치 입력 파일 업로드하기

Fine-tuning API와 유사하게, 먼저 입력 파일을 업로드해야 배치를 시작할 때 올바르게 참조할 수 있어요. .jsonl 파일을 Files API로 업로드하세요.

from openai import OpenAI

client = OpenAI()

batch_input_file = client.files.create(
    file=open("batchinput.jsonl", "rb"), purpose="batch"
)

print(batch_input_file)
curl https://api.openai.com/v1/files \
  -H "Authorization: Bearer ***" \
  -F purpose="batch" \
  -F file="@batchinput.jsonl"
openai files create \
  --file batchinput.jsonl \
  --purpose batch

JavaScript(openai.files.create), Go(client.Files.New), Java(client.files().create), Ruby(client.files.create)도 모두 purpose="batch"로 같은 방식으로 업로드해요.

3. 배치 생성하기

입력 파일을 성공적으로 업로드하면 입력 File 객체의 ID로 배치를 만들 수 있어요. 여기서는 파일 ID가 file-abc123이라고 가정해 볼게요. 현재 완료 창(completion window)은 24h로만 설정할 수 있어요. 선택적 metadata 파라미터로 커스텀 메타데이터를 제공할 수도 있어요.

batch = client.batches.create(
    input_file_id=batch_input_file.id,
    endpoint="/v1/chat/completions",
    completion_window="24h",
    metadata={"description": "nightly eval job"},
)
print(batch)
curl https://api.openai.com/v1/batches \
  -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json" \
  -d '{
    "input_file_id": "file-abc123",
    "endpoint": "/v1/chat/completions",
    "completion_window": "24h"
  }'
openai batches create \
  --input-file-id file-abc123 \
  --endpoint /v1/chat/completions \
  --completion-window 24h

JS/Golang/Java/Ruby에서도 client.batches.create, client.Batches.New, client.batches().create, client.batches.create로 각자 input_file_id, endpoint, completion_window를 넣으면 돼요.

이 요청은 배치에 대한 메타데이터를 담은 Batch 객체를 돌려줘요.

{
  "id": "batch_abc123",
  "object": "batch",
  "endpoint": "/v1/chat/completions",
  "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 객체를 돌려줘요.

batch = client.batches.retrieve(batch.id)
print(batch)
curl https://api.openai.com/v1/batches/batch_abc123 \
  -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json"
openai batches retrieve \
  --batch-id batch_abc123

Batch 객체의 상태는 다음 중 하나일 수 있어요.

상태 설명
validating 배치가 시작되기 전에 입력 파일을 검증하고 있음
failed 입력 파일이 검증 과정을 통과하지 못함
in_progress 입력 파일이 검증에 성공했고 배치가 현재 실행 중
finalizing 배치가 완료되었고 결과를 준비하고 있음
completed 배치가 완료되었고 결과가 준비됨
expired 배치가 24시간 창 안에 완료되지 못함
cancelling 배치가 취소되는 중(최대 10분 소요)
cancelled 배치가 취소됨

5. 결과 가져오기

배치가 완료되면 Batch 객체의 output_file_id 필드를 이용해 Files API에 요청하고, 이 경우 batch_output.jsonl로 컴퓨터의 파일에 쓰면 결과를 다운로드할 수 있어요.

# Replace the illustrative IDs and URLs below with your own resource values.

from openai import OpenAI

output_file_id = "file_123"
client = OpenAI()

file_response = client.files.content(output_file_id)
print(file_response.text)
curl https://api.openai.com/v1/files/file-xyz123/content \
  -H "Authorization: Bearer ***" > batch_output.jsonl
openai files content \
  --file-id file-xyz123 \
  --output batch_output.jsonl

출력 .jsonl 파일에는 입력 파일의 성공한 요청 줄마다 응답 줄 하나가 들어 있어요. 배치에서 실패한 요청은 배치의 error_file_id로 찾을 수 있는 오류 파일에 오류 정보가 기록돼요.

참고로 출력 줄 순서는 입력 줄 순서와 일치하지 않을 수 있어요. 결과를 처리할 때 순서에 의존하지 말고, 출력 파일 각 줄에 들어 있는 custom_id 필드를 사용해 입력의 요청을 출력의 결과에 매핑하세요.

{"id": "batch_req_123", "custom_id": "request-2", "response": {"status_code": 200, "request_id": "req_123", "body": {"id": "chatcmpl-123", "object": "chat.completion", "created": 1711652795, "model": "gpt-3.5-turbo-0125", "choices": [{"index": 0, "message": {"role": "assistant", "content": "Hello."}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 22, "completion_tokens": 2, "total_tokens": 24}, "system_fingerprint": "fp_123"}}, "error": null}
{"id": "batch_req_456", "custom_id": "request-1", "response": {"status_code": 200, "request_id": "req_789", "body": {"id": "chatcmpl-abc", "object": "chat.completion", "created": 1711652789, "model": "gpt-3.5-turbo-0125", "choices": [{"index": 0, "message": {"role": "assistant", "content": "Hello! How can I assist you today?"}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 20, "completion_tokens": 9, "total_tokens": 29}, "system_fingerprint": "fp_3ba"}}, "error": null}

출력 파일은 배치가 완료된 후 30일이 지나면 자동으로 삭제돼요.

6. 배치 취소하기

필요하다면 진행 중인 배치를 취소할 수 있어요. 실행 중인 요청이 끝날 때까지(최대 10분) 배치 상태가 cancelling으로 바뀌고, 이후 cancelled로 바뀌어요.

# Replace the illustrative IDs and URLs below with your own resource values.

from openai import OpenAI

batch_id = "batch_123"
client = OpenAI()

client.batches.cancel(batch_id)
curl https://api.openai.com/v1/batches/batch_abc123/cancel \
  -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json" \
  -X POST

7. 모든 배치 목록 가져오기

언제든 모든 배치를 볼 수 있어요. 배치가 많은 사용자는 limit와 after 파라미터로 결과를 페이지네이션할 수 있어요.

from openai import OpenAI

client = OpenAI()

client.batches.list(limit=10)
curl https://api.openai.com/v1/batches?limit=10 \
  -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json"
openai batches list \
  --limit 10

모델 가용성

Batch API는 대부분의 모델에서 널리 제공되지만, 전부는 아니에요. 사용 중인 모델이 Batch API를 지원하는지 모델 reference 문서에서 확인하세요. GPT-6 Sol과 Luna의 경우 EU 데이터 상주는 Standard 처리에서만 가능해요. 데이터 상주 자격 문서를 참고하세요.

Rate limits

Batch API rate limit은 기존 모델별 rate limit과 별개예요. Batch API에는 세 가지 유형의 rate limit이 있어요.

  1. 배치별 한도: 단일 배치에는 최대 50,000개의 요청이 포함될 수 있고, 배치 입력 파일은 최대 200MB까지 가능해요. /v1/embeddings 배치도 배치 내 모든 요청을 합쳐 최대 50,000개의 임베딩 입력으로 제한된다는 점 참고하세요.
  2. 모델별 큐잉된 프롬프트 토큰: 각 모델에는 배치 처리용으로 큐잉할 수 있는 최대 프롬프트 토큰 수가 있어요. 이 한도는 Platform 설정 페이지에서 찾을 수 있어요.
  3. 배치 생성 rate limit: 시간당 최대 2,000개의 배치를 만들 수 있어요. 더 많은 요청을 제출해야 한다면 배치당 요청 수를 늘리세요.

Batch API에는 현재 출력 토큰 한도가 없어요. Batch API rate limit은 새롭고 별도의 풀이기 때문에, Batch API를 쓰는 것이 표준 모델별 rate limit의 토큰을 소모하지 않아요. 요청과 처리된 토큰을 늘리는 편리한 방법이 되어 줍니다.

배치 만료

제때 완료되지 않는 배치는 결국 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."}}

더 알아보기 (Learn more)