AFD Plugin Explained

AFD config reference: the additional_config["afd"] keys

IntermediateReferenceabout 6 min read

Code version: afd-plugin @ 7452d52 · 2026-10-27 · vLLM @ ced6857

In one sentence

This page lists every AFD config key, its alias, type, default and validation, and the connector_extra_config keys that each connector accepts.

How the config is passed#

You give AFD config to vLLM under one key. Each vllm serve process gets --additional-config '{"afd": { ... }}'. vLLM stores the outer mapping on its additional_config field (vllm:vllm/config/vllm.py:434). The plugin reads the inner "afd" mapping and builds an AFDConfig dataclass (afd_plugin/config.py:42).

The two tables in the next section are generated from the source. The validation, read-site and example tables that follow are hand-written, each row with a citation.

The keys#

The build generates the tables below from AFDConfig and the connector source, so the names, types, defaults and lines stay correct at the pinned commit. Run python3 tools/gen_afd_config.py to refresh them.

Generated by tools/gen_afd_config.py from afd_plugin/config.py and the connector source. Do not edit between the markers.

The afd keys#

KeyAliasTypeDefaultWhat it isSource
connectorafd_connectorstr'P2pNcclAFDConnector'Connector implementation name used to create the backend data path.afd_plugin/config.py:52
async_dpasyncboolFalseWhether AFD owns async data-parallel runtime patches for this process.afd_plugin/config.py:54
roleafd_roleAFDRole'attention'Role owned by this process: Attention sends hidden states; FFN receives.afd_plugin/config.py:56
portafd_portint1239Port used by the AFD connector rendezvous/control path.afd_plugin/config.py:58
hostafd_hoststr'127.0.0.1'Host used by the AFD connector rendezvous/control path.afd_plugin/config.py:60
num_attention_ranks—int1Number of AFD Attention ranks participating in this topology.afd_plugin/config.py:62
num_ffn_ranks—int1Number of AFD FFN ranks participating in this topology.afd_plugin/config.py:64
compute_gate_on_attention—boolFalseWhether Attention computes MoE gate outputs before sending to FFN.afd_plugin/config.py:66
afd_process_group_timeout_s—int120Timeout, in seconds, for the AFD world process group rendezvous. The right value depends on rank count, placement, and model size, so it is left to the caller (deployment tooling) rather than derived here.afd_plugin/config.py:70
connector_extra_config—dict[str, Any]{} (empty mapping)afd_plugin/config.py:71

connector_extra_config by connector#

P2pNcclAFDConnector (GPU): no keys. A non-empty connector_extra_config raises ValueError (afd_plugin/connectors/gpu/p2p.py:155).

CAMP2pAFDConnector (NPU)

KeyTypeDefaultSource
core_numint > 08afd_plugin/connectors/npu/camp2p.py:116
attn_core_numint > 0, or nullNoneafd_plugin/connectors/npu/camp2p.py:120
ffn_core_numint > 0, or nullNoneafd_plugin/connectors/npu/camp2p.py:124
compute_gate_on_attentionboolFalseafd_plugin/connectors/npu/camp2p.py:128
hccl_buffer_sizeint > 0, or nullNoneafd_plugin/connectors/npu/camp2p.py:132
quant_modeint0afd_plugin/connectors/npu/camp2p.py:136

CAMAsyncAFDConnector (NPU)

The async connector accepts the wire key dynamicQuant for its typed field dynamic_quant.

KeyTypeDefaultSource
dynamicQuantint0afd_plugin/connectors/npu/async_cam.py:183
attn_ranks_per_dpint > 01afd_plugin/connectors/npu/async_cam.py:187
hccl_buffer_sizeint > 0, or nullNoneafd_plugin/connectors/npu/async_cam.py:191
ffn_two_streamboolFalseafd_plugin/connectors/npu/async_cam.py:195
ffn_compute_aic_numint > 012afd_plugin/connectors/npu/async_cam.py:198
ffn_compute_aiv_numint > 024afd_plugin/connectors/npu/async_cam.py:201
ffn_combine_aiv_numint > 024afd_plugin/connectors/npu/async_cam.py:204

Validation rules#

The plugin coerces each value to its type, then validates it. Coercion happens in _normalize_mapping (afd_plugin/config.py:120-176); validation happens in validate_afd_config (afd_plugin/config.py:311-350). An invalid value raises before the run starts.

