Skip to content

Feature/python native v2#1108

Open
baohengyi wants to merge 109 commits into
alibaba:feature/python_native_v2from
baohengyi:feature/python_native_v2
Open

Feature/python native v2#1108
baohengyi wants to merge 109 commits into
alibaba:feature/python_native_v2from
baohengyi:feature/python_native_v2

Conversation

@baohengyi

Copy link
Copy Markdown

Summary
Sync feature/python_native_v2 with the latest main branch. This merge brings all recent main-branch updates (multimodal refactor, new model support, VIT proxy server, etc.) into the python-native migration branch, resolving 37 merge conflicts.

Conflict Resolution Details

Modify/Delete Conflicts (27 files) - Followed feature branch deletions
All Bazel build artifacts were removed per the python-native migration:
Dependency lock files (deps/requirements_.txt): 9 files. Reason: Replaced by setup.py / pyproject.toml.
BUILD files: 13 files. Reason: Bazel test targets migrated to pytest.
.bzl test suites (suites_h20_oss.bzl, suites_rocm_oss.bzl): 2 files. Reason: Migrated to test_smoke_
.py.
.pyi type stubs: 4 files. Reason: No longer needed in python-native mode.
Content Conflicts (10 files) - Manually merged
.bazelrc: Merged main's conda/java paths with feature's updated cache_bust date.
arch_config/arch_select.bzl: Adopted feature branch: removed whl_deps/platform_deps/torch_deps.
deps/http.bzl: Adopted feature branch: removed torch/aiter http_archive definitions.
rtp_llm/BUILD: Adopted feature branch: minimal exports_files only.
rtp_llm/cpp/config/ConfigModules.h: Both sides merged: feature's string-based attention API + main's enable_paged_open_source_fmha, enable_trtv1_fmha, use_triton_pa=false (with regression comment).
rtp_llm/multimodal/multimodal_util.py: Kept main's refactored class imports + trans_config/trans_mm_input; fixed SSRF import path.
rtp_llm/tools/api/model_basic_info_analyzer.py: Adopted feature branch: profiling_debug_logging_config enhancement.
test_py_flashinfer_mha_decode.py: Kept main branch: feature's run_bs variable was undefined.
models_py/triton_kernels/BUILD (2 files): Adopted feature branch: minimal visibility declaration.
Main-Branch Features Included

Multimodal refactor: rtp_llm/multimodal/multimodal_mixins/ directory restructure (ChatGLM4V, DeepSeek-VL2, Kimi-K25, LLaVA, Qwen2-VL, Qwen2-Audio, Qwen3-VL, Qwen3.5-MoE).
VIT Proxy Server: vit_app.py, vit_proxy_server.py, vit_rpc_server.py.
New models: Qwen3-VL, Qwen3-VL-MoE, Qwen3.5-MoE-VL.
Beam Search: bfloat16/ROCm support, efficient topk.
FMHA: enable_paged_open_source_fmha, enable_trtv1_fmha, Triton PA default-off.
Items Requiring Follow-up
The following main-branch smoke test cases were defined in .bzl files (now deleted) and not yet ported to pytest:

mla_pure_cp_pd, moe_pure_dp_fp8_dp2 (new MLA/MoE configs)
kimi_tool_call (Kimi linear model)
qwen3_vl, qwen3_vl_moe, qwen35_moe_vl_fp8 (VL multimodal suite)
rocm_basic_beam_search_tp2, rocm_dense_qwen3_8b_ptpc_no_asm_pa
These will need manual migration to the pytest smoke framework in a follow-up commit.
Testing

No conflict markers remain (grep verified)
CICD pending

jacobwin-ai and others added 30 commits May 14, 2026 15:45
Add MoRI-based expert parallelism (EP) as an alternative to DeepEP for
ROCm GPUs, enabling efficient intranode and internode dispatch/combine
for MoE models.

Core components:
- MoriEPWrapper: singleton wrapper around mori EpDispatchCombineOp
- MoriEpIntranodeRouter: EP router with dispatch/combine flow,
  chunked dispatch for large token counts, and global-to-local ID
  remapping for fused expert kernels
- MoriEpFp4Strategy: strategy pairing MoRI router with FP4 executor
- RocmEpNormalStrategy: MoRI router as first-class option alongside
  DeepEP, with mutual exclusion validation

Config flow:
- --use_mori_ep CLI flag (env: USE_MORI_EP) → deep_ep_config →
  auto_configure_deepep() → moe_config.use_mori_ep
- C++ MoeConfig.use_mori_ep field with pybind binding
- MoEConfigAdapter exposes use_mori_ep and use_deepep_moe

Bazel: moriep_wrapper py_library target with modules dependency.
- FakeBalanceExpert ROCm C++ op for expert load balancing testing
- MoriEpIntranodeRouter unit tests
- BlockPoolConfigHelper adjustment for MoE cache allocation
- Remove TP-only unified allreduce optimization that caused numerical
  differences vs main branch (12 smoke test failures)
- Remove dead skip_allreduce code from FusedMoe.forward() and the
  entire router finalize() chain (base class, all implementations,
  associated test)
- Fix golden JSON files with Unicode curly quotes (rebuild with json.dump)
- Update stale golden values from CI actual output
- Refactor moriep_intranode_router_test to use production
  MoriEpIntranodeRouter instead of duplicated inline helpers
