Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:Mlc ai Mlc llm Microserving Endpoints

From Leeroopedia


Knowledge Sources
Domains Deep_Learning, Distributed_Serving
Last Updated 2026-02-09 00:00 GMT

Overview

Concrete tool for disaggregating the prefill and decode phases of autoregressive LLM inference across separate GPU instances, provided by MLC-LLM.

Description

The microserving endpoints module exposes three FastAPI HTTP endpoints that implement the three-step disaggregated serving protocol. Each endpoint is registered on a per-engine server instance and translates microserving-specific request parameters into the engine's internal DisaggConfig before delegating to the standard request_completion handler:

  • /microserving/prep_recv: Invoked on the decode instance. Allocates KV cache entries for the incoming prompt, checks the prefix cache for already-cached portions, and returns metadata (KV append addresses and prefix match length) that the prefill instance needs to perform direct GPU memory writes.
  • /microserving/remote_send: Invoked on the prefill instance. Computes the KV cache for the specified prompt range and uses NVSHMEM to transfer the data directly into the decode instance's GPU memory at the addresses provided by prep_recv. Returns an empty acknowledgment on completion.
  • /microserving/start_generate: Invoked on the decode instance after KV transfer is complete. Performs any remaining local prefill for the tail of the prompt and begins autoregressive decode, returning generated tokens as a streaming or non-streaming completion response.

All three endpoints internally set the appropriate DisaggConfig on the request's debug_config field, which instructs the engine to execute the correct disaggregated operation rather than a standard completion.

Usage

These endpoints are not called directly by users. They are invoked by the Router class during disaggregated request handling. Each MLC-LLM engine server automatically registers these endpoints when started in server mode. The router orchestrates the three-step protocol by making HTTP POST requests to these endpoints on the appropriate engine instances.

Code Reference

Source Location

  • Repository: MLC-LLM
  • File: python/mlc_llm/serve/entrypoints/microserving_entrypoints.py (Lines 22-73)
  • Protocol definitions: python/mlc_llm/protocol/microserving_protocol.py

Signatures

Endpoint 1: prep_recv

@app.post("/microserving/prep_recv")
async def prep_recv(
    request: PrepRecvRequest,
    raw_request: fastapi.Request,
) -> PrepRecvResponse:

Endpoint 2: remote_send

@app.post("/microserving/remote_send")
async def remote_send(
    request: RemoteSendRequest,
    raw_request: fastapi.Request,
) -> dict:

Endpoint 3: start_generate

@app.post("/microserving/start_generate")
async def start_generate(
    request: StartGenerateRequest,
    raw_request: fastapi.Request,
) -> Response:

Import

# The endpoints are registered as a FastAPI APIRouter
from mlc_llm.serve.entrypoints.microserving_entrypoints import app

# Protocol models used by the endpoints
from mlc_llm.protocol.microserving_protocol import (
    PrepRecvRequest,
    PrepRecvResponse,
    RemoteSendRequest,
    StartGenerateRequest,
)

I/O Contract

Endpoint 1: prep_recv

Inputs:

Name Type Required Description
request PrepRecvRequest Yes Extends CompletionRequest with an additional end field. Contains the full prompt and the KV window end index. The end field specifies the upper bound of the KV range ([0, end]) to allocate on the decode instance. Supports Python-style negative indexing (e.g., -1 means len(prompt) - 1).
raw_request fastapi.Request Yes The raw FastAPI request object, passed through to the engine for disconnection detection.

Outputs:

Name Type Description
(response) PrepRecvResponse A Pydantic model containing two fields: kv_append_metadata (a base64-encoded string describing the GPU memory addresses where KV data should be written) and prefix_matched_length (an integer indicating how many tokens of the prompt are already cached on the decode instance).

Endpoint 2: remote_send

Inputs:

Name Type Required Description
request RemoteSendRequest Yes Extends CompletionRequest with four additional fields: begin (start of the KV range to compute), end (end of the KV range to compute), kv_addr_info (base64-encoded metadata from prep_recv specifying destination GPU memory addresses), and recv_rank (the NVSHMEM PE offset of the destination decode instance).
raw_request fastapi.Request Yes The raw FastAPI request object.

Outputs:

Name Type Description
(response) dict An empty dictionary ({}) serving as an acknowledgment that the prefill computation and KV transfer have completed.

Endpoint 3: start_generate

Inputs:

Name Type Required Description
request StartGenerateRequest Yes Extends CompletionRequest with an additional begin field specifying the start of the KV range for local prefill on the decode instance. The range [begin:] will be prefilled locally before decode begins.
raw_request fastapi.Request Yes The raw FastAPI request object.

Outputs:

Name Type Description
(response) Response A standard completion response (streaming or non-streaming) as returned by request_completion. In streaming mode, this is a server-sent events stream of CompletionResponse chunks. In non-streaming mode, this is a single JSON CompletionResponse.

Usage Examples

Basic Usage

import aiohttp
import json

# These endpoints are called by the Router, not directly by users.
# This example shows the HTTP-level interaction for educational purposes.

async def disaggregated_completion(prompt_tokens, prefill_url, decode_url):
    headers = {"Content-Type": "application/json"}
    async with aiohttp.ClientSession() as session:
        # Step 1: Ask decode instance to prepare for receiving KV data
        prep_payload = {
            "prompt": prompt_tokens,
            "end": -1,  # full prompt minus last token
            "stream": False,
        }
        async with session.post(
            f"{decode_url}/microserving/prep_recv",
            json=prep_payload,
            headers=headers,
        ) as resp:
            data = await resp.json()
            kv_metadata = data["kv_append_metadata"]
            prefix_len = data["prefix_matched_length"]

        # Step 2: Ask prefill instance to compute and transfer KV
        kv_window_end = len(prompt_tokens) - 1
        if prefix_len < kv_window_end:
            send_payload = {
                "prompt": prompt_tokens,
                "begin": prefix_len,
                "end": kv_window_end,
                "kv_addr_info": kv_metadata,
                "recv_rank": 1,  # decode instance PE offset
                "stream": False,
            }
            async with session.post(
                f"{prefill_url}/microserving/remote_send",
                json=send_payload,
                headers=headers,
            ) as resp:
                await resp.json()  # wait for ack

        # Step 3: Ask decode instance to start generating
        gen_payload = {
            "prompt": prompt_tokens,
            "begin": kv_window_end,
            "stream": True,
            "max_tokens": 100,
        }
        async with session.post(
            f"{decode_url}/microserving/start_generate",
            json=gen_payload,
            headers=headers,
        ) as resp:
            async for chunk in resp.content:
                chunk = chunk.strip()
                if chunk and chunk != b"\n":
                    raw = chunk[6:].strip()
                    if raw != b"[DONE]":
                        print(json.loads(raw))

Related Pages

Implements Principle

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment