분리형 인코더
분리형 인코더 (Disaggregated Encoder)
멀티모달 LLM은 텍스트 생성 이전에 이미지/비디오를 "이해"하는 비전 인코더(vision encoder) 단계를 거쳐요. 분리형 인코더(Disaggregated Encoder) 는 이 비전 인코더 단계를, 프리필/디코더 단계와 별도의 프로세스로 분리해서 실행하는 방식이에요. 각 단계를 독립적인 vLLM 인스턴스로 배포하면 여러 실용적인 이점이 생깁니다.
왜 분리할까요? 세 가지 실용적 이점
두 단계를 독립적인 vLLM 인스턴스로 배포하면 다음 세 가지 장점이 생겨요.
- 프로세스 간 인코더 출력의 재사용과 캐싱 (Cross-process reuse and caching of encoder outputs)
- 첫 토큰까지의 시간(TTFT) 단축 (Lower time-to-first-token)
- 독립적이고 세밀한 스케일링 (Independent, fine-grained scaling)
설계 문서: https://docs.google.com/document/d/1aed8KtC6XkXtdoV87pWT0a8OJlZ-CpnuLLzmR8l9BAE
동기 (Motivation)
1. 독립적이고 세밀한 스케일링
- 인코더 노드는 독립적으로 추가/제거할 수 있어요.
- 인코더 플릿에 영향을 주지 않고 언어 모델만 병렬화할 수 있죠.
- 비전 인코더는 가볍지만, 언어 모델은 그보다 몇 자릿수 더 큽니다. 따라서 성장률이 다른 두 부분을 각각 맞춰 확장할 수 있다는 게 큰 장점이에요.
2. 첫 토큰까지의 시간(TTFT) 단축
- 인코더 출력은 필요한 어텐션 레이어에만 주입되기 때문에, 프리필의 핵심 경로(critical path)가 짧아져요.
- 언어 전용 요청은 비전 인코더를 완전히 건너뜁니다. 텍스트만 쓰는 요청이 이미지 처리 때문에 지연될 일이 없어지죠.
3. 프로세스 간 재사용과 캐싱
- 원격의 공유 캐시를 사용하면 어떤 워커든 기존 임베딩을 가져와 쓸 수 있어서, 중복 계산이 사라져요.
- 반면 프로세스 내 인코더(in-process encoder) 는 재사용 범위가 단일 워커로 제한됩니다.
사용 예시 (Usage Example)
현재 참조 경로(reference pathway)는 ExampleConnector예요. 바로 실행 가능한 스크립트들이 워크플로를 보여줍니다.
- 인코더 1개 + PD 1개 인스턴스:
examples/online_serving/disaggregated_encoder/disagg_1e1pd_example.sh - 인코더 1개 + 프리필 1개 + 디코드 1개 인스턴스:
examples/online_serving/disaggregated_encoder/disagg_1e1p1d_example.sh
테스트 스크립트 (Test Script)
tests/v1/ec_connector 디렉토리를 참고하세요.
개발 세부 사항 (Development)
분리형 인코딩은 두 부분을 실행하는 방식으로 구현돼요.
프리필/디코드(PD) 인스턴스 — 언어 프리필과 디코드를 수행합니다.
- PD는
disagg_encoder_example.sh(E→PD)처럼 하나의 일반 인스턴스일 수도 있고,disagg_epd_example.sh(E→P→D)처럼 분리된 인스턴스일 수도 있어요.
커넥터(Connector) — 인코더 인스턴스에서 PD 인스턴스로 인코더 캐시(EC) 임베딩을 전송합니다. 관련 코드는 모두 vllm/distributed/ec_transfer 아래에 있어요.
핵심 추상화 (Key abstractions)
- ECConnector — 인코더가 만든 EC 캐시를 가져오기 위한 인터페이스예요.
- 워커(Worker) 역할 — 임베딩을 메모리에 로드합니다.
- 스케줄러(Scheduler) 역할 — 캐시 존재 여부를 확인하고 로드를 스케줄링해요.
분리된 프리필(P→D) 부분에서는, 프리필 인스턴스가 위의 분리형 인코더 흐름과 똑같이 캐시를 받아요. 프리필 인스턴스는 1단계(프리필 → 토큰 1개 출력)를 수행한 뒤, 나머지 실행을 위해 KV 캐시를 디코드 인스턴스로 전송합니다. KV 전송은 PD 인스턴스의 실행 이후에 순수하게 발생하죠.
프리필 분리에 대한 간단한 개념은 docs/features/disagg_prefill.md에서 확인할 수 있어요. 예시 구성은 vllm/distributed/kv_transfer/kv_connector/v1/nixl_connector.py의 NixlConnector를 사용하며, tests/v1/kv_connector/도 참고하면 됩니다.