LLM ServingJuly 27, 2026 · 18 min read

From AFD Experiment to an Evidence-Driven vLLM Roadmap

The vLLM AFD Plugin makes Attention and FFN independently deployable. The harder next step is making every compatibility, model, backend, and topology claim independently verifiable.

By Hongsheng Liu

Why split Attention from FFN?

Mixture-of-Experts inference combines two workloads with different scaling pressures. Attention is stateful: it owns scheduling, sequence state, and the KV cache. The FFN or expert path is dominated by routed computation and all-to-all communication. A shared worker topology forces both paths into the same resource allocation even when their bottlenecks differ.

Attention–FFN Disaggregation (AFD) preserves vLLM's request-facing control plane while moving expert execution behind a narrow connector interface. Attention and FFN ranks can then scale independently, and backend-specific communication can evolve without leaking into the serving API.

Request path

Attention service

API, scheduler, batching, KV cache, model lifecycle, and sampling

Data path

AFD connector

Hidden states, routing metadata, graph state, and returned FFN outputs

Expert path

FFN service

Lightweight daemon for expert computation without request traffic or KV cache

FFN results return through the connector before the Attention path continues.

What the first release establishes

The plugin integrates through vllm.general_plugins and --additional-config, without modifying the vLLM source tree. Its current matrix includes NVIDIA GPU and Ascend NPU paths, synchronous decode and asynchronous prefill connectors, and wrappers for DeepSeek V2/V3-family and GLM MoE models.

Synchronous decode

P2P NCCL on GPU and CAMP2P/HCCL on NPU exchange activations and FFN outputs synchronously. Their current graph paths are decode-only.

Asynchronous prefill

CAM asynchronous dispatch and combine operators overlap Attention and FFN stages with AFD-managed MoE ubatching. Graph execution is not yet supported on this path.

Reading the architecture from the code

AFD is not implemented as one large fork of vLLM. It is a chain of deliberately small interception points: plugin registration selects AFD-aware workers and model classes; the Attention runner injects execution metadata; the model wrapper introduces the layer boundary; and a connector-driven FFN runner consumes that boundary.

Source fileRuntime responsibilityArchitectural consequence
afd_plugin/__init__.pyPlugin bootstrapRegisters AFD model architectures and installs narrow compatibility hooks through vllm.general_plugins.
afd_plugin/v1/worker/attention_model_runner.pyAttention control pathBuilds per-stage AFD metadata, injects it into vLLM's ForwardContext, and sends DP shape metadata.
afd_plugin/model_executor/models/deepseek_v2.pyLayer split pointConstructs role-specific modules and replaces the ordinary layer loop with send/receive boundaries around FFN.
afd_plugin/v1/worker/ffn_worker.pyFFN service lifecycleStarts the connector-driven daemon, rejects scheduler execution, and allocates no KV cache.
afd_plugin/v1/worker/ffn_model_runner.pyExpert executionIterates layer and microbatch stages, receives hidden states, calls compute_ffn_output(), and returns results.
afd_plugin/connectors/base.pyBackend-neutral contractDefines the four tensor-transfer operations and the separate DP metadata control-plane interface.
afd_plugin/connectors/gpu/p2p.pyCUDA transportImplements NCCL subgroup fan-in, token concatenation, output splitting, and graph-stable receive buffers.

1. Bootstrap: change the model lifecycle, not the API

The package exposes afd_plugin:register_afd as a vllm.general_plugins entry point. Registration maps native architecture names to plugin-owned wrappers such as AFDDeepseekV3ForCausalLM. Worker initialization then rewrites the model configuration to select that registered architecture.

This is why clients still use vllm serve. The public engine and OpenAI-compatible endpoint remain on the Attention service; the substitution happens below the serving interface, at worker and model construction time.

Conceptual bootstrap path
vllm serve
  └─ general_plugins entry point
      └─ register AFD model architectures
          └─ parse additional_config["afd"]
              ├─ role="attention" → AFDAttentionWorker
              └─ role="ffn"       → AFDFFNWorker
                  └─ rewrite model architecture → AFD model wrapper

2. Role-specific construction removes unused state

The DeepSeek decoder wrapper does more than skip half of a normal forward pass. During construction, each role creates only the modules it needs. The Attention layer builds self-attention and request-facing state; the FFN layer builds dense MLP or MoE modules. On the FFN worker, get_kv_cache_spec() returns an empty mapping and sampling is explicitly unsupported.

OwnershipAttention workerFFN worker
Request lifecycle and schedulerOwnsNone
KV cache and attentionOwnsNone
Embeddings, norm, residual, samplingOwnsNone
Dense or MoE FFN modulesRole-dependentOwns
Expert execution loopNoneConnector-driven
Connector and transfer metadataSends / receivesReceives / sends

