Skip to content

[TRTLLM-14815][feat] Enable disaggregated serving for Kimi K3 - #17334

Merged
brnguyen2 merged 14 commits into
NVIDIA:mainfrom
brnguyen2:k3/14815-disagg
Aug 8, 2026
Merged

[TRTLLM-14815][feat] Enable disaggregated serving for Kimi K3#17334
brnguyen2 merged 14 commits into
NVIDIA:mainfrom
brnguyen2:k3/14815-disagg

Conversation

@brnguyen2

@brnguyen2 brnguyen2 commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Description

Adds disaggregated-serving support for Kimi K3 (KimiLinear), in four commits:

  1. KDA/hybrid recurrent-state transfer in the native disaggregation layer:
    MambaPolicy state-region mapping for the KDA mixer, peer registration,
    bounce-buffer config/impl updates sized for the KDA state payload, and
    transceiver handling for hybrid (attention + recurrent-state) models.
  2. Executor wiring: the Kimi branch in pyexecutor/_util.py previously
    raised NotImplementedError for disaggregated serving (referencing this
    ticket); it now routes through the shared hybrid transceiver validation.
  3. Tests: KDA/hybrid state-transfer unit tests, bounce and auxiliary-region
    updates, plus a Kimi K3 disagg logits-parity integration harness.
  4. Example configs and benchmark wiring for a ctx/gen disagg deployment.

Base: #17269 (KimiLinear model) has merged; this PR is rebased onto
main and carries only the disaggregated-serving changes.

Notes

Test Coverage

  • tests/unittest/disaggregated/test_kda_mamba_transfer.py
  • tests/unittest/disaggregated/test_bounce.py
  • tests/unittest/disaggregated/region/test_aux.py
  • tests/integration/defs/kimi_k3_disagg_parity.py (harness, not list-wired)

PR Checklist

  • PR title follows the [TRTLLM-14815][feat] convention
  • Unit-suite verification on representative hardware to be attached before un-drafting

Dev Engineer Review

  • Adds native KDA/Kimi K3 disaggregated serving support.
  • Adds recurrent-state layout validation, peer registration checks, auxiliary transfer descriptors, payload sizing, and hybrid transceiver routing.
  • Updates bounce-buffer sizing with byte and legacy block thresholds.
  • Adds Kimi K3 launch, benchmark, proxy, and server configurations.
  • Adds container path restoration and trtllm-serve fallback handling.
  • Review follow-up is required for pipeline-parallel peer validation.
  • Review follow-up is required because generation-side replay-cache seeding is not invoked.
  • Speculative decoding remains unsupported pending #17327.
  • The parity harness is not connected to a test list.
  • No test-list, test-db/, or qa/ changes are included.

QA Engineer Review

  • Adds KDA descriptor, peer-validation, pipeline-parallel, and recurrent-state transfer tests.
  • Expands auxiliary transfer tests for zero-length buffers and transfer layouts.
  • Expands bounce-buffer tests for byte thresholds, KDA page tables, recurrent-state payloads, fan-in restrictions, and mixed reservations.
  • Adds the kimi_k3_disagg_parity.py parity harness with endpoint, token, logprob, GSM8K, reporting, CLI, and self-test coverage.
  • The new tests and parity harness are not registered in tests/integration/test_lists/, test-db/, or qa/.
  • Verdict: insufficient. Register applicable unit and integration coverage. Resolve the pipeline-parallel peer-validation and replay-cache invocation issues before approval.

@Shixiaowei02

Copy link
Copy Markdown
Collaborator

The new peer check wants both sides to have the same layer set, but each rank only holds its own pipeline stage, and the transfer code below it takes the overlap on purpose. So this rejects hybrid models with pipeline parallelism, including a Qwen3-Next test already in pre-merge. Also, the function that seeds the replay caches on the generation side is never called.

@brnguyen2

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@brnguyen2
brnguyen2 enabled auto-merge (squash) August 8, 2026 06:09
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64767 [ run ] triggered by Bot. Commit: 89bc6e4 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64677 [ run ] completed with state ABORTED. Commit: e0ba3cc

Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64767 [ run ] completed with state FAILURE. Commit: 89bc6e4
/LLM/main/L0_MergeRequest_PR pipeline #52611 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@brnguyen2

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64781 [ run ] triggered by Bot. Commit: 89bc6e4 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64781 [ run ] completed with state FAILURE. Commit: 89bc6e4
/LLM/main/L0_MergeRequest_PR pipeline #52625 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@brnguyen2

Copy link
Copy Markdown
Collaborator Author

/bot skip --comment "Union-green across two full runs on head 89bc6e4: pipeline 52625 ran single-GPU fully green and multi-GPU 140/142 stages green; the sole red stage (DGX_B200-8_GPUs-PyTorch-1, one SLURM job) failed 3 accuracy tests unrelated to this disaggregation-gated diff (NemotronV3 Super/Ultra, DeepSeekV4ProDSpark) with init-time environment signatures (c10d store timeout, CUDA OOM during symmetric-memory allocation); the NemotronV3Ultra case is already waived on B300 (nvbugs/6474894). Pipeline 52611 on the same head was green except one unrelated pip-install network failure in a test setup fixture."

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64798 [ skip ] triggered by Bot. Commit: 89bc6e4 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64798 [ skip ] completed with state SUCCESS. Commit: 89bc6e4
Skipping testing for commit 89bc6e4

Link to invocation

@brnguyen2
brnguyen2 merged commit 4d02d80 into NVIDIA:main Aug 8, 2026
8 checks passed
# the shared hybrid transceiver validation below: the Python NIXL
# transceiver selects the Mixed manager, whose KDA recurrent/conv
# states transfer through the bounce buffer.
if is_kimi_linear(config) and not use_v2 and not is_disagg:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that the fail-fast is gone, a K3 disagg deployment that leaves the transceiver runtime at its default resolves to the C++ path and reaches this block without any error.

@brnguyen2 brnguyen2 Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed, this is a real gap. KimiLinearForCausalLM does not override get_preferred_transceiver_runtime, so transceiver_runtime: auto resolves to the C++ transceiver, and this route then returns CppMambaHybridCacheManager with no error even though only the Python NIXL transceiver knows how to move the KDA state. Qwen3-Next already returns "PYTHON" from get_preferred_transceiver_runtime; K3 should do the same, plus a loud guard on this route for paths that skip model defaults (e.g. AutoDeploy resolves auto to the C++ fallback). Queued at the top of TRTLLM-15264: the failure mode is silent.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix is up: #17480 (KimiLinearForCausalLM.get_preferred_transceiver_runtime -> 'PYTHON' plus a loud guard on the K3 disagg route, with routing unit tests).

_MIN_BLOCKS_ENV = "TRTLLM_KV_CACHE_BOUNCE_MIN_BLOCKS"
# Test/advanced overrides for the size gates below (users only tune the bounce size). Read on the
# generation side, so set them there; unset uses the defaults.
_MIN_BYTES_ENV = "TRTLLM_KV_CACHE_BOUNCE_MIN_BYTES" # byte gate for recurrent-state payloads

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the two gates are selected by payload kind rather than by transfer cost, could a short note record what each one actually guards?

@brnguyen2 brnguyen2 Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, will add a note at the env-var definitions: min_bytes gates payloads carrying recurrent state (the fallback cost scales with bytes, and block counts are meaningless for the non-paged state), while min_blocks is the pre-existing gate kept for plain-KV payloads so already-deployed bounce users see no behavior change. Tracked under TRTLLM-15264, together with folding in the observation from your comment below (for K3 the byte gate never rejects; the arena capacity is the effective admission control).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix is up: #17483 (added notes at the min-bytes / min-blocks env-var gates documenting what each admission control covers — byte gate for recurrent-state payloads, block gate kept for plain-KV behavior compatibility).

# inter-node — 2 MiB in-place at that rate is ~5 ms vs well under 1 ms bounced. Below 2 MiB the
# fixed overhead dominates and arena slots are better kept for large transfers. Heuristic, tunable
# via TRTLLM_KV_CACHE_BOUNCE_MIN_BYTES.
DEFAULT_MIN_BYTES = 2 * _MIB

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For K3 every request carries the fixed recurrent payload, so this threshold can never reject anything and the arena size is the effective admission control.

@brnguyen2 brnguyen2 Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. K3's fixed KDA payload clears the 2 MiB gate on every request, so for this model admission control is effectively the arena capacity plus reservation backpressure (reserve falls back to the per-fragment path on oversize or timeout). The byte gate only bites for hybrid models with small recurrent payloads or very short transfers. Will record this in the gate documentation note (previous comment, TRTLLM-15264) so the next reader does not go looking for a rejection path that never fires for K3.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix is up: #17483 (the gate note records that for K3 the fixed KDA payload clears the byte gate on every request, so arena capacity plus reservation backpressure is the effective admission control and there is no per-request rejection path to look for).

warn_key="kv-bounce-unknown-slot-size",
)
total += int(block_ids.size) * self._block_bytes_per_group[g]
if extra_bytes > 0 and num_writers > 1:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Separating the classification from the size would remove that ambiguity and make the gate selection explicit.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. extra_bytes > 0 currently doubles as the payload classifier, so a hybrid transfer whose recurrent payload happens to compute to zero bytes (e.g. an empty layer intersection under PP) would be gated as plain KV. The fix is to pass an explicit carries-recurrent-state flag from dispatch_task alongside extra_bytes, so classification is by payload kind and the byte value is only a size. Queued with the TRTLLM-15194 gate hardening, which already covers whether the two gates can be unified.

@@ -182,9 +187,10 @@ def _reserve_and_gather(self, write_meta, *, timeout):
total = int(write_meta.sizes.sum())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The receiver's reservation size never reaches the sender, so a coalesced write larger than the region has nothing to stop it. Would some form of bound check be worth adding here?

@brnguyen2 brnguyen2 Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth adding, agreed. The receiver knows the reserved size but only ships bounce_dst_base to the sender, so nothing bounds the coalesced write. Plan: include the reserved byte count (per-writer share for fan-in) in the recv request so the sender can check total <= reservation before issuing the write, failing the transfer through the normal error path instead of overrunning the neighboring slot. This complements the receiver-side check you suggested in core.py (comparing reported bytes against the reservation at result-record time); both are tracked under TRTLLM-15194 with the rest of the bounce hardening.

