vLLM 워커에 요청 보내기
vLLM 워커에 요청 보내기
vLLM 워커는 다른 RunPod Serverless 엔드포인트와 같은 /run, /runsync 연산을 써요. 차이는 입력 형식이에요. 텍스트 생성을 위해 vLLM이 기대하는 건 프롬프트, 메시지, 샘플링 파라미터랍니다.
출처: vLLM 워커에 요청 보내기
입력 형식
메시지(Messages, 채팅 모델)
instruction-tuned 모델에 쓰는 형식이에요. 워커가 모델의 채팅 템플릿을 자동으로 적용해 줘요.
{
"input": {
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is the capital of France?"}
],
"sampling_params": {
"temperature": 0.7,
"max_tokens": 100
}
}
}
프롬프트(Prompt, 텍스트 완성)
베이스 모델이나 채팅 템플릿 없이 원문 텍스트를 줄 때 쓰는 형식이에요.
{
"input": {
"prompt": "The capital of France is",
"sampling_params": {
"temperature": 0.7,
"max_tokens": 50
}
}
}
프롬프트에 모델의 채팅 템플릿을 적용하고 싶다면 "apply_chat_template": true를 추가해요.
요청 보내기
비동기(/run) — 백그라운드에서 처리되는 잡을 제출하고 /status/{job_id}를 폴링해 결과를 받아요.
import requests
response = requests.post(
"https://api.runpod.ai/v2/ENDPOINT_ID/run",
headers={
"Authorization": "Bearer RUNPOD_API_KEY",
"Content-Type": "application/json"
},
json={
"input": {
"messages": [{"role": "user", "content": "Explain quantum computing."}],
"sampling_params": {"temperature": 0.7, "max_tokens": 200}
}
}
)
job_id = response.json()["id"]
print(f"Job ID: {job_id}")
# Poll for results
status = requests.get(
f"https://api.runpod.ai/v2/ENDPOINT_ID/status/{job_id}",
headers={"Authorization": "Bearer RUNPOD_API_KEY"}
)
print(status.json())
동기(/runsync) — 한 번의 요청으로 완전한 응답을 기다려요.
import requests
response = requests.post(
"https://api.runpod.ai/v2/ENDPOINT_ID/runsync",
headers={
"Authorization": "Bearer RUNPOD_API_KEY",
"Content-Type": "application/json"
},
json={
"input": {
"messages": [{"role": "user", "content": "Explain quantum computing."}],
"sampling_params": {"temperature": 0.7, "max_tokens": 200}
}
}
)
print(response.json())
스트리밍
완전한 응답을 기다리는 대신 토큰이 생성되는 대로 받아 볼 수 있어요.
import requests
import json
# Submit with streaming enabled
response = requests.post(
"https://api.runpod.ai/v2/ENDPOINT_ID/run",
headers={
"Authorization": "Bearer RUNPOD_API_KEY",
"Content-Type": "application/json"
},
json={
"input": {
"prompt": "Write a short story about a robot.",
"sampling_params": {"temperature": 0.8, "max_tokens": 500},
"stream": True
}
}
)
job_id = response.json()["id"]
# Stream results
stream_url = f"https://api.runpod.ai/v2/ENDPOINT_ID/stream/{job_id}"
with requests.get(stream_url, headers={"Authorization": "Bearer RUNPOD_API_KEY"}, stream=True) as r:
for line in r.iter_lines():
if line:
print(json.loads(line))
샘플링 파라미터
모델이 텍스트를 어떻게 생성할지 제어하는 파라미터예요. 요청의 sampling_params 객체에 넣어요.
공통 파라미터
| Parameter | Type | Default | Description |
|---|---|---|---|
max_tokens |
int |
16 |
생성할 최대 토큰 수 |
temperature |
float |
1.0 |
샘플링 무작위성. 낮을수록 결정적 |
top_p |
float |
1.0 |
고려할 상위 토큰의 누적 확률 |
top_k |
int |
-1 |
고려할 상위 토큰 수. -1 = 전부 |
stop |
string or list |
None |
이 문자열이 나오면 생성 중단 |
presence_penalty |
float |
0.0 |
출력에 등장한 토큰 페널티 |
frequency_penalty |
float |
0.0 |
빈도 기반 토큰 페널티 |
고급 파라미터
| Parameter | Type | Default | Description |
|---|---|---|---|
n |
int |
1 |
생성할 출력 시퀀스 수 |
best_of |
int |
n |
이만큼 생성 후 상위 n 반환 |
repetition_penalty |
float |
1.0 |
반복 토큰 페널티. 1보다 크면 반복 억제 |
min_p |
float |
0.0 |
상위 토큰 대비 최소 확률 임계값 |
min_tokens |
int |
0 |
EOS 허용 전 최소 토큰 수 |
use_beam_search |
bool |
false |
샘플링 대신 beam search 사용 |
length_penalty |
float |
1.0 |
beam search 길이 페널티 |
early_stopping |
bool |
false |
beam search 조기 중단 |
stop_token_ids |
list[int] |
None |
생성을 중단하는 토큰 ID |
ignore_eos |
bool |
false |
EOS 토큰 뒤에도 계속 생성 |
skip_special_tokens |
bool |
true |
출력에서 특수 토큰 생략 |
spaces_between_special_tokens |
bool |
true |
특수 토큰 사이에 공백 추가 |
truncate_prompt_tokens |
int |
None |
프롬프트를 이 토큰 수로 자르기 |
스트리밍 파라미터
| Parameter | Type | Default | Description |
|---|---|---|---|
stream |
bool |
false |
스트리밍 출력 활성화 |
max_batch_size |
int |
env default | 스트리밍 청크별 최대 토큰 수 |
min_batch_size |
int |
env default | 스트리밍 청크별 최소 토큰 수 |
batch_size_growth_factor |
int |
env default | 배치 크기 성장 계수 |
오류 처리
네트워크 문제, 요금 제한, 콜드 스타트를 다루려면 지수 백오프(exponential backoff) 방식의 재시도 로직을 넣는 걸 권장해요.
import requests
import time
def send_request(url, headers, payload, max_retries=3):
for attempt in range(max_retries):
try:
response = requests.post(url, headers=headers, json=payload, timeout=300)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
if e.response.status_code == 429: # Rate limit
time.sleep(5)
elif e.response.status_code >= 500:
time.sleep(2 ** attempt)
else:
raise
except requests.exceptions.RequestException:
time.sleep(2 ** attempt)
raise Exception("Max retries exceeded")