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.modelhosted_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