본문으로 바로가기

OpenAI Batch API 비용 절감: JSONL 요청부터 실패·만료 재시도까지

OpenAI Batch API의 50% 할인 범위와 GPT-6.1 Sol 캐시·장문 요금을 계산하고, Responses JSONL·custom_id·부분 재시도로 중복 처리와 재청구를 줄이는 방법을 정리합니다.

목차
OpenAI Batch API 비용 절감: JSONL 요청부터 실패·만료 재시도까지

OpenAI Batch API로 비용을 줄이려면, 기다릴 수 있는 작업을 모으고 성공한 요청을 다시 보내지 않아야 한다. 50% 할인은 같은 조건의 Standard 모델 토큰 요금과 비교한 값이다. 재시도, 결과 검수, 저장소와 워커 비용까지 포함한 전체 청구가 절반이 된다는 뜻은 아니다.

이 글은 10월 17일 AI 테크 브리핑의 자료 검증에서 도출한 독립 해설이다. 공식 문서·가격 확인일과 작성일은 2026년 10월 18일이다. API 예시는 문서와 대조했으며, 유료 API 실호출이나 실제 절감률 측정은 수행하지 않았다.

어떤 작업을 Batch API로 옮길 수 있나

Batch API는 요청들을 파일로 제출하고 나중에 결과 파일을 받는 방식이다. 현재 처리 창은 24h이며, 즉시 응답이 필요 없는 평가·문서 분류 같은 작업에 적합하다. 만료와 부분 실패도 처리할 수 있어야 한다.

업무 조건선택 기준
사용자가 답변을 보며 후속 질문을 한다실시간 응답 경로 유지
독립적인 문서 수천 건을 다음 날까지 분류한다Batch 후보
하나의 추론 작업이 길지만 당장 시작해야 한다Background mode와 비교
앞 요청 결과를 받아야 다음 요청을 만들 수 있다의존 단계를 나누거나 별도 작업 오케스트레이션 검토

위 표는 작업을 나누기 위한 운영 제안이다. 주말이나 심야라는 이유로 할인이 적용되는 것이 아니며, Background mode도 Batch 할인과 같은 상품으로 취급하면 안 된다.

50% 할인은 무엇과 비교해야 하나

아래는 OpenAI 공식 가격표의 GPT-6.1 Sol 텍스트 요금이다. 단위는 미국 달러 / 100만 토큰, 조건은 요청당 입력 272K토큰 이하다.

과금 항목StandardBatch
일반 입력$2.00$1.00
캐시 읽기$0.10$0.05
캐시 쓰기$2.50$1.25
출력$10.00$5.00

모델 문서에 따르면 입력이 272K토큰을 넘는 요청은 그 요청 전체의 입력·캐시 요금이 2배, 출력 요금이 1.5배다. Batch 장문 요금은 일반 입력 $2, 캐시 읽기 $0.10, 캐시 쓰기 $2.50, 출력 $7.50이 된다. 지역 처리 할증이나 도구 비용도 적용 여부를 별도로 확인해야 한다.

캐시 읽기는 전체 입력에 중복해서 더하는 항목이 아니다. 프롬프트 캐시 문서의 사용량 구분에 맞춰 다음처럼 계산한다.

일반 입력 = input_tokens - cached_tokens - cache_write_tokens
모델 토큰 비용 =
  (일반 입력 × 입력 단가
   + cached_tokens × 캐시 읽기 단가
   + cache_write_tokens × 캐시 쓰기 단가
   + output_tokens × 출력 단가) ÷ 1,000,000

출력 토큰 합계에 포함된 추론 토큰을 다시 더하지 않는다. 캐시 쓰기처럼 필요한 사용량 항목이 누락되면 0으로 추정해 절감률을 확정하지 말고, 실제 청구 내역과 대조한다.

예를 들어 여러 짧은 요청의 합계가 일반 입력 500만, 캐시 읽기 1,000만, 캐시 쓰기 200만, 출력 40만 토큰이라고 가정하자. 같은 사용량의 토큰 비용은 Standard $20, Batch $10이다. 이것은 산식 예시이며, 실제 Batch의 캐시 적중률과 출력량이 같다는 보장은 없다.

Responses JSONL을 만들고 제출한다

입력은 한 줄에 JSON 객체 하나인 requests.jsonl이다. 한 파일은 같은 모델을 사용하고 각 요청의 custom_id는 고유해야 한다. 다음 예시는 두 문서를 독립적으로 요약한다.

{"custom_id":"doc-101-v1-a1","method":"POST","url":"/v1/responses","body":{"model":"gpt-6.1-sol","input":"다음 문서를 세 문장으로 요약하세요: 배치 처리 도입 검토 문서입니다.","max_output_tokens":1024}}
{"custom_id":"doc-102-v1-a1","method":"POST","url":"/v1/responses","body":{"model":"gpt-6.1-sol","input":"다음 문서를 세 문장으로 요약하세요: 비용 집계 절차 검토 문서입니다.","max_output_tokens":1024}}

max_output_tokens는 추론 토큰도 포함하는 상한이다. 위의 1,024는 설명용 값이며, 실제 입력에서 미완료 응답이 발생하는지 평가해 조정한다.

Batch 생성 API는 purpose="batch"로 업로드한 파일을 받는다. 현재 파일당 최대 50,000요청·200MB이며, 모델별 대기 입력 토큰 한도도 확인해야 한다.

