# Disaggregated Encoder A **disaggregated encoder** runs the vision-encoder stage of a multimodal LLM in a process that is separate from the pre-fill / decoder stage. Deploying these two stages in independent vLLM instances brings three practical benefits: 1. **Independent, fine-grained scaling** 2. **Lower time-to-first-token (TTFT)** 3. **Cross-process reuse and caching of encoder outputs** Design doc: --- ## 1 Motivation ### 1. Independent, fine-grained scaling * Vision encoders are lightweight, while language models are orders of magnitude larger. * The language model can be parallelised without affecting the encoder fleet. * Encoder nodes can be added or removed independently. ### 2. Lower time-to-first-token (TTFT) * Language-only requests bypass the vision encoder entirely. * Encoder output is injected only at required attention layers, shortening the pre-fill critical path. ### 3. Cross-process reuse and caching * In-process encoders confine reuse to a single worker. * A remote, shared cache lets any worker retrieve existing embeddings, eliminating redundant computation. --- ## 2 Usage Example ### ExampleConnector The following scripts demonstrate the workflow with **ExampleConnector**: 1 Encoder instance + 1 PD instance: `examples/disaggregated/disaggregated_encoder/disagg_1e1pd_example.sh` 1 Encoder instance + 1 Prefill instance + 1 Decode instance: `examples/disaggregated/disaggregated_encoder/disagg_1e1p1d_example.sh` ### ECMooncakeConnector **ECMooncakeConnector** transfers encoder outputs using the Mooncake TransferEngine. See the [Mooncake integration example](../../tests/v1/ec_connector/integration/run_epd_mooncake_ec_full_pipeline.sh) for a complete 1 Encoder instance + 1 PD instance setup, including the producer and consumer `--ec-transfer-config` settings and proxy configuration. With vLLM and Mooncake installed, run the example from the repository root: ```bash GPU_E=0 GPU_PD=1 MOONCAKE_EC_PROTOCOL=tcp \ bash tests/v1/ec_connector/integration/run_epd_mooncake_ec_full_pipeline.sh ``` The script uses `Qwen/Qwen2.5-VL-3B-Instruct` by default, runs a single-GPU baseline, and compares the disaggregated outputs against it. Set `MODEL` to use another model or `MOONCAKE_EC_PROTOCOL=rdma` to use RDMA on supported hardware. See the script for additional configuration options. --- ## 3 Test Script For optional cross-Encoder output reuse while retaining Mooncake P2P delivery, see [Cross-encoder output reuse](cross_encoder_cache.md). Please refer to the directories `tests/v1/ec_connector` ## 4 Development Disaggregated encoding is implemented by running two parts: * **Encoder instance** – a vLLM instance to performs vision encoding. * **Prefill/Decode (PD) instance(s)** – runs language pre-fill and decode. * PD can be in either a single normal instance with `disagg_encoder_example.sh` (E->PD) or in disaggregated instances with `disagg_epd_example.sh` (E->P->D) A connector transfers encoder-cache (EC) embeddings from the encoder instance to the PD instance. All related code is under `vllm/distributed/ec_transfer`. ### Key abstractions * **ECConnector** – interface for retrieving EC caches produced by the encoder. * *Scheduler role* – checks cache existence and schedules loads. * *Worker role* – loads the embeddings into memory. Here is a figure illustrating disaggregate encoder flow: ![Disaggregated Encoder Flow](../assets/features/disagg_encoder/disagg_encoder_flow.png) For the PD disaggregation part, the Prefill instance receives cache exactly the same as the disaggregated encoder flow above. Prefill instance executes 1 step (prefill -> 1 token output) and then transfers KV cache to the Decode instance for the remaining execution. The KV transfer part purely happens after the execution of the PD instance. `docs/features/disagg_prefill.md` shows the brief idea about the disaggregated prefill (v0) We create the example setup with the **NixlConnector** from `vllm/distributed/kv_transfer/kv_connector/v1/nixl/` and referred to the `tests/v1/kv_connector/nixl_integration/toy_proxy_server.py` to facilitate the kv transfer between P and D;