프롬프트 임베딩 입력
프롬프트 임베딩 입력 (Prompt Embedding Inputs)
보통 LLM에 텍스트를 넣으면 토크나이저가 텍스트를 토큰 ID로 바꾸고, 그 토큰 ID를 다시 임베딩 행렬로 조회해서 임베딩 벡터를 얻는 흐름을 거쳐요. 하지만 vLLM은 이미 임베딩된 벡터를 직접 입력으로 넣는 것도 지원합니다. 이 페이지에서는 프롬프트 임베딩 입력(prompt embedding inputs) 을 vLLM에 전달하는 방법을 알려드릴게요.
프롬프트 임베딩이란? (What are prompt embeddings?)
LLM의 전통적인 텍스트 데이터 흐름은 다음과 같아요.
텍스트 → 토큰 ID (토크나이저) → 프롬프트 임베딩 (임베딩 행렬 조회)
일반적인 디코더 전용 모델(예: meta-llama/Llama-3.1-8B-Instruct)에서 토큰 ID를 프롬프트 임베딩으로 바꾸는 단계는 학습된 임베딩 행렬에서의 조회(look-up) 를 통해 이뤄져요. 하지만 모델은 반드시 자기 토큰 어휘에 해당하는 임베딩만 처리할 수 있는 건 아니에요. 즉, 외부에서 준비한 임베딩을 직접 주입할 수도 있죠.
오프라인 추론 (Offline Inference)
멀티모달 데이터를 입력하려면 vllm.inputs.EmbedsPrompt의 스키마를 따르면 돼요.
prompt_embeds: 토큰/프롬프트 임베딩의 시퀀스를 나타내는 torch tensor예요. 형태(shape)는(sequence_length, hidden_size)로,sequence_length는 토큰 임베딩 수,hidden_size는 모델의 히든 크기(임베딩 크기)예요.
Hugging Face Transformers 입력
Hugging Face Transformers 모델의 프롬프트 임베딩을 프롬프트 임베딩 딕셔너리의 'prompt_embeds' 필드에 전달할 수 있어요. 실제 예시는 examples/features/prompt_embed/prompt_embed_offline.py에서 확인할 수 있습니다.
온라인 서빙 (Online Serving)
OpenAI 호환 서버는 Completions API와 Chat Completions API 두 경로 모두에서 프롬프트 임베딩 입력을 받아요. 둘 다 vllm serve의 --enable-prompt-embeds 플래그로 활성화됩니다.
Completions API
프롬프트 임베딩 입력은 JSON 요청 본문의 'prompt_embeds' 키로 추가돼요.
- 단일 요청에서
'prompt_embeds'와'prompt'입력이 혼합되면, 프롬프트 임베딩이 항상 먼저 반환됩니다. - 프롬프트 임베딩은 base64로 인코딩된 torch tensor로 전달돼요.
- Completions 엔드포인트는
prompt_embeds에 채팅 템플릿을 적용하지 않아요. 모델이 특정 채팅 템플릿을 가정한다면, 호출자가 전체적인, 이미 템플릿이 적용된 프롬프트에 대한 임베딩을 생산해야 합니다. 즉, 채팅 템플릿을 먼저 적용하고, 그 결과 토큰 ID를 임베딩하면 돼요. 모델이 평소에 필요로 하는 것(시스템 프롬프트, 역할 마커, 생성 프롬프트 등)은 모두 임베딩된 토큰에 이미 녹아 있어야 해요.
Chat Completions API
프롬프트 임베딩은 채팅 메시지 안에서 텍스트와 인터리브(섞어) content part로 포함될 수 있어요.
{
"messages": [
{
"role": "system",
"content": [
{"type": "text", "text": "You are a helpful assistant."},
{"type": "prompt_embeds", "data": "<base64_encoded_tensor>"}
]
},
{
"role": "user",
"content": [
{"type": "prompt_embeds", "data": "<base64_encoded_tensor>"},
{"type": "text", "text": "Summarize the above."}
]
}
]
}
각 prompt_embeds content part는 (num_tokens, hidden_size) 형태의 base64 인코딩 torch.Tensor를 담은 data 필드를 포함해요. 여러 prompt_embeds part는 어떤 메시지에서도 텍스트 part와 상대적으로 어느 위치에나 올 수 있습니다. 서버는 채팅 템플릿 렌더링 중에 각 part를 올바른 수의 placeholder 토큰으로 확장한 뒤, 미리 계산된 임베딩을 모델 입력의 해당 위치에 이어 붙입니다.
Completions API와 달리, Chat Completions API의 prompt_embeds content part는 내용(content)만 인코딩해야 해요. 템플릿된 대화 전체가 아니라요. 서버는 요청 시점에 임베딩된 내용 주위를 채팅 템플릿으로 감싸는데, 이는 일반 텍스트 content 문자열에 하는 것과 같은 방식이에요. 만약 여기서 전체 템플릿 대화를 임베딩하면 템플릿이 두 번 적용되어 모델에 잘못된 입력이 생겨요.
⚠️ 경고: 잘못된 형태(shape)의 임베딩을 전달하면 vLLM 엔진이 크래시할 수 있습니다. 이 플래그는 신뢰할 수 있는 사용자에게만 켜야 해요!
OpenAI 클라이언트를 통한 Transformers 입력 (Transformers Inputs via OpenAI Client)
먼저 OpenAI 호환 서버를 실행합니다.
vllm serve meta-llama/Llama-3.1-2B-Instruct --runner generate \
--max-model-len 4096 --enable-prompt-embeds
그다음 OpenAI 클라이언트를 사용할 수 있어요. 실제 예시는 examples/features/prompt_embed/prompt_embed_inference_with_openai_client.py에서 확인할 수 있습니다.
핵심 요약
| 경로 | 템플릿 처리 | 임베딩 내용 |
|---|---|---|
Completions API (prompt_embeds 키) |
템플릿 적용 안 함 | 전체 템플릿된 프롬프트의 임베딩이어야 함 |
| Chat Completions API (content part) | 서버가 채팅 템플릿 적용 | 내용(content)만 인코딩해야 함 |