- Fix use_all_gather early return swallowing explicit USE_MORI_EP config
BatchGenerateCall (used by /batch_infer) bypasses PrefillRpcServer,
so PD separation is not applied. Add explicit endpoint "/" to the
PD golden so that prompt_batch queries go through the PD-aware
GenerateStreamCall path, matching main's behavior.
The model generates Unicode right single quote (') in PD streaming
path, not ASCII apostrophe ('). Update golden to match actual output.
MoriEP was passing parallelism_config.world_size to mori config, which
would mismatch ep_rank when TP×EP/DP co-existence is introduced. Fix by
using ep_size and adding explicit assertions that ep_size == world_size
(the only currently supported configuration) in both init paths. Add
corresponding validation test.
Replace triton.autotune with CachedAutotuner that loads checked-in
per-kernel JSON configs, eliminating cross-process autotune races
that caused non-deterministic kimi-linear smoke test failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace 6 separate elementwise HIP kernel launches (2x compare,
1x OR, 2x masked_fill, 1x add) in MoriEpIntranodeRouter with a
single fused Triton kernel that performs the same remap logic in
one pass. Reduces per-layer decode overhead by ~39us (6 launches
→ 1 launch).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Guard remap_to_local_ids against empty dispatch (N=0) to prevent
  0-block Triton kernel launch
- Move test to moe/test/ with Bazel BUILD (exec_properties MI308X-ROCM7),
  add module-level pytest.skip when no GPU available
- Change router import to lazy (inside _remap_to_local_ids method) so
  stub-based MoriEP tests are not broken by top-level triton import
- Preload remap_local_ids_kernel in MoriEP multi-GPU test stub loader
- Add parameterized test suite covering N=0, all-local, all-non-local,
  mixed, boundary IDs, various dtypes and topk values

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…kernel

Adds a ROCm-only single-pass QK RMSNorm path tuned for wave64 (one warp
per (token, head)). Replaces the per-head reshape+rmsnorm chain on the
hot path; falls back to the baseline when norm_size != 256 or bias is
present.

Default-on via ``rtp_llm_ops.fused_qk_rmsnorm_v2`` from
``modules/base/rocm/norm.py::FusedQKRMSNorm``.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…k kernel

Hand-tuned BF16 prefill kernel: vec=8, 4 tokens per block, smem-based
partner exchange for the rotary half-swap, and cos/sin reuse across all
heads inside one block (cos/sin only depends on token+rope_d, not on
head). Replaces the per-(token,head) launch pattern of the original V1
kernel; ~5.77x kernel speedup measured on Qwen3.5-9B prefill 15k TP=2,
on both the ASM and NonAsm dispatch paths.

V3 is gated by the production hot-path config (BF16, paged_fmha,
prefix=0, RopeStyle::Base, store_q+store_cache, no store_qkv/store_kv,
Tcache=BASE, no logn, head_dim%8==0, rot_dim%(VEC*2)==0,
qkv_bias==nullptr); anything else falls back to the original kernel.
The ASM and NonAsm invokers each select their own V_VEC_LAYOUT template
to match the corresponding FMHA reader (templated <BASE> vs
non-templated getVLocalIdx).

Also defensively null-checks position_ids in the Mrope branches of the
existing V1 kernels (orthogonal but caught while touching the file).

Includes precision regression suite (NonAsm + ASM dispatch paths,
Qwen3.5-9B uniform/varied/single-long, tail-block %4 residues, partial
rotary, prefix-prompt fallback, multi-batch packed consistency, smaller
head_dim fallback). Each hot-path test allocates a real LayerKVCache +
block table so store_cache=true and V3 actually fires (the dispatch
guard rejects kv_cache=None), then asserts Q against a torch fp32 ref
AND decodes K/V back from the paged pool using the kernel's documented
layout (kv_cache_utils.h:213-241) for direct comparison.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When use_paged_fmha=true && pad_query=false the prefill Q output buffer
is sized exactly [token_num, heads, dim] and the V3/V1 kernels write
every cell unconditionally, so the torch::zeros initialization is dead
HBM bandwidth. Switch to torch::empty in that case; keep torch::zeros
for the pad_query=true layout where padded slots between sequences
remain unwritten and downstream FMHA reads them as masked zeros.

Profile (Qwen3.5-9B prefill, seq_len=15000, ASM=1 TRITON=1):
  FillFunctor<BFloat16> 58 calls → 50 calls
  -8 calls × ~27µs = -219µs / prefill

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Per-layer FMHA prefill setup recomputed seqlen_k = input_lengths +
prefix_lengths every layer in AiterPrefillAttnOp._forward_paged, firing
a per-layer trio of kernels (prefix-zeros alloc + cu_seqlens diff +
add + dtype-cast) that produced the same value 28 times in a 28-layer
model. Hoist the computation into FMHAParams.__init__ once per prefill
and read the cached int32 tensor in forward.

Cached value is bit-exact identical to the per-layer recomputation —
this is a hoist refactor, not a new operator. Cuda-graph replay path
uses AiterPrefillAttnOpPaged (not _forward_paged), so it is untouched.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ositions

Address PR review (P1): the ROCm fused RoPE+KV-cache prefill/decode dispatch
always passes position_ids=nullptr at all four call sites (ASM/Non-ASM x
Prefill/Decode). The kernel's Mrope branch only sets position_id when
position_ids is non-null, otherwise it silently falls back to -1 and produces
wrong RoPE positions. combo_position_ids is not plumbed through PyAttentionInputs
in PyWrappedModel::buildPyAttentionInputs yet, so Mrope on this path is
unsupported.

Throw at op construction with an actionable message. Plumbing real combo
position_ids through the prepare/forward chain is left for a follow-up.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Introduce two MoE communication paths for pure-parallel topologies that
bypass DeepEP and use NCCL allgather + reduce_scatter:

- PureCpRouter: tp == ep > 1, dp == 1. allgather across TP, reduce_scatter
  back. No padding needed since CP splits context evenly across ranks.
- PureDpRouter: tp == 1, ep == dp > 1. allgather across DP_AND_TP with -1
  sentinel padding for unequal batch sizes, reduce_scatter back. Reuses
  the existing valid-mask guard in recompute_topk_ids_sum_expert_count.

Supporting infrastructure:
- MoeConfigResolver.is_cp_equal_ep(): physical-tp view (parallelism_config
  .tp_size == ep_size) used to detect pure CP topology even when adapter
  tp_size is squashed to 1 by get_attn_tp_size().
- collective_torch.reduce_scatter helper.
- Document the -1 sentinel contract on recompute_topk_ids_sum_expert_count
  (slots not counted, output preserves -1, out-of-range collapses to -1)
  with a dedicated kernel test.
- multiprocessing + NCCL closed-loop test for the allgather → partial →
  reduce_scatter cycle on tp4 and tp2_dp2 topologies.
Wire CudaFp8PerBlockPureCPStrategy and CudaFp8PerBlockPureDPStrategy into
the factory and CLI:

- Add fp8_per_block_pure_cp / fp8_per_block_pure_dp to --moe_strategy
  choices.
- moe_strategy=auto picks PureCP for pure CP+EP (dp==1, tp==ep>1, prefill
  CP enabled) and PureDP for pure DP+EP (tp==1, ep==dp>1).
- Mixed tp>1+dp>1 still falls back to DeepEP intentionally.

Gate use_all_gather=True on pure-parallel topologies so other
configurations route through DeepEP.

can_handle unit tests cover both strategies' explicit/auto paths and all
false branches (dp_gt_1, tp_ne_ep, cp_disabled, ep_ne_dp,
no_all_gather, etc.) plus router_type / executor_type priority assertions.
- moe_pure_dp_fp8_dp2: Qwen3-30B-A3B FP8, tp=1 dp=2 ep=2,
  --use_deepep_moe 0 --use_all_gather 1, fp8_per_block_pure_dp
- mla_pure_cp_pd: GLM-5 PD-separated; prefill switched to
  allgather+RS (fp8_per_block_pure_cp), decode unchanged

Model paths use /mnt/nas1/hf/ to match existing OSS smoke convention.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- PureCP/PureDP strategies require explicit --moe_strategy=fp8_per_block_pure_cp/_dp;
  auto-config falls back to DeepEP to keep the default MoE path unchanged.
- Preserve use_all_gather in auto_configure_deepep when --moe_strategy explicitly
  opts into PureCP/PureDP and the topology matches; otherwise the strategy's
  check_conditions (which requires use_all_gather) would never hold.
- Drop implicit cross-call instance state in PureDpRouter; recover local batch
  size via extra_finalize_args["original_num_tokens"] (matches deepep_normal_router).
- Fix triton ep_kernels build deps + non-blocking P2/P3 cleanups from review.
- Add TODO at PureDpRouter._pad_to_max for hot-path .item() D2H sync follow-up.
…shapes to cktile

Add dimension-aware kernel dispatch for gemm_a8w8_bpreshuffle:
- K < 192: always cktile (small-K specialized kernel)
- M >= 1536: cktile FlatmmKernel (large-M prefill, +4~23%)
- M >= 512 AND N > 1536: cktile (large-N crossover at M~512, +22%)
- otherwise: aiter default (decode-friendly, protects M<=256)
Cover threshold boundaries M=511/512/1535/1536 and N<=1536/N>1536
to verify both cktile and default paths produce correct results.
Fix Qwen3.5-397B FP8_PER_CHANNEL_COMPRESSED startup OOM by quantizing
MoE expert weights to FP8 inline during fastsafetensors loading, inspired
by sglang's load-time quantization approach (6d98b53).

Three root-cause bugs fixed:
1. _build_stacked_key_config: scale template overwrites kernel template
   for the same checkpoint key, causing per-expert keys to mismatch
   collector target keys — collectors never complete
2. LoadQuantPerChannelFp8Weight.get_tensor_names: includes scale expert
   keys that don't exist in BF16 checkpoints — collectors never complete
3. _load_moe_inline_quant: missing transpose_stack_moe_w1 in allowed
   process_fun list — fused gate_up_proj skips inline quant path

Key changes:
- TensorCollector: add FP8 pre-quantization storage (store_fp8_quantized,
  has_prequantized_scale, get_scale)
- loader._load_from_fastsafetensor: inline BF16->FP8 quantization per
  expert tensor, periodic empty_cache + gc.collect
- loader._is_memory_enough_for_fastsafetensor: skip model_mem doubling
  when inline FP8 quantization is active
- per_channel_fp8_quant_weight: _load_moe_inline_quant reuses pre-quantized
  FP8 data from collector without re-quantization

Verified: 480 MoE weights (60 layers x 2 x 4 ranks) all prequantized=True,
fastsafetensors 100% loaded, zero GPU/CPU OOM.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cover the three root-cause bugs fixed in the PTPC OOM commit:
- TensorCollector FP8 storage: store/load/clear/completion
- _build_stacked_key_config: no-overwrite when kernel and scale share
  the same checkpoint key
- per_channel_cast_to_fp8_expert: matches 3D stacked path semantics
- _load_moe_inline_quant: transpose_stack_moe_w1 gate/up swap
- get_tensor_names: excludes scale expert keys

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…te view copies

In Qwen3-Next GDN prefill, splitting mixed_qkv along the channel dim and
then .view(1, M, n_heads, head_dim) triggers an implicit .contiguous() copy
per q/k/v slice because the slice stride doesn't match the contig stride
required by the target shape. With 24 GDN layers this is ~72 direct_copy
kernel events per prefill.

This replaces the split + view chain with scatter_qkv (Triton kernel,
adapted from SGLang's scatter_fused_proj) which reads mixed_qkv contig
and writes 3 contig (1, M, n_heads, head_dim) buffers in one pass.

Threshold M >= 2048 to avoid kernel-launch overhead at small batches
(microbench: scatter wins from M=4096, neutral around M=2048, loses
~2us below). Decode path uses a different reshape+split that doesn't
trigger view copies, so this only applies to prefill (Prefill._fla and
GatedDeltaNet._forward_cp_prefill).

Measured on Qwen3.5-9B TP2, 15K prefill + 100 decode (n=10, unique
prompts to avoid REUSE_CACHE hits):
  - TTFT:  1036.37 ms -> 1026.21 ms   (-10.16 ms, -0.98%)
  - direct_copy events per prefill: 107 -> 38 (-69 events, -3.50 ms)
  - scatter_qkv adds 24 events / +1.97 ms; net copy time -1.53 ms
  - TTFT savings exceed raw copy time savings, suggesting better cache
    locality for downstream FLA chunk_gated_delta_rule

Equivalence tests cover:
  - Qwen3-Next TP=2 production shape (M=15384, 8/16 heads, head_dim=128)
  - Threshold boundary (M = 2047, 2048, 2049) -- the kernel must be correct
    even though qwen3_next.py only invokes scatter_qkv at M>=2048
  - Dtypes: bf16 (production), fp16, fp32
  - Head configurations: Qwen3-Next TP=1/2/4 plus MQA-like and 1:1 ratio
  - Small M (1, 16, 256, 1024) for chunked-prefill correctness
  - Exact call-site mirror for Qwen3NextGatedDeltaNetPrefill._fla
  - Negative cases: 3D input, non-contiguous input, wrong last-dim

scatter_qkv is pure data movement (no math), so equivalence is checked
bit-exact via torch.equal, not numerically close. All 7 tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… path)

In Qwen3-Next GDN, in_proj_qkvz and in_proj_ba are two separate column-parallel
linears that take the SAME hidden_states input and produce non-overlapping
output ranges. Fusing them into a single in_proj_fused GEMM (cat along dim=1
of the weights) reads hidden_states only once and amortizes the GEMM launch.

The fusion is a pure compute-graph rearrangement:
  out_qkvz = hidden_states @ qkvz_w        (N=6144 on Qwen3.5-9B TP=2)
  out_ba   = hidden_states @ ba_w          (N=32)
becomes:
  fused_out = hidden_states @ cat([qkvz_w, ba_w], dim=1)  (N=6176)
  out_qkvz  = fused_out[..., :6144]
  out_ba    = fused_out[..., 6144:]

Weight buffer sharing:
  Rather than torch.cat (which would leave ~48MB redundant copies of qkvz_w
  per layer, ~1.16GB across 24 GDN layers), allocate the fused buffer once
  and copy qkvz/ba into it, THEN replace the dict entries with views into
  the fused buffer. This achieves both:
    (a) zero redundant weight memory (originals get released when init
        returns; only fused_w stays resident), and
    (b) online-weight-update correctness: WeightManager.update_layer_weight
        runs `ori_tensor.copy_(data)` against the dict entry; with the entry
        being a view into fused_w, the update writes directly into the right
        slice of the fused buffer that in_proj_fused.weight references, so
        the next forward sees the new weights. copy_ accepts non-contig
        destinations, so the view's stride mismatch is fine.

A new _input_project helper hides the fusion vs 2-GEMM dispatch from forward
and any external caller (notably the existing CP linear-attn test), so the
fused branch (where in_proj_qkvz / in_proj_ba are None) doesn't break code
that was directly invoking those modules.

Decode (M=1) is HBM-bandwidth bound, so reading the hidden tensor once for
both projections matters. Trace shows the savings come from eliminating 24
small in_proj_ba kernel launches (~12us each) — CUDA Graph doesn't fully
amortize launch overhead.

Measured on Qwen3.5-9B TP=2, 15K prefill + 100 decode (n=10, unique prompts):
  - TTFT:  1036.37 ms -> 1035.06 ms   (-1.31 ms, noise)
  - TPOT:    6.992 ms ->   6.775 ms   (-0.217 ms, -3.1%)
  - Total:  1728.6  ms -> 1705.8  ms  (-22.8 ms / request)

Decode-bound workloads (long generation) get most of the win; short-output
workloads see ~0 net change. Independent of (and composes with) the
scatter_qkv prefill optimization on feat/gdn-scatter-qkv-triton.

FP8/quantized fallback: qkvz has scales but ba doesn't, dtype mismatch makes
direct cat impossible. The fallback keeps the original 2-GEMM path.

Tests added (rtp_llm/models_py/model_desc/test/qwen3_next_qkvz_ba_fusion_test.py):
  - test_fused_slice_equals_separate_gemms: low-level math equivalence
    cat([qkvz_w, ba_w]) @ x == [qkvz_w @ x | ba_w @ x] within bf16 tolerance.
  - test_bf16_path_takes_fusion: verifies _qkvz_ba_fused=True and that the
    single in_proj_fused module is constructed.
  - test_quantized_path_falls_back_in_constructor: mocks LinearFactory to
    bypass FP8 strategy lookup and asserts qkvz_s presence triggers the
    2-GEMM fallback (in_proj_fused is None, both in_proj_qkvz and in_proj_ba
    are constructed, factory is invoked with the scale key).
  - test_input_project_helper_shapes: verifies the new helper API.
  - test_dict_entries_are_views_into_fused_buffer: verifies qkvz / ba dict
    entries share storage with in_proj_fused.weight (no redundant memory).
  - test_online_weight_update_propagates_to_fused: simulates WeightManager's
    in-place copy_() on the qkvz dict entry and verifies the fused buffer
    sees the update — i.e. online weight update is preserved.
All six pass locally.

Existing CP linear-attn test (test_cp_linear_attn.py) updated to call the
new _input_project helper instead of in_proj_qkvz / in_proj_ba directly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ive prefetch

- Extract _sanitize_and_pad_block_table() shared helper for both
  AiterPrefillAttnOp and AiterPrefillAttnOpPaged classes
- Remove global .clamp() that silently masked invalid block ids;
  only padding/speculative columns are now filled with last-valid-block-id
- Remove per-layer .item() GPU sync in _forward_paged hot path;
  use pre-computed fmha_params.max_seqlen_k directly
- Add tokens_per_block and _block_positions to AiterPrefillAttnOpPaged
  and apply sanitize+pad in its forward() to prevent CK kernel OOB
- Update test assertions to match new compact buffer size (unique+1
  for trailing dummy block) and last-valid-block-id fill semantics

Squashed from 6 original commits.
…filter

QuantWeight.get_components() returns [self] without recursing into
sub_weights. For FP8 quantized models, this caused
_collect_ckpt_tensor_name_regexes to miss expert tensor patterns,
leading to over-aggressive checkpoint file filtering (94 -> 2 files)
and model loading failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
AiterPrefillImplAsm/NonAsm's kv_cache=None shortcut bypassed RoPE,
sending raw QKV straight into varlen FMHA. Models that rely on
positional encoding (e.g. tbstars with rope_theta=10000) produced
severely diverged outputs.

Run rope_kvcache_impl first when need_rope_kv_cache=True, and have
the C++ FusedRopeKVCachePrefillOp return padded K/V (instead of empty
tensors) on the non-FP8 no-cache path so the existing _forward_varlen
tuple path can consume them.
@LLLLKKKK

Copy link
Copy Markdown
Collaborator

AI Code Review - PR #1108

Status: BLOCKING

Summary: P0/2 · P1/17 · P2/36 · P3/0

Blocking Issues

P0

  • ROCm DeepEP 路径丢失路由权重,MoE 输出会静默错误 @ rtp_llm/models_py/modules/factory/fused_moe/impl/rocm/executors/deepep_normal_fused_moe_executor.py:197
    • 建议:DeepEP normal 路径仍需在 ck_moe_stage2 传入 sorted_weights,或让 DeepepNormalRouter.finalize/combine 显式使用 topk_weights;不要按 ep_size 跳过权重。
  • Qwen3Next 全注意力层始终使用第 0 层 KV cache @ rtp_llm/models_py/model_desc/qwen3_next.py:954
    • 建议:给 Qwen3NextAttention 增加 layer_idx 参数,构造处传入当前 layer_idx,并在 super().init 中传 layer_idx=layer_idx。

P1

  • ROCm DeepEP 量化配置解析后仍固定使用非量化 executor @ rtp_llm/models_py/modules/factory/fused_moe/impl/rocm/strategy/ep.py:140
    • 建议:DeepEP 分支应返回解析出的 executor_class,或在 DeepEP normal 下明确拒绝 FP8/FP4 量化配置,避免量化权重走无量化 ck_moe_stage1/2。
  • TRT allreduce 不支持的 world_size 会被误判为可用 @ rtp_llm/models_py/modules/base/rocm/trt_allreduce.py:73
    • 建议:world_size==1 或不在支持集合时设置 disabled=True,且 ensure/is_trt_allreduce_ready 同时检查 handle is not None,保证上层能回退 RCCL。
  • ROCm EP FP4 分支缺少 dtype/硬件能力检查 @ rtp_llm/models_py/modules/factory/fused_moe/impl/rocm/strategy/ep.py:51
    • 建议:复用 mxfp4.py 的 _get_mxfp4_dtype(),或在 check_conditions 中检查 is_gfx950() 和 hasattr(torch, "float4_e2m1fn_x2"),不满足时让策略不可选而不是 AttributeError/运行期崩溃。
  • ORIGINAL all_probs 模式下 cum_log_probs 使用了原始分布 @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:208
    • 建议:为 cum_log_probs 单独保存最终采样分布,先从过滤/重归一化后的概率 gather,再按 ORIGINAL 模式覆盖对外返回的 all_probs。
  • 批量 D2D 拷贝的临时 workspace 可能在异步 kernel 完成前释放 @ rtp_llm/models_py/bindings/core/CudaOps.cc:273
    • 建议:对 workspace 调用 CUDA/ROCm caching allocator 的 record_stream,或把 completion event 放到 kernel 后并保证 workspace 生命周期覆盖该 stream 完成;补开启 comm overlap 的批量 D2D 压测。
  • BatchDecodeScheduler 在 ReturnAllProbs 混合时可能永久不调度 @ rtp_llm/cpp/engine_base/schedulers/BatchDecodeScheduler.h:142
    • 建议:不要把 NONE 单独成组;按候选 DEFAULT/ORIGINAL 合并 NONE,或在同组不足但总 waiting 满足时允许小批调度,避免请求一直留在 waiting_streams_。
  • DeepSeek VL2 默认图片 preprocess config 构造会 TypeError @ rtp_llm/openai/renderers/deepseek_vl2_renderer.py:100
    • 建议:与 llava/qwen renderer 保持一致,从 rtp_llm.ops 导入 C++ MMPreprocessConfig,或扩展 Python dataclass 并确保后续能转换为 C++ config。
  • 批解码按概率模式分组后会卡住混合队列 @ rtp_llm/cpp/engine_base/schedulers/BatchDecodeScheduler.h:174
    • 建议:按注释允许最大组以小 batch 入队,或把 NONE 流填充到 DEFAULT/ORIGINAL 组;补 batch_size 下 DEFAULT/ORIGINAL/NONE 混合等待队列的调度单测。
  • URL 缓存返回共享 BytesIO,存在并发读写游标竞态 @ rtp_llm/multimodal/multimodal_util.py:204
    • 建议:缓存不可变 bytes,命中时返回新的 BytesIO(cached_bytes);或返回 BytesIO(cached_res.getvalue()),不要把共享可变 stream 暴露给调用方。
  • HTTP 多模态 URL 下载会因缺失 ssrf_check 直接失败 @ rtp_llm/multimodal/multimodal_util.py:32
    • 建议:把 ssrf_check.py 及 BUILD/package 依赖随 PR 一起加入,或改为仓库内已有的安全下载实现,确保 http/https 图片输入可用且仍 fail-closed。
  • 批量预处理超时取最小值会误杀同请求中的长超时输入 @ rtp_llm/multimodal/mm_process_engine.py:328
    • 建议:对不可部分返回的 work_item 使用 batch/request 级 max timeout;若要支持 strict input,需要拆分 work_item 或实现逐输入取消/错误返回语义。
  • CPU 后端成功启动后父进程会一直等待 ready @ rtp_llm/start_backend_server.py:428
    • 建议:CPU 路径也调用 local_rank_start(global_controller, py_env_configs, 0, pipe_writer),保证所有启动成功/失败路径都遵守 pipe 协议。
  • DeepSeek-VL2 图像 token id 可能取自未补 special token 的 tokenizer @ rtp_llm/models/deepseek_vl2/deepseek_vl2.py:152
    • 建议:复用 self.tokenizer 中已初始化的底层 tokenizer 或 DeepSeekVLV2Tokenizer.image_token_id,不要重新创建未补齐 special token 的 AutoTokenizer。
  • CPU 后端启动成功后父进程会一直等待 ready @ rtp_llm/start_backend_server.py:429
    • 建议:CPU 路径改为 local_rank_start(global_controller, py_env_configs, 0, pipe_writer),保证所有启动路径都遵守 ready/error pipe 协议。
  • Qwen3Next 全注意力层丢失 layer_idx @ rtp_llm/models_py/model_desc/qwen3_next.py:527
    • 建议:给 Qwen3NextAttention.init 增加 layer_idx 参数,并从 Qwen3NextDecoderLayer 构造处传入,再传给 CausalAttention。
  • backend 启动健康检查可能无限等待 pipe @ rtp_llm/start_server.py:71
    • 建议:所有 start_backend_server 分支都必须向 pipe_writer 发送 success/failed;同时给 run_health_checks 设置启动超时并在超时后失败退出。
  • VIT 空 embedding 以 OK 响应返回会触发 C++ 检查失败 @ rtp_llm/server/vit_rpc_server.py:35
    • 建议:VIT 侧空 embeddings 应设置 gRPC error;或在 RPC server 返回 INVALID_ARGUMENT/INTERNAL,避免 C++ 侧 CHECK。

Non-blocking Suggestions

P2

  • CP 场景仍会先触发一次不必要的 GPU 同步 @ rtp_llm/models_py/modules/factory/attention/attn_factory.py:41
    • 建议:先计算 cp_enabled 并在 .max().item() 前短路,例如 attn_inputs.is_prefill and not cp_enabled and ...max().item(),避免 CP prefill 选路时做无用 GPU→CPU 同步。
  • 空 topk 输入仍会启动 0-grid Triton kernel @ rtp_llm/models_py/triton_kernels/moe/ep_kernels.py:586
    • 建议:在 num_total == 0 时直接返回 empty_like(topk_ids) 和全 0 expert_count,避免 PureDP fake/empty batch 依赖 Triton 0-grid launch 行为。
  • MoriEP router 在 MoE 热路径逐层 info 日志 @ rtp_llm/models_py/modules/factory/fused_moe/impl/rocm/routers/mori_ep_intranode_router.py:92
    • 建议:降为 debug,或仅初始化/首次命中时打印;避免每层每 token step 产生高频日志和字符串格式化开销。
  • [符号已在common.h定义-自动降级] ROCm 采样分支引用块作用域外变量导致无法编译 @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:522
    • 建议:将 torch::Tensor filtered_probs = probs_t; 提到采样分支前,并在 top_k==1 与通用采样路径都维护为最终采样分布。
  • ROCm allreduce capture 回滚会尝试关闭本 rank 本地指针 @ rtp_llm/models_py/bindings/rocm/kernels/trtllm_allreduce_fusion.cu:1302
    • 建议:回滚时按 index 遍历并跳过 rank_,或显式记录哪些指针来自 hipIpcOpenMemHandle 后只关闭远端句柄。
  • combo_position_ids 在同一次 Python forward 中重复搬运到 GPU @ rtp_llm/cpp/models/PyWrappedModel.cc:480
    • 建议:在 forward 内只生成一次 CUDA tensor,并复用到 PyModelInputs.combo_position_idsattention_inputs.combo_position_ids,micro-batch 路径同理。
  • top_k renorm 热路径每次固定分配并清零 1MB workspace @ rtp_llm/models_py/bindings/cuda/kernels/sampling/api.cu:148
    • 建议:按实际 num_groups * sizeof(RadixRowState) 计算 workspace,或由 Sampler 复用缓存 workspace;如果 kernel 已初始化必要字段,避免整块 zero-fill。
  • ROCm prefill 计算了 rope_cache 但没有传给内核 @ rtp_llm/models_py/bindings/rocm/FusedRopeKVCacheOp.cc:323
    • 建议:将 rope_cache_ptr 传入 prefill invoker;如果该路径不打算用 cache,则删除这次 getRopeCacheOnce,避免首轮初始化未使用的 cache。
  • Deepep normal router 用例不再被 pytest 收集 @ rtp_llm/models_py/modules/factory/fused_moe/impl/rocm/test/deepep_normal_router_test.py:183
    • 建议:补充 pytest 可收集的 wrapper,例如 test_deepep_normal_router 加参数化和 GPU 数量 skip;或确认该文件由 Bazel 以脚本入口执行。
  • 多模态特征 hash 会同步整块 embedding 到 CPU @ rtp_llm/cpp/multimodal_processor/MultimodalProcessor.cc:28
    • 建议:优先在多模态预处理结果中携带稳定 hash,或用 GPU/异步 hash;至少缓存每个特征的 hash,避免 expandTokenIds 热路径 D2H 阻塞。
  • Qwen3.5 MoE VIT 位置插值每次 forward 发生 CPU 回读和 H2D 重建 @ rtp_llm/multimodal/multimodal_mixins/qwen3_5_moe/qwen3_5_moe_vit.py:462
    • 建议:保留 grid_thw 的 CPU 元数据用于 shape 计算,并按 grid shape 缓存 idx/weight;或改成纯 GPU 张量计算,避免每次 VIT forward 同步。
  • Qwen3VL 批量 embedding 先搬到 GPU 再 tolist 触发同步 @ rtp_llm/multimodal/multimodal_mixins/qwen3_vl_mixin.py:170
    • 建议:在 grid_thw 仍为 CPU tensor/list 时计算 split_sizes;Qwen3_5MoeImageEmbedding 中同样的 batched_embedding 路径一起修复。
  • 流式输出每步重复分配并遍历多模态长度 @ rtp_llm/cpp/normal_engine/NormalGenerateStream.cc:111
    • 建议:在 multimodal_features 写入或 GenerateInput 初始化后预计算一次 multimodal_lengths,流式每 token 输出阶段直接复用。
  • 多模态 gather 路径重复扫描并复制 feature 向量 @ rtp_llm/cpp/normal_engine/NormalModelInputGatherer.cc:365
    • 建议:每个 context stream 只取一次 mm_features/mm_locs 并计算一次 reuse_mm_count,传给 feature 和 extra_input 两个 gather 分支复用。
  • Qwen3VL 前向路径重复回读 multimodal locs @ rtp_llm/models_py/model_desc/qwen3vl.py:100
    • 建议:把 locs 的 CPU 列表化集中到一个 helper 中复用,或让 embedding/deepstack injector 接收同一份预计算 locs,避免每次 forward 重复 .to(cpu).tolist()。
  • Qwen3VL MoE 前向路径重复回读 multimodal locs @ rtp_llm/models_py/model_desc/qwen3vl_moe.py:103
    • 建议:与 Qwen3VL 普通版共用 locs 预处理逻辑,或调整 injector 接口避免同一 mm_feature_locs 在单次 forward 中多次 CPU 化。
  • TP-only shared expert 路径退化为两次 all_reduce @ rtp_llm/models_py/model_desc/generic_moe.py:162
    • 建议:保留 EP 修正的同时恢复 TP-only 的 unified allreduce 分支:routed/shared 都 skip 内部 allreduce,合并后对 experts_output 做一次 TP all_reduce。
  • VIT proxy 默认超时与 worker 默认超时不一致 @ rtp_llm/server/vit_proxy_server.py:31
    • 建议:让 proxy 默认超时来自 VitConfig.mm_timeout_ms,或启动 proxy 时显式传入同一配置,保证 proxy deadline 与 worker 处理超时一致。
  • batched_embedding 返回数量不匹配会被 zip 静默截断 @ rtp_llm/multimodal/mm_process_engine.py:575
    • 建议:在写回前校验 len(batch_outputs) == len(pending_items),不匹配时抛出带 batch/input 数量的异常,避免静默丢特征。
  • Profiler 初始化失败会泄漏 active 计数 @ rtp_llm/multimodal/mm_profiler.py:219
    • 建议:把 profiler 创建也纳入清理 finally,或在 profiler 成功进入上下文后再增加 active 计数,异常路径必须 decrement 并 notify。
  • URL 缓存复用同一个 BytesIO 有并发读指针竞态 @ rtp_llm/multimodal/multimodal_util.py:200
    • 建议:缓存不可变 bytes,命中时返回新的 BytesIO(cached_bytes),避免 PIL/decord 并发读取互相移动指针。
  • trans_mm_input 的 list 分支类型与字段不一致 @ rtp_llm/multimodal/multimodal_util.py:265
    • 建议:统一接受 rtp_llm.ops.MultimodalInput,或把本地 MultimodalInput.config 显式转换为 _CppMMPreprocessConfig。
  • scatter_qkv 异常类型测试与实现不一致 @ rtp_llm/models_py/triton_kernels/common/test/scatter_qkv_test.py:137
    • 建议:把测试期望改为 ValueError,或把实现输入校验统一改成 assert。
  • BeamSearch 参数矩阵过大,单测容易拖慢或撑爆 GPU CI @ rtp_llm/cpp/testing/BeamSearchOpTest.hpp:132
    • 建议:把大规模 case 拆成少量边界测试或 perf/large 标签测试;常规 CI 只保留小矩阵和一个最大 beam 冒烟 case。
  • DeepSeekVLV2 启动时重复加载 tokenizer @ rtp_llm/models/deepseek_vl2/deepseek_vl2.py:146
    • 建议:复用 self.tokenizer.encode('', add_special_tokens=False) 或底层 tokenizer 对象,避免二次解析 tokenizer 文件和重复占用内存。
  • 多模态 embedding 每个请求重复做 VIT 地址发现 @ rtp_llm/embedding/embedding_endpoint.py:103
    • 建议:在 EmbeddingEndpoint 内缓存 VIT role 地址,按 TTL 或 RPC 失败时刷新,避免请求热路径反复做服务发现。
  • MoriEP 关键拓扑校验使用 assert @ rtp_llm/models_py/distributed/moriep_wrapper.py:79
    • 建议:改成显式 if ...: raise ValueError/RuntimeError,并在注册 shmem process group 前完成全部拓扑校验。
  • reduce_scatter 输入形状校验使用 assert @ rtp_llm/models_py/distributed/collective_torch.py:673
    • 建议:改成显式 if input_tensor.shape[0] % world_size != 0: raise ValueError(...),保持与 output_tensor 校验一致。
  • VIT proxy 启动中途异常可能遗留已启动 worker @ rtp_llm/start_server.py:186
    • 建议:用 try/except 包住 VIT 启动流程,异常时 terminate/join 已启动进程;或每个进程 start 后立即登记到 ProcessManager。
  • inline FP8 加载每个完成权重都触发 GC @ rtp_llm/model_loader/loader.py:447
    • 建议:把 gc.collect() 和 device_props 查询改为按 N 个权重或 reserved memory 阈值触发,避免大模型加载时频繁全局停顿。
  • transpose_stack_moe_w1 额外克隆半个 MoE 权重 @ rtp_llm/model_loader/per_channel_fp8_quant_weight.py:853
    • 建议:加载 expert 时直接写入交换后的目标 slice,避免完整写入后再 clone/copy 半个 fp8_out 和 scale_out。
  • enqueue 重复序列化请求 @ rtp_llm/cpp/model_rpc/model_rpc_client.py:491
    • 建议:选路只依赖 input_py,保留一次 trans_input(input_py) 即可;建议删除前面的早期序列化或后面的重复序列化。
  • TensorPB shape 缺少边界校验 @ rtp_llm/cpp/model_rpc/TensorPbConvert.cc:59
    • 建议:逐维校验 dim >= 0,并用 checked multiply 计算 numel;溢出或负维度应返回明确解析错误,避免畸形 RPC payload 触发错误分配或异常外溢。
  • 远端多模态输出校验用异常路径 @ rtp_llm/cpp/model_rpc/QueryConverter.cc:242
    • 建议:把远端 VIT 返回的 split_size/embedding 校验改成 ErrorInfo/StatusOr,或在调用方捕获 RTP_EXCEPTION 并转为 MM_PROCESS_ERROR,避免坏响应直接走未捕获异常路径。
  • [平台条件编译已覆盖-自动降级] ROCm TopK 快路径忽略 mask_val,破坏 beam search 的 -inf mask 语义 @ 3rdparty/trt_beam_search/topkLastDim.cu:1630
    • 建议:让 ROCm efficient_topk 支持 mask_val 的 tie 处理;或在 mask_val.has_value() 时让 workspace size 与 invoke 同步走 stable radix fallback。
  • 普通 embedding 传 position_ids 时退化到非向量化路径 @ rtp_llm/models_py/bindings/common/RtpEmbeddingLookup.cc:59
    • 建议:当没有 position/token_type embedding table 时忽略 position_ids/token_type_ids,或按 table 是否存在决定 vectorized 路径。

Checklist ✅ (56 items passed)

Strengths

  • MLA/MHA 工厂新增 support_parallelism_config 过滤,能避免不支持 CP 的实现被错误实例化。
  • XQA CUDA Graph 路径开始显式维护 capture 时的 sequence_lengths storage,修复方向符合 graph replay 参数更新需求。
  • scatter_qkv 对输入维度、contiguous 和 packed last_dim 做了显式校验,能避免错误 stride 下静默拆错 Q/K/V。
  • 多模态 embedding/deepstack 注入对 loc 数量、shape、dtype、device 和越界位置都有明确校验。
  • TRT allreduce graph capture 失败路径增加跨 rank 协调和回滚,降低单 rank 异常导致 collective hang 的风险。
  • TRT allreduce graph capture 增加了跨 rank 成功标志和 handle 数量一致性检查,降低单 rank 异常导致 collective hang 的风险。
  • copy_kv_cache_offset 在 shape 不一致时先清零再拷贝重叠区域,比旧逻辑更不容易留下过期 offset。
  • 多模态 embedding/deepstack 注入路径增加了形状、dtype、边界位置校验,错误更早暴露。
  • top_k=1 且不返回 all_probs 的 fast path 用 selected_logits - logsumexp 更新 cum_log_probs,避免全量 log_probs 物化。
  • return_all_probs enum 保留旧 bool payload fallback,并对越界枚举做 clamp,兼容性处理较稳。

P1:
- LRO response type mismatch / empty response handling in remote executor
- Prevent EXIT_CODE in stdout from overriding non-OK REAPI status
- BatchDecodeScheduler: treat NONE ReturnAllProbsMode as wildcard
- Add rtp_llm.utils.ssrf_check and route HTTP downloads through it
- DeepSeek VL2: use rtp_llm.ops.MMPreprocessConfig (9-arg) consistently
- FlashInfer CUDA graph replay: avoid calling plan() on replay path
- standalone/BUILD: drop deleted arch_select symbols and stale labels

P2:
- MoriEP router tests: register pytest gpu(type/count) markers
- MultimodalInput: align field name with trans_mm_input, avoid mutable defaults
- verify_smoke_suites: discover test_smoke_*.py and fail on empty match
- perf_runner: fail when configured baseline file is missing or empty
- ROCm fused_moe conftest: only ignore GPU-specific tests
- CAS client: fail batch upload / ByteStream write on size/status errors
@LLLLKKKK

Copy link
Copy Markdown
Collaborator

AI Code Review - PR #1108

Status: BLOCKING

Summary: P0/2 · P1/13 · P2/26 · P3/0

Blocking Issues

P0

  • Qwen3Next 全注意力层丢失 layer_idx @ rtp_llm/models_py/model_desc/qwen3_next.py:954
    • 建议:给 Qwen3NextAttention 增加 layer_idx 参数,构造处传当前 layer_idx,并传给 CausalAttention.init
  • SSRF 校验未覆盖重定向目标 @ rtp_llm/utils/ssrf_check.py:52
    • 建议:禁用自动重定向,手动逐跳解析并校验 Location;同时在实际连接地址上做校验,避免重定向或 DNS rebinding 绕过。

P1

  • 销毁分布式环境时未释放 MoriEP 单例 @ rtp_llm/models_py/distributed/collective_torch.py:423
    • 建议:在 destroy_distributed_environment() 中 import-guard MoriEPWrapper,若已初始化先调用实例 reset_op() 再 MoriEPWrapper.reset(),并在 destroy_process_group 前完成。
  • CPU 后端启动成功后不会向父进程发送 ready @ rtp_llm/start_backend_server.py:429
    • 建议:CPU 路径改为 local_rank_start(global_controller, py_env_configs, 0, pipe_writer),并确保失败路径也通过同一个 pipe 协议返回。
  • DeepSeek-VL2 图像 token id 取自未补 special token 的 tokenizer @ rtp_llm/models/deepseek_vl2/deepseek_vl2.py:152
    • 建议:复用 self.tokenizer.image_token_id 或 self.tokenizer.tokenizer.encode('', add_special_tokens=False),不要重新创建未初始化 special token 的 AutoTokenizer。
  • URL 缓存复用同一个 BytesIO 存在并发游标竞态 @ rtp_llm/multimodal/multimodal_util.py:199
    • 建议:缓存不可变 bytes;每次命中返回新的 BytesIO(cached_bytes),不要把共享可变 stream 暴露给调用方。
  • 本地多模态 batch 超时语义与远端路径不一致 @ rtp_llm/multimodal/mm_process_engine.py:328
    • 建议:统一本地与远端 deadline 语义;若 work_item 不能部分返回,建议使用请求级 max timeout,或拆分 work_item 实现逐输入超时结果。
  • ROCm 采样路径引用了块作用域外变量 @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:522
    • 建议:将 filtered_probs 声明提升到采样分支外,并在 top_k==1 快路径保持为 probs_t;或为 cum_log_probs 分支分别处理 top_k==1 和过滤采样两种情况。
  • 返回原始 all_probs 时会用错误分布更新 cum_log_probs @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:217
    • 建议:为 cum_log_probs 保留单独的最终采样分布 tensor,或在覆盖 original all_probs 前先 gather 采样 logprob。
  • Mori EP 路由会被本地 expert id 重映射的维度检查直接打断 @ rtp_llm/models_py/triton_kernels/moe/remap_local_ids_kernel.py:38
    • 建议:允许 dispatch_ids/weights 为同形状二维张量:保留原 shape,内部 flatten 后 launch kernel,输出 reshape 回原 shape;或在 router 调用前显式 flatten 并恢复形状。同步修正/运行 moriep_intranode_router_test 与 test_remap_local_ids。
  • TRT allreduce 未支持 world size 时仍被标记为可用 @ rtp_llm/models_py/modules/base/rocm/trt_allreduce.py:70
    • 建议:在 world_size==1/unsupported 分支设置 disabled=True,或让 ensure/is_trt_allreduce_ready 同时要求 dist_env.handle is not None;allreduce 路径应返回 False/抛 RuntimeError 以便 RCCL fallback。
  • BatchDecode 混合 logprobs 模式仍可能永久不调度 @ rtp_llm/cpp/engine_base/schedulers/BatchDecodeScheduler.h:190
    • 建议:当总等待数已达 batch_size 但兼容组不足时,应调度选中兼容组的小批次,或按兼容组分别判断触发条件,避免等待队列永久卡住。
  • BatchDecodeScheduler 混合概率模式时可能永久不调度 @ rtp_llm/cpp/engine_base/schedulers/BatchDecodeScheduler.h:182
    • 建议:在无兼容组能凑满 batch 时允许最大兼容组小批调度,或让 BatchDecodeScheduler 明确拒绝/拆分互斥模式;补 DEFAULT/ORIGINAL/NONE 混合等待队列的调度单测。
  • VIT 空 embedding 以 OK 空响应返回会触发 C++ CHECK @ rtp_llm/server/vit_rpc_server.py:35
    • 建议:VIT 侧空 embedding 应通过 context.abort/非 OK gRPC 状态返回明确错误,或在 PB 中携带错误字段;不要返回空 OK PB。
  • 本地多模态可能被误构造成 RemoteMultimodalProcessor @ rtp_llm/cpp/model_rpc/LocalRpcServer.cc:42
    • 建议:C++ init 同时检查 vit_separation/role/tp_rank;只有 VIT_SEPARATION_REMOTE 才构造 RemoteMultimodalProcessor,本地模式缺少 mm_process_engine 时 fail fast。

Non-blocking Suggestions

P2

  • BeamSearch 单测矩阵过大,容易拖慢 GPU CI @ rtp_llm/cpp/testing/BeamSearchOpTest.hpp:132
    • 建议:常规 CI 只保留小矩阵和少量最大 beam 冒烟;大 batch/beam/seq_len case 拆到 large/perf 标签。
  • 多模态 embedding 请求热路径重复做 VIT 地址发现 @ rtp_llm/embedding/embedding_endpoint.py:103
    • 建议:在 EmbeddingEndpoint 缓存 VIT role 地址,按 TTL 或 RPC 失败刷新,避免每个请求重复服务发现和日志开销。
  • DeepSeekVLV2 启动时重复加载 tokenizer @ rtp_llm/models/deepseek_vl2/deepseek_vl2.py:146
    • 建议:复用 self.tokenizer 已持有的 tokenizer 或其 image_token_id,避免二次解析 tokenizer 文件和重复占用内存。
  • inline FP8 每个完成权重仍触发全局 GC @ rtp_llm/model_loader/loader.py:447
    • 建议:将 gc.collect() 改为按权重计数或内存阈值触发,与 empty_cache() 使用同一节流策略。
  • transpose_stack_moe_w1 仍会克隆半个 MoE 权重 @ rtp_llm/model_loader/per_channel_fp8_quant_weight.py:848
    • 建议:加载 expert 时直接写入交换后的目标 slice,避免完整写入后再 clone/copy 半个输出。
  • 多模态 mixin loader 一次性 materialize 全量 VIT 权重 @ rtp_llm/model_loader/multimodal_mixin_loader.py:41
    • 建议:改成流式加载到目标参数,或至少优先保留 CPU tensor 并在赋值后释放,降低 VIT 初始化峰值显存。
  • reduce_scatter 形状前置校验会被 Python -O 跳过 @ rtp_llm/models_py/distributed/collective_torch.py:673
    • 建议:改成显式 if ...: raise ValueError(...),与 output_tensor 的 shape/device/dtype 校验保持一致。
  • MoriEP 关键拓扑校验使用 assert @ rtp_llm/models_py/distributed/moriep_wrapper.py:79
    • 建议:将这些拓扑约束改成显式 RuntimeError/ValueError,并在注册 WORLD shmem group 前完成校验。
  • VIT proxy 启动异常可能遗留已启动 worker @ rtp_llm/start_server.py:186
    • 建议:用 try/except 包住 VIT 启动流程,异常时 terminate/join 已启动进程;或每个进程 start 后立即登记到 ProcessManager。
  • Tensor 默认值判断会触发异常或误替换 @ rtp_llm/multimodal/multimodal_util.py:101
    • 建议:改为 self.tensor = tensor if tensor is not None else torch.empty(1),避免对 Tensor 做 truthiness 判断。
  • scatter_qkv 异常类型测试与实现不一致 @ rtp_llm/models_py/triton_kernels/common/test/scatter_qkv_test.py:137
    • 建议:把测试期望改为 ValueError,或把实现输入校验统一改成 assert。
  • Profiler 创建失败会泄漏 active 计数 @ rtp_llm/multimodal/mm_profiler.py:219
    • 建议:把 profiler 创建纳入清理 finally,或在 profiler 成功进入上下文后再增加 active 计数。
  • TP-only shared expert 路径退化为两次 all_reduce @ rtp_llm/models_py/model_desc/generic_moe.py:162
    • 建议:保留 EP 修正,同时恢复 TP-only unified allreduce:routed/shared 跳过内部 allreduce,合并后统一 all_reduce。
  • Qwen3VL 前向重复回读 multimodal locs @ rtp_llm/models_py/model_desc/qwen3vl.py:100
    • 建议:把 locs 的 CPU list 预处理集中复用,或让 embedding/deepstack injector 接收同一份预计算 locs。
  • Qwen3VL MoE 前向重复回读 multimodal locs @ rtp_llm/models_py/model_desc/qwen3vl_moe.py:103
    • 建议:与 Qwen3VL 普通版共用 locs 预处理逻辑,避免单次 forward 内重复 CPU 化。
  • VIT proxy 默认超时短于 worker 默认超时 @ rtp_llm/server/vit_proxy_server.py:34
    • 建议:让 proxy 默认超时来自 VitConfig.mm_timeout_ms,或启动 proxy 时显式传入同一配置。
  • CP prefill 选路前仍触发一次 GPU 同步 @ rtp_llm/models_py/modules/factory/attention/attn_factory.py:41
    • 建议:先计算 cp_enabled,并在 .max().item() 前短路:attn_inputs.is_prefill and not cp_enabled and cu_kv_seqlens.max().item() <= indexer_topk。
  • MoriEP MoE 热路径使用 info 日志 @ rtp_llm/models_py/modules/factory/fused_moe/impl/rocm/routers/mori_ep_intranode_router.py:92
    • 建议:降为 debug,或只在初始化/首次命中时打印,避免 decode 阶段每层每步产生日志格式化和 I/O 开销。
  • [平台条件编译已覆盖-自动降级] ROCm TopK 快路径绕过 mask 语义 @ 3rdparty/trt_beam_search/topkLastDim.cu:1630
    • 建议:让 rocm_efficient_topk 支持 mask_val 的 tie/skip_reorder 语义;或在 mask_val.has_value() 时 workspace size 与 invoke 同步走 stable radix fallback。
  • enqueue 重复序列化请求 @ rtp_llm/cpp/model_rpc/model_rpc_client.py:491
    • 建议:选路只依赖 input_py,保留一次 trans_input(input_py) 即可;删除早期或后面的重复序列化。
  • TensorPB shape 乘积缺少边界校验 @ rtp_llm/cpp/model_rpc/TensorPbConvert.cc:59
    • 建议:逐维校验 dim >= 0,并用 checked multiply 计算 numel;溢出或非法 shape 应返回明确解析错误。
  • 远端多模态坏响应会走异常路径 @ rtp_llm/cpp/model_rpc/QueryConverter.cc:242
    • 建议:将 split_size/embedding 校验改成 ErrorInfo/StatusOr,或在 RemoteMultimodalProcessor 捕获并转成 MM_PROCESS_ERROR。
  • 视觉 attention 每层触发 GPU 到 CPU 同步 @ rtp_llm/multimodal/multimodal_mixins/qwen2_vl/modeling_qwen2_vl.py:230
    • 建议:在 visual.forward 中预先计算一次 host 侧 max_seqlen,并作为参数传入各层 attention;避免每层 .item() 同步。
  • BatchDecodeScheduler 分组在调度锁内增加线性拷贝和重复扫描 @ rtp_llm/cpp/engine_base/schedulers/BatchDecodeScheduler.h:142
    • 建议:单次遍历时记录候选迭代器,调度成功后用迭代器 erase,避免额外 list 节点分配和 O(batch_size * waiting_size) remove 扫描。
  • MoE reduce_scatter 热路径未复用输出 buffer @ rtp_llm/models_py/modules/factory/fused_moe/impl/cuda/routers/pure_cp_router.py:142
    • 建议:为 PureCpRouter/PureDpRouter 接入 workspace 或按 shape 缓存 output_tensor,并传给 reduce_scatter;DP 截断前复用完整 chunk buffer。
  • Qwen3VL deepstack 路径每次同步 mm_features_locs 到 CPU @ rtp_llm/models_py/model_desc/qwen3vl.py:101
    • 建议:在 C++ 侧保留/传递 host locs,或将 deepstack injector 改为直接消费 GPU tensor,避免 Python .tolist() 同步。

Checklist ✅ (56 items passed)

Strengths

  • inline MoE FP8 量化路径减少了加载阶段完整 BF16 MoE 权重的显存峰值。
  • DeepEP 改为可选依赖 lazy import,降低非 DeepEP 环境的启动失败和 import 成本。
  • reduce_scatter 新增 output_tensor 参数,为热路径复用通信输出 buffer 留出了接口。
  • empty_cache() 已增加 reserved memory 阈值判断,避免每个 tensor 都刷新 CUDA allocator。
  • RtpLLMOp 的参数重排已同步 Python wrapper 调用,避免 token_processor 与 mm_process_engine 位置误传。
  • 在线 FP8 加载新增 TensorCollector 预量化存储和专项单测,覆盖了 scale 对齐、stacked key 不覆盖、gate/up swap 等关键边界。
  • VIT worker 端口范围增加了启动前校验,能更早暴露端口越界配置。
  • RtpLLMOp 的 token_processor 与 mm_process_engine 参数顺序在 C++ pybind 和 Python 包装层当前保持一致。
  • HTTP 下载路径改为懒加载 safe_request_get,缺少 SSRF 校验模块时 fail-closed。
  • MultimodalInput 默认参数从可变/运行时对象改为 None 入口,方向上减少了共享默认对象风险。

P0:
- SSRF redirect validation: manual redirect follow with per-Location
  scheme/host/IP re-check and relative URL resolution.
- BatchDecodeScheduler: partial-batch fallback when incompatible modes
  prevent filling batch_size_.

P1:
- FIFOScheduler: initialize batch return_all_probs mode from running
  streams and reject incompatible DEFAULT/ORIGINAL waiting streams.
- multimodal_util: restore cache_size <= 0 disables cache; recreate LRU
  when disabled cache gets positive size.
- triton_kernels/BUILD: restore py_library targets for common/fla/kimi_kda/
  moe/causal_conv1d/sparse_mla.
- verify_smoke_suites: AST-only SMOKE_CASES parsing (stdlib-only).
- attn_factory: restore get_global_weight_or_none for RoPE-less MLA;
  validate attn_backend/disable_attn_backends names and add flashinfer
  alias for py_flashinfer.
- case_runner: server_manager/remote_kvcm cleanup in finally with
  idempotent stop/log copy.
- conftest/__init__: defer heavy torch/triton/ops imports during
  pytest collect-only and plugin discovery.
- ConfigModules: default use_triton_pa=false to align ROCm defaults.
- smoke_framework/runner: copy shared env list to every role in multi-role
  smoke cases.
- comparer_registry: auto-register internal mainse comparers before OSS
  fallback.
- arch_select.bzl: restore requirement/internal_deps/triton_deps shims.
- validation: add 'eval' to known smoke markers.
- P0-1: pass layer_idx through Qwen3NextAttention to CausalAttention
- P0-2: SSRF check validates redirects and pins connections to resolved IPs
- P1-1: reset MoriEP singleton before destroying process groups
- P1-2: CPU backend sends ready signal via local_rank_start
- P1-3: reuse self.tokenizer.image_token_id in DeepSeek-VL2
- P1-4: cache URL bytes and return fresh BytesIO copies
- P1-5: align local MM batch timeout semantics with remote path
- P1-6/P1-7: fix ROCm filtered_probs scope and cum_log_probs distribution
- P1-8: support 2-D dispatch_ids/weights in remap_local_ids
- P1-9: disable TRT allreduce for unsupported world sizes
- P1-10: avoid permanent stall in BatchDecodeScheduler mixed logprobs mode
- P1-11: abort VIT RPC on empty embeddings
- P1-12: choose Local/RemoteMultimodalProcessor by vit_separation/role/tp_rank
@LLLLKKKK

Copy link
Copy Markdown
Collaborator

AI Code Review - PR #1108

Status: BLOCKING

Summary: P0/0 · P1/10 · P2/21 · P3/0

Blocking Issues

P1

  • HTTPS 多模态 URL 下载会因 TLS 主机名错位失败 @ rtp_llm/utils/ssrf_check.py:138
    • 建议:不要只改写 request.url 后依赖 Host 头;为当前 requests/urllib3 版本实现真正的 SNI/hostname 校验绑定,或升级并显式覆盖兼容路径,并补 HTTPS 域名下载回归测试。
  • 新增 Bazel py_library 缺少运行时依赖 @ rtp_llm/models_py/triton_kernels/BUILD:18
    • 建议:为 :kimi_kda 增加 //rtp_llm/models_py/triton_kernels/autotune_cache 依赖,并为 :moe 补齐 models_py/utils/math 的 Bazel target 依赖,确保 py_test runfiles 完整。
  • BatchDecodeScheduler 混合 return_all_probs 时会遗留请求卡住 @ rtp_llm/cpp/engine_base/schedulers/BatchDecodeScheduler.h:242
    • 建议:部分调度后若 waiting_streams_ 仍非空,应继续触发下一轮并允许不足 batch_size 的兼容分组被调度,或增加明确的 timeout/flush 条件。
  • BatchDecode 拆分混合概率模式后仍会留下永久等待请求 @ rtp_llm/cpp/engine_base/schedulers/BatchDecodeScheduler.h:192
    • 建议:混合 DEFAULT/ORIGINAL 被拆成部分 batch 后,应继续调度剩余兼容组,或在 running 为空且 waiting 非空时允许最大兼容组小批运行;补 2 DEFAULT + 2 ORIGINAL、batch_size=4 的单测。
  • MoriEP 销毁未释放 shmem 运行时 @ rtp_llm/models_py/distributed/collective_torch.py:477
    • 建议:在 destroy_process_group 前调用 mori.shmem.shmem_finalize()(若存在);并用 finally 保证 reset_op 抛错时 MoriEPWrapper.reset() 仍执行,补 destroy/reinit 回归测试。
  • return_original_all_probs 会让 cum_log_probs 记录原始分布 @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:167
    • 建议:将 cum_log_probs 需要的采样分布和用户返回的 original all_probs 分离;即使 return_original_all_probs=true,也应为 cum_log_probs 生成 top_k/top_p 过滤并 renorm 后的临时分布,并补充该组合测试。
  • ROCm ORIGINAL all_probs 返回被过滤后的分布 @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:473
    • 建议:ROCm 路径在过滤前保留 raw_probs_t,或让 filtered_probs = probs_t.clone();ORIGINAL 输出必须从未过滤的 softmax 分布拷贝。
  • ROCm 采样忽略请求级 random_seed @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:519
    • 建议:将 params.generator 接入 ROCm multinomial 路径;若 batch 内 generator 不同,应按行采样或用已生成的 per-row random 值实现采样。
  • 全局禁用列表按单阶段校验会误拒合法配置 @ rtp_llm/models_py/modules/factory/attention/attn_factory.py:198
    • 建议:将 disable_attn_backends 按 prefill+decode 全 registry 的并集校验,并先展开别名;实际跳过时再按当前阶段匹配,避免 xqa 这类 decode-only 后端在 prefill 阶段报错。
  • flashinfer 禁用别名在 auto 模式下不会生效 @ rtp_llm/models_py/modules/factory/attention/attn_factory.py:207
    • 建议:解析 blocklist 后统一做别名归一化,例如把 flashinfer 展开为需要禁用的实际 NAME(至少 py_flashinfer,按语义决定是否包含 py_flashinfer_paged),auto 和显式路径都使用归一化后的集合。

Non-blocking Suggestions

P2

  • FlyDSL 变长路径构造了未使用的 chunk_offsets @ rtp_llm/models_py/triton_kernels/fla/flydsl_chunk_gdn_mi308x.py:1090
    • 建议:删除当前 FlyDSL kernel 未使用的 chunk_offsets 构造和参数传递,或只在真正读取 chunk_offsets 的 kernel 变体中计算,避免每次 prefill 额外 GPU op/临时 tensor。
  • remap kernel 调用前额外做整张权重 fp32 转换 @ rtp_llm/models_py/triton_kernels/moe/remap_local_ids_kernel.py:79
    • 建议:直接传入原始 dispatch_weights,在 Triton kernel 内将 tl.load 的 weights 转为 tl.float32 后 store,避免 EP prepare 热路径的一次全量临时分配/拷贝。
  • 手动跳转时中间响应未及时关闭 @ rtp_llm/utils/ssrf_check.py:172
    • 建议:在 continue 前对 redirect response 调用 close(),超过最大跳转次数或空 Location 路径也应释放最后一个响应,避免高并发下载时连接/FD 滞留。
  • 缓存命中仍会按原始媒体大小分配新缓冲 @ rtp_llm/multimodal/multimodal_util.py:202
    • 建议:保留每次调用独立游标的修复,但避免缓存命中复制整块 bytes;可提供基于 bytes/memoryview 的只读 seek/read 包装,或在调用方支持不可变 bytes 直传解码。
  • 混合超时语义缺少回归测试 @ rtp_llm/multimodal/mm_process_engine.py:328
    • 建议:补充 MMWorkItem/预处理批次测试,覆盖同一 batch 内多个 mm_timeout_ms 时取 max,以及全为 0 时回退 VitConfig 默认值。
  • Tensor 默认值判断会触发异常 @ rtp_llm/multimodal/multimodal_util.py:101
    • 建议:改为 self.tensor = tensor if tensor is not None else torch.empty(1),不要对 Tensor 做 truthiness 判断。
  • scatter_qkv 异常类型测试不匹配 @ rtp_llm/models_py/triton_kernels/common/test/scatter_qkv_test.py:137
    • 建议:将测试期望改为 ValueError,或把实现侧输入校验统一改成 assert。
  • Profiler 创建失败会泄漏 active 计数 @ rtp_llm/multimodal/mm_profiler.py:219
    • 建议:把 profiler 构造纳入清理 finally,或在 profiler 成功进入上下文后再增加 active 计数。
  • 调度持锁路径新增线性扫描 @ rtp_llm/cpp/engine_base/schedulers/FIFOScheduler.cc:211
    • 建议:将当前 running batch 的 ReturnAllProbsMode 缓存在调度器状态中,随 RUNNING 队列更新/清空维护,避免每轮 schedule 持锁遍历。
  • reduce_scatter 输入校验会被优化模式跳过 @ rtp_llm/models_py/distributed/collective_torch.py:686
    • 建议:改成显式 if 检查并 raise ValueError,与 output_tensor 的 shape/device/dtype 校验保持一致。
  • MoeConfig pickle 丢失 fp4_moe_op @ rtp_llm/cpp/pybind/ConfigInit.cc:652
    • 建议:把 fp4_moe_op 加入 MoeConfig 的 pickle tuple,并兼容旧 12 字段状态;补一条 pickle round-trip 单测。
  • ROCm cum_log_probs 仍会物化整张 log_probs @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:535
    • 建议:改成先 gather 选中 token 的概率再对 [batch] 向量取 log,和 CUDA 分支一致,避免每步额外分配并计算 [batch, vocab]。
  • allreduce capture 回滚会关闭本地指针 @ rtp_llm/models_py/bindings/rocm/kernels/trtllm_allreduce_fusion.cu:1299
    • 建议:回滚关闭 captured IPC handle 时跳过本 rank 的本地指针,并检查 hipIpcCloseMemHandle 返回值,避免失败清理路径污染 HIP error 状态。
  • fake_balance_expert 未校验 scale dtype @ rtp_llm/models_py/bindings/rocm/FakeBalanceExpertOp.cc:16
    • 建议:增加 expert_scales.dtype()==torch::kFloat32 的 TORCH_CHECK,或按 dtype dispatch,避免非 float32 输入被静默按 float 解释。
  • PureDP MoE 每层触发 D2H 同步和临时 padding @ rtp_llm/models_py/modules/factory/fused_moe/impl/cuda/routers/pure_dp_router.py:120
    • 建议:把各 rank token 数在 step/model-input 层作为 host 元数据一次性传入 router,并复用 padding buffer,避免每个 MoE layer 做 scalar all_gather、.item() 和 F.pad 分配。
  • 多模态注入器在 forward 中同步回读 locs @ rtp_llm/models_py/modules/base/common/multimodal_embedding.py:80
    • 建议:在输入构造阶段保留/缓存 host 侧 loc list,embedding 和 deepstack 共用同一份;或改成 GPU 侧批量 scatter/copy,避免 forward 内 GPU→CPU 同步。
  • MoriEP router 在 MoE 热路径打印 info 日志 @ rtp_llm/models_py/modules/factory/fused_moe/impl/rocm/routers/mori_ep_intranode_router.py:92
    • 建议:删除 per-layer info 日志,或降为 debug 并用 logger.isEnabledFor 包住 f-string;需要观测时用采样日志或指标。
  • ROCm paged prefill 每层重复构造辅助张量 @ rtp_llm/models_py/modules/factory/attention/rocm_impl/aiter.py:831
    • 建议:把 sanitized/padded block_table、kv_indptr、empty page index、descale 等 buffer 提前分配并复用;forward 只更新必要内容,避免 prefix prefill 每层分配和全表 torch.where/cat。
  • mainse_arpc 缺失时会回退默认比较器 @ rtp_llm/test/smoke/comparer_registry.py:56
    • 建议:将 q_r.get("mainse_arpc", False) 纳入 is_mainse 判断,或为 mainse_arpc 单独抛出未注册错误,避免静默使用默认比较器。
  • 多模态超时默认值在 proxy/worker/远端不一致 @ rtp_llm/server/vit_proxy_server.py:46
    • 建议:统一默认值来源:将 VitConfig.mm_timeout_ms 写入转发请求,或让 proxy/C++ remote 使用与服务配置一致的默认 timeout。
  • disable_attn_backends 的 flashinfer 别名无法禁用 auto 后端 @ rtp_llm/models_py/modules/factory/attention/attn_factory.py:209
    • 建议:对 backends 和 blocked 统一做别名归一化,例如将 flashinfer 展开/映射为 py_flashinfer,再进入 auto/explicit/校验逻辑。

Checklist ✅ (56 items passed)

Strengths

  • 新增 autotune_cache 可用已签入 JSON 配置绕过 Triton 首次 benchmark,方向上减少 CI/启动抖动。
  • scatter_qkv 用单个 Triton kernel 替代 split/view/contiguous 三段拷贝,符合大 prefill 的内存带宽优化目标。
  • FlyDSL/Gluon 路径增加了形状和 dtype gate,并避免在 GPU cu_seqlens 上做 .item() 校验。
  • LocalRpcServer 对缺失本地 mm_process_engine 改为 fail-fast,避免静默走错处理路径。
  • remap_to_local_ids 保留二维 topk shape,并继续校验 shape/device/dtype/contiguous。
  • smoke runner 的多角色 env 现在会继承共享 env,减少配置遗漏。
  • SSRF 检查补充了手动 redirect 校验,避免 3xx 跳转到内网地址。
  • 多角色 smoke env 合并 shared envs,修复了共享环境变量没有传到各 role 的问题。
  • Qwen3Next dense attention 现在透传 layer_idx,可避免 headwise/per-layer attention 配置全部落到默认 0 层。
  • URL 数据缓存改为缓存不可变 bytes,修复了共享 BytesIO 游标在并发预处理中的竞态风险。

- P2-1: gate large BeamSearch test matrix behind env var for CI
- P2-2: cache VIT role address in EmbeddingEndpoint with TTL refresh
- P2-4: throttle gc.collect() by weight count threshold in FP8 loader
- P2-7: replace assert with explicit ValueError in reduce_scatter
- P2-8: replace assert with explicit RuntimeError in MoriEP topology checks
- P2-9: clean up VIT proxy workers on startup exception
- P2-10: use 'is not None' instead of truthiness for Tensor default
- P2-11: align scatter_qkv test exception type with implementation
- P2-12: fix profiler active count leak on creation failure
- P2-16: use VitConfig.mm_timeout_ms for VIT proxy default timeout
- P2-17: short-circuit GPU sync in CP prefill attention routing
- P2-18: downgrade MoriEP router hot-path log from info to debug
- P2-20: remove duplicate trans_input serialization in enqueue
- P2-21: add per-dim boundary check and checked multiply in TensorPbConvert
- P2-22: convert remote multimodal bad response to ErrorInfo
- P2-23: precompute host-side max_seqlen for Qwen2VL visual attention
- P2-24: optimize BatchDecodeScheduler stream removal with set + remove_if
- P2-25: reuse output buffer in PureCpRouter reduce_scatter hot path
@LLLLKKKK

Copy link
Copy Markdown
Collaborator

AI Code Review - PR #1108

Status: BLOCKING

Summary: P0/0 · P1/17 · P2/31 · P3/0

Blocking Issues

P1

  • BatchDecode 混合概率模式会遗留请求永久等待 @ rtp_llm/cpp/engine_base/schedulers/BatchDecodeScheduler.h:248
    • 建议:部分调度后若 waiting_streams_ 仍非空,应继续触发下一轮并允许不足 batch_size 的兼容组运行,或增加明确 timeout/flush;补混合 DEFAULT/ORIGINAL 单测。
  • ROCm D2D batch copy 的临时 workspace 生命周期早于 kernel @ rtp_llm/models_py/bindings/core/CudaOps.cc:288
    • 建议:把事件记录/等待放到 invokeBatchCopy 之后,或对 workspace 做 record_stream/延长持有到 copy kernel 完成;ROCm 在修复前应回退 batchCopyFallback。
  • CUDA ORIGINAL all_probs 会让 cum_log_probs 使用原始分布 @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:167
    • 建议:将返回给用户的 original all_probs 与 cum_log_probs 所需的采样分布拆成两个 tensor;即使 return_original_all_probs=true 也要为 cum_log_probs 生成过滤/renorm 后分布。
  • ROCm ORIGINAL all_probs 被原地过滤污染 @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:473
    • 建议:ROCm 过滤前先 clone raw_probs,或让 filtered_probs 独立于 probs_t;ORIGINAL 输出必须从未过滤的 softmax 分布生成。
  • ROCm 采样忽略请求级 random_seed @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:519
    • 建议:将 params.generator 接入 ROCm multinomial;若 batch 内 generator 不同,应逐行传 generator 采样或用 seed_h/offset_h 生成 per-row random。
  • VIT 地址缓存会绕过多后端轮询导致热点 @ rtp_llm/embedding/embedding_endpoint.py:111
    • 建议:不要缓存单个 VIT 地址;改为按 TTL 缓存地址列表并每次请求本地 round-robin,或继续调用 HostService 的 cached host list 选择逻辑,同时在失败时 refresh。
  • MoriEP 销毁遗漏 shmem_finalize @ rtp_llm/models_py/distributed/collective_torch.py:469
    • 建议:在 reset MoriEPWrapper 后、destroy_process_group 前,按 moriep 测试清理路径调用 mori.shmem.shmem_finalize()(需 hasattr 保护),避免同进程重启/重初始化残留 shmem 运行时。
  • Quark MXFP4 堆叠 MoE 权重 key 被错误截断 @ rtp_llm/model_loader/mixed_fp4_quant_weight.py:554
    • 建议:参考 per_block_fp8_quant_weight 的处理,先判断 endswith('.weight');对 stacked/Quark key 不要截断,并使用正确的 Quark scale key,同时补 Qwen35 MoE MXFP4 stacked key 单测。
  • attention 禁用列表的跨阶段与别名语义不一致 @ rtp_llm/models_py/modules/factory/attention/attn_factory.py:194
    • 建议:先用 prefill+decode registry 的并集校验 blocklist,并把公开别名 flashinfer 归一化/展开到实际 NAME;auto 和显式路径共用同一套归一化结果。
  • 全局禁用列表按单阶段校验会误拒合法配置 @ rtp_llm/models_py/modules/factory/attention/attn_factory.py:201
    • 建议:用 prefill+decode 全 registry 的并集校验 disable_attn_backends;实际跳过时再按当前阶段匹配。
  • flashinfer 禁用别名在 auto 模式下静默失效 @ rtp_llm/models_py/modules/factory/attention/attn_factory.py:208
    • 建议:解析 blocklist 时统一归一化别名,把 flashinfer 展开成实际 NAME 集合,并让 auto/显式路径共用归一化结果。
  • Bazel 目标漏依赖 autotune_cache @ rtp_llm/models_py/triton_kernels/BUILD:17
    • 建议:给 :kimi_kda 增加 //rtp_llm/models_py/triton_kernels/autotune_cache 依赖;如其他 py_library 直接 import 该包,也同步补齐 deps。
  • HTTPS 多模态下载会因 SNI 丢失失败 @ rtp_llm/utils/ssrf_check.py:137
    • 建议:实现与当前 requests/urllib3 版本兼容的 HTTPS 连接池,显式设置 server_hostname/assert_hostname 为原域名;或避免直接把 HTTPS URL host 改成 IP,并补 HTTPS URL 下载回归测试。
  • kimi_kda 的 Bazel target 缺少 autotune_cache 依赖 @ rtp_llm/models_py/triton_kernels/BUILD:20
    • 建议:在 kimi_kda 的 deps 中加入 //rtp_llm/models_py/triton_kernels/autotune_cache:autotune_cache,并跑受影响的 Bazel py_test。
  • 多模态 C++ 输入长度不一致时会被静默截断 @ rtp_llm/multimodal/mm_process_engine.py:462
    • 建议:在 zip 前显式校验四个列表长度完全一致;不一致时抛 ValueError 并带上各自长度,避免少处理图片后继续返回成功结果。
  • MoriEP 节点 GPU 数量被硬编码为 8 @ rtp_llm/models_py/distributed/moriep_wrapper.py:105
    • 建议:使用 parallelism_config.local_world_size 作为 gpu_per_node,并校验 ep_size/world_size 能被 local_world_size 整除;若 MORI 仅支持 8 卡节点,应显式报错而不是传错拓扑。
  • ROCm 采样未使用请求级 random_seed @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:519
    • 建议:ROCm 路径应按 batch 使用 params.generator 调用 multinomial,或用 seed_h/offset_h 驱动向量化采样 kernel;同时补充 per-request random_seed 回归测试。

Non-blocking Suggestions

P2

  • 多模态 cache key 哈希强制整块特征 D2H @ rtp_llm/cpp/multimodal_processor/MultimodalProcessor.cc:28
    • 建议:避免在 C++ 请求路径拷回完整 embedding;可在 VIT 侧产出紧凑内容 hash,或用 GPU kernel/异步 D2H 只回传每行 hash。
  • Qwen2-VL SDPA 路径新增每层 GPU 同步 @ rtp_llm/multimodal/multimodal_mixins/qwen2_vl/modeling_qwen2_vl.py:314
    • 建议:只在 flash attention 实现需要时计算,或在 Qwen2VisionTransformerPretrainedModel.forward 中计算一次并传给所有 block。
  • BatchDecode 调度锁内新增多次节点分配 @ rtp_llm/cpp/engine_base/schedulers/BatchDecodeScheduler.h:143
    • 建议:用固定 3 个计数/数组先选 mode,再单 pass 选择待调度 stream;至少对临时容器 reserve,减少持锁分配和遍历。
  • FIFO 调度持锁路径新增 running batch 扫描 @ rtp_llm/cpp/engine_base/schedulers/FIFOScheduler.cc:211
    • 建议:把当前 running batch 的 ReturnAllProbsMode 缓存在调度器状态中,随 RUNNING 队列更新/清空维护。
  • ROCm cum_log_probs 会整表取 log @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:535
    • 建议:先 gather 选中 token 的概率,再对 [batch] 向量取 log,避免每步额外分配和计算 [batch, vocab]。
  • ROCm sampling fallback 逐行触发 PyTorch topk/sort @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:490
    • 建议:将 ROCm top_k/top_p 过滤合并到单个批量 kernel,或至少避免按行发起 topk/sort/scatter 多个 ATen op。
  • 多模态输入绕过 fusedCopy @ rtp_llm/cpp/models/PyWrappedModel.cc:423
    • 建议:复用 tensorHoldHostAndToCuda 和 d2d_copies_ 批量拷贝这些输入,避免多次独立 .cuda() 带来的额外分配和拷贝调度。
  • fake_balance_expert 缺少 expert_scales dtype 校验 @ rtp_llm/models_py/bindings/rocm/FakeBalanceExpertOp.cc:16
    • 建议:增加 expert_scales.scalar_type()==torch::kFloat32 的 TORCH_CHECK,或按 dtype dispatch。
  • allreduce capture 回滚会关闭本 rank 本地指针 @ rtp_llm/models_py/bindings/rocm/kernels/trtllm_allreduce_fusion.cu:1302
    • 建议:invalidate_capture 关闭 captured IPC handle 时和析构一致跳过本 rank,并检查 hipIpcCloseMemHandle 返回值。
  • allreduce capture 回滚会关闭本 rank 本地指针 @ rtp_llm/models_py/bindings/rocm/kernels/trtllm_allreduce_fusion.cu:1299
    • 建议:回滚关闭 captured IPC handle 时跳过本 rank 的本地指针,并检查 hipIpcCloseMemHandle 返回值,避免失败清理路径污染 HIP error 状态。
  • MoeConfig pickle 丢失 fp4_moe_op @ rtp_llm/cpp/pybind/ConfigInit.cc:651
    • 建议:把 fp4_moe_op 加入 getstate/setstate tuple,并将 size 校验更新为 13,补一个 pickle round-trip 测试。
  • 默认 BeamSearch 测试不再覆盖超大 beam @ rtp_llm/cpp/testing/BeamSearchOpTest.hpp:139
    • 建议:保留一个默认 CI 的大 beam_width 边界用例(如 2500、较小 batch/seq),或新增专门 target 定期运行,避免大 beam 路径长期只靠手动环境变量覆盖。
  • [平台条件编译已覆盖-自动降级] ROCm beam search TopK 快路径丢失 mask_val 语义 @ 3rdparty/trt_beam_search/topkLastDim.cu:1631
    • 建议:让 ROCm efficient_topk 支持同等 mask_val 语义;或当 mask_val.has_value() 时回退 radix path,并同步 workspace size 计算。
  • LLaVA llama3 分支丢弃请求级多模态预处理配置 @ rtp_llm/openai/renderers/llava_renderer.py:100
    • 建议:在 LLAMA_3 分支与普通分支一致地收集 get_preprocess_config 或默认 MMPreprocessConfig,并传入 PromptWithMMInput
  • Kimi-K2.5 图片请求丢弃 preprocess_config @ rtp_llm/openai/renderers/kimi_k25_renderer.py:61
    • 建议:为 KimiK25Renderer 收集并返回 preprocess_configs,image_url 分支复用 get_preprocess_config 或构造默认 rtp_llm.ops.MMPreprocessConfig
  • 多模态位置注入会触发 GPU 到 CPU 同步 @ rtp_llm/models_py/modules/base/common/multimodal_embedding.py:80
    • 建议:避免在 forward 内对 CUDA tensor 做 to(cpu).tolist();优先传入 CPU locs,或改成设备侧 scatter/index_copy 流程。
  • PureDP MoE 每层执行 D2H 同步取 max_n @ rtp_llm/models_py/modules/factory/fused_moe/impl/cuda/routers/pure_dp_router.py:124
    • 建议:把 max batch size 提前到 step/batch 级别计算并传入 router,避免每个 MoE layer 都 all_gather 后 .item() 同步。
  • MoriEP finalize 热路径有 info 日志 @ rtp_llm/models_py/modules/factory/fused_moe/impl/rocm/routers/mori_ep_intranode_router.py:225
    • 建议:删除该日志或降为 lazy debug(logger.debug("...", args)),避免每层 MoE finalize 产生日志格式化和 IO 压力。
  • FlyDSL 热路径每次分配哨兵 tensor @ rtp_llm/models_py/triton_kernels/fla/flydsl_chunk_gdn_mi308x.py:1127
    • 建议:按 (device, dtype) 缓存 0-size sentinel,或让 launcher 接受可选参数,避免每层每步走 CUDA allocator。
  • remap kernel 前可能多一次权重拷贝 @ rtp_llm/models_py/triton_kernels/moe/remap_local_ids_kernel.py:79
    • 建议:直接传原 dtype 权重给 Triton,在 kernel 内 weights.to(tl.float32) 后写入 fp32 输出。
  • 空 TensorPB 序列化会丢 shape 和 dtype @ rtp_llm/utils/grpc_util.py:50
    • 建议:仅对 None 返回默认 TensorPB;对 numel()==0 仍写入原始 shape 和 data_type,payload 允许为空。
  • TP-only shared expert 路径退回两次 all_reduce @ rtp_llm/models_py/model_desc/generic_moe.py:156
    • 建议:保留 EP 特判的同时,对 ep_size==1 && ffn_tp_size>1 && fused_moe 支持跳过 allreduce 的路径继续合并为一次 TP all_reduce,并补充 TP-only shared expert perf 回归测试。
  • Qwen3VL forward 中重复 GPU 到 CPU 回读 locs @ rtp_llm/models_py/model_desc/qwen3vl.py:100
    • 建议:在 model input 构造阶段保留 pinned CPU locs 或在 forward 开始只转换一次,并把同一个 locs list 传给 embedding/deepstack 两个 injector。
  • URL 缓存 miss 并发下会重复下载 @ rtp_llm/multimodal/multimodal_util.py:179
    • 建议:为 URL cache 增加 per-key lock/future singleflight,或下载前在同一 key 锁内二次检查,避免同一图片高并发请求重复拉取和解码。
  • 批量 embedding 输出数量不匹配时会静默丢结果 @ rtp_llm/multimodal/mm_process_engine.py:575
    • 建议:校验 batch_outputs 非 None 且 len(batch_outputs) == len(pending_items),并校验每个 result 至少包含 embedding/position 两项;否则 fail fast。
  • 并发 profile 请求可能复用同一个 trace 序号 @ rtp_llm/multimodal/mm_profiler.py:204
    • 建议:在拿到 _profile_slot 并重新确认会 profile 后,再在锁内分配唯一 request_idx;或单独维护 next_trace_idx 并在锁内自增。
  • VIT proxy 直接使用默认 VitConfig 会因 None 超时崩溃 @ rtp_llm/multimodal/vit_proxy_start_server.py:79
    • 建议:对 mm_timeout_ms 做 None/<=0 兜底,例如回退到 DEFAULT_PROXY_RPC_TIMEOUT_SECONDS 或 120000ms,并补一个 PyEnvConfigs() 直接启动的单测。
  • 远程 VIT extra_input 数量未在转换层校验 @ rtp_llm/cpp/model_rpc/QueryConverter.cc:263
    • 建议:在 transMMOutput 中当 contain_extra_input 时校验 extra_input 数量等于 split_sizes.size(),错误时返回 MM_PROCESS_ERROR;Python trans_output 也可提前校验。
  • PureDP reduce_scatter 热路径每次分配输出 @ rtp_llm/models_py/modules/factory/fused_moe/impl/cuda/routers/pure_dp_router.py:185
    • 建议:在 PureDpRouterBase 按 expected_shape/device/dtype 缓存 output buffer,并传给 reduce_scatter;batch shape 变化时再重建。
  • TP-only shared expert MoE 产生两次 TP all_reduce @ rtp_llm/models_py/model_desc/generic_moe.py:168
    • 建议:为 fused_moe 增加 skip_allreduce/partial-output 模式,TP-only shared expert 场景先合并 routed/shared partial output,再执行一次 TP all_reduce。
  • MoriEP remap 权重非 fp32 时强制拷贝 @ rtp_llm/models_py/triton_kernels/moe/remap_local_ids_kernel.py:77
    • 建议:让 Triton kernel 直接读取 fp16/bf16 并在内部转 fp32 输出,或约束 MoriEP dispatch 输出 fp32 且在入口处避免重复转换。

Checklist ✅ (56 items passed)

Strengths

  • BatchDecodeScheduler 将逐个 waiting_streams_.remove(stream) 改为 set + 单次 remove_if,避免 O(batch_size * waiting_size) 删除。
  • VIT server 启动失败时会清理已启动进程,减少失败路径资源泄漏。
  • 多模态 cache key 改为基于特征内容,方向上能降低不同图片误复用 KV cache 的正确性风险。
  • GenerateConfig 对 return_all_probs 新枚举保留旧 bool 兼容,并校验非法取值。
  • 多模态远端处理新增 gRPC deadline,并在失败后移除连接,避免复用异常 VIT worker。
  • 多模态 cache key 改为基于特征内容 hash,降低不同图片复用同一 KV cache 的风险。
  • VIT 启动路径在异常时会终止已启动的 worker/proxy 进程,减少启动失败后的残留进程。
  • return_all_probs 三态解析保留 bool 兼容路径,降低旧客户端请求失败风险。
  • CUDA greedy top_k=1 的 cum_log_probs 使用 gather+logsumexp,避免了整张 log_probs 物化。
  • BeamSearch 改为 log_softmax_out 原地写回,减少了一份 logits 级别临时张量。

P1 fixes:
- HTTPS SSRF: stop rewriting URL to IP; pin connection pool host instead,
  preserving TLS SNI/cert verification via server_hostname/assert_hostname
- VIT role separation: VIT_SEPARATION_ROLE with non-VIT role now uses
  RemoteMultimodalProcessor instead of requiring local mm_process_engine
- flashinfer alias: expand 'flashinfer' <-> 'py_flashinfer' in blocklist
  for both auto and explicit backend modes
- legacy FMHA: consume enable_fmha (global switch) and enable_open_source_fmha
  in _is_fmha_impl_disabled_legacy
- kimi_kda BUILD: add autotune_cache dependency
- LRO error: classify recoverable infra failures (exit_code=-1 + infra_category)
  instead of treating all LRO errors as normal test failures
- proto generation: add build_py/sdist custom commands to generate proto
  files before packaging
- smoke runner: use per-test data_root to compute local REL_PATH instead
  of import-time captured value

P2 fixes:
- SSRF redirect: close response before following next hop to avoid FD leak

Already fixed in prior commits (verified):
- CudaSampleOp cum_log_probs sampling distribution
- TensorPbConvert shape boundary/overflow check
- BatchDecodeScheduler stream removal optimization
@LLLLKKKK

Copy link
Copy Markdown
Collaborator

AI Code Review - PR #1108

Status: BLOCKING

Summary: P0/0 · P1/6 · P2/39 · P3/1

Blocking Issues

P1

  • initThreadPool 条件反转导致线程池永不创建 @ rtp_llm/cpp/model_rpc/DecodeRpcServer.cc:50
    • 建议:条件改为 if (resource_.workers.size() == 0) return;
  • loadCacheAsyncForTp push_back 导致 gRPC Finish 指针悬空 @ rtp_llm/cpp/model_rpc/DecodeRpcServer.cc:391
    • 建议:删除 push_back(all_context 已通过 sized 构造分配),直接用 all_context[i];或改为 reserve(2*worker_size)。
  • SSRF get_connection 回退路径静默吞掉校验失败 @ rtp_llm/utils/ssrf_check.py:141
    • 建议:将 except ValueError: pass 改为 raise,确保 SSRF 校验失败时不放行连接。
  • prompt 缓存刷新后仍从旧 REL_PATH 加载 @ rtp_llm/test/smoke_framework/runner.py:168
    • 建议:清除缓存后还需 patch utils 模块的 REL_PATH:_smoke_utils.REL_PATH = local_rel_path。或改 utils.py 为 import common_def 后用 common_def.REL_PATH。
  • start_server 健康检查成功后缺少启动成功日志 @ rtp_llm/start_server.py:404
    • 建议:在健康检查通过后加回启动成功日志和耗时统计:logging.info(f'start server took {time.time()-start_time:.2f}s')
  • ROCm decode 路径使用 assert 校验 kv_cache,release 构建下空指针崩溃 @ rtp_llm/models_py/bindings/rocm/FusedRopeKVCacheOp.cc:470
    • 建议:替换为 TORCH_CHECK(kv_cache.has_value(), "decode should have kv cache.")。

Non-blocking Suggestions

P2

  • RemoteRpcServiceImpl::stop() 中 decode_server_ 可能为空 @ rtp_llm/cpp/model_rpc/RemoteRpcServiceImpl.h:82
    • 建议:改为 } else if (decode_server_) { decode_server_->stop(); }
  • loadCacheSyncForTp 中 min/max_response_done_time_us 数据竞争 @ rtp_llm/cpp/model_rpc/DecodeRpcServer.cc:502
    • 建议:使用 std::atomic<int64_t> 或在 futures.get() 后串行聚合。
  • model_rpc_client trailing_metadata 可能为 None @ rtp_llm/cpp/model_rpc/model_rpc_client.py:438
    • 建议:添加 metadata = e.trailing_metadata() or [] 保护。
  • PrefillRpcServer static local 初始化只执行一次 @ rtp_llm/cpp/model_rpc/PrefillRpcServer.cc:92
    • 建议:改为普通 local 变量。
  • MoriEP gpu_per_node 硬编码 min(8, ep_size) @ rtp_llm/models_py/distributed/moriep_wrapper.py:105
    • 建议:使用 parallelism_config.local_world_size 替代硬编码 8。
  • mm_embedding_cpp zip 静默截断不等长输入 @ rtp_llm/multimodal/mm_process_engine.py:466
    • 建议:zip 前校验四个列表长度一致,不一致抛 ValueError。
  • batch_outputs 数量不匹配 pending_items 时静默丢失结果 @ rtp_llm/multimodal/mm_process_engine.py:575
    • 建议:zip 前校验长度一致,不匹配时抛异常。
  • enable_fmha=False 在显式 backend 模式下不生效 @ rtp_llm/models_py/modules/factory/attention/attn_factory.py:112
    • 建议:进入显式 backend 循环前加 early-return 检查 enable_fmha 状态。
  • DeepEP low-latency _handle 在 prepare 异常时泄漏 @ rtp_llm/models_py/modules/factory/fused_moe/impl/cuda/routers/deepep_low_latency_router.py:150
    • 建议:在 dispatch 后用 try/except 清理 handle 或 reset buffer 状态。
  • TreeDFA input_list_ 初始化为 10 个零元素 @ rtp_llm/cpp/models/logits_processor/DFAUtil.h:127
    • 建议:改为 input_list_() 空构造 + reserve(10)。
  • PrefixToCandidateTokens 中重复 static EMPTY 声明 @ rtp_llm/cpp/models/logits_processor/PrefixToCandidateTokens.h:386
    • 建议:删除内层重复声明,统一使用外层 EMPTY。
  • allreduce_fusion 缺少 hidden_dim=5120/2560 分支 @ rtp_llm/models_py/bindings/rocm/kernels/trtllm_allreduce_fusion.cu:748
    • 建议:补全 5120/2560 分支或在文档中注明限制。
  • TrtllmArFusionHandle 未禁止拷贝构造 @ rtp_llm/models_py/bindings/rocm/TrtllmAllReduceFusion.h:14
    • 建议:添加 = delete 禁止拷贝和赋值。
  • get_fp8_dtype 未检查 hipGetDevice/hipGetDeviceProperties 返回值 @ rtp_llm/models_py/bindings/rocm/FusedRopeKVCacheOp.cc:15
    • 建议:检查返回值,失败时 TORCH_CHECK 报错。
  • MultimodalInput/MMPreprocessConfig pickle 缺少 tuple 大小校验 @ rtp_llm/cpp/pybind/ConfigInit.cc:39
    • 建议:添加 if (t.size() != N) throw std::runtime_error("Invalid state!") 校验。
  • multimodal_mixin_loader load_weights 缺少空 tensor 保护 @ rtp_llm/model_loader/multimodal_mixin_loader.py:33
    • 建议:检查 parts 非空,weight.weights 为空时 skip 或 raise 描述性错误。
  • MoriEpIntranodeRouter _dispatch_ids 跨方法共享有并发风险 @ rtp_llm/models_py/modules/factory/fused_moe/impl/rocm/routers/mori_ep_intranode_router.py:125
    • 建议:确认只用于单流路径,或通过 payload/extra_finalize_args 传递。
  • GrpcConfig::from_json 正则不支持嵌套大括号 @ rtp_llm/cpp/config/ConfigModules.cc:436
    • 建议:添加注释说明限制,或改用 JSON 库解析。
  • top_k_renorm_probs 使用固定 1MB row_states @ rtp_llm/models_py/bindings/cuda/kernels/sampling/api.cu:149
    • 建议:根据 num_groups * sizeof(RadixRowState) 计算所需大小,或保留 1MB 但加 TORCH_CHECK 断言足够。
  • BatchDecodeScheduler NONE 模式流可能饥饿 @ rtp_llm/cpp/engine_base/schedulers/BatchDecodeScheduler.h:170
    • 建议:添加监控指标跟踪各 mode 调度延迟。
  • _load_moe_inline_quant 对 transpose_stack_moe_w1 处理脆弱 @ rtp_llm/model_loader/per_channel_fp8_quant_weight.py:764
    • 建议:is_w1 判断改为 in ("stack_moe_w1", "transpose_stack_moe_w1")。
  • MixedFp4Weight Quark 路径未检查 mixed_attention @ rtp_llm/model_loader/mixed_fp4_quant_weight.py:168
    • 建议:确认 Quark 是否总 mixed_attention=True,如不是应增加检查。
  • PureDpRouter._pad_to_max 每层 D2H sync @ rtp_llm/models_py/modules/factory/fused_moe/impl/cuda/routers/pure_dp_router.py:123
    • 建议:在 FusedMoe.forward 外部预计算 max_n 传入,或 decode 阶段缓存。
  • MtpExecutor .to(kCUDA).clone() 冗余拷贝 @ rtp_llm/cpp/normal_engine/speculative/MtpExecutor.cc:541
    • 建议:直接使用 .to(kCUDA) 返回值,去掉 .clone()。
  • draftModelDecode .cpu().clone().pin_memory() 三步可合并 @ rtp_llm/cpp/normal_engine/speculative/MtpExecutor.cc:839
    • 建议:用 torch::empty(..., pinned_memory(true)) + copy_() 一步完成。
  • getFeatureHash 对每个 multimodal embedding 做全量 D2H 拷贝 @ rtp_llm/cpp/multimodal_processor/MultimodalProcessor.cc:28
    • 建议:考虑 GPU 端计算哈希或异步 D2H + pinned memory。
  • computeReusedMultimodalCount 在同一 stream 被重复调用两次 @ rtp_llm/cpp/normal_engine/NormalModelInputGatherer.cc:365
    • 建议:将结果提到外层缓存,计算一次传给两个消费者。
  • mm_extra_input 无条件 .to(kCUDA) 未检查是否已在 GPU @ rtp_llm/cpp/normal_engine/NormalModelInputGatherer.cc:373
    • 建议:参考同函数 mm_features 处理,先检查 is_cuda()。
  • ROCm sampleGreedy 逐 batch 串行 topk/topp @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:490
    • 建议:使用 torch::topk 的 batch 维度版本一次处理整个 [batch,vocab]。
  • buildPyAttentionInputs 每次 forward 分配 pinned 内存 @ rtp_llm/cpp/models/PyWrappedModel.cc:87
    • 建议:预分配 pinned buffer 复用,或使用 PyTorch pinned memory pool。
  • FusedRopeKVCacheOp D2H sync @ rtp_llm/models_py/bindings/rocm/FusedRopeKVCacheOp.cc:75
    • 建议:从 host 端直接计算 max 传入,或缓存 prepare() 阶段结果。
  • EP 模式 shared expert 未使用 fused sigmoid_gate_scale_add @ rtp_llm/models_py/model_desc/generic_moe.py:185
    • 建议:至少用 shared_expert_output.mul_(torch.sigmoid(gate_output)) 做 in-place 消除中间分配。
  • VIT_EMBEDDING_RT_METRIC 包含锁等待时间 @ rtp_llm/multimodal/mm_process_engine.py:565
    • 建议:将 Timer 移到 mm_embedding_lock 内部,或新增单独指标。
  • MultimodalDeepstackInjector 每层 D2H sync @ rtp_llm/models_py/modules/base/common/multimodal_embedding.py:141
    • 建议:在上层提前转 CPU list 并缓存,或首次调用时缓存。
  • autotune_cache lru_cache 使环境变量变更不生效 @ rtp_llm/models_py/triton_kernels/autotune_cache/cache.py:86
    • 建议:如果是设计意图,添加注释说明。如需动态切换则去掉缓存。
  • fastsafetensors loading 中 per_channel_cast_to_fp8 未使用 @ rtp_llm/model_loader/loader.py:379
    • 建议:删除 per_channel_cast_to_fp8 导入。
  • _is_online_ptpc 用 getattr 访问私有 _quant_config @ rtp_llm/model_loader/loader.py:335
    • 建议:在 ModelDeployWeightInfo 上提供公开 property 或 getter。
  • sampleGreedy penalty_ws 每次调用分配 [batch,vocab] GPU tensor @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:69
    • 建议:在 Sampler 层缓存 workspace tensor 复用,避免反复 cudaMalloc。
  • CommWorkspace 每次 cache hit 做两次 hipPointerGetAttribute @ rtp_llm/models_py/bindings/rocm/kernels/trtllm_allreduce_fusion.cu:1099
    • 建议:用 epoch/generation counter 检测复用,避免 runtime query。

P3

  • TreeDFA::next 用 std::to_string 做整数比较 @ rtp_llm/cpp/models/logits_processor/DFAUtil.h:157
    • 建议:直接用 input == endTokenId() 整数比较。

Checklist ✅ (56 items passed)

Strengths

  • SSRF adapter 不再重写 URL,简化代码流程,redirect 添加 response.close() 防资源泄漏
  • LocalRpcServer VIT_SEPARATION_ROLE 逻辑修正:非 VIT 角色正确使用 RemoteMultimodalProcessor
  • TensorPbConvert 新增完善的 shape/size 校验(溢出检查、data size mismatch),提升 RPC 鲁棒性
  • autotune_cache 模块设计优雅 fallback:缓存缺失时退化到 Triton 原生 autotune 不阻塞服务
  • QueryConverter::transMMOutput 对 split_size 做空检查和 sum 一致性校验,防止 tensor split 崩溃
  • moriep_wrapper 将 assert 改为 raise ValueError,避免 -O 模式下跳过断言
  • MMWorkItem 超时从 min 改为 max,与 C++ RemoteMultimodalProcessor max_timeout_ms 语义对齐
  • executor.py 为 LRO 错误添加 infra 分类和 failover 支持,提高远程测试容错性
  • ssrf_check.py 实现完整 SSRF 防护(DNS rebinding、redirect 重验证、IP pinning)
  • CP 启用时短路避免 cu_kv_seqlens.max().item() 的 GPU→CPU sync,改善 CP 场景性能

- BatchDecode: partial scheduling + 100ms flush timeout + set reserve

- ROCm/CUDA sampling: clone probs, per-request seed, gather+log cum_log_probs

- VIT: round-robin addrs, proxy timeout fallback, URL singleflight

- MoriEP: shmem finalize, local_world_size, finalize debug log

- Quant: MXFP4 stacked MoE keys, fp4_moe_op pickle, fake_balance dtype check

- MM: input length/batch output validation, extra_input count check

- Renderers: preprocess_config for llama3/kimi_k25, empty TensorPB shape/dtype

- Qwen2-VL/Qwen3VL: max_seqlen once, CPU locs reuse

- Kernels: FlyDSL sentinel cache, remap fp32 cast, PureDP RS buffer cache

- BeamSearch: default large-beam boundary test
@LLLLKKKK

Copy link
Copy Markdown
Collaborator

AI Code Review - PR #1108

Status: BLOCKING

Summary: P0/0 · P1/3 · P2/27 · P3/3

Blocking Issues

P1

  • KimiK25Renderer 访问 ImageURL 上不存在的 preprocess_config 属性 @ rtp_llm/openai/renderers/kimi_k25_renderer.py:68
    • 建议:将 part.image_url.preprocess_config 改为 part.preprocess_config(与 llava_renderer.py 中 content_part.preprocess_config 的用法一致)。
  • BatchDecodeScheduler partial batch 调度逻辑无法生效 @ rtp_llm/cpp/engine_base/schedulers/BatchDecodeScheduler.h:255
    • 建议:将 schedule() 中 255 行的条件改为也允许 timeout 后调度:增加 || !waiting_streams_.empty() 条件(或在 wait_for 超时后单独调用 evaluateWaitingStreams),以配合 evaluateWaitingStreams 中的 partial batch 逻辑。同时更新 wait_for 的 predicate 以包含 !waiting_streams_.empty()
  • MultiprocessPreprocessExecutor.submit 在 pool 为 None 时会 NPE 崩溃 @ rtp_llm/multimodal/mm_process_engine.py:200
    • 建议:在 submit() 入口检查 if self.pool is None: raise RuntimeError('Preprocessing pool is not available'),或在 _rebuild_pool 中 _create_pool 失败时回退到旧 pool 而不是保持 None。

Non-blocking Suggestions

P2

  • singleflight 下载失败时 waiter 可能重复下载已知失败 URL @ rtp_llm/multimodal/multimodal_util.py:222
    • 建议:当 downloader 失败(异常)时,所有等待的 waiter 都会各自重新下载。对于大规模并发访问同一个失败 URL 的场景,建议在 finally 中记录失败状态,waiter 可直接抛出相同异常而不重试。
  • mm_process_engine.py for 循环体多了一层缩进 @ rtp_llm/multimodal/mm_process_engine.py:596
    • 建议:for 循环体(597-603 行)缩进多了一级(12 空格 vs 应该 8 空格)。Python 语法上合法但误导后续维护者,建议修正为与上方 validation for-loop(590 行)一致的缩进。
  • CudaOps cudaEvent 在 check_cuda_value 抛出时泄漏 @ rtp_llm/models_py/bindings/core/CudaOps.cc:293
    • 建议:如果 cudaEventRecord 或 cudaEventSynchronize 中 check_cuda_value 抛异常,cudaEventDestroy 永远不会执行。建议用 RAII wrapper(如 struct EventGuard)确保 event 在异常路径上被销毁。
  • BatchDecodeScheduler 100ms 唤醒周期可能增加空闲 CPU 开销 @ rtp_llm/cpp/engine_base/schedulers/BatchDecodeScheduler.h:241
    • 建议:从 30s 降到 100ms 意味着空闲时每秒唤醒 10 次(之前 ~0.03 次),在无流量场景下增加 CPU 开销。考虑使用两阶段超时:有 waiting streams 时用 100ms,waiting 为空时回退到较长超时。
  • _get_moe_quant_ckpt_infos 混合 stacked/unstacked 权重未校验 @ rtp_llm/model_loader/mixed_fp4_quant_weight.py:256
    • 建议:如果 src_weight_info.weights 中同时存在以 W_SUFFIX 结尾和不以其结尾的条目(混合 stacked/unstacked),is_stacked=True 会导致使用 identity 作为 merge 函数,但 ckpt_infos 中包含了需要 stack 的 per-expert 条目。建议添加断言确保所有 weights 格式一致(全部是 stacked 或全部是 per-expert)。
  • MultimodalEmbeddingInjector.forward 类型注解与实际行为不匹配 @ rtp_llm/models_py/modules/base/common/multimodal_embedding.py:64
    • 建议:函数签名仍声明 multimodal_locs: torch.Tensor,但实际代码已支持 list 类型输入(qwen3vl.py 传入 cpu_locs list)。应更新类型注解为 Union[torch.Tensor, Sequence[int]] 以匹配实际行为。
  • sampleGreedy 非 greedy 路径无条件 clone 整个 probs 张量 @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:480
    • 建议:改为条件 clone:filtered_probs = params.return_original_all_probs ? probs_t.clone() : probs_t;。当 return_original_all_probs 为 false(常见路径)时省去 batch_size × vocab_size × 4B 的 GPU 分配(batch=128, vocab=150K 时约 72MB)。
  • 有 generator 时 multinomial 逐行采样导致 batch_size 次 kernel launch @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:528
    • 建议:可以分组:无 generator 的行合并为一次 batched multinomial 调用,只有有 generator 的行单独采样。减少 kernel launch 次数。或者预构建 seed tensor 传给 batched multinomial(若 PyTorch 支持 per-row generator)。当前实现在 batch_size 较大时(如 128+)会产生显著的 kernel launch overhead。
  • BatchDecodeScheduler 从 30s 降到 100ms poll 但 schedule() 仍要求 waiting >= batch_size_ @ rtp_llm/cpp/engine_base/schedulers/BatchDecodeScheduler.h:245
    • 建议:100ms timeout 本意是 flush 不足 batch_size_ 的 partial group,但 schedule() 仍要求 waiting >= batch_size_ 才调用 evaluateWaitingStreams()。空闲时 10 次/秒的唤醒白白消耗 CPU。应在 schedule() 中添加 partial batch flush 逻辑(如超时后 waiting > 0 也调用 evaluateWaitingStreams),或恢复较长 timeout。
  • grpc_util trans_from_tensor 保存了 empty tensor 的 shape,但 trans_tensor 不恢复 @ rtp_llm/utils/grpc_util.py:55
    • 建议:在 trans_tensor 的 empty tensor 分支,使用 torch.empty(list(t.shape), dtype=...) 恢复保存的形状,而不是返回 torch.tensor([], ...)。
  • 每张图片都重复创建相同的默认 MMPreprocessConfig 对象 @ rtp_llm/openai/renderers/kimi_k25_renderer.py:73
    • 建议:将默认 MMPreprocessConfig 提取为模块级常量 _DEFAULT_MM_PREPROCESS_CONFIG = MMPreprocessConfig(-1, -1, -1, -1, -1, -1, -1, [], 30000),循环内直接引用。注意:因为 [] 是 mutable,需确认下游不会修改 crop_positions list;如果会修改则保持现状。
  • mm_process_engine for 循环体多了一级缩进 @ rtp_llm/multimodal/mm_process_engine.py:597
    • 建议:将 597-603 行的缩进减少 4 个空格,使 for 循环体与同文件其他代码风格一致。Python 可以解析但违反 PEP8 和项目 Black 格式化要求。
  • FLA sentinel cache 非线程安全 @ rtp_llm/models_py/triton_kernels/fla/flydsl_chunk_gdn_mi308x.py:55
    • 建议:当前无功能性影响(benign race),但如果希望严格正确可以加 threading.Lock 或在模块加载时预填充常用 (device, dtype) 组合。标记为 P2 因无实际损害。
  • FusedRopeKVCacheDecodeOp._dummy_scale 的懒初始化无线程保护 @ rtp_llm/ops/fused_rope_kvcache_op.py:192
    • 建议:_dummy_scale 仅增长不缩减,且 torch.ones 是原子分配,最坏情况是重复分配而非数据竞争,建议标注注释说明线程安全性保证,或考虑预分配避免运行时分配。
  • MoriEPWrapper.init 不在锁内执行,可能在 _create 的 lock 释放后和 _initialized 设置前出现竞态 @ rtp_llm/models_py/distributed/moriep_wrapper.py:228
    • 建议:当前 _create 已在 _lock 内调用 cls(config),所以实际是安全的。但 init 本身可以被外部直接调用绕过锁。考虑将 init 设为非公开(_MoriEPWrapper)或在 init 中做 guard。
  • VitProxyServer.stop() 仅用 grace=None 不等待飞行中请求完成 @ rtp_llm/server/vit_proxy_server.py:288
    • 建议:建议使用有界 grace 时间(如 grace=5)让飞行中请求完成后再关闭连接池,否则 connection_pool.close_all() 可能关闭仍在使用的 channel 导致 RPC 异常。
  • vit_proxy_start_server 中 socket 对象未在异常路径中关闭 @ rtp_llm/multimodal/vit_proxy_start_server.py:320
    • 建议:用 try/finally 确保 sock.close(),或在异常路径中关闭 socket 防止 FD 泄露。同样的问题存在于 vit_app.py:84。
  • vit_rpc_server RemoteMultimodalEmbedding 在 abort 后仍然执行 trans_output @ rtp_llm/server/vit_rpc_server.py:64
    • 建议:context.abort() 会抛出 grpc.RpcError,所以 trans_output 不会执行,代码实际是安全的。但为了可读性建议 abort 后 return,或直接依赖 trans_output 的 ValueError。两道防线稍显冗余。
  • backend_manager 的 DeepEP/MoriEP 初始化 catch-then-re-raise 吞掉了原始异常的 traceback @ rtp_llm/server/backend_manager.py:109
    • 建议:新的 RuntimeError 丢失了原始异常的 traceback。建议保留原始异常:raise RuntimeError('...') from e,或直接在 except 中 raise 而不用 success flag 模式。
  • moriep_wrapper init 函数使用 assert 而非异常做运行时校验 @ rtp_llm/models_py/distributed/moriep_wrapper.py:272
    • 建议:assert 在 python -O 下会被跳过。对于运行时必须满足的条件(如 world_size 匹配),应该使用 if ... raise ValueError/RuntimeError,与 from_config_adapter 中的风格保持一致。
  • ROCm 采样路径 per-row top_k/top_p 循环导致 O(batch*vocab) GPU kernel 发射 @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:484
    • 建议:考虑批量化 top_k/top_p 操作:对同一 k 值的行进行 batched topk (torch::topk 支持 2D);或将不同 k 值分组后分别批量处理,减少逐行 kernel launch 次数。在 batch_size 较大时(如 64+)此循环显著增加延迟。
  • runtimeBatchCopy 中 cudaEventSynchronize 阻塞 host,可能不必要 @ rtp_llm/models_py/bindings/core/CudaOps.cc:299
    • 建议:如果后续操作在同一 stream 上执行,stream ordering 已保证数据就绪,不需要 host-side sync。如果确实需要跨 stream 同步,应在消费侧 cudaStreamWaitEvent 而非在生产侧 cudaEventSynchronize(后者 block host thread)。
  • prepareInPlace 中 .max().item<int32_t>() 触发 GPU→CPU sync @ rtp_llm/models_py/bindings/rocm/FusedRopeKVCacheOp.cc:75
    • 建议:input_lengths/prefix_lengths 通常有 CPU host 副本(PyAttentionInputs 中 host 字段可获取)。对于 CUDA graph replay(prepareInPlace 的主要场景),应从 host 端 tensor 计算 max 以避免隐式 GPU sync。如果确实只有 device tensor,可以考虑将 max 计算融合到后续 kernel 中。
  • repetition penalty 路径每次分配 [batch_size, vocab_size_padded] int32 workspace @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:69
    • 建议:对于典型 vocab_size=****** 和 batch=64,此分配为 ~37MB。在 decode 热路径中频繁 alloc/free 造成 CUDA allocator 压力。考虑预分配 workspace 并缓存(按最大 batch_size * vocab_size 上限分配一次),或使用 caching allocator hints。
  • PrefixToCandidateTokens::getCandidateTokens 在 hot path 持 mutex @ rtp_llm/cpp/models/logits_processor/PrefixToCandidateTokens.h:384
    • 建议:getCandidateTokens 在每个 batch element 的 logits processing 中被调用(via DFAUtil::getCandidateTokenIds → TreeLogitsProcessor::process)。由于 prefix_to_cadicates_ 在 reload 后不变,应改用 shared_mutex (read lock) 或 RCU-style 方案,避免多请求间的 mutex 串行化。
  • ROCm multiMergeCopy 使用 std::memcpy 而非异步 HIP copy @ rtp_llm/models_py/bindings/core/CudaOps.cc:182
    • 建议:如果 src/dst 是 device memory,std::memcpy 是错误的(UB/segfault)。如果是 host memory,仍应使用 hipMemcpyAsync 以支持 overlap。需确认 params 中指针类型:若为 device 指针则改用 hipMemcpyAsync D2D;若为 host 指针则当前行为正确但应加注释说明。
  • trans_tensor 反序列化丢失空 tensor 的高维 shape @ rtp_llm/utils/grpc_util.py:32
    • 建议:修改 trans_tensor 空 tensor 分支,使用 torch.empty(list(t.shape), dtype=...) 代替 torch.tensor([], dtype=...),以保留多维 shape 信息

P3

  • MoriEpIntranodeRouter finalize 日志使用 %s 格式化布尔值 @ rtp_llm/models_py/modules/factory/fused_moe/impl/rocm/routers/mori_ep_intranode_router.py:223
    • 建议:使用 %d 表示 ep_rank 更明确,或保持 %s 统一格式。当前功能正确,仅 nit。
  • CUDA 路径 flashinferSampleGreedy 中 per-element random 生成循环 @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:143
    • 建议:当大部分 batch 使用相同 generator 时,可以按 generator 分组批量生成 random numbers,减少 kernel launch 数。对于无 generator 的 element 已经批量生成了(line 142),但有 generator 的 element 仍是逐个 launch。
  • execNoBlockCopy 名称暗示非阻塞但实际调用 cudaStreamSynchronize @ rtp_llm/models_py/bindings/core/ExecOps.cc:397
    • 建议:函数名 NoBlockCopy 暗示非阻塞语义,但实现包含 cudaStreamSynchronize 使其变为阻塞。如果调用方依赖非阻塞语义,这是一个 bug;如果阻塞是有意的,建议重命名函数以避免误用(如 execCopyOnSeparateStream)。

Checklist ✅ (56 items passed)

Strengths

  • CUDA event 顺序修复正确解决了 workspace tensor 生命周期问题,避免 GPU 内存腐败
  • singleflight 模式有效防止多线程重复下载同一 URL,且 finally 保证 event 始终 set
  • VIT round-robin 负载均衡 + 失败刷新策略是生产级改进
  • MMProfiler 将 profiled_count++ 前移到 lock 内,消除了并发竞态
  • MoriEP 配置增加 divisibility 验证,提前暴露部署配置错误
  • QueryConverter 增加 extra_input count 校验防止越界
  • _get_moe_quant_ckpt_infos 统一抽取降低重复代码且正确区分 stacked vs per-expert 格式
  • multimodal_embedding_injector 支持 list 和 Tensor 两种 locs 类型提升灵活性
  • singleflight URL 下载模式避免同一 URL 的并发重复下载,显著减少多模态请求的网络开销和延迟
  • PureDpRouter 复用 reduce_scatter output tensor,消除 MoE finalize 热路径上的每步 GPU 分配

- multi_runner.sh: PID tracking + EXIT_CODE propagation for build/kill/copy/clean/test

- Fix broken [ -z "$TP_SIZE" ] / [ -z "$MODEL_TYPE" ] spacing

- .bazelrc: document cuda12 as shared base config; use cuda12_6/12_9/12_9_arm

- pyproject.toml: document transformers 4.51.2 pin rationale

- oss_optional_extras.toml: document aiter 0.1.13.dev14 pin rationale
- Restore rtp_llm/test/smoke/defs.bzl and thin BUILD wrapper for internal CI.
- test_gdn_block_prefill.py: run _test_one_case for bs > 1.
- BatchDecodeScheduler.h: schedule partial batch when flush timeout fires.
- ssrf_check.py: narrow ValueError catch so private-IP validation propagates.
- case_runner.py: OpenaiComparer get("query"), concurrency compare fix, LoRA or validation.
- multi_inst_case_runner.py: try/finally cleanup for Pd/Dp/Vit/FrontApp; null-safe stop.
- setup.py: move install_requires/extras computation under if __name__ == "__main__"; append retry logs.
- comparer_registry.py: narrow bare except to ImportError/ModuleNotFoundError.
- conftest.py: preserve explicit empty CUDA_VISIBLE_DEVICES pool.
- concurrency_limit_test.py: patch env vars so tearDown restores them.
- fp8_kernel.py: guard fp8_grouped_gemm_ptpc None with RuntimeError.
- kimi_k25_renderer.py: use part.preprocess_config, not image_url.preprocess_config.
- CudaSampleOp: conditional clone only when return_original_all_probs
- grpc_util: preserve multi-D shape for empty tensors; graceful dtype fallback
- multimodal_embedding: fix forward() type annotation for multimodal_locs
- case_runner: raise Tau2BenchComparer priority; add as_completed timeout
- utils.py: use common_def.REL_PATH dynamic reference instead of snapshot
- normal_comparer: guard against empty chunks IndexError; detect aux_info mismatch
- mm_process_engine: fix excessive indentation in for-loop body
- deepgemm_wrapper: add ImportError to exception catch list
- ops/__init__: catch TypeError when LIBDIR is None
- maga_server_manager: replace mutable default args with None
- server_args: move _env_mappings from class var to instance var
- vit_rpc_server: add explicit return after context.abort()
- ssrf_check: close response before raising on max redirects
- conftest: log GPU cleanup exceptions; register atexit for faulthandler fd
- mixed_fp4_quant_weight: assert stacked/per-expert weight consistency
@LLLLKKKK

Copy link
Copy Markdown
Collaborator

AI Code Review - PR #1108

Status: BLOCKING

Summary: P0/3 · P1/10 · P2/40 · P3/13

Blocking Issues

P0

  • _env_mappings 从类属性移至实例属性后,类级引用全部失效导致启动崩溃 @ rtp_llm/server/server_args/server_args.py:237
    • 建议:将第237行改为 self._env_mappings[action.dest] = full_env_name,同时将第398、400、405、415、416、419行的 EnvArgumentParser._env_mappings 全部改为 self._env_mappings。print_env_mappings 和 get_env_mappings 也需要更新。
  • QWenV2Weight.transformer_prefix 拼接顺序颠倒,language_model 前缀场景下权重加载路径错误 @ rtp_llm/models/qwen_v2.py:63
    • 建议:将第63行改回 self.transformer_prefix = self.prefix + self.model_prefix,保持与 HF checkpoint key 一致的拼接顺序。已通过读源文件确认 _process_meta 中 prefix='language_model.' 且 model_prefix='model.' 时拼接结果错误。
  • EnvArgumentParser._env_mappings 类级写入引用不存在的类属性导致 AttributeError @ rtp_llm/server/server_args/server_args.py:237
    • 建议:将 line 237 改为 self._env_mappings[action.dest] = full_env_name,同时将 print_env_mappings/get_env_mappings 中的 EnvArgumentParser._env_mappings 改为 self._env_mappings。

P1

  • SmokeException 缺少必需参数 error_status,会抛出 TypeError @ rtp_llm/test/smoke/normal_comparer.py:137
    • 建议:改为 raise SmokeException(QueryStatus.VALID_FAILED, "Streaming response chunks are empty but return_incremental is True"),与同文件其他调用点(如 line 41-43)保持一致
  • PD/DP 分离测试中 self.remote_kvcm_server 未初始化时被无条件访问,会抛出 AttributeError @ rtp_llm/test/smoke/multi_inst_case_runner.py:187
    • 建议:在 run() 方法开头初始化 self.remote_kvcm_server = None(或在 _cleanup_servers 调用时用 getattr(self, 'remote_kvcm_server', None))。PdSeperationCaseRunner (line 159,170,187) 和 DpSeperationCaseRunner (line 322,334,351) 均需修复
  • XQADecodeImpl._captured_seq_lens 在 new_seq_lens 更大时未清零尾部 @ rtp_llm/models_py/modules/factory/attention/cuda_impl/xqa.py:171
    • 建议:在 copy 前先对 self.captured_seq_lens 进行 zero(),与 copy_kv_cache_offset 中 shape 不匹配时的处理保持一致。如果 captured 比 new 大,旧的 seq_lens 尾部包含上一次 batch 的残留值,XQA kernel 在 CUDA graph replay 中可能读到过期数据导致越界或错误输出。加 if n < self._captured_seq_lens.numel(): self._captured_seq_lens[n:].zero_()
  • getFeatureHash 在请求热路径上做同步 D2H 拷贝 + 全字节 FNV 哈希 @ rtp_llm/cpp/multimodal_processor/MultimodalProcessor.cc:28
    • 建议:改用 GPU 端哈希(如对每行做 reduce sum/hash kernel)或仅对 embedding 的子采样(如 stride 取样)做哈希,避免全量 D2H + 逐字节 CPU 遍历。如果必须 CPU 端哈希,至少用 SIMD 加速(如 xxhash/CityHash 等库替代 FNV-1a 逐字节循环),并用 pinned memory 异步拷贝而非 .to(kCPU)。
  • QWen2_VL._create_config 在 config.json 缺失时返回空 ModelConfig 而非报错 @ rtp_llm/models/qwen2_vl.py:207
    • 建议:与同 PR 中 QWenV2._from_hf 的处理保持一致,在 config.json 不存在时抛出 FileNotFoundError 并附带路径信息,而非返回默认值全零的 ModelConfig(会导致下游引擎用错误配置初始化或产生无意义 assert 失败)。
  • QWen3_VL._from_hf 和 QWen3_VL_MOE._from_hf 在 config.json 缺失时静默返回 @ rtp_llm/models/qwen3_vl.py:65
    • 建议:与 QWenV2._from_hf 保持一致,在 config.json 不存在时抛出 FileNotFoundError。静默返回会使 _create_config 返回只有 rope/activation 等默认值但缺少 head_num/num_layers/vocab_size 等关键字段的 config,导致下游引擎崩溃或产生难以诊断的错误。
  • lm_head 权重路径移除 self.prefix,language_model 嵌套场景下找不到权重 @ rtp_llm/models/qwen_v2.py:314
    • 建议:改回 CkptWeightInfo(self.prefix + 'lm_head.weight', identity),或使用条件判断:如果 prefix 非空则带前缀。注意 embed_tokens(line 307)正确使用了 self.transformer_prefix 前缀。
  • InternVL 和 MiniCPMV 模型完全删除且未保留 register_model,HF 架构名无法识别 @ rtp_llm/models/__init__.py:42-50
    • 建议:如果 InternVL/MiniCPMV 支持被暂时移除是有意的(python_native_v2 分支重构),需在 PR 描述中明确说明并标注后续计划。否则需要新建简化的 model 类并保留 register_model 注册,确保 HuggingFace 架构名可被识别。
  • SmokeException 构造缺少 error_status 参数导致 TypeError @ rtp_llm/test/smoke/normal_comparer.py:137
    • 建议:改为 raise SmokeException(QueryStatus.COMPARE_FAILED, 'Streaming response chunks are empty but return_incremental is True')。
  • PD/DP 分离 CaseRunner cleanup 路径无条件访问未初始化的 remote_kvcm_server @ rtp_llm/test/smoke/multi_inst_case_runner.py:159
    • 建议:在 PdSeperationCaseRunner/DpSeperationCaseRunner.run() 开头初始化 remote_kvcm_server = None,cleanup 改为 _cleanup_servers(started_managers, getattr(self, 'remote_kvcm_server', None)),与基类 CaseRunner.run() line 260 的 guard 模式一致。

Non-blocking Suggestions

P2

  • 并发测试结果不一致时不 break,err_msg 被覆盖只保留最后一个差异 @ rtp_llm/test/smoke/case_runner.py:316
    • 建议:在设置 err_msg 后加 break,保留第一个发现的差异(最有诊断价值)
  • defs.bzl 中 gpu_type[0] 未做非空校验,空列表时 Starlark 会崩溃 @ rtp_llm/test/smoke/defs.bzl:182
    • 建议:在函数开头加 if not gpu_type: fail('gpu_type must be non-empty') 做前置检查
  • PureDpRouter._pad_to_max 每层 MoE 热路径上做 D2H 同步 @ rtp_llm/models_py/modules/factory/fused_moe/impl/cuda/routers/pure_dp_router.py:125-127
    • 建议:代码已有 TODO 记录,但应确认此路径不会在 decode 阶段(每 token 一次)被触发,否则 D2H sync 会严重影响延迟。建议在 strategy check_conditions 中加 is_prefill_only 或把 max_n 提升到 step 级别元数据中。
  • MoriEpIntranodeRouter._finalize_single 未清理 self._dispatch_ids 引用 @ rtp_llm/models_py/modules/factory/fused_moe/impl/rocm/routers/mori_ep_intranode_router.py:243
    • 建议:在 _finalize_single 结尾将 self._dispatch_ids = None,与 chunked 路径的清理行为保持一致。这能防止异常恢复后意外复用过期的 dispatch_ids,也能让 GC 及时回收 GPU tensor。
  • RocmEpNormalStrategy 通过 can_handle 中的 self._config 副作用传递状态给 get_attributes @ rtp_llm/models_py/modules/factory/fused_moe/impl/rocm/strategy/ep.py:25-28
    • 建议:如果 get_attributes 在 can_handle 之外被调用(如序列化或调试),_config 为 None 导致 resolver.get_quant_method(None) 异常或静默回退到 BF16。建议把 config 作为 get_attributes 参数传递,或在 get_attributes 开头加 assert config is not None 做防御。
  • RocmMXFp4PureTPStrategy 缺少 check_conditions,理论上可在非 gfx950 上被选中 @ rtp_llm/models_py/modules/factory/fused_moe/impl/rocm/strategy/mxfp4.py:21
    • 建议:虽然注册处有 is_gfx950() 保护,但 Strategy 自身也应 override check_conditions 加 checker.check(is_gfx950()) 和 quant_method=='QuarkMXFP4' 断言,与其他 strategy 保持一致的防御模式。router 的 check_conditions 虽然有此校验,但 strategy 级别的缺失不够健壮。
  • PureCpRouter.finalize 没有像 PureDpRouter 那样校验 original_num_tokens @ rtp_llm/models_py/modules/factory/fused_moe/impl/cuda/routers/pure_cp_router.py:138-161
    • 建议:CP 理论上保证各 rank token 数一致,但增加一个 assert output.shape[0] == original_num_tokens 做防御检查更安全,防止 CP padding 行为变更时静默出错。
  • get_fmha_impl 每次调用都重建 name_to_impls 字典和 known_names 集合 @ rtp_llm/models_py/modules/factory/attention/attn_factory.py:184
    • 建议:name_to_impls 和 registered_names 仅取决于静态的 PREFILL/DECODE_MHA_IMPS 列表(模块加载后不变)。可在模块级别缓存这两个映射(或使用 functools.lru_cache),避免每次 forward 调用时重建。旧代码仅在 explicit backend 路径构建此字典,新代码无论 auto/explicit 都构建。列表很小(~6 项)所以实际开销可忽略,但在纯 auto 模式下是不必要的工作。
  • pure_dp_router.finalize 中 expected_shape 构造使用 list 拼接 @ rtp_llm/models_py/modules/factory/fused_moe/impl/cuda/routers/pure_dp_router.py:189
    • 建议:对比 pure_cp_router 使用 tuple unpacking (fused_output.shape[0] // self.tp_size, *fused_output.shape[1:]) 更高效(避免 list 分配 + 双 tuple() 转换)。建议统一为 tuple 写法,保持一致性并减少热路径上的小对象分配。
  • MoriEpIntranodeRouter.prepare 仍使用 f-string 格式化 debug 日志 @ rtp_llm/models_py/modules/factory/fused_moe/impl/rocm/routers/mori_ep_intranode_router.py:92
    • 建议:finalize() 已改为 %-style 延迟格式化(仅当 debug 启用时才求值),但 prepare() 仍用 f-string(无论日志级别都会触发 .shape[0] 求值和字符串拼接)。建议统一为 logging.debug('[MoriEpIntranodeRouter] prepare called, tokens=%d, ep_rank=%d', a1.shape[0], self.ep_rank) 以避免热路径上不必要的字符串构造。
  • safe_request_get 每次调用创建新 Session,多媒体批量下载时有连接复用开销 @ rtp_llm/utils/ssrf_check.py:180
    • 建议:考虑提供 module-level 或 thread-local 的 Session 复用方案(需确保 _SSRFAdapter 的 send() 每次都重新 resolve,已做到),避免对同一 host 重复 TLS 握手。当前 per-call 模式在批量多模态图片下载场景(一个请求含 10+ 图片 URL)可能带来不必要的连接建立延迟。
  • get_aiter_envs 中 split('=') 解包会在 value 含 '=' 时崩溃 @ rtp_llm/test/smoke/defs.bzl:84
    • 建议:改为 k, _, = env.split('=', 1) 或 k = env[:env.index('=')] 只取 key 部分,与同文件 extract_data 的处理方式一致
  • _cleanup_servers 中 stop_server 异常会阻止后续服务器清理 @ rtp_llm/test/smoke/multi_inst_case_runner.py:21
    • 建议:虽然 MagaServerManager.stop_server() 内部有 broad except,但 _stop_server_safe 最好也加 try/except 兜底,确保一个 manager 的 stop 失败不会阻止其余清理
  • trans_from_tensor 对不支持 dtype 的空 tensor 静默丢弃 shape @ rtp_llm/utils/grpc_util.py:66
    • 建议:如果确实要 graceful degradation,至少 log warning 提示 dtype 不支持,避免静默丢 shape 掩盖 bug;或者返回 res(已有 shape 但无 data_type)而非全空 TensorPB()
  • multi_runner.sh: 多 PID 失败时仅保留最后一个失败的 exit code @ rtp_llm/test/perf_test/multi_node/multi_runner.sh:34
    • 建议:这比之前的 wait 已经是改进。如需保留第一个失败的退出码,可改为 wait "${PID}" || { [ $EXIT_CODE -eq 0 ] && EXIT_CODE=$?; }。当前行为是可接受的。
  • assert 用于运行时数据校验,可被 -O 禁用 @ rtp_llm/model_loader/mixed_fp4_quant_weight.py:259
    • 建议:此断言保护的是外部模型权重的一致性(数据边界校验),如果 Python 以 -O 运行会被跳过。建议改为 if ... and ...: raise ValueError(...)。不过项目中 assert 用于校验的模式很多,属于整体风格问题,不阻塞合并。
  • multimodalFeatures() 按值返回 vector,在同一 stream 上被调用多达 4 次 @ rtp_llm/cpp/normal_engine/NormalModelInputGatherer.cc:366
    • 建议:1) GenerateStream::multimodalFeatures() 应返回 const 引用而非值拷贝。2) 在 processContextStreams 中,将 multimodalFeatures 调用结果缓存到局部变量,避免重复构造 vector。3) line 366 的 CHECK 仅需 size,可用 multimodalFeaturesLength() 替代整个 vector 构造。
  • computeReusedMultimodalCount 每个 stream 被调用两次(features + extra_input),且内含 is_sorted 断言 @ rtp_llm/cpp/normal_engine/NormalModelInputGatherer.cc:159
    • 建议:将 computeReusedMultimodalCount 结果缓存到 processContextStreams 的 per-stream 局部变量中,传入 gatherMultimodalFeaturesForContextBatch。is_sorted 断言改为 debug-only (#ifndef NDEBUG) 以避免在生产中每个请求都做 O(N) 排序检查。
  • BatchDecodeScheduler::evaluateWaitingStreams 每次调度周期分配 std::map @ rtp_llm/cpp/engine_base/schedulers/BatchDecodeScheduler.h:143
    • 建议:用 std::array<std::list, 3> 替代 std::map,按枚举值索引。避免每次调度周期 (100ms) 的 map 节点堆分配。
  • BatchDecodeScheduler 超时从 30s 降至 100ms,空闲时产生 10 次/秒唤醒 @ rtp_llm/cpp/engine_base/schedulers/BatchDecodeScheduler.h:241
    • 建议:考虑使用自适应超时:在有 waiting_streams 时用短超时 (100ms) 以避免饥饿,在无等待任务时用长超时 (1-5s) 以减少空闲 CPU 开销。或在 wait_for 的 predicate 中加入 !waiting_streams_.empty() 条件来避免空轮询。
  • loader.py 在 fastsafetensor 加载循环中反复查询 torch.cuda.get_device_properties @ rtp_llm/model_loader/loader.py:422
    • 建议:在循环外一次性获取 device_props.total_memory 缓存到局部变量,循环内只调用 torch.cuda.memory_reserved() 做比较。同样 torch.cuda.is_available() 也应缓存。
  • mm_extra_input 逐个 tensor .to(torch::kCUDA) 在循环中触发独立 H2D 传输 @ rtp_llm/cpp/normal_engine/NormalModelInputGatherer.cc:373
    • 建议:如果 extra_input tensors 形状一致,可先 stack 成单个 tensor 做一次 H2D 传输再 unbind。如形状不一致,至少在同一 CUDA stream 上批量提交 async copy 减少 launch overhead。
  • needReturnAllProbs() 不再短路,必须遍历所有 streams @ rtp_llm/cpp/engine_base/stream/StreamGroups.h:137
    • 建议:在调度器已保证同 batch 内不混合 DEFAULT/ORIGINAL 的前提下,可恢复短路逻辑:找到第一个非 NONE mode 后直接返回。或在 StreamGroups 构造函数中一次性计算并缓存结果,避免每次调用都遍历。
  • vit_rpc_server 中 context.abort() 后 return 实为不可达代码 @ rtp_llm/server/vit_rpc_server.py:69
    • 建议:保留 return 作为防御性编程是可以的,但建议加注释说明 abort() 会抛异常,return 仅作为额外保护。
  • trans_output 与 RemoteMultimodalEmbedding 对空 embeddings 有重复校验 @ rtp_llm/server/vit_rpc_server.py:37
    • 建议:trans_output 中的校验作为防御性编程可保留(可被其他调用者复用),无需修改。
  • cutlass_moe_mm_fp8_scaled 中重复计算 min() — 热路径冗余开销 @ rtp_llm/models_py/kernels/cuda/fp8_kernel/fp8_kernel.py:236
    • 建议:line 236 已计算 key,line 237 应改为 config = configs[key],避免在 MoE GEMM 热路径上重复遍历 configs.keys()(pre-existing,但此 PR 修改了该文件)
  • singleflight waiter 回退下载成功后未写入缓存 @ rtp_llm/multimodal/multimodal_util.py:228
    • 建议:waiter 下载成功后加一行 url_data_cache_.insert_cache(url, cached_bytes) 再返回,避免同一 URL 重复下载。
  • _download_url_bytes 异常包装丢失原始 traceback @ rtp_llm/multimodal/multimodal_util.py:187
    • 建议:改为 raise Exception(...) from e,保留原始异常链,便于排查下载失败的根因。
  • vit_start_server 在无 GPU 环境下 device_count() 返回 0 导致 ZeroDivisionError @ rtp_llm/multimodal/vit_start_server.py:59
    • 建议:在除法前检查 device_count > 0,否则抛出明确的 RuntimeError 说明 VIT worker 需要 CUDA 设备。
  • reduce_scatter output_tensor 验证使用 != 比较 device,可能在 meta device 上误判 @ rtp_llm/models_py/distributed/collective_torch.py:708
    • 建议:考虑用 output_tensor.device.type != input_tensor.device.type or output_tensor.device.index != input_tensor.device.index 做更精确的设备比较,或使用 torch.device(output_tensor.device) != torch.device(input_tensor.device)
  • qwen3vl_moe forward 中 mm_feature_locs 产生重复 GPU→CPU 同步 @ rtp_llm/models_py/model_desc/qwen3vl_moe.py:99
    • 建议:参照 qwen3vl.py 的模式:在调用 embedding_injector 前先计算 cpu_locs = mm_feature_locs.to(device='cpu', dtype=torch.long).view(-1).tolist(),然后将 cpu_locs 传给 embedding_injector 和 deepstack_injector,消除重复 GPU→CPU 同步。
  • transMMInputsPB 参数按值传递 vector,产生不必要深拷贝 @ rtp_llm/cpp/model_rpc/QueryConverter.h:26
    • 建议:将签名改为 transMMInputsPB(const std::vector<MultimodalInput>& mm_inputs),与同 PR 中 transMMPreprocessConfig 的 pass-by-reference 修复保持一致。
  • FLA chunk_delta_h V-first 布局在内循环引入 tl.trans(tl.dot()) 寄存器转置开销 @ rtp_llm/models_py/triton_kernels/fla/chunk_delta_h.py:290
    • 建议:这是 V-first cache 布局统一的设计取舍(与 SGL/FLA state_v_first=True 对齐),减少 cache store/load 路径的转置。建议在合并前做 A/B benchmark(H20 上 chunk_gated_delta_rule prefill 延迟),确认净增的 tl.trans 不会抵消 cache 布局收益。若 regression >10%,可考虑在 dot 操作数侧预转置 b_k/b_v 来避免 post-dot transpose。
  • EVA2CLIPImageEmbedding.init 中 self.data_type 赋值为死代码 @ rtp_llm/models/eva2clip_vit.py:20
    • 建议:删除 self.data_type = config.compute_dtype 这行死代码。同时 docstring 放在了赋值语句之后(第21行),不会被 Python 识别为 init 的文档字符串。
  • transMMInputsPB 按值传递 vector 导致不必要拷贝 @ rtp_llm/cpp/model_rpc/QueryConverter.cc:203
    • 建议:将参数改为 const std::vector& mm_inputs 以避免不必要的深拷贝。头文件 QueryConverter.h 对应声明也需同步修改。
  • Gluon CDNA4 kernel 仍使用 K-first 布局,通过 _GLUON_PATH_VFIRST_DONE=False 门控回退 @ rtp_llm/models_py/triton_kernels/fla/chunk_delta_h_gluon.py:496
    • 建议:当前实现通过门控避免了布局不匹配,是安全的。建议在 _GLUON_PATH_VFIRST_DONE 处添加跟踪 issue 链接,后续 PR 完成 Gluon V-first 移植。
  • scatter_qkv 大 k_dim 时 BLK_QK 可能超出 Triton 寄存器限制 @ rtp_llm/models_py/triton_kernels/common/scatter_qkv.py:87
    • 建议:考虑对 k_dim 较大的情况分 tile 处理(循环 BLK_QK=min(next_power_of_2(k_dim), 1024)),或添加 k_dim 上限断言。
  • model_rpc_client.py 未使用的 import trans_from_tensor @ rtp_llm/cpp/model_rpc/model_rpc_client.py:29
    • 建议:移除未使用的 import trans_from_tensor。
  • get_aiter_envs 中 split('=') 在 value 含 '=' 时崩溃 @ rtp_llm/test/smoke/defs.bzl:84
    • 建议:改为 k, _, = env.split('=', 1) 或 k = env.split('=')[0]。
  • 并发测试结果差异比较不 break 且 err_msg 被覆盖 @ rtp_llm/test/smoke/case_runner.py:316
    • 建议:找到第一个差异后 break; 或收集所有差异到列表。考虑用 results = [f.result() for f in futures] 按提交顺序收集以获得确定性基准。

P3

  • PureDpRouterBase.router_type 返回 RouterType.PURE_TP 而非独立类型 @ rtp_llm/models_py/modules/factory/fused_moe/impl/cuda/routers/pure_dp_router.py:68
    • 建议:DP 和 CP router 复用 PURE_TP 类型可能导致日志/调试时混淆。考虑新增 RouterType.PURE_DP 和 RouterType.PURE_CP 枚举值。
  • Embedding.forward 新增 Optional 参数但缺少对 C++ ops 的 None 传递文档 @ rtp_llm/models_py/modules/base/common/embedding.py:37-39
    • 建议:确认 C++ 端 rtp_llm_ops.embedding 的 pybind 签名支持接收 None(py::none)作为后三个参数。如果支持则正确,可加简短注释说明。
  • case_runner concurrency 比较用 str() 序列化全响应做差异检测 @ rtp_llm/test/smoke/case_runner.py:317
    • 建议:str(result) 会对整个 TaskStates 对象做字符串序列化,重复 5 次比较时开销叠加。可以改用 dataclass 的 eq 或只比较关键字段(如 response body)来减少序列化开销。不过此路径仅在 smoke test concurrency 模式触发,对生产无影响。
  • ssrf_check: redirect 耗尽后的 response.close() 是 double-close @ rtp_llm/utils/ssrf_check.py:202
    • 建议:当所有迭代都是 redirect 时,response 已在 line 195 close。虽然 close() 幂等不会报错,但此代码冗余。如果用 with session: 重构则可以去掉这段。
  • conftest atexit handler 中 broad except 可细化 @ conftest.py:108
    • 建议:可以 except (OSError, ValueError): pass,避免屏蔽意外异常。不过作为进程退出清理代码,broad except 也可接受。
  • gc.collect() 按固定间隔触发而非按内存压力触发 @ rtp_llm/model_loader/loader.py:456
    • 建议:将 gc.collect() 也改为按内存压力触发(与 empty_cache 使用相同条件),或增大间隔(如每 500 个 completed weight)。加载阶段非推理热路径,影响不大。
  • get_cutlass_groupgemm_best_config 每次 GEMM 调用时执行 torch.cuda.get_device_name() @ rtp_llm/models_py/kernels/cuda/fp8_kernel/fp8_kernel.py:233
    • 建议:get_cutlass_groupgemm_best_config 内部调用 torch.cuda.get_device_name() + 字符串处理 + logging.info(f-string),均在热路径上。建议用 @lru_cache 或模块级缓存,减少每次 forward 的开销(pre-existing issue)
  • destroy_distributed_environment 中 MoriEP reset 的 import 每次调用都执行 @ rtp_llm/models_py/distributed/collective_torch.py:476
    • 建议:可以接受(Python 有模块缓存),但如果在意代码清洁度可将 import 提至文件顶部并用 TYPE_CHECKING guard。
  • crop_positions 三处 push_back 循环缺少 reserve @ rtp_llm/cpp/model_rpc/QueryConverter.cc:138
    • 建议:在循环前添加 reserve() 或使用范围构造:std::vector<float>(mm_preprocess_config->crop_positions().begin(), mm_preprocess_config->crop_positions().end())
  • split_sizes vector 构造缺少 reserve @ rtp_llm/cpp/model_rpc/QueryConverter.cc:237
    • 建议:添加 split_sizes.reserve(output_pb->split_size_size()) 或使用范围构造。
  • qwen3vl/qwen3vl_moe 非多模态 decode 每层仍调用 deepstack_injector @ rtp_llm/models_py/model_desc/qwen3vl_moe.py:122
    • 建议:在循环外设 has_deepstack = bool(mm_deepstack_embeds) 标记,循环内用 if has_deepstack: 条件跳过调用。
  • FLA chunk.py 对 q/k/v/g/beta 无条件 .contiguous() 及 beta 双重 contiguous @ rtp_llm/models_py/triton_kernels/fla/chunk.py:360
    • 建议:删除 line 360 的 .contiguous()。305-309 行可改为条件调用 x = x if x.is_contiguous() else x.contiguous(),但影响极小。
  • remap_to_local_ids 非本地 expert 输出 0 而非 sentinel 值 @ rtp_llm/models_py/triton_kernels/moe/remap_local_ids_kernel.py:25
    • 建议:当前语义是非本地 expert 的 weight 为 0 不贡献计算。建议在函数文档中明确此约定,或考虑使用 -1 作为 sentinel。

Checklist ✅ (56 items passed)

Strengths

  • case_runner.py 将 LoRA 更新条件从 and 改为 or 修复了逻辑错误 — 旧代码 exp_update_status != update_status and update_response != exp_update_response 要求两者同时不匹配才报错,状态码错误但 response 碰巧一致时会漏检
  • multi_inst_case_runner.py 用 try/finally + _cleanup_servers() 替代手动 stop_server() 调用,确保异常路径下也能清理服务器进程,设计合理
  • comparer_registry.py 从 bare except Exception 收窄为 except (ImportError, ModuleNotFoundError) 避免吞掉非预期异常
  • Tau2BenchComparer 注册优先级提升到 OpenaiComparer 之前,修复了 tau2_bench 用例因 query 中含 messages 字段被 OpenaiComparer 抢先匹配的问题
  • utils.py 改为 common_def.REL_PATH 延迟属性访问,正确支持 set_default_data_root() 动态修改 REL_PATH 的场景
  • normal_comparer.py 新增空 chunks 检查和 aux_info None 对比,强化了 smoke 测试的错误检测能力
  • TrtllmDistEnv._consume_capture 重构全面:用 all_gather_object 同步 success_flags 和 handle 数量,避免跨 rank 不一致导致的死锁;begin_capture_session/invalidate_capture/commit_capture 提供了正确的回滚语义
  • copy_kv_cache_offset 升级为双向 min-slice + zero_() 模式,比旧代码更安全地处理 shape 不匹配场景
  • CudaSampleOp.cc 中跳过不必要的 clone 是正确的优化:probs_t 来自 torch::softmax(新建 tensor),不是 params.logits 的别名;所有需要原始概率的下游路径(line 544)都由 return_original_all_probs 守护,确保在需要原始值时才 clone
  • multimodal_embedding.py 的类型注解修正使 MultimodalEmbeddingInjector.forward 的 multimodal_locs 参数签名与运行时 isinstance 分支逻辑一致,也与 MultimodalDeepstackInjector 保持统一

P0:
- server_args: fix EnvArgumentParser._env_mappings → self._env_mappings
  in _register_env_mapping, print_env_mappings, get_env_mappings

P1:
- normal_comparer: add QueryStatus.VISIT_FAILED to SmokeException
- multi_inst_case_runner: init self.remote_kvcm_server = None in Pd/Dp runners
- case_runner: add break on first concurrency inconsistency
- grpc_util: preserve shape on unsupported empty tensor dtype (FP32 fallback)
- BatchDecodeScheduler: conditional timeout (5s idle / 100ms busy);
  remove FINISHED zombie streams from waiting_streams_
- docs/README.md: inline docs deps, remove deleted requirements.txt ref

P2:
- multi_inst_case_runner: try/except in _stop_server_safe and cleanup
- ssrf_check: use session context manager; init response=None
- case_runner: assign results[0] on consistent concurrency; OpenaiComparer
  type-safe predicate with isinstance check
- conftest: _fh.disable() before closing fault file
- sparse_mla_decode_op_test: remove hardcoded sys.path
- norm.py: FusedQKRMSNorm None flashinfer check in __init__
- docs/start/install.md: update source build instructions for pip wheel
@LLLLKKKK

Copy link
Copy Markdown
Collaborator

AI Code Review - PR #1108

Status: BLOCKING

Summary: P0/2 · P1/8 · P2/40 · P3/2

Blocking Issues

P0

  • transformer_prefix 拼接顺序错误导致 QWenV2Audio 权重加载失败 @ rtp_llm/models/qwen_v2.py:63
    • 建议:将顺序恢复为 self.transformer_prefix = self.prefix + self.model_prefix。当 prefix="language_model." 时,正确路径应为 "language_model.model.layers...",当前新顺序 "model.language_model." 不匹配 HF checkpoint 键名,会导致 QWenV2Audio 权重找不到。
  • lm_head.weight 丢失 prefix 导致 QWenV2Audio 输出层权重加载失败 @ rtp_llm/models/qwen_v2.py:314
    • 建议:恢复为 CkptWeightInfo(self.prefix + "lm_head.weight", identity)。对于带 language_model. 前缀的模型(如 QWenV2Audio),去掉 prefix 会导致找不到 lm_head 权重键。

P1

  • BatchDecodeScheduler: FINISHED 流变 stream 未从 waiting_streams_ 中移除 @ rtp_llm/cpp/engine_base/schedulers/BatchDecodeScheduler.h:211
    • 建议:在 line 207 的 remove_if 之前构建 scheduled_ptrs(即用原始的 new_streams 而非过滤后的),确保所有已处理的 stream(包括变为 FINISHED 的)都从 waiting_streams_ 中移除。否则 FINISHED stream 会在 waiting_streams_ 中残留一个调度周期,理论上可在下一次 evaluateWaitingStreams 中被重复选中并再次调用 reportEvent(CanRun)。
  • mm_extra_input 与 multimodal_features 跨 stream 收集时对齐可能不一致 @ rtp_llm/cpp/normal_engine/NormalModelInputGatherer.cc:363
    • 建议:当 ctx.has_mm_extra_input 为 true 但某个 stream 的 mm_extra_input 为空时,应为该 stream 的每个 non-reused feature 填充空 tensor(或 zeros),以保持 gathered_mm_extra_input 和 gathered_mm_features 一一对应。或者在 processContextStreams 末尾增加长度一致性断言。
  • ROCm multiMergeCopy 使用 std::memcpy 操作 GPU 指针导致段错误 @ rtp_llm/models_py/bindings/core/CudaOps.cc:182
    • 建议:ROCm 路径应使用 hipMemcpyAsync 替代 std::memcpy,与 CUDA 路径使用 InvokeMultiMergeCopyKernel 保持一致。调用者传入的是 GPU device 指针,std::memcpy 无法操作设备内存,会导致段错误或数据损坏。
  • Sampler 中 RTP_LLM_CHECK_WITH_INFO 格式字符串缺少参数——触发时为 UB @ rtp_llm/cpp/models/Sampler.cc:146
    • 建议:补全缺失的 printf 参数:"sample_batch_size[%zu] must divide by current_num_beams_in[%ld]", batch_size_in, cur_num_beams_in。当前格式字符串有两个 %d 占位符但零个参数,触发时读取栈上随机数据(UB)。
  • TreeLogitsProcessor 中 getStatus() 未判空 dfa_ptr 导致空指针崩溃 @ rtp_llm/cpp/models/logits_processor/TreeLogitsProcessor.cc:98
    • 建议:在 getStatus() 中检查 if (tree_info.dfa_ptr) 再解引用。同时将 StreamTreeInfo 默认构造函数中 in_tree_mode 初始化为 false:bool in_tree_mode = false;。process() 和 updateStatus() 中的 dfa_ptr 解引用(行20、62-63)也应加空指针检查。
  • ModelTypes.cc 中 hidden_states_dim1 计算在 RTP_LLM_CHECK 之前可能除以零 @ rtp_llm/cpp/models/ModelTypes.cc:182
    • 建议:先检查 hidden_states_dim0 != 0 再做除法:RTP_LLM_CHECK(hidden_states_dim0 > 0); auto hidden_states_dim1 = ...;。当前代码在 check 之前就执行了除法,如果 comboTokens 为 0 则是 UB。
  • CudaSampleOp reinterpret_cast<uint32_t> 将 int32_t top_k 误读为 unsigned* @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:162
    • 建议:使用 int32_t* 而非 reinterpret_cast<uint32_t*> 来操作 top_k 数据。当前代码将负值的 top_k(如 -1 表示未设置)解读为极大 unsigned 值,导致 t <= 0 永远为 false(unsigned 不会小于 0),采样逻辑分支选择错误。CUDA 和 ROCm 路径均受影响。
  • QWen3_VL/QWen3_VL_MOE 缺少 config.json 时静默返回不完整配置 @ rtp_llm/models/qwen3_vl.py:65
    • 建议:当 config.json 不存在时,应抛出异常 raise FileNotFoundError(f"config.json not found at {config_path}") 而非静默返回。QWenV2._from_hf 和 QWenV2Audio._from_hf 都在缺失时正确抛出异常。

Non-blocking Suggestions

P2

  • 并发测试默认 TaskStates 缺少 query_status,成功时靠赋值兜底 @ rtp_llm/test/smoke/case_runner.py:302
    • 建议:逻辑正确但依赖隐式兜底:当 all results match 时用 results[0] 替换空壳 task_states。建议直接 task_states = results[0] 在循环前赋值,失败时再覆盖,更易读。
  • CaseRunner.run() 中 stop_server 和 copy_logs 在同一 try 块,stop 失败会跳过 copy_logs @ rtp_llm/test/smoke/case_runner.py:261
    • 建议:参照 multi_inst_case_runner.py _cleanup_servers 的修复方式,将 stop_server() 和 copy_logs() 放入独立的 try 块,确保 stop 失败时日志仍能被拷贝
  • DpSeperationCaseRunner 错误消息引用了错误的类名 PdSeperationCaseRunner @ rtp_llm/test/smoke/multi_inst_case_runner.py:214
    • 建议:将 DpSeperationCaseRunner.init 中两处错误消息从 'PdSeperationCaseRunner' 修正为 'DpSeperationCaseRunner'(虽为预存问题,但既然已在修改此文件可一并修复)
  • computeReusedMultimodalCount 对同一 stream 重复调用,产生冗余 vector 拷贝 @ rtp_llm/cpp/normal_engine/NormalModelInputGatherer.cc:365
    • 建议:在 processContextStreams 的 per-stream 循环顶部调用一次 computeReusedMultimodalCount 并缓存结果 reuse_mm_count,传给 gatherMultimodalFeaturesForContextBatch 和 mm_extra_input 块,避免两次向量拷贝和重复遍历。
  • mm_extra_input 无条件 .to(torch::kCUDA) 即使已在 GPU 上 @ rtp_llm/cpp/normal_engine/NormalModelInputGatherer.cc:373
    • 建议:与 mm_features 处理一致,先检查 mm_extra_input[j].is_cuda() 再决定是否调 .to(torch::kCUDA),避免已在 GPU 的 tensor 产生不必要的 D2D 拷贝开销。
  • multimodalLengths() 在每次 decode step 输出时重复构建 std::map @ rtp_llm/cpp/normal_engine/NormalGenerateStream.cc:111
    • 建议:multimodal 输入在请求生命周期内不变,应在流初始化时计算一次并缓存到成员变量,prepareGenerateOutput 直接赋值,避免每步重建 std::map(含 tree node allocation)。
  • needReturnAllProbs() 遍历两次所有 streams,逻辑可在 StreamGroups 构造时预计算 @ rtp_llm/cpp/engine_base/stream/StreamGroups.h:137
    • 建议:在 StreamGroups 构造函数中预计算 max ReturnAllProbsMode(类似 has_multimodal_input_),存为成员变量。needReturnAllProbs() 直接返回,避免每次调用遍历全部 streams。
  • FMHAConfig/MoeConfig pickle 格式不向后兼容 @ rtp_llm/cpp/pybind/ConfigInit.cc:306
    • 建议:在 unpickle 中增加对旧 tuple 大小的兼容处理(如 if t.size() == 12: 用旧字段映射),或记录此为 breaking change 确保同版本部署。multiprocessing spawn 模式下通常同版本,但滚动更新场景会触发。
  • getFeatureHash 对大 embedding 执行全量 D2H + 逐字节哈希 @ rtp_llm/cpp/multimodal_processor/MultimodalProcessor.cc:28
    • 建议:用 GPU hash kernel 或 XXH3 等 SIMD 友好算法替代逐字节 FNV-1a,或只 hash 采样子集。
  • VIT 进程清理时 join timeout 后无 kill 兜底 @ rtp_llm/start_server.py:237
    • 建议:在 p.join(timeout=5) 后检查 p.is_alive(),若仍存活则调用 p.kill() + p.join() 确保彻底清理。
  • BatchDecodeScheduler: 部分 batch 调度可能导致低吞吐 @ rtp_llm/cpp/engine_base/schedulers/BatchDecodeScheduler.h:262
    • 建议:确认 100ms partial batch flush 是预期行为且不会导致 GPU 利用率过低。可考虑对 NONE mode 保持原始 batch_size_ 要求,仅对混合 ReturnAllProbsMode 场景启用 partial flush。
  • multimodal_util.py 中的 Python MultimodalInput 类 mm_preprocess_config 类型标注不一致 @ rtp_llm/multimodal/multimodal_util.py:310
    • 建议:纯 Python MultimodalInput 的 mm_preprocess_config 在 trans_mm_input() 中被直接传给 C++ MultimodalInput 构造函数。需要确认 Python 版 MMPreprocessConfig 能被 pybind11 隐式转换为 C++ 版,或在传递前显式转换(如 trans_config 那样)。由于 Python 版 MMPreprocessConfig 字段少于 C++ 版(缺少 crop_positions 和 mm_timeout_ms),实际传入时会报类型错误。
  • decode_fused_rope_kvcache 新增 position_ids 参数需要与 rtp_kernel 版本对齐 @ rtp_llm/ops/fused_rope_kvcache_op.py:207
    • 建议:这是跨包 API 变更。确认 rtp_kernel.fused_rope_kvcache.decode_fused_rope_kvcache 的函数签名已同步更新,否则位置参数偏移将导致运行时错误。
  • _get_kv_scale 中 dummy_scale 的尺寸计算可能不足 @ rtp_llm/ops/fused_rope_kvcache_op.py:188
    • 建议:该 dummy scale 计算依赖于 convert_offset_to_block_array 的偏移编码方式(K=page2, V=page2+1),但注释中也承认 MHAKVCacheSpec 在正常操作下总会提供 kv_scale_base,此分支是防御性代码。建议添加单元测试验证尺寸计算正确性。
  • generic_moe.py EP 模式下移除了 fused_moe 的 skip_allreduce 参数 @ rtp_llm/models_py/model_desc/generic_moe.py:168
    • 建议:在纯 TP 模式下(ep_size==1, ffn_tp_size>1),旧代码通过 use_unified_allreduce 合并两次 allreduce 为一次。新代码移除了该优化,routed expert 和 shared expert 各自独立 allreduce。TODO 注释已说明未来会恢复,但当前是性能回退(约 2x allreduce)。确认这是有意的取舍。
  • setup_args() 中 PYTEST_CURRENT_TEST 自动检测可能影响集成测试 @ rtp_llm/server/server_args/server_args.py:492
    • 建议:在 pytest 环境下自动跳过 sys.argv 解析是好主意,但如果集成测试需要测试 CLI 参数解析,这个逻辑会意外跳过。建议在集成测试中显式传入 args 参数而非依赖 PYTEST_CURRENT_TEST 检测。
  • EP 模式 shared expert gate 用 torch.sigmoid + mul 代替 fused kernel @ rtp_llm/models_py/model_desc/generic_moe.py:183
    • 建议:EP 模式下 allreduce 需要在 add 之前执行,不能用原 fused op。但可以写一个 sigmoid_scale(不含 add)的 fused kernel,省去一次中间张量分配和一次 kernel launch。或者先做 sigmoid_scale_add 到 shared_expert_output(in-place),再 allreduce shared_expert_output,最后 experts_output += shared_expert_output。
  • VitProxy LoadBalancer 每请求 3 次独立锁获取 @ rtp_llm/server/vit_proxy_server.py:185
    • 建议:将 get_worker() 和 increment_connections() 合并为一个 get_worker_and_increment() 方法,只获取一次锁。或者对 round_robin 策略使用 AtomicInteger 代替锁。高 QPS 下可减少锁竞争。
  • WorkerConnectionPool.get_stub() 稳态下仍获取锁 @ rtp_llm/server/vit_proxy_server.py:132
    • 建议:使用 double-check locking:先无锁检查 self.stubs.get(worker_address),命中则直接返回(CPython GIL 保证 dict 读安全)。未命中再获取锁创建。稳态下完全无锁。
  • qkvz+ba fused GEMM 输出切片产生非连续张量 @ rtp_llm/models_py/model_desc/qwen3_next.py:669
    • 建议:确认下游 fix_query_key_value_ordering 中的 torch.split → view → contiguous 链是否触发额外拷贝。如果 view 失败触发 contiguous(),可以考虑在 _input_project 中直接 .contiguous() 两个切片(明确开销),或使用 torch.split 代替手动切片(split 在连续维度上返回连续视图)。对于小 M(decode),额外拷贝开销可能超过融合 GEMM 收益。
  • singleflight event.wait() 无超时,可能导致线程长期阻塞 @ rtp_llm/multimodal/multimodal_util.py:223
    • 建议:建议给 event.wait() 添加超时参数(如 safe_request_get 的 timeout * MAX_REDIRECTS + margin),超时后直接调用 _download_url_bytes 而非无限等待。当前下游 safe_request_get 有 timeout=10s,实际风险有限,但防御性编程更好。
  • request_get 移除 requests.get fallback 后首次调用失败会永久 cache ImportError @ rtp_llm/multimodal/multimodal_util.py:28
    • 建议:当前行为正确——如果 ssrf_check 不存在,后续调用依然会每次重试 import(因为 _request_get_impl 未被赋值)。逻辑正确。但移除 fallback 属于安全加固的 breaking change,建议在 PR 描述中明确标注,确保所有部署环境都已包含 ssrf_check 模块。
  • _download_url_bytes 异常链信息丢失 @ rtp_llm/multimodal/multimodal_util.py:186
    • 建议:应使用 raise Exception(...) from e 保留原始异常链的 traceback,否则调试时丢失根因堆栈。同样的问题也存在于 get_json_result_from_url:164。
  • PrefillRpcServer::multimodalProcess 逐元素 add_token_ids 效率低 @ rtp_llm/cpp/model_rpc/PrefillRpcServer.cc:179
    • 建议:使用 mutable_request->mutable_token_ids()->Add(ids_ptr, ids_ptr + numel) 一次性批量添加,减少 repeated field 扩容开销。原代码 TODO 注释也标注了 'optimize copy'。
  • 并发测试使用 as_completed 顺序作为基准比较 @ rtp_llm/test/smoke/case_runner.py:311
    • 建议:as_completed 返回完成顺序而非提交顺序,results[0] 是最快完成的请求而非第一个提交的。这是预存问题未被本 PR 引入,但 break + results[0] 赋值的修复逻辑依赖这一假设。若需确定性基准,应改用 list(executor.map(...)) 或 [f.result() for f in futures] 保持提交顺序。
  • grpc_util 对不支持的 dtype 静默回退 FP32 未做日志告警 @ rtp_llm/utils/grpc_util.py:65
    • 建议:对空 tensor 的不支持 dtype(如 int8、float64)静默转换为 FP32 是合理的降级,但建议添加 logging.warning 记录原始 dtype,便于排查下游 shape/dtype 不一致问题。比旧代码(丢失 shape)好很多。
  • ssrf_check: streaming response 从 with session 内返回,session 提前关闭 @ rtp_llm/utils/ssrf_check.py:186
    • 建议:return response 退出 with 块时 session.close() 会清理连接池。虽然已借出的连接不受影响(实际可正常读取 response.content),但连接变成孤儿、不再归池管理。建议将 with session 改为 try/except/finally,仅在错误路径关闭 session,或在成功路径不关闭 session。
  • DFAUtil.h TreeDFA input_list_ 用 size 10 初始化而非 reserve @ rtp_llm/cpp/models/logits_processor/DFAUtil.h:127
    • 建议:改为 input_list_() 并用 input_list_.reserve(10) 预留容量。当前 input_list_(10) 创建了 10 个默认元素,isFinished() 检查最后一个元素是否等于 endTokenId,这 10 个零元素会干扰状态判断。
  • DFAUtil.h getCandidateTokenIds 遇到负 token ID 抛出异常可能中断所有推理 @ rtp_llm/cpp/models/logits_processor/DFAUtil.h:178
    • 建议:将 throw 改为 LOG_WARNING + skip 处理。在推理热路径中抛异常会导致整个 batch 的所有请求中断,应当降级为跳过该 token 或返回 endTokenId。
  • CudaSampleOp 原地修改 params.top_k/top_p 输入 tensor 可能影响后续迭代 @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:165
    • 建议:克隆 top_k/top_p tensor 后再做修改,或使用局部 buffer。当前原地修改会影响生成循环中复用这些 tensor 的后续迭代。
  • qwen3_5_moe_vit.py max_seqlen 未调用 .item() 导致传入 tensor 而非 int @ rtp_llm/multimodal/multimodal_mixins/qwen3_5_moe/qwen3_5_moe_vit.py:295
    • 建议:改为 max_seqlen = (cu_seqlens[1:] - cu_seqlens[:-1]).max().item(),确保传给 flash_attn 的是 Python int 而非 0-dim tensor,与 kimi_k25_vit.py 保持一致。
  • multimodal_common.py 硬依赖 pillow_heif 无 fallback 保护 @ rtp_llm/multimodal/multimodal_mixins/multimodal_common.py:13
    • 建议:用 try/except 包裹 pillow_heif 的 import 和 register_heif_opener(),与 decord 的处理方式一致。缺少 pillow_heif 时当前会导致整个 multimodal 模块不可导入。
  • timeout_decorator 超时后线程仍继续运行且 shutdown(wait=True) 会阻塞 @ rtp_llm/multimodal/multimodal_mixins/multimodal_common.py:33
    • 建议:超时后 with 块退出时 executor.shutdown(wait=True) 会等待底层线程完成,实际上会一直阻塞直到函数返回,无法实现真正超时。建议使用 cancel_futures=True(Python 3.9+)或改用 multiprocessing 实现可终止超时。
  • OpDefs.h getLayerCache 对 kv_cache_base_by_layer 和 layer_attn_types 用不同 vector 做 bounds check @ rtp_llm/models_py/bindings/OpDefs.h:54
    • 建议:应同时检查 idx < kv_cache_base_by_layer.size()。当前仅检查 layer_attn_types 的大小,如果两个 vector 大小不一致则 kv_cache_base_by_layer 会越界。
  • TreeLogitsProcessor updateStatus 中 num_new_tokens 为负时 size_t 溢出导致越界读 @ rtp_llm/cpp/models/logits_processor/TreeLogitsProcessor.cc:60
    • 建议:在循环前加 RTP_LLM_CHECK(num_new_tokens >= 0)。num_new_tokens 是 int32_t,隐式转为 size_t 时负值变成极大数,导致大量越界读取。
  • base_multimodal_mixin.py torch.set_default_dtype 为进程级全局状态,多线程下不安全 @ rtp_llm/multimodal/multimodal_mixins/base_multimodal_mixin.py:99
    • 建议:如果可能并发初始化多个 mixin,应使用 threading.Lock 保护此段代码,或避免使用 set_default_dtype,改为在各个 tensor 创建时显式指定 dtype。
  • QWenV2Audio._create_config 断言弱于基类 @ rtp_llm/models/qwen_v2_audio.py:69
    • 建议:将断言改为与 QWenV2._create_config 一致的完整检查:assert config.attn_config.head_num > 0 and config.attn_config.kv_head_num > 0 and config.attn_config.size_per_head > 0 and config.num_layers > 0 and config.inter_size > 0,以便在 config.json 结构异常时尽早报错。
  • QWen3_VL 中未使用的 import @ rtp_llm/models/qwen3_vl.py:5
    • 建议:删除未使用的 import:torch, torch.library, PIL.Image, AutoProcessor, Qwen3VLConfig, Qwen3VLVisionModel, VitConfig。这些不影响正确性但会增加导入时间和引入不必要的依赖。
  • tl.wrap_triton monkey-patch 在模块级别执行 @ rtp_llm/models/qwen3_vl.py:15
    • 建议:模块级别 monkey-patch torch.library 可能影响其他使用者。建议加注释说明此 workaround 的原因和 Triton/torch 版本条件,或移至专门的 compat 模块中集中管理。
  • scatter_qkv kernel 未做 autotuning,num_warps=4 硬编码 @ rtp_llm/models_py/triton_kernels/common/scatter_qkv.py:89
    • 建议:根据 K_DIM 选择 num_warps:K_DIM<=256 用 2 warps,K_DIM>512 用 8 warps。考虑在 prefill M 很大时每个 block 处理多行以减少 kernel launch overhead。

P3

  • start_server.py 中成功启动日志被移除 @ rtp_llm/start_server.py:398
    • 建议:恢复启动耗时日志,对运维排查有帮助。
  • ops/init.py 重复 import sys @ rtp_llm/ops/__init__.py:89
    • 建议:删除重复的 import sys

Checklist ✅ (56 items passed)

Strengths

  • 修复了 OpenaiComparer 注册谓词中 q_r['query'] 非 dict 时的 TypeError 崩溃(isinstance 防御)
  • SmokeException 补齐了必需的 error_status 参数,与构造函数签名 (error_status, message) 一致
  • PdSeperationCaseRunner / DpSeperationCaseRunner 新增 self.remote_kvcm_server = None 初始化,防止 _cleanup_servers 中 AttributeError
  • _stop_server_safe 和 _cleanup_servers 增加 try/except 防止清理阶段异常掩盖原始失败
  • 并发测试逻辑修复:break 提前退出避免覆盖首个 mismatch 错误信息,且成功路径正确返回 results[0]
  • 移除了硬编码路径 sys.path.append 和无用 import sys

Vinkle-hzt and others added 4 commits June 24, 2026 14:10
P0:
- rtp_llm/BUILD: restore 12 py_library stub targets (pip shims +
  testlib/sdk) required by smoke defs.bzl for Bazel analysis

P1:
- executor.py: _write_final_stream_files only overwrites when
  ByteStream not started or result data is longer
- platform.py: fallback to nvcc --version when version.json missing,
  ultimate default cuda12_6
- remote_exec_rtp.py: guard prepare_venv.py with if-exists check
- comparer_registry.py: fix mainse import path and class names
  (MainseDecodeArpcComparer / MainseEmbeddingArpcComparer)
- generic_moe.py: move GroupTopK() and config attrs to __init__
- ssrf_check.py: re-raise ValueError in get_connection fallback
  for security parity with send()
P2:
- cas_client: log.warning in download_blob on gRPC failure
- cas_client: add committed_size check in _bytestream_write_file_parallel
- endpoint_info: add threading.RLock to ExecutorEndpointPool
- BatchDecodeScheduler: predicate checks !waiting_streams_.empty()
  for immediate first-request wakeup
- trtllm_gen: assert kv_cache is not None in forward()
- plugin: validate MAX_RETRIES >= 0 in _execute_with_retry
- distributed_server_test: dedent 17 test methods from tearDown
  to class body level
- runner: add ENABLE_STABLE_SCATTER_ADD=ON in multi-role path
- OpenaiEndpoint: add comment explaining logprobs=false priority
- warp_topk: upgrade to std::shared_mutex for occupancy cache
- MultimodalProcessor: .to(kCPU).contiguous() avoids GPU temp alloc
- MultimodalProcessor: replace FNV-1a with std::hash<string_view>
- generic_moe: EP path uses fused sigmoid_gate_scale_add operator
- ssrf_check: _validate_url before session creation

P3:
- multi_inst_case_runner: fix DpSeperation error message
- runs_plugin: shallow copy keywords in _clone_item
- LocalRpcServer.cc: remove PyErr_Fetch leak, use e.what() directly
- comparer_registry: split mainse imports into per-file modules
- reranker_comparer: Exception → SmokeException(COMPARE_FAILED)
- embedding_comparer: Exception → SmokeException(COMPARE_FAILED)
- multi_inst_case_runner: assert GPU count before slicing gpu_ids
- openai_comparer: add weights_only=False to torch.load
- llava_renderer: validate crop_positions h/w != 0 before division
@LLLLKKKK

Copy link
Copy Markdown
Collaborator

AI Code Review - PR #1108

Status: BLOCKING

Summary: P0/1 · P1/11 · P2/8 · P3/0

Blocking Issues

P0

  • QWenV2Weight._process_meta 中 transformer_prefix 拼接顺序反转,Audio/VL 模型权重路径错误 @ rtp_llm/models/qwen_v2.py:63
    • 建议:确认此变更是否与 python_native_v2 重构配套。若非有意变更,恢复原始顺序 self.prefix + self.model_prefix。同时 lm_head 路径也删除了 prefix 前缀(line 314),需一并验证。

P1

  • Sampler.cc RTP_LLM_CHECK_WITH_INFO 格式串缺少实参导致 UB @ rtp_llm/cpp/models/Sampler.cc:147
    • 建议:补全格式实参:RTP_LLM_CHECK_WITH_INFO(..., "...[%d]...[%d]", (int)batch_size_in, (int)cur_num_beams_in)。
  • TreeLogitsProcessor::getStatus 无条件解引用可能为空的 dfa_ptr @ rtp_llm/cpp/models/logits_processor/TreeLogitsProcessor.cc:98
    • 建议:循环中加 if (!tree_info.dfa_ptr) continue;
  • TreeLogitsProcessor::updateStatus 中 int32_t 与 size_t 比较,负值变巨大循环 @ rtp_llm/cpp/models/logits_processor/TreeLogitsProcessor.cc:60
    • 建议:循环前加 if (num_new_tokens <= 0) continue;
  • fused_recurrent 中 read_block_id <= 0 时 early return 留下未初始化输出 @ rtp_llm/models_py/triton_kernels/fla/fused_recurrent.py:123
    • 建议:early return 前将 p_o 区域置零,或改用 torch.zeros 分配 o
  • post_reorder_triton_kernel 在 fp16/bf16 dtype 下做加权累加,精度严重损失 @ rtp_llm/models_py/triton_kernels/moe/ep_kernels.py:747
    • 建议:sum_vec 用 tl.float32 累加,store 时再 .to(InDtype)
  • CudaSampleOp 中 params.generator 无边界检查即按 batch_size 索引 @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:143
    • 建议:循环前加 RTP_LLM_CHECK(params.generator.size() >= batch_size)
  • CudaSampleOp 就地修改调用方的 top_k/top_p CPU tensor @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:162
    • 建议:修改前 clone tensor 隔离副作用:auto top_k = params.top_k.clone();
  • ROCm 采样路径未处理 do_sample=false 标志 @ rtp_llm/models_py/bindings/core/CudaSampleOp.cc:345
    • 建议:ROCm sampleGreedy 开头添加与 CUDA 路径相同的 do_sample 检查:has_not_do_sample 时保存原始 logits,处理后恢复
  • MultimodalMixinLoader.load_weights 未处理 load_tensor 返回空列表 @ rtp_llm/model_loader/multimodal_mixin_loader.py:46
    • 建议:调用 merge_fun 前校验:if not parts: raise RuntimeError(f'ViT weight "{name}" not found')
  • start_server.py 删除启动耗时日志且 start_time 成为死代码 @ rtp_llm/start_server.py:346
    • 建议:恢复启动耗时日志,或删除未使用的 start_time 赋值
  • base/init.py 中 all 仅在 CUDA 分支定义,ROCm wildcard import 行为异常 @ rtp_llm/models_py/modules/base/__init__.py:62
    • 建议:在 ROCm 分支也定义 all,或移到 if/else 外部

Non-blocking Suggestions

P2

  • MoeConfig pickle 反序列化严格检查 t.size()==13,滚动升级时不兼容 @ rtp_llm/cpp/pybind/ConfigInit.cc:668
    • 建议:改为 t.size() >= 11 且新字段用默认值填充,确保滚动升级兼容
  • MtpExecutor 强制覆盖 return_all_probs 为 DEFAULT,用户 ORIGINAL 模式失效 @ rtp_llm/cpp/normal_engine/speculative/MtpExecutor.cc:760
    • 建议:仅在 NONE 时升级:if (getReturnAllProbs() == NONE) setReturnAllProbs(DEFAULT);
  • use_triton_pa 默认值从 true 改为 false,可能影响 ROCm 部署 @ rtp_llm/cpp/config/ConfigModules.h:114
    • 建议:确认 ROCm smoke test 覆盖此变更,考虑在 ROCm 配置中显式设为 true
  • combo_position_ids 重复 H2D 传输 @ rtp_llm/cpp/models/PyWrappedModel.cc:97
    • 建议:移除外层或内层的重复 tensorHoldHostAndToCuda 调用
  • transMMInputsPB 参数按值传递导致不必要的 vector 拷贝 @ rtp_llm/cpp/model_rpc/QueryConverter.h:26
    • 建议:改为 const std::vector& mm_inputs
  • Qwen2.5 VL SDPA forward 每次调用 torch.cuda.get_device_name(0) @ rtp_llm/multimodal/multimodal_mixins/qwen2_5_vl/modeling_qwen2_5_vl.py:392
    • 建议:移到 init 中缓存结果
  • kimi_k25_image_processor._navit_resize_image 在 width=0 或 height=0 时除零 @ rtp_llm/multimodal/multimodal_mixins/kimi_k25/kimi_k25_image_processor.py:35
    • 建议:入口增加 width = max(1, width); height = max(1, height)
  • defs.bzl: gpu_type 为空列表时 gpu_type[0] 导致 Starlark 阶段崩溃 @ rtp_llm/test/smoke/defs.bzl:182
    • 建议:函数开头加 if not gpu_type: fail('gpu_type must be non-empty')

Checklist Violations (1 fail / 56 total)

General Principles Checklist

  • [6.1] Architecture — 兼容性:公开 API/持久数据/配置/环境迁移安全 → issue MoeConfig pickle 反序列化严格检查 t.size()==13,滚动升级时不兼容
    MoeConfig pickle 严格检查 t.size()==13 导致旧版序列化数据不兼容;use_triton_pa 默认值从 true 改为 false 可能影响 ROCm 部署

Strengths

  • BaseMultiModalMixin.init 正确使用 try/finally 恢复 torch 默认 dtype,避免进程级污染
  • load_mm_weight 增加空权重 fail-fast 检查,防止静默使用随机初始化权重
  • ROCm cuda_shims.h 提供完备的 CUDA→HIP 符号映射,包括 atomic_ref 的 TTAS 实现
  • 采样中 cum_log_probs 更新改为 gather+log 代替全量 probs_t.log(),从 O(batch*vocab) 降到 O(batch)
  • autotune_cache 基础设施设计清晰:env-var 控制、JSON 配置落盘、单配置短路跳过 benchmark

HongminTan and others added 6 commits June 26, 2026 13:16
…ve_v2

# Conflicts:
#	deps/requirements_base.txt
#	deps/requirements_lock_cuda12_arm.txt
#	deps/requirements_lock_rocm.txt
#	deps/requirements_lock_torch_arm.txt
#	deps/requirements_lock_torch_cpu.txt
#	deps/requirements_lock_torch_gpu_cuda12.txt
#	deps/requirements_lock_torch_gpu_cuda12_9.txt
#	rtp_llm/BUILD
#	rtp_llm/test/BUILD
#	rtp_llm/test/generate_config_test.py
#	rtp_llm/test/smoke/BUILD
#	rtp_llm/test/smoke/suites_h20_oss.bzl
The outer PID/EXIT_CODE wait loop only reports a host as failed when its
per-host subshell exits non-zero, but commands were joined with ';' so a
failing non-final command was masked.

- build/kill/clean/test: leading `scp` of the executor now `|| exit $?`,
  so a failed dispatch is no longer hidden by the trailing ssh.
- copy: the ssh result is captured via $(...) which masks its exit code;
  check it explicitly, guard empty TEST_OUTPUT_PATH, and fail on the
  critical process.log / *Result.json scp. Trace files (normal_*) stay
  best-effort (|| true).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…hells

Address review: multi_copy_script continued after a failed scp. Adopt
`set -e` at the top of every per-host subshell as the single, consistent
error-propagation mechanism, replacing the scattered `|| exit $?` guards.

- copy: a failed scp (or empty/failed remote exec) now aborts the host's
  subshell instead of running the remaining scp commands.
- build/kill/clean/test: same `set -e` guard for consistency.
- Trace files (normal_*) stay best-effort via `|| true`; empty
  TEST_OUTPUT_PATH is still guarded explicitly.

multi_kill_script already had the PID/EXIT_CODE propagation pattern.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CI failed on the rocm config with:
  no such package '@pip_gpu_rocm_torch//flydsl' ... referenced by
  '//rtp_llm/models_py/triton_kernels:fla'

fla/flydsl_chunk_gdn_mi308x*.py import the ROCm/MI308X-only `flydsl`
package, which is not a pip dependency in the rocm lockfile. These modules
are lazy-imported at runtime (fla/chunk.py) and shipped via setup.py, so
import-based dependency resolution over :fla's srcs should not pull flydsl
into the Bazel graph. Exclude them from the glob.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@LLLLKKKK

Copy link
Copy Markdown
Collaborator

AI Code Review - PR #1108

Status: BLOCKING

Summary: P0/1 · P1/12 · P2/22 · P3/2

Blocking Issues

P0

  • CPFlashInferImpl.forward 第三参数与基类签名不匹配,layer_idx=0 时 RoPE 被跳过 @ rtp_llm/models_py/modules/factory/attention/cuda_cp_impl/prefill_cp_flashinfer.py:174
    • 建议:将 forward 签名改为 forward(self, qkv, kv_cache, layer_idx: int = 0),内部使用 self.need_rope_kv_cache(init 已在 line 138 从 attn_configs 正确初始化)来判断是否执行 RoPE,而非依赖第三参数。当前代码导致 CP 模式第 0 层位置编码丢失...

P1

  • forwardMicroBatched 在 layer_num_==1 时可产生混合 batch 触发 fatal 断言 @ rtp_llm/cpp/models/PyWrappedModel.cc:774
    • 建议:在 planMicroBatches 的 layer_num_==1 分支中,确保每个 micro-batch 不同时含 prefill 和 decode(即 batch_info 的 prefill_num 和 decoder_num 不能同时 >0),或者在 buildPyAttentionInputs 中对 micro-batch 放宽断言。当前 decode_batch_0_size...
  • transformer_prefix 拼接顺序反转导致 Qwen2-Audio 等 language_model 前缀模型权重加载失败 @ rtp_llm/models/qwen_v2.py:63
    • 建议:恢复为 self.transformer_prefix = self.prefix + self.model_prefix。当前拼接产生 'model.language_model.' 前缀,与 HF checkpoint 的 'language_model.model.' 不匹配,会导致 Qwen2-Audio 等使用 language_model. 前缀的模型权重找不到。
  • lm_head 权重路径移除 self.prefix 导致 language_model 前缀模型 lm_head 加载失败 @ rtp_llm/models/qwen_v2.py:314
    • 建议:恢复为 CkptWeightInfo(self.prefix + 'lm_head.weight', identity),否则使用 language_model. 前缀的模型(如 Qwen2-Audio)无法找到 lm_head 权重。
  • Qwen2_5_VL Flash Attention 每层触发 GPU→CPU 同步 @ rtp_llm/multimodal/multimodal_mixins/qwen2_5_vl/modeling_qwen2_5_vl.py:262
    • 建议:参照 qwen2_vl 的做法,在 Qwen2_5_VisionTransformerPretrainedModel.forward() 中预计算 max_seqlen 并通过 block 传递到 attention 层,避免每层 GPU→CPU 同步。
  • VisionAttention 缺少 self.head_dim 初始化,运行时必崩 @ rtp_llm/multimodal/multimodal_mixins/qwen2_vl/modeling_qwen2_vl.py:161
    • 建议:在 init 中添加 self.head_dim = dim // num_heads,与 Qwen2_5_VLVisionAttention(modeling_qwen2_5_vl.py:295)保持一致。默认路径是 flash_attention_2 或 sdpa,不走 eager,但若显式指定 attn_implementation='eager' 会触发 AttributeE...
  • VisionAttention 注意力掩码用布尔加法代替 -inf,cross-segment attention 会泄漏 @ rtp_llm/multimodal/multimodal_mixins/qwen2_vl/modeling_qwen2_vl.py:184
    • 建议:参考 Qwen2_5_VLVisionAttention 的做法:用 torch.full(..., torch.finfo(q.dtype).min) 初始化掩码,within-segment 位置设为 0。布尔掩码 +0/+1 对 softmax 几乎无效,不能正确阻止跨 segment 的注意力。同样仅影响 eager 路径。
  • _can_swizzle_kn 维度检查与 swizzle_tensor 约束相反(ROCm) @ rtp_llm/multimodal/multimodal_mixins/qwen2_5_vl/qwen2_5_vl_mixin.py:247
    • 建议:参数命名与实际语义反转。应改为 n, k = weight_kn.shape(因传入的是 weight_nk 形状 (N,K)),然后检查 (n % 16 == 0) and (k % 32 == 0)。否则当 N%32!=0 但 N%16==0 时,guard 会放行但 swizzle_tensor 内部 assert 会崩溃。
  • Pipeline 创建 MultimodalInput 使用硬编码 magic number 作为默认 MMPreprocessConfig @ rtp_llm/pipeline/pipeline.py:193
    • 建议:使用命名参数构造 MMPreprocessConfig(width=-1, height=-1, ...) 避免位置依赖,或者提供一个 DEFAULT_PREPROCESS_CONFIG 常量在 multimodal_util 模块中统一定义。
  • PureDpRouter._pad_to_max 每层 D2H 同步导致推理延迟不可预测 @ rtp_llm/models_py/modules/factory/fused_moe/impl/cuda/routers/pure_dp_router.py:127
    • 建议:代码中已有 TODO 注释,但这是 P1 级别性能问题:DeepSeek V3 有 61 层 MoE,每层 .item() 都产生 GPU→CPU 同步。建议在 step 级别(进入 MoE 栈之前)做一次 all_gather 获得 max_n,然后作为参数传入 router,而不是延后到 follow-up PR。
  • RocmEpNormalStrategy DeepEP 分支硬编码 FusedMoeExecutor,忽略量化感知 executor @ rtp_llm/models_py/modules/factory/fused_moe/impl/rocm/strategy/ep.py:140
    • 建议:将 line 140 的 executor_class=FusedMoeExecutor 改为 executor_class=executor_class,与 MoriEP 分支保持一致。当前代码在 quantized 模型 + DeepEP 组合下静默使用不支持量化的 FusedMoeExecutor,量化权重被当作 BF16 消费导致推理结果错误。
  • RocmExpertsFp4PerGroup 和 RocmExpertsMXFp4 直接修改共享的 quant_config 实例 @ rtp_llm/models_py/modules/factory/fused_moe/impl/rocm/executors/rocm_moe.py:422
    • 建议:在两个类的 init 中修改 quant_config 属性前先执行 self.quant_config = copy.copy(self.quant_config),与 RocmExpertsFp8PerChannel/RocmExpertsFp8PerBlock 保持一致。否则多 MoE 层复用同一 strategy 实例时共享 quant_config 被污染,导致后续层的策略...
  • CUDA graph prefill 模式 qo_indptr 构建错误:batch_size>1 时 FlashInfer 读取错误 Q tokens @ rtp_llm/models_py/modules/factory/attention/cuda_impl/py_flashinfer_mha.py:181
    • 建议:FlashInfer ragged API 中 qo_indptr[i] 是 batch i 在 Q 缓冲区的起始偏移。padded 布局下 batch i 从 imax_sl 开始,但当前 qo_indptr[1]=input_len_0 而非 max_sl。修复方案:qo_indptr[i] 设为 imax_sl(每 batch 起始),qo_indptr[i+1] 设为 i*max...

Non-blocking Suggestions

P2

  • base_model.py 中 json.load(open(...)) 泄露文件描述符 @ rtp_llm/models/base_model.py:115
    • 建议:使用 with open(...) as f: json.load(f) 确保文件句柄及时关闭。在非 CPython 环境下 open() 返回的对象可能延迟释放导致 FD 耗尽。
  • forwardMicroBatched 未在 forward() 的 try/catch 中,Python 异常未被捕获 @ rtp_llm/cpp/models/PyWrappedModel.cc:466
    • 建议:将 forwardMicroBatched 调用移到 try 块内,确保 py::error_already_set 等 Python 异常被正确捕获和转化为 std::runtime_error,否则异常直接传播给上层导致不可预期行为。
  • mm_extra_input 所有 tensor 假定同一 dtype,混合 dtype 场景会出错 @ rtp_llm/cpp/models/ModelTypes.cc:55
    • 建议:当前实现与 multimodal_features 保持一致(也是单 dtype 广播),如果后续支持混合 dtype extra-input,需要为每个 tensor 独立广播 dtype。建议添加注释说明此限制。
  • Qwen2_5_VL SdpaAttention 每层调用 torch.cuda.get_device_name(0) @ rtp_llm/multimodal/multimodal_mixins/qwen2_5_vl/modeling_qwen2_5_vl.py:392
    • 建议:将设备名检测移到 init 中缓存为 self._is_mi308x,forward 中直接使用缓存值。
  • Qwen2_5_VL SdpaAttention 每层创建 O(N²) attention mask @ rtp_llm/multimodal/multimodal_mixins/qwen2_5_vl/modeling_qwen2_5_vl.py:394
    • 建议:在模型 forward() 中预计算 attention_mask(或 window mask 变体),传递给各层复用,而非每层重复创建。同时可用 torch.block_diag 等向量化方式替代 Python for 循环。
  • qwen2_vl VisionAttention 引用未定义的 self.head_dim @ rtp_llm/multimodal/multimodal_mixins/qwen2_vl/modeling_qwen2_vl.py:197
    • 建议:在 init 中添加 self.head_dim = dim // num_heads。虽然 eager 路径是 fallback 不常触发,但也应修复以防止意外崩溃。标注为 P2 而非 P0,因为默认使用 flash_attn 或 sdpa,eager 是显式回退。
  • get_preprocess_config 中 config.mm_timeout_ms 为 0 时会被 or -1 替换 @ rtp_llm/openai/renderers/llava_renderer.py:53
    • 建议:Python 的 or 运算会将 0 视为 falsy。如果用户显式传入 mm_timeout_ms=0 表示 '无超时',会被替换为 -1。对其他字段(width, height, fps 等)同理。建议改用 config.mm_timeout_ms if config.mm_timeout_ms is not None else -1。目前 0 值在实际场景中不太可能作为有效输入...
  • [MMPreprocessConfig(...)] * len 创建共享引用,如后续被修改会影响所有 inputs @ rtp_llm/openai/renderers/custom_renderer.py:288
    • 建议:用列表推导 [MMPreprocessConfig(-1,...) for _ in range(len(input_urls))] 代替 [X]*n,避免所有元素指向同一对象。当前默认值不太会被修改,但如果 C++ 侧或下游修改了 config 字段,会导致难以追踪的 bug。
  • timeout_decorator 因 ThreadPoolExecutor.exit 阻塞而实际无法超时 @ rtp_llm/multimodal/multimodal_mixins/multimodal_common.py:33
    • 建议:ThreadPoolExecutor 的 exit 会 shutdown(wait=True),等待 worker 完成后才返回,导致 TimeoutError 实际不会抛出。应将 executor 放在 with 外面或用 shutdown(wait=False, cancel_futures=True),或者改用 threading.Timer + daemon thread 方案。
  • load_mm_weight 的 ctype 参数标注为 str 但实际传入 torch.dtype @ rtp_llm/multimodal/multimodal_mixins/base_multimodal_mixin.py:176
    • 建议:将类型标注改为 ctype: Union[str, torch.dtype],或直接改为 ctype: torch.dtype 以匹配实际调用方式。
  • computeReusedMultimodalCount 对同一 stream 重复调用 @ rtp_llm/cpp/normal_engine/NormalModelInputGatherer.cc:365
    • 建议:将 computeReusedMultimodalCount 的结果缓存在 gatherMultimodalFeaturesForContextBatch 返回/输出,或在 processContextStreams 循环中只调用一次并复用结果。对于多图的 context batch 来说,避免重复的 std::is_sorted 和 multimodalFeatures() 拷贝。
  • mm_extra_input 无条件 .to(torch::kCUDA),缺少已在 CUDA 的检查 @ rtp_llm/cpp/normal_engine/NormalModelInputGatherer.cc:373
    • 建议:与 mm_features 的处理一致,先检查 mm_extra_input[j].is_cuda(),已在 GPU 则直接 emplace_back 避免无意义的 D2D copy。
  • multimodal_util: request_get 移除 requests.get 回退改为强制 ImportError @ rtp_llm/multimodal/multimodal_util.py:30
    • 建议:这是安全加固(强制 SSRF 保护),但会导致缺少 ssrf_check 模块的部署立即失败。建议在 CHANGELOG 或迁移文档中标注此 breaking change,确保所有部署环境已安装 ssrf_check。
  • ConfigInit.cc: FMHAConfig pickle 格式不向后兼容 @ rtp_llm/cpp/pybind/ConfigInit.cc:308
    • 建议:FMHAConfig pickle tuple 从 12→14、MoeConfig 从 12→13,旧版本序列化的对象无法反序列化。multiprocessing 同版本使用不受影响,但若有 checkpoint 或跨版本 pickle 场景需注意。考虑使用 dict-based pickle 或容忍旧长度做版本适配。
  • ROCm shuffle_moe_weight 在非 MXFP4 scale 路径下缺少 squeeze 还原 @ rtp_llm/device/device_impl.py:898
    • 建议:将 squeeze 逻辑移到函数末尾 return 前(if original_ndim == 2: x_ = x_.squeeze(-1)),使所有路径对 2D 输入都正确还原维度。注意:此行为与 PR 前一致(旧代码也没有 squeeze),但既然 PR 引入了 original_ndim 追踪,应一并修复。
  • MoeConfig pickle 向后兼容性断裂:tuple size 从 11 变为 13 @ rtp_llm/cpp/pybind/ConfigInit.cc:676
    • 建议:考虑容忍旧 tuple size(如 t.size() >= 11),对新增字段使用默认值。这对于 checkpoint 兼容性(如 multiprocessing spawn 场景、缓存文件)很重要。
  • distributed_server_test.py 缩进修复后 stop_event 被覆盖导致线程无法正确停止 @ rtp_llm/distribute/test/distributed_server_test.py:329
    • 建议:这是旧代码的 bug(缩进修复只是暴露了它)。应移除重复的 stop_event = threading.Event(),确保同一个 Event 被传递给线程和最终 set()。
  • backend_manager DeepEP 初始化失败只记录 error 但异常信息不含 traceback @ rtp_llm/server/backend_manager.py:110
    • 建议:添加 exc_info=True 参数:logging.error(f"Failed to initialize DeepEP wrapper: {e}", exc_info=True),MoriEP 同理。
  • getFeatureHash 对每个多模态嵌入做 D2H 全量拷贝 @ rtp_llm/cpp/multimodal_processor/MultimodalProcessor.cc:28
    • 建议:每个多模态 embedding(如 1000+ tokens × 4096 hidden dim × 2 bytes = 8MB+)都从 GPU 拷回 CPU 做逐行 hash。虽然这在请求处理初始化路径(非每步 decode)上,但对于高并发多模态场景仍有显著开销。可以考虑 (1) 只取每行前 N 字节做哈希以减少 D2H 量,或 (2) 在 GPU 侧做 hash kernel,或 (3...
  • multimodalLengths() 在每个 decode step 重复构造 std::map @ rtp_llm/cpp/normal_engine/NormalGenerateStream.cc:111
    • 建议:multimodalLengths() 每次调用都遍历 multimodal_inputs/features 向量并构造 std::map,但这些数据在整个请求生命周期内不变。建议在 GenerateInput 初始化或 multimodal 处理完成后缓存结果,避免每个 decode step 重复分配和构造。对于非多模态请求影响微小(返回空 map),但对多图请求每步都有不必要的堆分配。
  • [符号已在oss_optional_extras.toml定义-自动降级] qwen2_vl VisionAttention.head_dim 未定义导致运行时崩溃 @ rtp_llm/multimodal/multimodal_mixins/qwen2_vl/modeling_qwen2_vl.py:197
    • 建议:在 VisionAttention.init 中添加 self.head_dim = dim // num_heads(参考 VisionTransformer 中 head_dim = config.embed_dim // config.num_heads 的计算方式)。注意:此为 shard P2 issue 的跨文件确认升级,vanilla attention 路径可达时为 P1。
  • enable_layer_micro_batch 与 enable_prefill_cp 互斥未断言 @ rtp_llm/cpp/models/PyWrappedModel.cc:466
    • 建议:在 forward() 入口添加断言:RTP_LLM_CHECK(!device_props_.enable_layer_micro_batch || !device_props_.enable_prefill_cp) 或在 forwardMicroBatched 中集成 CP 支持。

P3

  • QWenV2._from_hf 改为 raise FileNotFoundError 可能影响子类默认行为 @ rtp_llm/models/qwen_v2.py:366
    • 建议:这是正确的改进(消除静默失败),但需确认所有直接/间接调用 QWenV2._from_hf 的子类都已有 config.json。当前 Qwen2Moe 和 QWenV2Audio 都独立校验了 config.json 存在性,所以没有问题。
  • EVA2CLIPImageEmbedding.data_type 属性赋值位置不规范 @ rtp_llm/models/eva2clip_vit.py:15
    • 建议:docstring 应在 self.data_type 赋值之前(紧跟 def init 下方)。当前放置位置使 data_type 赋值看起来是类级别的 docstring,容易误读。

Checklist ✅ (56 items passed)

Strengths

  • 多模态处理重构为独立 multimodal_mixins 模块,各模型 VIT 逻辑解耦清晰
  • 新增 PrefixToCandidateTokens SAX 流式解析器,避免大 JSON 一次性加载内存
  • 37 个合并冲突的解决整体质量高,保持了功能一致性
  • Beam search 新增 BF16/ROCm 支持,efficient topk 实现完整

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.