렌더러 API
렌더러 API (Renderer APIs)
렌더러(renderer) API는 분리 서빙(disaggregated serving)에서 중요한 역할을 해요. 요청을 토큰 ID로 바꾸는 전처리 단계를 GPU 없이 분리해서, 엔진을 순수한 token-in / token-out 서비스로 만들 수 있어요. 이 페이지에서 렌더러 API의 개요를 살펴볼게요.
렌더러 API는 render 단계(전처리)를 분리하고 token-in / token-out API 서버를 가능하게 하도록 설계됐어요.
- 프론트엔드의 GPU-less 배포: 전처리(토크나이제이션, MM 입력 처리)와 후처리(디토크나이제이션, tool call 파싱, reasoning 파싱)를 GPU 없이 실행할 수 있게 해요.
- 분리된 토크나이제이션: llm-d, Dynamo, 커스텀 프론트엔드처럼 vLLM의 전처리 로직만 필요로 하는 사용 사례를 지원해요. 전체 추론 엔진은 돌릴 필요 없이요.
- token-in / token-out 엔진: 엔진을 요청 전처리와 분리된 순수 token-in / token-out 서비스로 만들어요.
전용 vllm launch render 서버는 VLLM_ENABLE_SCALE_OUT_ENDPOINTS가 설정되지 않았거나 1일 때 항상 /render와 /derender 엔드포인트를 노출해요. 명시적 값 0은 렌더러 명령과 충돌하므로 시작 시 거부돼요.
/render, /derender, /inference/v1/generate를 포함한 확장(scale-out) 엔드포인트는 표준 추론 서버에서 기본적으로 비활성화돼요. vllm serve로 노출하려면 명시적으로 opt-in해야 해요.
VLLM_ENABLE_SCALE_OUT_ENDPOINTS=1 vllm serve <model>
API 참조 (API Reference)
- Completions Render API (
/v1/completions/render)- 완성 요청 렌더링.
- Chat Completions Render API (
/v1/chat/completions/render)- 챗 완성 렌더링.
- Responses Render API (
/v1/responses/render)- 자체 포함된 Responses 요청 렌더링.
Responses render 엔드포인트는 /v1/responses와 동일한 프롬프트 구성을 사용하고 token-in GenerateRequest 하나를 반환해요. 이는 무상태(stateless)예요. 인라인 히스토리는 지원하지만 previous_response_id는 지원하지 않아요. 호출자는 저장된 응답 상태를 해결하고 결과 히스토리를 요청에 포함한 뒤 렌더링해야 해요.
멀티모달 요청의 경우 GenerateRequest에는 모델이 처리한 멀티모달 페이로드가 포함돼요. 이는 소스 이미지나 비디오보다 훨씬 클 수 있어요. 호출자는 그 페이로드를 변경 없이 생성 서비스로 전달하고, 전송 한도와 메모리를 그에 맞게 준비해야 해요.
curl http://localhost:8000/v1/responses/render \
-H "Content-Type: application/json" \
-d '{
"model": "meta-llama/Llama-3.1-8B-Instruct",
"input": "Explain prefix caching in one sentence.",
"max_output_tokens": 32
}'
생성된 토큰 ID를 다시 OpenAI 호환 응답으로 바꾸는 후처리 대응물은 디렌더러 API를 참고하세요.
멀티모달 렌더 기능 (Multimodal Render Features)
멀티모달 렌더 응답에는 modality별 해시, placeholder 범위, 직렬화된 프로세서 데이터가 있는 features 객체가 포함돼요. 모델이 placeholder-metadata나 keep_on_cpu 필드(예: image_grid_thw)를 노출하면 응답에 mm_metadata도 포함돼요. 각 mm_metadata 항목은 그 필드들만 담은 base64 인코딩된 MultiModalKwargsItem이에요. pixel_values 같은 인코더 입력은 포함하지 않아요.
mm_hashes, mm_placeholders, kwargs_data, mm_metadata의 배열은 같은 modality별 항목 순서를 사용해요. 다운스트림 worker는 이 필드들을 나눠야 해요.
- Encode 요청은
kwargs_data를 유지해요. - Prefill 요청은
ec_transfer_params도 설정된 경우에만kwargs_data를 생략하고mm_metadata만 보낼 수 있어요. 임베딩은 EC 커넥터가 로드하기 때문이에요.ec_transfer_params없이kwargs_data를 생략하면 거부돼요. mm_metadata를 무시하고kwargs_data를 계속 보내는 레거시 클라이언트도 여전히 작동해요.
예제 (Example)
아래 예시는 분리된 encode/prefill 코디네이터가 멀티모달 렌더 응답을 나누는 방법을 보여줘요. render 단계는 kwargs_data(인코더 텐서 + 메타데이터)와 mm_metadata(메타데이터만) 모두를 반환해요. Encode는 전체 페이로드를 유지하고, prefill은 EC 커넥터가 임베딩을 게시한 뒤 kwargs_data를 버려요.
import httpx
MODEL = "Qwen/Qwen3-VL-2B-Instruct"
RENDER = "http://localhost:8100" # vllm launch render ...
ENCODE = "http://localhost:8200" # encode worker
PREFILL = "http://localhost:8300" # prefill worker
chat_request = {
"model": MODEL,
"messages": [
{
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": "<data-url>"}},
{"type": "text", "text": "Describe this image."},
],
}
],
}
with httpx.Client(timeout=120.0) as client:
# 1. Render: preprocess into token IDs and multimodal features.
render_response = client.post(
f"{RENDER}/v1/chat/completions/render", json=chat_request
).json()
features = render_response["features"]
# 2. Encode: send full kwargs_data so the encoder can run vision towers.
encode_response = client.post(
f"{ENCODE}/inference/v1/generate",
json={
"token_ids": render_response["token_ids"],
"features": {
"mm_hashes": features["mm_hashes"],
"mm_placeholders": features["mm_placeholders"],
"kwargs_data": features["kwargs_data"],
},
"sampling_params": {"max_tokens": 1},
},
).json()
ec_transfer_params = encode_response["ec_transfer_params"]
# 3. Prefill: omit kwargs_data; load embeddings via EC connector.
prefill_response = client.post(
f"{PREFILL}/inference/v1/generate",
json={
"token_ids": render_response["token_ids"],
"features": {
"mm_hashes": features["mm_hashes"],
"mm_placeholders": features["mm_placeholders"],
"mm_metadata": features["mm_metadata"],
},
"ec_transfer_params": ec_transfer_params,
"sampling_params": {"max_tokens": 64},
},
).json()
print(prefill_response["choices"][0]["token_ids"])
단일 프로세스 클라이언트는 kwargs_data가 있을 때 mm_metadata가 선택적이고 무시되므로, 전체 렌더 응답을 /inference/v1/generate에 변경 없이 계속 넘길 수 있어요.