One subtlety: normalization and other shared lifecycle components may exist on both role-specific wrappers where the upstream model-loading contract requires them. “Split” means role-required construction, not a blanket claim that every non-expert parameter exists on only one side.

3. One layer, end to end

The actual split point lives inside the model wrapper's layer loop. Attention computes through post-attention normalization, sends that hidden state to FFN, and later receives the expert result. The residual stays on the Attention side, preserving request-local transformer state.

01

Prepare step metadata

The Attention runner records token counts, stage IDs, graph flags, and a transaction ID in ForwardContext.

02

Receive the prior FFN result

From layer 1 onward, Attention first receives the previous layer's returned FFN tensor.

03

Run Attention locally

The wrapper executes input norm, self-attention, residual handling, and post-attention norm.

04

Dispatch the split tensor

The connector sends the normalized hidden states with layer/stage/token metadata.

05

Aggregate on FFN

The GPU P2P path concatenates tensors from the Attention peers mapped to the same FFN rank.

06

Compute experts

The FFN runner calls the model wrapper's compute_ffn_output(hidden_states, layer_idx).

07

Split and return

The connector slices the aggregate output by the original per-peer token lengths and sends each slice home.

08

Complete the model

After the last dispatch, Attention performs one final receive, then continues to final norm and sampling.

Simplified execution pseudocode
# Attention process
for layer in layers:
    previous_ffn = receive_if_pending()
    attn_state, residual = layer.compute_attention(previous_ffn, residual)
    send_to_ffn(attn_state, layer_id, microbatch_id)
final_state = receive_last_ffn()
sample(final_norm(final_state, residual))

# FFN process: driven by connector metadata, not request scheduling
for layer_id in layers:
    for microbatch_id in active_stages:
        aggregate, transfer = receive_attention_states()
        expert_output = model.compute_ffn_output(aggregate, layer_id)
        split_and_return(expert_output, transfer.peer_token_lengths)

4. The connector is a two-plane protocol

The connector abstraction separates tensor movement from execution coordination. The data plane has four symmetric operations; the control plane carries per-stage DP token counts and warmup or graph-capture state so the FFN side can allocate the correct buffers before tensors arrive.

Control plane

  • • stage → DP token-count metadata
  • • graph-capture and warmup flags
  • • receive shape and reusable-buffer preparation
  • • triggers the connector-driven FFN step

Tensor data plane

  • send_attn_output()
  • recv_attn_output()
  • send_ffn_output()
  • recv_ffn_output()

Each transfer carries backend-neutral layer_idx, stage_idx, and per-peer sequence lengths. Backends can attach their own transfer state without changing the model-facing call sites. That is what lets NCCL P2P, CAMP2P/HCCL, and asynchronous CAM share one layer loop.

5. GPU topology: fan in, compute, fan out

For P2pNcclAFDConnector, global ranks are ordered FFN first, then Attention. The current topology requires at least as many Attention ranks as FFN ranks and an integer ratio. Each FFN rank owns one subgroup of consecutive Attention peers.

Attention A0 · t₀ tokens
Attention A1 · t₁ tokens
Attention A2 · t₂ tokens
concat
FFN F0
shape = (t₀+t₁+t₂, hidden)
larger expert batch
split [t₀,t₁,t₂]
result for A0
result for A1
result for A2

The important systems effect is aggregation: FFN sees tokens from several independently scheduled Attention lanes as one expert batch. The cost is a round trip at every split layer. AFD wins only when improved expert utilization and independent capacity planning outweigh communication, synchronization, and the extra FFN devices.

6. Ubatching turns the round trip into a pipeline

A synchronous implementation that executes Attention, sends, waits for FFN, receives, and only then starts the next slice would serialize the new boundary. AFD's stage metadata and ubatch wrapper create multiple in-flight slices so Attention work for one stage can overlap FFN work for another.

Attention L₀
Stage 0
FFN L₀
Stage 0
Attention L₀
Stage 1
Attention L₁
Stage 0

Useful pipeline mental model

Tstep ≈ startup + max(TA, TF) × (mL − 1)

Here TA and TF are per-stage Attention and FFN times, m is the ubatch count, and L is the number of split layers. This simplified model, also used to reason about FastAFD-style pipelines, explains why balance matters: steady state is limited by the slower side. It is not a performance formula implemented by the plugin.

More stages are not automatically better. They create overlap but also multiply small-kernel launches, metadata handling, and graph shapes. The currently validated DBO path is intentionally limited to exactly two ubatches; the async CAM prefill path owns a separate ubatching mechanism and currently does not support graph execution.

