OpenAI 배치 파일 포맷으로 오프라인 추론

OpenAI 배치 파일 포맷으로 오프라인 추론

여러 요청을 한 번에 묶어서 처리하려면 OpenAI의 배치(batch) 파일 포맷을 쓰는 게 편리해요. vLLM이 이 포맷을 어떻게 처리하는지 살펴볼게요.

출처: vLLM Offline Inference with the OpenAI Batch file format

파일 포맷

OpenAI 배치 파일 포맷은 새 줄로 구분된 일련의 json 객체로 이뤄져요.

예시 파일은 여기에서 볼 수 있어요.

각 줄은 별도의 요청을 나타내요. 자세한 내용은 OpenAI 패키지 레퍼런스를 참고하세요.

사전 준비

  • 이 문서의 예시는 meta-llama/Meta-Llama-3-8B-Instruct를 사용해요.

!!! note 현재 /v1/chat/completions, /v1/embeddings, /v1/score 엔드포인트를 지원해요(completions는 곧 지원 예정).

!!! important 이 문서는 OpenAI 배치 파일 포맷을 이용한 배치 추론 가이드이지, 완전한 배치(REST) API가 아니에요.

예제 1: 로컬 파일로 실행

1단계: 배치 파일 만들기

예제를 따라 하려면 예시 배치를 다운로드하거나, 작업 디렉토리에 자신만의 배치 파일을 만들면 돼요.

wget https://raw.githubusercontent.com/vllm-project/vllm/main/examples/features/openai_batch/openai_example_batch.jsonl

배치 파일을 만들었다면 이렇게 생겼을 거예요.

cat examples/features/openai_batch/openai_example_batch.jsonl
{"custom_id": "request-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "meta-llama/Meta-Llama-3-8B-Instruct", "messages": [{"role": "system", "content": "You are a helpful assistant."},{"role": "user", "content": "Hello world!"}],"max_completion_tokens": 1000}}
{"custom_id": "request-2", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "meta-llama/Meta-Llama-3-8B-Instruct", "messages": [{"role": "system", "content": "You are an unhelpful assistant."},{"role": "user", "content": "Hello world!"}],"max_completion_tokens": 1000}}

2단계: 배치 실행

배치 실행 도구는 커맨드 라인에서 사용하도록 설계됐어요.

다음 명령으로 배치를 실행할 수 있는데, 결과는 results.jsonl 파일에 기록돼요.

python -m vllm.entrypoints.launchers.run_batch \
    -i examples/features/openai_batch/openai_example_batch.jsonl \
    -o results.jsonl \
    --model meta-llama/Meta-Llama-3-8B-Instruct

또는 커맨드 라인을 사용할 수도 있어요.

vllm run-batch \
    -i examples/features/openai_batch/openai_example_batch.jsonl \
    -o results.jsonl \
    --model meta-llama/Meta-Llama-3-8B-Instruct

3단계: 결과 확인

이제 results.jsonl에 결과가 있을 거예요. cat results.jsonl로 결과를 확인해보세요.

cat results.jsonl
{"id":"vllm-383d1c59835645aeb2e07d004d62a826","custom_id":"request-1","response":{"id":"cmpl-61c020e54b964d5a98fa7527bfcdd378","object":"chat.completion","created":1715633336,"model":"meta-llama/Meta-Llama-3-8B-Instruct","choices":[{"index":0,"message":{"role":"assistant","content":"Hello! It's great to meet you! I'm here to help with any questions or tasks you may have. What's on your mind today?"},"logprobs":null,"finish_reason":"stop","stop_reason":null}],"usage":{"prompt_tokens":25,"total_tokens":56,"completion_tokens":31}},"error":null}
{"id":"vllm-42e3d09b14b04568afa3f1797751a267","custom_id":"request-2","response":{"id":"cmpl-f44d049f6b3a42d4b2d7850bb1e31bcc","object":"chat.completion","created":1715633336,"model":"meta-llama/Meta-Llama-3-8B-Instruct","choices":[{"index":0,"message":{"role":"assistant","content":"*silence*"},"logprobs":null,"finish_reason":"stop","stop_reason":null}],"usage":{"prompt_tokens":27,"total_tokens":32,"completion_tokens":5}},"error":null}

예제 2: 원격 파일 사용

배치 러너는 http/https로 접근 가능한 원격 입력·출력 URL을 지원해요.

예를 들어 https://raw.githubusercontent.com/vllm-project/vllm/main/examples/features/openai_batch/openai_example_batch.jsonl에 있는 예시 입력 파일에 대해 실행하려면:

python -m vllm.entrypoints.launchers.run_batch \
    -i https://raw.githubusercontent.com/vllm-project/vllm/main/examples/features/openai_batch/openai_example_batch.jsonl \
    -o results.jsonl \
    --model meta-llama/Meta-Llama-3-8B-Instruct

또는 커맨드 라인 사용:

vllm run-batch \
    -i https://raw.githubusercontent.com/vllm-project/vllm/main/examples/features/openai_batch/openai_example_batch.jsonl \
    -o results.jsonl \
    --model meta-llama/Meta-Llama-3-8B-Instruct

예제 3: AWS S3 연동

클라우드 블롭 스토리지와 연동하려면 presigned URL을 사용하는 걸 권장해요.

[S3 presigned urls에 대해 더 알아보기]

추가 사전 준비

  • S3 버킷 만들기.
  • 자격 증명을 구성하고 s3를 대화형으로 사용하려면 awscli 패키지(pip install awscli 실행).
  • presigned URL을 생성하려면 boto3 파이썬 패키지(pip install boto3 실행).

1단계: 입력 스크립트 업로드

예제를 따라 하려면 예시 배치를 다운로드하거나, 작업 디렉토리에 자신만의 배치 파일을 만들면 돼요.

wget https://raw.githubusercontent.com/vllm-project/vllm/main/examples/features/openai_batch/openai_example_batch.jsonl

이제 배치 파일을 S3 버킷에 업로드해요.

aws s3 cp examples/features/openai_batch/openai_example_batch.jsonl s3://MY_BUCKET/MY_INPUT_FILE.jsonl

2단계: presigned URL 생성

presigned URL은 SDK로만 생성할 수 있어요. 다음 파이썬 스크립트로 presigned URL을 생성할 수 있어요. MY_BUCKET, MY_INPUT_FILE.jsonl, MY_OUTPUT_FILE.jsonl 플레이스홀더를 자신의 버킷·파일 이름으로 바꾸는 걸 잊지 마세요.

(스크립트는 https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/python/example_code/s3/s3_basics/presigned_url.py에서 각색했어요.)

import boto3
from botocore.exceptions import ClientError

def generate_presigned_url(s3_client, client_method, method_parameters, expires_in):
    """
    Generate a presigned Amazon S3 URL that can be used to perform an action.

    :param s3_client: A Boto3 Amazon S3 client.
    :param client_method: The name of the client method that the URL performs.
    :param method_parameters: The parameters of the specified client method.
    :param expires_in: The number of seconds the presigned URL is valid for.
    :return: The presigned URL.
    """
    try:
        url = s3_client.generate_presigned_url(
            ClientMethod=client_method,
            Params=method_parameters,
            ExpiresIn=expires_in,
        )
    except ClientError:
        raise
    return url


s3_client = boto3.client("s3")
input_url = generate_presigned_url(
    s3_client,
    "get_object",
    {"Bucket": "MY_BUCKET", "Key": "MY_INPUT_FILE.jsonl"},
    expires_in=3600,
)
output_url = generate_presigned_url(
    s3_client,
    "put_object",
    {"Bucket": "MY_BUCKET", "Key": "MY_OUTPUT_FILE.jsonl"},
    expires_in=3600,
)
print(f"{input_url=}")
print(f"{output_url=}")

이 스크립트는 이런 출력을 내야 해요.

input_url='https://s3.us-west-2.amazonaws.com/MY_BUCKET/MY_INPUT_FILE.jsonl?AWSAccessKeyId=ABCDEFGHIJKLMNOPQRST&Signature=abcdefghijklmnopqrstuvwxyz12345&Expires=1715800091'
output_url='https://s3.us-west-2.amazonaws.com/MY_BUCKET/MY_OUTPUT_FILE.jsonl?AWSAccessKeyId=ABCDEFGHIJKLMNOPQRST&Signature=abcdefghijklmnopqrstuvwxyz12345&Expires=1715800091'

3단계: presigned URL로 배치 러너 실행

이제 이전 단계에서 생성한 URL로 배치 러너를 실행할 수 있어요.

python -m vllm.entrypoints.launchers.run_batch \
    -i "https://s3.us-west-2.amazonaws.com/MY_BUCKET/MY_INPUT_FILE.jsonl?AWSAccessKeyId=ABCDEFGHIJKLMNOPQRST&Signature=abcdefghijklmnopqrstuvwxyz12345&Expires=1715800091" \
    -o "https://s3.us-west-2.amazonaws.com/MY_BUCKET/MY_OUTPUT_FILE.jsonl?AWSAccessKeyId=ABCDEFGHIJKLMNOPQRST&Signature=abcdefghijklmnopqrstuvwxyz12345&Expires=1715800091" \
    --model meta-llama/Meta-Llama-3-8B-Instruct

또는 커맨드 라인 사용:

vllm run-batch \
    -i "https://s3.us-west-2.amazonaws.com/MY_BUCKET/MY_INPUT_FILE.jsonl?AWSAccessKeyId=ABCDEFGHIJKLMNOPQRST&Signature=abcdefghijklmnopqrstuvwxyz12345&Expires=1715800091" \
    -o "https://s3.us-west-2.amazonaws.com/MY_BUCKET/MY_OUTPUT_FILE.jsonl?AWSAccessKeyId=ABCDEFGHIJKLMNOPQRST&Signature=abcdefghijklmnopqrstuvwxyz12345&Expires=1715800091" \
    --model meta-llama/Meta-Llama-3-8B-Instruct

4단계: 결과 확인

결과는 이제 S3에 있어요. 터미널에서 다음 명령으로 확인할 수 있어요.

aws s3 cp s3://MY_BUCKET/MY_OUTPUT_FILE.jsonl -

예제 4: embeddings 엔드포인트 사용

추가 사전 준비

  • vllm >= 0.5.5를 사용하고 있는지 확인하세요.

1단계: 배치 파일 만들기

배치 파일에 embedding 요청을 추가해요. 다음은 그 예시예요.

{"custom_id": "request-1", "method": "POST", "url": "/v1/embeddings", "body": {"model": "intfloat/e5-mistral-7b-instruct", "input": "You are a helpful assistant."}}
{"custom_id": "request-2", "method": "POST", "url": "/v1/embeddings", "body": {"model": "intfloat/e5-mistral-7b-instruct", "input": "You are an unhelpful assistant."}}

사용하는 모델이 chat completion과 embedding을 모두 지원하기만 하면, 배치 파일에서 chat completion과 embedding 요청을 섞을 수도 있어요(모든 요청이 같은 모델을 사용해야 한다는 점을 기억하세요).

2단계: 배치 실행

이전 예시와 같은 명령으로 배치를 실행할 수 있어요.

3단계: 결과 확인

cat results.jsonl로 결과를 확인할 수 있어요.

cat results.jsonl
{"id":"vllm-db0f71f7dec244e6bce530e0b4ef908b","custom_id":"request-1","response":{"status_code":200,"request_id":"vllm-batch-3580bf4d4ae54d52b67eee266a6eab20","body":{"id":"embd-33ac2efa7996430184461f2e38529746","object":"list","created":444647,"model":"intfloat/e5-mistral-7b-instruct","data":[{"index":0,"object":"embedding","embedding":[0.016204833984375,0.0092010498046875,0.0018358230590820312,-0.0028228759765625,0.001422882080078125,-0.0031147003173828125,...]}],"usage":{"prompt_tokens":8,"total_tokens":8,"completion_tokens":0}}},"error":null}
...

예제 5: score 엔드포인트 사용

추가 사전 준비

  • vllm >= 0.7.0을 사용하고 있는지 확인하세요.

1단계: 배치 파일 만들기

배치 파일에 score 요청을 추가해요. 다음은 그 예시예요.

{"custom_id": "request-1", "method": "POST", "url": "/v1/score", "body": {"model": "BAAI/bge-reranker-v2-m3", "queries": "What is the capital of France?", "documents": ["The capital of Brazil is Brasilia.", "The capital of France is Paris."]}}
{"custom_id": "request-2", "method": "POST", "url": "/v1/score", "body": {"model": "BAAI/bge-reranker-v2-m3", "queries": "What is the capital of France?", "documents": ["The capital of Brazil is Brasilia.", "The capital of France is Paris."]}}

사용하는 모델이 이들을 모두 지원하기만 하면 chat completion, embedding, score 요청을 배치 파일에서 섞을 수 있어요(모든 요청이 같은 모델을 사용해야 한다는 점을 기억하세요).

2단계: 배치 실행

이전 예시와 같은 명령으로 배치를 실행할 수 있어요.

3단계: 결과 확인

cat results.jsonl로 결과를 확인할 수 있어요.

cat results.jsonl
{"id":"vllm-f87c5c4539184f618e555744a2965987","custom_id":"request-1","response":{"status_code":200,"request_id":"vllm-batch-806ab64512e44071b37d3f7ccd291413","body":{"id":"score-4ee45236897b4d29907d49b01298cdb1","object":"list","created":1737847944,"model":"BAAI/bge-reranker-v2-m3","data":[{"index":0,"object":"score","score":0.0010900497436523438},{"index":1,"object":"score","score":1.0}],"usage":{"prompt_tokens":37,"total_tokens":37,"completion_tokens":0,"prompt_tokens_details":null}}},"error":null}
{"id":"vllm-41990c51a26d4fac8419077f12871099","custom_id":"request-2","response":{"status_code":200,"request_id":"vllm-batch-73ce66379026482699f81974e14e1e99","body":{"id":"score-13f2ffe6ba40460fbf9f7f00ad667d75","object":"list","created":1737847944,"model":"BAAI/bge-reranker-v2-m3","data":[{"index":0,"object":"score","score":0.001094818115234375},{"index":1,"object":"score","score":1.0}],"usage":{"prompt_tokens":37,"total_tokens":37,"completion_tokens":0,"prompt_tokens_details":null}}},"error":null}

더 알아보기 (Learn more)