vLLM - Batch + Files API
vLLM - Batch + Files API
OpenAI Batch API가 있는 vLLM 서버에 LiteLLM이 배치 및 파일 API를 제공하는 방법을 알아봐요.
출처: 문서
본문
vLLM의 OpenAI 호환 서버는 /v1/chat/completions, /v1/completions, /v1/embeddings, /v1/responses를 제공하지만 /v1/files나 /v1/batches 라우트는 없어요. LiteLLM이 그 빈틈을 메워요. Files API가 없는 서버의 hosted_vllm 배포의 경우, proxy가 배치 입력 자체를 저장하고, 모든 줄을 배포를 통해 실행하며, 배치 상태와 출력 파일을 제공하므로 OpenAI Batch API를 vLLM에 대해 변경 없이 동작하게 해요.
| 기능 | 지원 |
|---|---|
/v1/files |
✅ LiteLLM이 저장 |
/v1/batches |
✅ LiteLLM이 실행 |
| Cost Tracking | ✅ 배치를 만든 키에 모든 줄이 과금 |
이 흐름은 proxy에서 실행되며 입력 파일, 배치 상태, 결과 파일이 거기에 살기 때문에 데이터베이스(DATABASE_URL)가 필요해요.
LiteLLM이 배치를 직접 실행하는 경우
LiteLLM은 요청별로 결정해요. litellm_params.model이 hosted_vllm/로 시작하고 해당 서버의 GET {api_base}/files가 404로 응답하면 배포가 해당되는 거예요. 다른 모든 배포와 Files API를 구현한 서버의 hosted_vllm 배포(예: vLLM production-stack 라우터)는 통과(passthrough) 동작을 유지해요. 즉 업로드와 배치를 서버로 전달하고 서버가 배치를 실행해요.
프로브가 올바른 라우트에 도달하도록 api_base를 서버의 /v1 루트로 지정하세요.
빠른 시작
1. config.yaml 설정
model_list:
- model_name: my-vllm-model
litellm_params:
model: hosted_vllm/Qwen/Qwen2.5-0.5B-Instruct
api_base: http://localhost:8000/v1 # your vLLM server
api_key: os.environ/HOSTED_VLLM_API_KEY # only if your server checks one
general_settings:
database_url: os.environ/DATABASE_URL
2. LiteLLM Proxy 시작
litellm --config /path/to/config.yaml
3. 배치 파일 생성
각 줄은 OpenAI 배치 입력 형태를 따릅니다. LiteLLM은 body.model을 배치의 배포 이름으로 교체하므로, 거기 넣는 내용은 어떤 서버가 줄을 실행할지를 바꾸지 않아요.
{"custom_id": "request-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "my-vllm-model", "messages": [{"role": "user", "content": "Hello!"}]}}
{"custom_id": "request-2", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "my-vllm-model", "messages": [{"role": "user", "content": "How are you?"}]}}
모든 줄이 같은 url을 지칭해야 하고, 배치에 준 endpoint와 일치해야 해요. stream: true 줄, 중복 custom_id, 알 수 없는 최상위 필드는 업로드 시 줄을 명시한 400으로 거부돼요.
4. 파일 업로드 & 배치 생성
모델 라우팅: 업로드는 x-litellm-model 헤더, ?model= 쿼리 파라미터, 또는 target_model_names 폼 필드로 배포를 지칭해야 해요. purpose=batch를 사용하세요. LiteLLM이 배치를 실행하는 배포에 다른 purpose의 업로드는, 파일을 보관할 서버가 없으므로 400으로 응답해요. 반환된 파일 id는 OpenAI식 file-... id가 아닌 긴 base64 id이며, 이에 대한 배치 연산은 자동으로 같은 배포로 라우팅돼요.
파일 업로드:
curl http://localhost:4000/v1/files \
-H "Authorization: Bearer ***" \
-H "x-litellm-model: my-vllm-model" \
-F purpose="batch" \
-F file="@batch_requests.jsonl"
배치 생성:
curl http://localhost:4000/v1/batches \
-H "Authorization: Bearer ***" \
-H "Content-Type: application/json" \
-d '{
"input_file_id": "",
"endpoint": "/v1/chat/completions",
"completion_window": "24h"
}'
배치 상태 확인:
curl http://localhost:4000/v1/batches/<batch_id> \
-H "Authorization: Bearer ***"
결과 다운로드:
curl http://localhost:4000/v1/files/<file_id>/content \
-H "Authorization: Bearer ***"
OpenAI SDK 사용:
import time
from openai import OpenAI
client = OpenAI(api_key="sk-1234", base_url="http://localhost:4000/v1")
input_file = client.files.create(
file=open("batch_requests.jsonl", "rb"),
purpose="batch",
extra_headers={"x-litellm-model": "my-vllm-model"},
)
batch = client.batches.create(
input_file_id=input_file.id,
endpoint="/v1/chat/completions",
completion_window="24h",
)
while batch.status not in ("completed", "failed", "cancelled", "expired"):
time.sleep(5)
batch = client.batches.retrieve(batch.id)
if batch.output_file_id:
print(client.files.content(batch.output_file_id).text)
if batch.error_file_id:
print(client.files.content(batch.error_file_id).text)
지원 연산
| 연산 | 엔드포인트 | 메서드 |
|---|---|---|
| 파일 업로드 | /v1/files |
POST |
| 파일 조회 | /v1/files/{file_id} |
GET |
| 파일 삭제 | /v1/files/{file_id} |
DELETE |
| 파일 콘텐츠 가져오기 | /v1/files/{file_id}/content |
GET |
| 배치 생성 | /v1/batches |
POST |
| 배치 목록 | /v1/batches |
GET |
| 배치 조회 | /v1/batches/{batch_id} |
GET |
| 배치 취소 | /v1/batches/{batch_id}/cancel |
POST |
배치 endpoint는 /v1/chat/completions, /v1/completions, /v1/embeddings, 또는 /v1/responses일 수 있어요.
배치 실행 방식
배치는 validating으로 생성되고, create를 받은 proxy 복제본이 줄을 실행하는 동안 in_progress로, 결과 파일이 쓰이는 동안 finalizing으로, 끝나면 completed로 전환돼요. 서버가 거부한 줄은 서버의 상태 코드와 함께 오류 파일에 들어가고, 배치는 여전히 완료돼요. 취소는 배치를 cancelling으로 표시하고, 진행 중인 줄을 마치게 한 뒤 cancelled로 끝내며, 이미 끝난 줄의 출력을 유지해요. 24시간 completion_window도 같은 방식으로 적용돼요. 닫힐 때 끝나지 않은 줄은 잘리고 batch_expired로 오류 파일에 들어가며, 배치는 expired로 끝나서 제시간에 끝난 줄의 출력을 유지해요.
결과는 OpenAI의 배치 출력 형태로 반환돼요. output_file_id는 성공한 각 요청당 한 줄, error_file_id는 실패한 각 요청당 한 줄을 담아요. 둘 다 배치를 만든 키에만 제공돼요.
각 줄은 라우터를 통해 자체 요청으로 과금되며, 생성 키·팀·태그가 스펜드 로그에, 가격은 배포에 구성된 대로 계산돼요. 가격이 없는 배포는 줄을 spend 0으로 기록해요.
배치를 실행하는 복제본이 재시작되면, 마지막 진행 기록 후 3분 이상 지나 조회될 때 배치가 runner_lost 오류로 failed로 표시돼요. 다시 제출하세요.
설정
| 설정 | 기본값 | 설명 |
|---|---|---|
LITELLM_EXECUTED_BATCH_CONCURRENCY |
4 |
한 배치의 몇 줄을 병렬로 실행할지 |
general_settings.allow_client_side_credentials |
false |
배치 줄은 실시간 요청과 같은 규칙을 따름. body에 api_base, api_key 또는 다른 클라이언트 측 자격 증명 필드가 있는 줄은 true이거나 배포가 configurable_clientside_auth_params에 필드를 나열하지 않으면 업로드 시 거부 |
배치 줄은 제공사가 실행하는 배치와 마찬가지로 proxy의 사전 호출 가드레일을 건너뛰어요.
관련
- vLLM 제공사 개요
- Batch API 개요
- Files API
더 알아보기 (Learn more)
- vLLM 제공사 개요
- LiteLLM Batch API