7. The code makes invalid ownership fail fast

No scheduler-driven FFN

AFDFFNWorker.execute_model() raises instead of silently running request work on the expert service.

No FFN KV cache

The FFN worker returns an empty KV-cache specification and skips cache allocation.

No sampling on FFN

GPUFFNModelRunner.sample_tokens() raises; token selection remains request-local on Attention.

Exact role validation

Both model runners parse the same AFD config with an expected role, catching mismatched launches early.

Shape-checked transfers

Connector metadata validates the leading token dimension before send and return operations.

Backend isolation

Connector-specific configuration and transfer state stay behind the factory and base contract.

Early performance signals—and their limits

The announcement reports two focused experiments. They are useful because they expose both the opportunity and the main systems lesson: disaggregation only helps when the Attention-to-FFN allocation matches the workload.

ExperimentComparisonReported result
Ascend synchronous decode64A16F versus EP64+11.3% tokens/s/die at 16K input; +9.0% at 32K
Ascend asynchronous prefillAFD versus DP4PCP8 baseline at 12 req/sMedian TTFT from 15.1s to 8.0s, about 47% lower

Read these as path validation, not universal speedups.

The decode study used simulated logical scale and forced expert balancing that changes model outputs. The prefill study used a reduced 10-layer model. A smaller 48A16F decode allocation also trailed the EP64 baseline, reinforcing that topology selection is part of the result.

Support is a stack, not a checkbox

The roadmap's most important idea is to replace a global “supported” label with three evidence layers. A successful import does not validate a model, and a successful launch does not validate a production topology.

1

Core compatibility

The plugin works with one exact vLLM version.

Minimum evidence

Contract tests, package build/install, plugin-disabled isolation, and pinned-version checks.

2

Model + backend

A named model works correctly on a named backend.

Minimum evidence

Model review, correctness or accuracy results, exact environment, and backend-specific E2E tests.

3

Recipe + topology

A named topology has a reproducible, measured serving recipe.

Minimum evidence

Hardware and network disclosure, launch commands, correctness, performance, sustained load, and validation review.

Six workstreams, not six release phases

The roadmap is organized by dependency rather than calendar. Compatibility and delivery are foundational, while model, prefill, hardware, feasibility, and contributor-tooling work can advance in parallel when their prerequisites exist.

01

Compatibility, CI/CD, and releases

Define a maintainable vLLM alignment window, mirrored package versions, CPU-safe checks on every pull request, and tag-triggered GitHub and PyPI releases.

02

Model expansion

Adapt DeepSeek-V4 and GLM-5.2 through the native vLLM lifecycle, with backend validation and known exclusions documented per model.

03

Prefill and cache compatibility

Test chunked prefill and prefix caching independently and together, using long prompts and replayable coding-agent traces.

04

NVIDIA and AMD recipes

Build reproducible, topology-specific large-scale serving recipes with correctness, performance, sustained-load, and recovery evidence.

05

Kimi-K3 feasibility

Treat heterogeneous-attention prefill as a study first, and promote it to a support target only when measured goodput and tail TTFT justify it.

06

Repository-backed agent skills

Create thin orchestration skills for upgrades, model adaptation, hardware recipes, E2E tests, and releases while keeping deterministic logic in the repository.

Measure realistic prefill, not just launch success

The prefill workstream proposes a four-mode matrix: chunked prefill and prefix caching are tested with both features off, each enabled independently, and both enabled together. Correctness comes before performance interpretation.

Fixed 16K, 32K, and 128K prompts isolate long-context behavior. Multi-turn coding-agent trace replay adds growing shared prefixes and incremental tool output—the pattern that real agent systems produce. Reporting should include failure or hang behavior, TTFT tails, SLO-constrained prefill goodput, and cache effectiveness, not only averages.

The takeaway

AFD creates a clean systems boundary: keep vLLM's scheduler and KV-cache-aware Attention path intact, then make expert compute independently deployable through connectors. The launch proves that this boundary can work across multiple backends and execution modes.

The roadmap defines what must happen next: narrow version contracts, backend-specific model evidence, reproducible topology recipes, realistic workload evaluation, and honest negative results. That evidence discipline is what can turn a promising experimental plugin into durable serving infrastructure.

References

  1. 1.Announcing vLLM AFD Plugin: Disaggregating Attention and FFN for Flexible MoE Serving
  2. 2.[Draft] [RFC]: afd-plugin project roadmap
  3. 3.vLLM AFD Plugin repository
  4. 4.FastAFD architecture and performance analysis