RuleApplies toSource
Unknown afd key raises ValueErrorany key not a field or alias afd_plugin/config.py:134-139
An alias and its canonical key together raise ValueErrorfor example role and afd_roleafd_plugin/config.py:140-144
role must be "attention" or "ffn"role afd_plugin/config.py:318-321
connector must be one of the three registered namesconnector afd_plugin/config.py:326-330
async_dp=true needs connector="CAMAsyncAFDConnector" async_dpafd_plugin/config.py:331-334
host must be non-emptyhost afd_plugin/config.py:339-340
port must be in 1..65535port afd_plugin/config.py:341-342
num_attention_ranks and num_ffn_ranks must be positive both rank countsafd_plugin/config.py:343-350
For P2pNcclAFDConnector: num_attention_ranks >= num_ffn_ranks GPU P2P onlyafd_plugin/distributed/topology.py:52-58
Booleans accept true/false, 1/0, yes/no, on/off async_dp, compute_gate_on_attention afd_plugin/config_utils.py:8-24
Integers reject bool and float inputs port, rank countsafd_plugin/config_utils.py:35-45

Where each value is read, and what it changes#

The table lists the main GPU read site of each key. The NPU connectors read the same keys through their own code.

KeyRead at (GPU)What it changes
connectorafd_plugin/connectors/factory.py:57-60 Which connector class the factory builds.
roleafd_plugin/validation.py:350-354 The expected worker class, so attention or FFN. The worker runs the matching runner.
host, portafd_plugin/connectors/gpu/p2p.py:271 The TCP rendezvous where the two roles set up the connector groups.
num_attention_ranks, num_ffn_ranks afd_plugin/distributed/topology.py:46-49 The world size and the per-FFN subgroups (afd_plugin/distributed/topology.py:118-146).
async_dpafd_plugin/config.py:303-308 Selects AFD async mode through is_afd_async_dp. It gates the NPU async-DP patches (afd_plugin/compat/npu/runtime.py:44-53); on GPU it must be false.
compute_gate_on_attentionafd_plugin/v1/worker/ffn_model_runner.py:211-215 Whether the attention side computes the MoE gate; the FFN side then runs only the expert layers.
afd_process_group_timeout_safd_plugin/connectors/gpu/p2p.py:275 How long the world process-group rendezvous waits before it fails.
connector_extra_configafd_plugin/connectors/base.py:105-107 The per-connector options; stored on extra_info after the connector parses it.

Where the final value is set#

Lesson from the fact checks: a default is not final until the code sets it. Trace each value through four steps. A missing key takes the dataclass default; a present key is coerced, stored, then validated.

Figure: one key from the recipe to the validated config. The dataclass default applies only when the recipe omits the key.
Open full size ↗
  1. Recipe or CLI. The --additional-config JSON gives the raw mapping. vLLM stores it on additional_config (vllm:vllm/config/vllm.py:434).
  2. Normalize. _normalize_mapping rewrites aliases, splits out connector_extra_config, and coerces port, the rank counts, the timeout and the booleans (afd_plugin/config.py:147-174).
  3. Construct. AFDConfig(**normalized) fills any absent key with the dataclass default (afd_plugin/config.py:189-190). So the defaults in the table apply only to keys the recipe omits.
  4. Validate. validate_afd_config raises on a bad value (afd_plugin/config.py:311-350). The worker re-parses and re-validates through assert_compatible_afd_stack (afd_plugin/validation.py:328).

Worked example: the recipe's afd block#

This block is the attention server from the simplest GPU recipe, 2a2f_eager_dbo_dp1tp2.sh (recipe/gpu/P2pNcclAFDConnector/deepseek_v2_lite/prefill_decode_colocation/2a2f_eager_dbo_dp1tp2.sh:11-20). The FFN server uses the same block with "role": "ffn". The tour Tour: Life of a request follows a request through this recipe.

{
  "afd": {
    "role": "attention",
    "connector": "P2pNcclAFDConnector",
    "host": "127.0.0.1",
    "port": 6269,
    "num_attention_ranks": 2,
    "num_ffn_ranks": 2
  }
}
KeyValueEffect for this recipe
role"attention" This server runs the attention worker and the API server. The FFN server sets "ffn".
connector"P2pNcclAFDConnector" The GPU connector. It takes no connector_extra_config.
host, port"127.0.0.1", 6269 Both servers meet at this address. The value overrides the default port 1239.
num_attention_ranks2 Two attention ranks (A0, A1). The server runs --tensor-parallel-size 2.
num_ffn_ranks2 Two FFN ranks (F0, F1). A0 maps to F0 and A1 maps to F1 (afd_plugin/distributed/topology.py:135-136).

The recipe omits five keys, so they take their defaults: async_dp=false, compute_gate_on_attention=false, afd_process_group_timeout_s=120, an empty connector_extra_config, and the coerced port and rank integers. The A >= F rule holds because both counts are 2 (afd_plugin/distributed/topology.py:52-58).