if peer_infos.page_table is None:
allow_bounce = False # cannot size the sender's recurrent-state payload
else:
extra_bytes = MambaPolicy.payload_bytes(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rank info cached per info endpoint comes from context rank 0, whose page table is pipeline-stage-local, so under PP the layer sets can fail to intersect and this returns zero while the actual sending stage still appends its full recurrent payload.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed; this is the PP sizing gap tracked under TRTLLM-15194 (also raised by @chienchunhung on the PR thread). Under PP the cached RankInfo is stage-local to context rank 0, so payload_bytes can size from the wrong stage, including a zero from an empty layer intersection, while the real sending stage appends its full payload. It cannot trigger today (K3 requires pp_size 1 and every shipped config uses PP1), but the plan under TRTLLM-15194 is to size from per-rank page tables or disable recurrent-state bounce when the peer has pp_size > 1, plus a PP regression test.

# reject here — before REGISTER_RANK_INFO is even sent — to fail
# the first gen request loudly instead of hanging on a transfer
# the sender will never serve.
MambaPolicy.validate_peer_compatible(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This raises on the executor thread with nothing catching it upstream, so a single mismatched context instance would take down the whole generation worker, including traffic from healthy peers. Failing just the affected request through the existing transfer-error path would keep the blast radius local while still surfacing the diagnostic.

@brnguyen2 brnguyen2 Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point. The raise is deliberately at first-contact registration (fail the first request loudly rather than hang on a transfer the sender will never serve), but you are right that it propagates on the executor thread and takes down the whole generation worker even when other context peers are healthy. Will reroute it through the existing transfer-error path so only requests targeting the incompatible peer fail, keeping the diagnostic message. Tracked under TRTLLM-15264.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix is up: #17482 (validate_peer_compatible failures now raise a typed PeerIncompatibleError that Receiver.dispatch_task turns into a per-request DISAGG_TRANS_ERROR, so only requests targeting the incompatible peer fail; the peer is cached to fast-fail later requests without re-validating, healthy peers and in-flight requests are unaffected, and the diagnostic is preserved).

if slice.mamba_state_index is not None:
total += len(lg.mamba_layer_offsets) * (
lg.conv_states.slot_bytes + lg.ssm_states.slot_bytes
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A cross-reference would help, since the two byte accountings added in this PR already differ on the pool-view axis.

@brnguyen2 brnguyen2 Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, will cross-reference the two accountings. Note the pool-view difference is also a real sizing issue on the bounce side (block_bytes_per_group reads pool 0 only, per your comment there); once that sums pool views the two accountings agree on the axis, and the comments will point at each other. Tracked under TRTLLM-15264 (the pool-view sizing fix itself is under TRTLLM-15194).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix is up: #17483 (added cross-referencing comments between _slice_num_bytes (sums all pool views) and bounce block_bytes_per_group (pool 0 only); the pool-0-only sizing fix itself is tracked under TRTLLM-15194).

are pre-scaled by tp_size when attention-DP is off so the per-rank
state stays full-size (EP-only parallelism, replicated KDA state).
"""
state_tp = tp if not enable_attention_dp else 1

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file isn't in any test list, and the CPU sweep ignores modules without the cpu-only marker at collection time. Besides, the fixture pre-scales the head count so the per-rank state stays full size, which cancels the manager's own division

@brnguyen2 brnguyen2 Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both parts are right. On wiring: test-list registration and the GPU/NIXL markers for these suites are handled in #17332 so the gating lands together; the CPU-runnable subset gets its marker there too. On the fixture: the pre-scaling does cancel the manager's division, and the docstring's claim that this mirrors production is stale. The merged mapping (extract_mamba_kv_cache_params) passes lin["num_heads"] through unscaled, so with attention-DP off the manager shards heads across TP; the fixture instead models a replicated full-size per-rank state. The follow-up will build the fixture through the production mapping (shared helper rather than hand-built kwargs) and cover both the ADP-on (replicated) and ADP-off (sharded) geometries that production actually constructs. Tracked under TRTLLM-15264.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix is up: #17483 (_create_kda_managers now builds its Mamba cache params via the production extract_mamba_kv_cache_params with unscaled global head counts, so the manager's own attention-DP gate does the sharding; the stale "mirrors production" docstring is corrected).



def test_kda_hetero_tp_rejected():
"""Replicated KDA state + heterogeneous TP (ADP off) must be rejected.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following from the fixture above, this asserts a rejection for a geometry production doesn't build.

@brnguyen2 brnguyen2 Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following from the fixture discussion above: correct. With the production (unscaled) mapping, ADP-off heterogeneous TP produces sharded per-rank state whose TP-aggregated size matches, so validate_peer_compatible would accept it; the rejection this test asserts only arises from the fixture's pre-scaled (replicated) geometry, which production does not build for K3. The follow-up reworks this to assert what production actually produces: positive transfer coverage through the TP-mismatch mappers for the sharded case, and a config-level rejection for any geometry K3 genuinely does not support. Tracked under TRTLLM-15264.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix is up: #17483 (test_kda_hetero_tp_rejected became test_kda_hetero_tp_sharded_accepted — under the production head-sharded mapping, ADP-off hetero TP is accepted, so the test now asserts concrete per-rank slot sizes before acceptance rather than a rejection production never builds).

# NIXL/PYTHON dropped for now: V2 _exchange_rank_info mpi_allgather can
# hang under this harness (srun --mpi=pmix).
- {backend: "NIXL", runtime: "CPP"}
- {backend: "UCX", runtime: "CPP"}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This cache-transceiver test is intended to sweep UCX environment variables and identify a suitable UCX configuration. It is not a model benchmark framework. adding a model specific yaml config is not appropriate. Also, K3 requires a python runtime cache transceiver ,but this config only involve cpp runtime

@brnguyen2 brnguyen2 Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed on both points. The config existed to reproduce the KDA-sized payload measurement, but it is model-specific and only sweeps the CPP runtime, which K3 cannot use. Will remove it from cache_transceiver_test under TRTLLM-15264; the payload-size derivation (the header math) moves into the K3 example docs where the same numbers are already used.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix is up: #17483 (removed the config from cache_transceiver_test; the payload-size derivation is preserved in the K3 disagg README where the same numbers are used).

prerequisites for every worker shell (see caveats below for why):

```bash
export UCX_TLS=tcp,self,sm,cuda_copy,cuda_ipc # on clusters where verbs cannot

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UCX_TLS=tcp,self,sm,cuda_copy,cuda_ipc is a workaround for a specific cluster where the verbs transports fail to initialize. It should not be hard-coded into the default K3 benchmark configuration.
This transport list excludes RDMA/verbs transports. On B200/B300 clusters whose inter-node communication depends on RDMA, it may cause initialization or registration failures,or force communication onto an unintended TCP path.
Could this be moved to an optional troubleshooting section, with the default recommendation being to leave UCX_TLS unset unless the cluster's validated UCX configuration
requires an override?

@brnguyen2 brnguyen2 Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Will move the UCX_TLS override out of the default launch sequence into a troubleshooting subsection, with the default guidance being to leave UCX_TLS unset so verbs/RDMA transports stay available on clusters that depend on them, plus a note on the symptom that motivates the override (NIXL/UCX initialization failure where verbs transports cannot come up). Tracked under TRTLLM-15264.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix is up: #17479 (default is now no UCX_TLS pin in the README launch sequence and the benchmark config; the override moved to the troubleshooting caveats, scoped to clusters where verbs transports cannot initialize).



@pytest.mark.timeout(180)
@pytest.mark.parametrize(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need test cases that ctx_tp != gen_tp and adp =false/true?

@brnguyen2 brnguyen2 Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, and this ties into the fixture rework from the thread above (the current fixture pre-scales heads, which does not match the merged production mapping). Planned parametrization for the follow-up: matched TP with ADP on and off, and heterogeneous ctx/gen TP with ADP on (replicated per-group state) and ADP off (sharded state through the TP-mismatch mappers), asserting transfer correctness or a loud rejection according to what production supports for each geometry. Tracked under TRTLLM-15264.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix is up: #17483 (new transfer parametrizations: matched TP2 with attention-DP on and off, and heterogeneous 2->4 / 4->2 with bitwise output comparison).

brnguyen2 added a commit to brnguyen2/TensorRT-LLM that referenced this pull request Aug 10, 2026
…disaggregated serving

A K3 disaggregated deployment that left transceiver_runtime at its
default ('auto') silently resolved to the C++ transceiver: the hybrid
manager routing returned CppMambaHybridCacheManager with no error, even
though only the Python NIXL transceiver (KvCacheTransceiverV2) can move
the KDA recurrent state. The C++ path is unvalidated for K3 and would
serve wrong results rather than fail.

Two layers of fix:

- KimiLinearForCausalLM now overrides get_preferred_transceiver_runtime
  to 'PYTHON' (the Qwen3-Next pattern), so model loading resolves
  'auto' to the Python transceiver when the backend is NIXL.
- get_kv_cache_manager_cls rejects any K3 disagg route that is not
  PYTHON+NIXL with an actionable error, covering explicit non-Python
  runtimes and paths that skip model-default resolution (e.g.
  AutoDeploy, where 'auto' falls back to the C++ runtime).

Adds routing unit tests: the preference override, rejection of
no-config / unresolved-auto / explicit-CPP / UCX routes, and the
positive PYTHON+NIXL route to MixedMambaHybridCacheManager.

Addresses review feedback on NVIDIA#17334.

Signed-off-by: Brian Nguyen <brnguyen@nvidia.com>
brnguyen2 added a commit to brnguyen2/TensorRT-LLM that referenced this pull request Aug 12, 2026
…disaggregated serving

A K3 disaggregated deployment that left transceiver_runtime at its
default ('auto') silently resolved to the C++ transceiver: the hybrid
manager routing returned CppMambaHybridCacheManager with no error, even
though only the Python NIXL transceiver (KvCacheTransceiverV2) can move
the KDA recurrent state. The C++ path is unvalidated for K3 and would
serve wrong results rather than fail.

Two layers of fix:

- KimiLinearForCausalLM now overrides get_preferred_transceiver_runtime
  to 'PYTHON' (the Qwen3-Next pattern), so model loading resolves
  'auto' to the Python transceiver when the backend is NIXL.
- get_kv_cache_manager_cls rejects any K3 disagg route that is not
  PYTHON+NIXL with an actionable error, covering explicit non-Python
  runtimes and paths that skip model-default resolution (e.g.
  AutoDeploy, where 'auto' falls back to the C++ runtime).

Adds routing unit tests: the preference override, rejection of
no-config / unresolved-auto / explicit-CPP / UCX routes, and the
positive PYTHON+NIXL route to MixedMambaHybridCacheManager.

Addresses review feedback on NVIDIA#17334.

Signed-off-by: Brian Nguyen <brnguyen@nvidia.com>
brnguyen2 added a commit to brnguyen2/TensorRT-LLM that referenced this pull request Aug 12, 2026
…disaggregated serving

A K3 disaggregated deployment that left transceiver_runtime at its
default ('auto') silently resolved to the C++ transceiver: the hybrid
manager routing returned CppMambaHybridCacheManager with no error, even
though only the Python NIXL transceiver (KvCacheTransceiverV2) can move
the KDA recurrent state. The C++ path is unvalidated for K3 and would
serve wrong results rather than fail.

Two layers of fix:

- KimiLinearForCausalLM now overrides get_preferred_transceiver_runtime
  to 'PYTHON' (the Qwen3-Next pattern), so model loading resolves
  'auto' to the Python transceiver when the backend is NIXL.
- get_kv_cache_manager_cls rejects any K3 disagg route that is not
  PYTHON+NIXL with an actionable error, covering explicit non-Python
  runtimes and paths that skip model-default resolution (e.g.
  AutoDeploy, where 'auto' falls back to the C++ runtime).

Adds routing unit tests: the preference override, rejection of
no-config / unresolved-auto / explicit-CPP / UCX routes, and the
positive PYTHON+NIXL route to MixedMambaHybridCacheManager.

Addresses review feedback on NVIDIA#17334.

Signed-off-by: Brian Nguyen <brnguyen@nvidia.com>
brnguyen2 added a commit to brnguyen2/TensorRT-LLM that referenced this pull request Aug 13, 2026
…disaggregated serving

A K3 disaggregated deployment that left transceiver_runtime at its
default ('auto') silently resolved to the C++ transceiver: the hybrid
manager routing returned CppMambaHybridCacheManager with no error, even
though only the Python NIXL transceiver (KvCacheTransceiverV2) can move
the KDA recurrent state. The C++ path is unvalidated for K3 and would
serve wrong results rather than fail.

Two layers of fix:

- KimiLinearForCausalLM now overrides get_preferred_transceiver_runtime
  to 'PYTHON' (the Qwen3-Next pattern), so model loading resolves
  'auto' to the Python transceiver when the backend is NIXL.
- get_kv_cache_manager_cls rejects any K3 disagg route that is not
  PYTHON+NIXL with an actionable error, covering explicit non-Python
  runtimes and paths that skip model-default resolution (e.g.
  AutoDeploy, where 'auto' falls back to the C++ runtime).

Adds routing unit tests: the preference override, rejection of
no-config / unresolved-auto / explicit-CPP / UCX routes, and the
positive PYTHON+NIXL route to MixedMambaHybridCacheManager.

Addresses review feedback on NVIDIA#17334.

Signed-off-by: Brian Nguyen <brnguyen@nvidia.com>
brnguyen2 added a commit to brnguyen2/TensorRT-LLM that referenced this pull request Aug 14, 2026
…disaggregated serving

A K3 disaggregated deployment that left transceiver_runtime at its
default ('auto') silently resolved to the C++ transceiver: the hybrid
manager routing returned CppMambaHybridCacheManager with no error, even
though only the Python NIXL transceiver (KvCacheTransceiverV2) can move
the KDA recurrent state. The C++ path is unvalidated for K3 and would
serve wrong results rather than fail.

Two layers of fix:

- KimiLinearForCausalLM now overrides get_preferred_transceiver_runtime
  to 'PYTHON' (the Qwen3-Next pattern), so model loading resolves
  'auto' to the Python transceiver when the backend is NIXL.
- get_kv_cache_manager_cls rejects any K3 disagg route that is not
  PYTHON+NIXL with an actionable error, covering explicit non-Python
  runtimes and paths that skip model-default resolution (e.g.
  AutoDeploy, where 'auto' falls back to the C++ runtime).

Adds routing unit tests: the preference override, rejection of
no-config / unresolved-auto / explicit-CPP / UCX routes, and the
positive PYTHON+NIXL route to MixedMambaHybridCacheManager.

Addresses review feedback on NVIDIA#17334.

Signed-off-by: Brian Nguyen <brnguyen@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.