아래는 openai Python SDK와 서버 환경의 OPENAI_API_KEY를 사용하는 제출 예시다. 실행하면 과금 가능한 작업이 생성된다. 반복 실행 전에 이미 제출된 배치가 있는지 확인한다.

from openai import OpenAI
 
client = OpenAI()
with open("requests.jsonl", "rb") as source:
    uploaded = client.files.create(file=source, purpose="batch")
 
batch = client.batches.create(
    input_file_id=uploaded.id,
    endpoint="/v1/responses",
    completion_window="24h",
    metadata={"run_key": "document-summary-2026-10-18-v1"},
)
print(batch.id)  # 이 ID를 작업 기록에 저장한다.

여기의 run_key는 운영자가 조회할 표식이며 서버의 중복 생성 방지 보장을 뜻하지 않는다. 제출 파일의 해시, input_file_id, batch.id를 함께 기록하면 통신 실패 후의 재제출 판단에 도움이 된다.

배치 완료와 업무 성공을 나눠 확인한다

상태는 Batch 조회 API로 확인한다. 진행 중에 원본을 다시 제출하지 말고 저장한 배치 ID를 조회한다.

배치 상태다음 행동
validating, in_progress, finalizing간격을 두고 조회
failed입력 검증 오류의 줄·원인 수정
completed결과와 오류 파일을 모두 확인
expired완료된 결과를 먼저 확보하고 미완료 요청 분리
cancelling취소 확정까지 조회
cancelled남은 결과와 실제 처리 상태 확인

completed 배치에도 실패 요청이 있을 수 있다. request_counts를 확인하고, 반환된 output_file_id와 error_file_id로 결과를 만료 전에 내려받아 보존한다. 아래 다운로드 예시는 종료 상태를 확인한 뒤 실행하는 부분 코드다.

batch = client.batches.retrieve("batch_실제_ID로_교체")
for field, path in [
    ("output_file_id", "output.jsonl"),
    ("error_file_id", "errors.jsonl"),
]:
    file_id = getattr(batch, field)
    if file_id:
        with open(path, "w", encoding="utf-8") as destination:
            destination.write(client.files.content(file_id).text)

결과 순서는 입력과 다를 수 있으므로 행 번호가 아니라 custom_id로 연결한다. Responses 본문의 status와 필요한 출력도 확인한다. 추론 모델 안내는 토큰 상한에 도달하면 incomplete 응답이 발생할 수 있다고 설명한다. HTTP 성공 응답이라도 출력이 미완료이거나 업무 형식을 충족하지 못하면 검수 대상으로 남긴다.

실패·만료 요청만 다시 보낸다

공식 Batch 만료 안내에 따르면 expired 배치의 미완료 요청은 취소되고, 완료한 결과는 내려받을 수 있으며 완료 요청의 사용 토큰은 청구된다. 만료를 이유로 원본 전체를 다시 보내면 이미 끝난 작업을 또 처리할 수 있다.

다음은 운영 절차 제안이다.

  1. 결과·오류 파일을 원본 custom_id 목록과 대조한다. 사라진 ID는 실패로 단정하지 말고 상태를 확인한다.
  2. 성공 결과를 먼저 저장한다. 업무 키와 입력·프롬프트 버전을 기준으로 이미 확정된 결과가 있는지 검사한다.
  3. batch_expired와 재시도 가능한 일시 오류를 선별한다. 잘못된 파라미터·권한·입력 오류는 원인을 고친 뒤 다시 평가한다.
  4. 선별한 요청으로 새 JSONL을 만들고 doc-101-v1-a2처럼 시도 번호를 올린다. 이전 시도와의 연결은 별도 작업 기록에 남긴다.
  5. 재시도 횟수·비용·업무 마감의 상한을 둔다. 초과하면 검토 대상으로 보내거나 필요한 요청만 다른 처리 경로로 전환한다.

custom_id는 결과를 연결하는 키다. 같은 값을 재사용해도 별도 배치의 실행·청구가 자동으로 막힌다고 가정하면 안 된다. 여러 워커가 결과를 반영한다면 업무 키에 대한 고유 제약과 상태 변경을 같은 트랜잭션으로 처리하는 방법을 검토한다.

배치 생성 응답을 받지 못한 경우도 곧바로 새 배치를 만들지 않는다. 저장한 파일 ID와 실행 표식을 배치 목록에서 대조하고, 접수 여부를 확인할 때까지 해당 제출을 미확정 상태로 관리한다.

절감률은 성공 작업당 비용으로 판단한다

도입 판단에는 토큰 단가 외에 검수를 통과한 고유 작업 한 건의 비용을 함께 둔다. 아래 식은 운영 비교를 위한 제안이다.

성공 작업당 비용 =
  (최초 호출 + 재시도 + 도구·저장·워커·검수 비용)
  ÷ 검수를 통과한 고유 작업 수

가령 모델 요금 $10, 재시도 $2, 나머지 처리비 $3, 검수 통과 작업 90건이라고 가정하면 성공 작업당 약 $0.167이다. 원본을 다시 보내 중복 결과가 늘어도 분모에는 같은 업무를 한 번만 센다.

먼저 작은 작업군에서 Standard와 Batch의 입력·프롬프트 버전과 검수 기준을 맞춰 비교한다. 성공 작업당 비용, 마감 준수율, 재시도 비중이 함께 개선되는지 확인한 뒤 적용 범위를 넓히는 것이 이 글의 결론이다. Gemini 모델 교체·장문 출력 조건은 기존 Argon 마이그레이션 가이드에서 따로 확인할 수 있다.

참고 자료

깊이 읽기 모아 보기