Chat GPT API를 사용해본 개발자들은 얼마나 이놈이 비싼지 알거다...
특히 회사가 아닌 개인이 사용하는 경우 그냥 눈물이 난다.
이러한 니즈로 등장하게 된 것이 Batch API이다.

batch API의 공식 문서에 소개를 간결하게 요약하면
일단 주피터로 간단하게 코드만 짰다.
query_list = ["사과를 먹고 잠을 자면 안 좋은 이유는 머야?", "AI는 장점을 알려줘"]
이렇게 보내고 싶은 query_list가 있다고 하자.
init_template = {
"custom_id": None, # custom_id는 batch내에서 유일한 값을 가지도록 설정해야합니다.
"method": "POST",
"url": "/v1/chat/completions",
"body": {"model": "gpt-3.5-turbo-0125", #사용할 모델의 종류 입니다.
"messages": # message의 마지막에 실제 query를 추가할 것입니다. role : system은 대답을 요구하지 않는 prompt입니다.
[{"role": "system", "content": "You are a helpful assistant."},
{"role": "system", "content": "You can only answer in Korean"}],
"max_tokens": 1000 #모델이 대답으로 생성 가능한 토큰의 최대 길이입니다.
}
}
대충 주석을 추가해 두었다. GPT에게 요청 보내고 싶은 하나의 질문당 위와 같은 body 하나를 만들것이다. 이때 custom_id는 batch 내에서 고유한 값을 가져야 함을 기억하자.
from copy import deepcopy
import json
batches = []
for id, query in enumerate(query_list):
temp = deepcopy(init_template)
temp['custom_id'] = f'{id}'
temp['body']['messages'].append({"role": "system", "content": query})
batches.append(temp)
with open('batchinput.jsonl', 'w') as file:
for item in batches:
json_string = json.dumps(item)
file.write(json_string + '\n')

deepcopy 써서 조금 마음이 걸리는데 더 나이스한 방법이 있으면 적용하면 좋을듯 합니다.
qeury list의 값을 하나씩 읽어서 batch 리스트를 만들고 batch list를 batchinput.jsonl 파일로 저장했다.
from openai import OpenAI
client = OpenAI(api_key="개인API키 입력하세요.")
# available only in version after openai==1.2.0
batch_input_file = client.files.create(
file=open("batchinput.jsonl", "rb"),
purpose="batch"
)
batch_input_file_id = batch_input_file.id
client.batches.create(
input_file_id=batch_input_file_id,
endpoint="/v1/chat/completions",
completion_window="24h", #응답 요청 시간(240502기준 24h만 가능)
metadata={
"description": "nightly eval job"
}
)
위 코드를 돌리면 Batch object를 수 있다.
{
"id": "batch_abc123",
"object": "batch",
"endpoint": "/v1/completions",
"errors": null,
"input_file_id": "file-abc123",
"completion_window": "24h",
"status": "validating",
"output_file_id": null,
"error_file_id": null,
"created_at": 1711471533,
"in_progress_at": null,
"expires_at": null,
"finalizing_at": null,
"completed_at": null,
"failed_at": null,
"expired_at": null,
"cancelling_at": null,
"cancelled_at": null,
"request_counts": {
"total": 0,
"completed": 0,
"failed": 0
},
"metadata": {
"customer_id": "user_123456789",
"batch_description": "Nightly eval job",
}
}
이런 body가 돌아올 거다. 여기서 중요한건 "id", "status" "expires_at" 이다
1. id는 조회할때 사용해야하는 값이니 까먹으면 안된다.
2. status는 상태를 나타내며 해당 값을 계속 조회할거다
3. expires_at은 결과를 만들어두면 해당 기간 내에 찾아 가야한다는 거다.
-> 근데 찍어보니까 시간이 이쁘게 안나온다. ex) 1714717550
client.batches.retrieve("batch_5gwXWG9KF2bP8NGLL95ghZ0r").status

임시 테스트 자료여서 batch id를 그냥 올렸는데 상관 없겄지~~
이렇게 계속 상태 확인하다가 "completed"뜨면 결과 받아오면 된다.
for batch in client.batches.list():
print(batch)
해당 클라이언트(API_KEY)로 생성한 batch들을 확인하느 코드이다.

현재 보낸 batch가 잘 올라갔다.

실수로 생성한 Batch를 만들었다. 상태는 'in_progress'인 상태로 요청을 기다릴 중이다.
client.batches.cancel("batch_EHk4bgb4BMIBrzlwkZf92Zw7")
위 코드에 batch_id를 넣으면 요청이 취소되고 'status'가 'cancelling'으로 바뀐다.

내일 결과가 나오면 결과 확인해서 저장하는 코드도 가져오겠다.
https://platform.openai.com/docs/guides/batch/getting-started
https://cookbook.openai.com/examples/batch_processing