Skip to content

feat: rtp atom plugin support - #1330

Closed
lcong-amd wants to merge 6 commits into
alibaba:mainfrom
yuzho-amd:feat/rtp_atom_plugin_support_cla_fix
Closed

lcong-amd wants to merge 6 commits into
alibaba:mainfrom
yuzho-amd:feat/rtp_atom_plugin_support_cla_fix

Conversation

@lcong-amd

Copy link
Copy Markdown

Supersedes #1266 to refresh the PR branch after root-authored commits caused the CLA check to stay pending.

Summary:

  • RTP atom plugin support
  • Review fix for kv_lora_rank 128-alignment validation
  • Restores Alibaba main CI workflow files while keeping fork-specific CI out of the PR diff

Validation:

zhiqchen-amd and others added 6 commits August 11, 2026 13:02
- Add RTP_LLM_CHECK_WITH_INFO for kv_lora_rank alignment in MLAKVCacheSpec.h
- Use rtp_llm::RTPException instead of std::exception in test assertion
- Add MLAKVCacheSpecTest fixture to reset user_ft_core_dump_on_exception
- Declare static_config dependency in BUILD

Verified locally with --config=rocm, all 4 tests pass.
leader(zhiqchen) on leave, changes made per code owner LLLLKKKK review recommendation.

@LLLLKKKK LLLLKKKK left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

AI Code Review - PR #1330

Status: LGTM

Summary: P0/0 · P1/0 · P2/13 · P3/8

Reviewed: commit 3b7659e3441d · 2026-08-25 15:14 UTC+8

lgtm ready to ci

Non-blocking Suggestions

P2

  • enable_env 在两个同名入口语义分叉,EnvArgumentParser 层因未向委托 group 透传而静默失效 @ rtp_llm/server/server_args/server_args.py:229
    • 建议:将 enable_env 与 env_name 显式下传给委托调用(self._optionals.add_argument(*args, enable_env=enable_env, env_name=env_name, **kwargs))并去掉外层重复的 _register_env_mapping;或直接删除 EnvArgumentParser.add_argument 上这个当前无业务调用方的参数(YAGNI),只保留 EnvArgumentGroup 一个可信入口。若保留,请补一条单测:直接在 parser 上注册 enable_env=False 参数,断言其 dest 不出现在 get_env_mappings() 中。
  • 仅 CLI 通道对运维完全不可见——无任何告警,env→CLI 生成脚本永不产出该参数,最终报错误导根因 @ rtp_llm/server/server_args/model_group_args.py:92
    • 建议:在 parse_args 完成后对声明 enable_env=False 的 dest 做显式检查:若 EXTERNAL_MODEL_PACKAGES / RTP_LLM_EXTERNAL_MODEL_PACKAGES 存在于 os.environ 而 CLI 未传,输出 logging.warning 明确提示「该参数出于安全考虑仅支持命令行配置,环境变量已被忽略」,并在 test_environment_variables_are_ignored 中用 assertLogs 断言该告警,把「静默」变为「可观测的拒绝」。help 文案补一句该参数会在启动时 import 并执行指定包的代码。同时在 PR description 或部署文档中说明:纯 env 部署下如何在启动命令追加该参数、回滚手段(去掉该 flag 即完全不生效),并确认 load_external_model_packages 的 INFO 日志在各角色进程都会输出。
  • 采用该仅 CLI 参数会翻转 has_cmd_args 分支,使其他所有 env 参数的畸形值从 fail-fast 退化为静默取默认值 @ rtp_llm/server/server_args/server_args.py:268
    • 建议:把 :373 的 except (ValueError, TypeError): pass 与 :371 的 ArgumentTypeError 分支统一为 self.error(...),让两种解析模式对畸形 env 值都 fail-fast;若为兼容性需保留,至少补 logging.warning 记录被丢弃的 env_name 与原值。并补一个混合场景测试:sys.argv 只带 --external_model_packages,同时用 env 设 MODEL_TYPE 与一个畸形 MAX_SEQ_LEN,断言 env 项正确绑定且畸形值不被静默吞掉。
  • 仅 CLI 保证依赖类级 _env_mappings 的「缺失」而非显式拒绝 @ rtp_llm/server/server_args/server_args.py:178
    • 建议:在 EnvArgumentParser 上新增 _env_disabled_dests: Set[str],enable_env=False 时写入该集合;_register_env_mapping 遇到已在集合中的 dest 直接跳过并告警,:276 与 :350 两处 env 读取回路也跳过该集合。这样「仅 CLI」从依赖遗漏变为正向拒绝,不再依赖全局状态的洁净程度。并补一条断言 assertNotIn("external_model_packages", parser.get_env_mappings()) 的单测,对机制而非结果建立护栏。
  • ROCm 稀疏 fp8 紧凑布局的 576 字节/token 与仓内 fp8 MLA 布局不吻合,且当前无任何读写方可验证 @ rtp_llm/cpp/cache/MLAKVCacheSpec.h:48
    • 建议:合并前请补充证据:明确目标 ROCm 内核确实按 [512B fp8 nope | 64B fp8 rope] 读写且不需要 scale 区。若 rope 实际仍为 bf16,应写成 no_pe + rope * 2;若需要 scale 区应显式计算而非复用非 fp8 分支的表达式。注意 spec->block_size_bytes() 会直接成为 kv_block_stride_bytes,而 DeepSeek V3.2(deepseek_v2.py:711 设 is_sparse = True,kv_lora_rank=512)在 ROCm 构建下已可触达该分支,一旦有 kernel 沿用 656 字节假设即为越界写。若 ROCm MLA 尚未落地,建议把该分支拆出本 PR、与 ROCm sparse MLA 读写实现一并提交;若保留,请在 MLAKVCacheSpec.h:46 上方注释说明「为何不需要 scale 区、rope 为何按 1 字节存」,并在 build() 成功后按 tag 打一条 INFO 记录最终布局与 elems_per_token。
  • kv_lora_rank 128 对齐硬校验对全平台生效,未对齐配置由静默过量分配变为启动失败且无回退开关 @ rtp_llm/cpp/cache/MLAKVCacheSpec.h:52
    • 建议:请确认线上是否存在 MLA + fp8 且 kv_lora_rank % 128 != 0 的模型(含未进入本仓的外部模型)。若存在,建议改为向上取整 (no_pe + 127) / 128 * 4,保持「不小于实际需求」的分配语义而非直接拒绝;若确实要 fail-fast,请在错误信息中给出可行动的处置建议(改用 bf16 kv cache,或用 opaque spec 覆盖),并在 PR description 中说明受影响模型集为空的依据与回滚手段。
  • 外部包加载的两个生产接入点零测试覆盖,单测把 import 边界整体 mock @ rtp_llm/utils/test/import_util_test.py:8
    • 建议:补一个不依赖 mock 的用例:用临时目录造一个真实包(__init__.py 内调用 register_model(..., support_architectures=["FakeArch"])),加入 sys.path 后调用 load_external_model_packages,断言 ModelDict.get_ft_model_type_by_hf_architectures("FakeArch") 返回预期名;并对 setup_default_args 补一个用例,让包在 import 时写时序标记,断言其早于 model_type 推断。同时可参考 server_args_test.py:76 对 pd_separation_config 的写法,为 ModelArgs.external_model_packages 补一次 pickle 往返断言,保护 spawn 子进程的字段传递。
  • 新增 CLI 测试类偏离同文件已注释说明的 addCleanup 隔离约定 @ rtp_llm/server/server_args/test/server_args_test.py:539
    • 建议:对齐 ServerArgsGrammarConfigTest:在修改全局状态之前注册 self.addCleanup(_restore),并在 _setup() 内先 importlib.reload(rtp_llm.server.server_args.server_args) 以复位类级 _env_mappings。更彻底的做法是把 environ/argv 隔离提取为文件内共享 mixin 或基类,让三个测试类复用同一实现,避免继续分叉。
  • env 免疫性用例只覆盖两条注入路径中的一条,且只断言结果未验证机制 @ rtp_llm/server/server_args/test/server_args_test.py:603
    • 建议:补直接断言 self.assertNotIn("external_model_packages", parser.get_env_mappings()),对机制而非结果建立回归护栏。再补一个混合用例:sys.argv = ["prog", "--model_type", "qwen"] 同时设置 EXTERNAL_MODEL_PACKAGES,断言前者正确生效而后者仍为 None,以覆盖 :350 的回填循环;并加一个正向对照(某 enable_env=True 参数在同一路径下确实被 env 回填),避免用例因整条路径未触发而假通过。
  • 非法模块名用例只断言 SystemExit,参数改名或拼错也会假通过 @ rtp_llm/server/server_args/test/server_args_test.py:618
    • 建议:改为直接对 parse_external_model_packages 做单元断言,用 assertRaisesRegex(argparse.ArgumentTypeError, "invalid external model package path") 固定错误信息;若必须走整条 CLI,可用 contextlib.redirect_stderr 断言 stderr 含该提示并断言 exc.code == 2。建议同时参数化补齐 ../x、a/b.py、a-b、前导点等典型非法输入。
  • fp8 字节期望隐式依赖 ENABLE_FP8/USING_ROCM 构建宏,而新 cc_test 无任何平台门禁 @ rtp_llm/cpp/cache/test/BUILD:88
    • 建议:两种做法任选:一是给新 target 加 target_compatible_with 或按 config select,仅在定义了 ENABLE_FP8/USING_ROCM 的配置下启用;二是让断言不依赖编译期 dtype 大小——优先断言 block_size()(元素数,与平台无关),需要字节数时用 block_size() * getTypeSize(dtype) 推导而非硬编码 656。最低成本兜底是在断言前加 ASSERT_EQ(getTypeSize(DataType::TYPE_FP8_E4M3), 1u) 前置校验,使非 GPU 构建下失败原因自解释。建议在 cpu/arm 配置各跑一次该 target 确认。另请补齐边界:is_fp8 判定含 TYPE_FP8_E8M0(MLAKVCacheSpec.h:40,该类型 getTypeSize 恒为 1)但无用例,seq_size_per_block 恒为 1、== 0 → 1 兜底(:33)也未验证。
  • 平台分支测试复制了生产代码同一个 #if,无法发现门控写错且 ROCm 紧凑布局零执行覆盖 @ rtp_llm/cpp/cache/test/MLAKVCacheSpecTest.cc:63
    • 建议:把「是否使用紧凑布局」从预处理宏提升为可注入参数(如 SpecBuildContext 增加显式字段,或抽出纯函数 mlaElemsPerToken(dtype, no_pe, rope, use_compact)),使两条布局在任意平台都能被枚举测试,测试也不再需要复制 #if;期望值由测试独立给出的常量表提供(按 spec 类型 + dtype + sparse 三元组)。另请确认 ROCm 流水线确实会执行 //rtp_llm/cpp/cache/test:mla_kv_cache_spec_test(该包多数 target 依赖 CUDA,通配符跑法在 ROCm 上可能整包失败);若不会,可参考 rtp_llm/utils/test/BUILD:96-107 的 tags = ["rocm"] + exec_properties 约定单独挂一个 ROCm target。
  • MLA KV cache 布局改动与本 PR 声明的插件支持目标无功能耦合,且缺少设计说明 @ rtp_llm/cpp/cache/MLAKVCacheSpec.h:47
    • 建议:建议把 KV cache 布局改动拆成独立 PR,并在 description 中给出:目标 ROCm 内核与其期望的每 token 字节布局、为什么用 is_sparse 而非独立布局开关判定、fp8 对齐校验的动机(哪个配置触发了静默截断)、以及 ROCm 侧 smoke 结果。若因排期必须同 PR 提交,请至少拆成两个独立 commit(一个 plugin、一个 kv cache),便于后续 bisect 与回滚。

P3

  • create_propose_model_config 重建 ModelArgs 时漏拷 external_model_packages @ rtp_llm/model_factory.py:447
    • 建议:在 :453 之后补一行 propose_model_args.external_model_packages = model_args.external_model_packages,让新字段与其余字段一致地传播;或在该方法开头也调用一次 load_external_model_packages(model_args.external_model_packages)(对已 import 的包是幂等的)。若确认要保留顺序依赖,请在该方法 docstring 中显式写明「必须在 create_model_config 之后调用,外部模型包由后者加载」。
  • -h/--help 仍被注册为 HELP 环境变量映射,本 PR 新增的 enable_env 恰是其自然修复点 @ rtp_llm/server/server_args/server_args.py:186
    • 建议:先按上文修好 parser 层 enable_env 的透传,再在 __init__ 中改用 add_help=False 后手动以 enable_env=False 添加 help 动作(或在 _register_env_mapping 中对 argparse._HelpAction/_VersionAction 直接跳过),使控制类动作永不进入 env 映射表,随后即可移除 generate_args_from_env_clean.py:130 的特判。属顺手清理,可另开 PR。
  • 空项被静默丢弃使 None 与空列表下游语义不可区分,配置笔误无反馈 @ rtp_llm/server/server_args/model_group_args.py:7
    • 建议:若用户显式传入了该参数但解析结果为空列表,直接抛 argparse.ArgumentTypeError 提示「未解析出任何有效模块路径」,让配置笔误在启动最前端 fail-fast;这样 None(未配置)与非空列表成为唯一两种合法状态,也简化下游判断。
  • mock.patch 打在全局 importlib 模块属性上,可能把 Mock 结果写进进程级 lru_cache @ rtp_llm/utils/test/import_util_test.py:25
    • 建议:优选做法是让 load_external_model_packages 接受可注入的 importer(默认 importlib.import_module),测试传入 fake,彻底避免改写全局模块属性;若维持现状,建议在 tearDown 中显式调用 import_optional_internal_source_entrypoint.cache_clear() 与 has_internal_source.cache_clear(),并加一行注释说明该 patch 的作用域是进程级。
  • 未固定 dense fp8 下 k/v 分块字节与总字节不相等这一约束 @ rtp_llm/cpp/cache/test/MLAKVCacheSpecTest.cc:66
    • 建议:在 DenseFp8UsesNativeLayout 中显式断言当前预期(例如断言 k+v == 576 且 < block_size_bytes()),并加一行注释说明 fp8 scale 区不计入 k/v 分块、该等式仅在紧凑布局下成立。若后续 MLA fp8 会以 spec 字节进入 CP 切分路径,应作为独立的正确性问题上报。
  • 新测试重复实现了已有的 MLA spec 构造工具函数 @ rtp_llm/cpp/cache/test/MLAKVCacheSpecTest.cc:10
    • 建议:给 makeResolvedMlaSpec 增加默认为 false 的 is_sparse 参数,新测试改为依赖 :cache_config_test_utils 复用该 helper;seq_size_per_block 也能顺带参数化,便于补齐前述 seq_size_per_block > 1 覆盖。
  • 新增 C++ 测试文件未过 clang-format、缺文件末尾换行,且直接 include 了未声明的依赖头 @ rtp_llm/cpp/cache/test/MLAKVCacheSpecTest.cc:34
    • 建议:对该文件执行一次 pre-commit run clang-format --files rtp_llm/cpp/cache/test/MLAKVCacheSpecTest.cc 修正 = 对齐并补上文件末尾换行;在 test/BUILD:91 的 deps 中显式加上 //rtp_llm/cpp/utils:core_utils。顺带建议把 MLAKVCacheSpec.h:52-54 中挤在同一行的 desc.tag.c_str(), no_pe 改为每行一个实参,与同函数内既有三处检查保持一致。
  • 用例名 test_cli_space_separated_value 与其实际覆盖的输入形态不一致 @ rtp_llm/server/server_args/test/server_args_test.py:560
    • 建议:改名为能反映 argv 形态的名字(例如 test_cli_separate_token_form_parses_comma_separated_packages),与 equals 形态用例形成「书写形式」维度的对照;并把「去重 / 去空白」的断言从 equals 形态用例中拆出为独立用例,使每个用例只声明一件事。

Checklist Findings (18 fail / 48 total)

General Principles Checklist

  • [6.1] Architecture — 依赖方向:无循环依赖/跨层惊喜 → issue 新增 C++ 测试文件未过 clang-format、缺文件末尾换行,且直接 include 了未声明的依赖头
    .clang-format 配置 AlignConsecutiveAssignments: true,.pre-commit-config.yaml 对该目录启用 clang-format(仅排除 rtp_llm/cpp/cutlass/)。最长 LHS 为 StaticConfig::user_ft_core_dump_on_exception,故 :35 与 :38 的 = 前应为单空格,实际各多一个空格;:38 作为独立作用域内的单条语句本不应被补齐对齐。diff 末行显示 \ No newline at end of file。此外 :5 直接 #include "rtp_llm/cpp/utils/Exception.h",但 test/BUILD:91-96 只声明了 kv_cache_specs 与 static_config,该头属 //rtp_llm/cpp/utils:core_utils,目前靠依赖传递生效,一旦启用 layering_check 即断。
  • [6.1] Architecture — 兼容性:外部 HTTP/RPC API、持久数据、配置、环境迁移安全 → issue kv_lora_rank 128 对齐硬校验对全平台生效,未对齐配置由静默过量分配变为启动失败且无回退开关
    use_compact_fp8_layout 仅在 #if USING_ROCM(.bazelrc:353,仅 build:rocm)内可能为真,故 CUDA/CPU/ARM 下 no_pe % 128 == 0 对所有 fp8 MLA 生效,经 myAssert 抛 RTPException 导致 cache config 创建失败即服务启动失败。kv_lora_rank 来自 HF config.json(deepseek_v2.py:622-624、kimi_k25.py:115)而非仓内硬编码,模型侧可为任意值;仓内也存在 scale 分组非 128 的 fp8 MLA 变体(按 64 元素/tile 分组),说明 128 并非唯一合法分组。改前未对齐配置按 floor 除法过量分配仍可启动,改后直接拒绝。已确认仓内经本 spec 的 MLA 模型 kv_lora_rank 均为 512,DSV4 在 deepseek_v4.py:617/621 置 use_mla=False、kv_lora_rank=0 并走 Op
  • [6.1] Architecture — 可观测性:日志/指标/超时可操作、非噪声 → issue ROCm 稀疏 fp8 紧凑布局的 576 字节/token 与仓内 fp8 MLA 布局不吻合,且当前无任何读写方可验证
    MLAKVCacheSpec.h:46-58:ROCm 下 fp8 且 is_sparse 改走 no_pe + rope。getTypeSize(TYPE_FP8_E4M3) 在 ROCm 为 1(Types.cc:110-113),故 512/64 配置得 576 字节/token,等价于 rope 也按 1 字节存且完全不预留 nope 反量化 scale 区——MLAKVCacheSpec 未重写 scale_block_size_bytes(),该 scale 区原本就靠 no_pe/128*4 这一内联项承载,移除即无处存放,没有 scale 无法做 fp8 反量化。仓内 fp8 MLA 布局为 656 字节:test_dpsk32_fp8.py:70-73 的 entry_size = kv_lora_rank + 4*4 + 2*qk_rope_head_dim,flash_mla_layout_probe_test.py:31 的 ENTRY_BYTES_V32 = 512 + 16 + 128。同时 `models_p
  • [6.1] Architecture — 回滚路径:风险行为存在运维回滚手段 → issue -h/--help 仍被注册为 HELP 环境变量映射,本 PR 新增的 enable_env 恰是其自然修复点
    EnvArgumentParser.__init__ 先设 env_prefix(:181)再调 super().__init__()(:186),而 argparse 在 add_help=True 时会调用被重写的 self.add_argument("-h", "--help", ...),经上文已确认的委托链使 _env_mappings["help"] = "HELP" 被注册。纯 env 分支(:276-298)遍历 _env_mappings,若环境中存在 HELP 会拼出 --help <value>,导致服务器打印帮助并退出,表现为「启动即退出、无错误日志」。旁证:generate_args_from_env_clean.py:130 用 long_option == "--help" 硬编码绕开,说明这是已知需 workaround 的历史瑕疵,非本 PR 引入。
  • [6.1] Architecture — 状态不变量:创建/更新/失败/重试/回滚路径有效 → issue 未固定 dense fp8 下 k/v 分块字节与总字节不相等这一约束
    测试仅在 ROCm 分支断言 k_block_size_bytes() + v_block_size_bytes() == block_size_bytes()(:66-68)。dense fp8 路径下该等式并不成立:block_size_bytes() 为 656,而 k+v 仍为 512+64=576(MLAKVCacheSpec.h:55 只改了 elems_per_token,k_block_size/v_block_size 沿用 nope/rope)。KVCacheSpecBase.h:39 的 splitKVPartitionBytes 又以 RTP_LLM_CHECK_WITH_INFO 硬校验 k+v == full(已确认 MemoryLayoutStrategy.cc:247 传入的是 kv_block_stride_bytes 与其折半值,非 spec 的 k/v 字节,故当前不触发)。测试把该不变式只在一个平台上断言,读者无法判断 dense fp8 的不相等是有意设计还是遗漏。
  • [6.1] Architecture — 错误语义:fail-fast/retry/fallback/silent 行为显式 → issue 空项被静默丢弃使 None 与空列表下游语义不可区分,配置笔误无反馈
    parse_external_model_packages 对空段执行 continue(:11-12),因此 --external_model_packages ",," 返回 [] 而不报错(server_args_test.py:611 已将该行为固化为期望)。[] 非 None,会被 _apply_config_bindings(server_args.py:413 的 value is not None)真实写入 model_args,但在 import_util.py:30 的 if not package_names: return 处与默认 None 因 falsy 短路而完全等价,字段声明的 Optional[List[str]] 因此不承载任何可区分信息。运维若因模板拼接错误传入全空值,会得到与未配置完全相同的「成功启动但插件未加载」结果,随后在 model_type 阶段才失败,排查成本高。
  • [6.1] Quality — Commit 原子、message 与行为匹配 → issue MLA KV cache 布局改动与本 PR 声明的插件支持目标无功能耦合,且缺少设计说明
    本 PR 12 个改动文件中有 9 个围绕 external_model_packages 这一条主线(分支名亦标明本 PR 目标为 plugin support),而 MLAKVCacheSpec.h + MLAKVCacheSpecTest.cc + cpp/cache/test/BUILD 改的是 MLA fp8 KV cache 字节布局与启动期硬校验,与插件加载无任何调用或依赖关系(import_util.py 与 cpp/cache/ 之间无引用)。PR description 未给出该布局改动的动机、目标 ROCm 内核,以及 576 字节/token 的依据;代码中也无注释解释为何「注意力稀疏性」(is_sparse)可以决定「latent KV 的存储宽度」这两个本不相关的概念。二者混在一个 PR 中,CI 失败时无法按功能二分定位,KV cache 这一高风险改动也被插件功能的描述掩盖。
  • [6.1] Quality — Mega-PR 已拆分为独立变更 → issue MLA KV cache 布局改动与本 PR 声明的插件支持目标无功能耦合,且缺少设计说明
    本 PR 12 个改动文件中有 9 个围绕 external_model_packages 这一条主线(分支名亦标明本 PR 目标为 plugin support),而 MLAKVCacheSpec.h + MLAKVCacheSpecTest.cc + cpp/cache/test/BUILD 改的是 MLA fp8 KV cache 字节布局与启动期硬校验,与插件加载无任何调用或依赖关系(import_util.py 与 cpp/cache/ 之间无引用)。PR description 未给出该布局改动的动机、目标 ROCm 内核,以及 576 字节/token 的依据;代码中也无注释解释为何「注意力稀疏性」(is_sparse)可以决定「latent KV 的存储宽度」这两个本不相关的概念。二者混在一个 PR 中,CI 失败时无法按功能二分定位,KV cache 这一高风险改动也被插件功能的描述掩盖。
  • [6.1] Quality — PR description 说明动机与设计 → issue MLA KV cache 布局改动与本 PR 声明的插件支持目标无功能耦合,且缺少设计说明
    本 PR 12 个改动文件中有 9 个围绕 external_model_packages 这一条主线(分支名亦标明本 PR 目标为 plugin support),而 MLAKVCacheSpec.h + MLAKVCacheSpecTest.cc + cpp/cache/test/BUILD 改的是 MLA fp8 KV cache 字节布局与启动期硬校验,与插件加载无任何调用或依赖关系(import_util.py 与 cpp/cache/ 之间无引用)。PR description 未给出该布局改动的动机、目标 ROCm 内核,以及 576 字节/token 的依据;代码中也无注释解释为何「注意力稀疏性」(is_sparse)可以决定「latent KV 的存储宽度」这两个本不相关的概念。二者混在一个 PR 中,CI 失败时无法按功能二分定位,KV cache 这一高风险改动也被插件功能的描述掩盖。
  • [6.1] Quality — 逻辑变更未混入无关格式化 → issue 新增 C++ 测试文件未过 clang-format、缺文件末尾换行,且直接 include 了未声明的依赖头
    .clang-format 配置 AlignConsecutiveAssignments: true,.pre-commit-config.yaml 对该目录启用 clang-format(仅排除 rtp_llm/cpp/cutlass/)。最长 LHS 为 StaticConfig::user_ft_core_dump_on_exception,故 :35 与 :38 的 = 前应为单空格,实际各多一个空格;:38 作为独立作用域内的单条语句本不应被补齐对齐。diff 末行显示 \ No newline at end of file。此外 :5 直接 #include "rtp_llm/cpp/utils/Exception.h",但 test/BUILD:91-96 只声明了 kv_cache_specs 与 static_config,该头属 //rtp_llm/cpp/utils:core_utils,目前靠依赖传递生效,一旦启用 layering_check 即断。
  • [6.1] Software Engineering — DRY:重复非平凡逻辑被抽取或显式复用 → issue 新测试重复实现了已有的 MLA spec 构造工具函数
    cpp/cache/test/CacheConfigTestUtils.h:116 已有 makeResolvedMlaSpec(dtype, kv_lora_rank, rope_head_dim, seq_size_per_block, tag),逻辑与新增的 makeMlaSpec 几乎一致(同样填 AttentionConfigs、KVCacheSpecDesc、SpecBuildContext 后 dynamic_pointer_cast),差别仅在新函数额外设置 attn.is_sparse 且把 rope_head_dim/seq_size_per_block 硬编码为 64/1。该 helper 已通过 visibility = ["//visibility:public"] 的 cache_config_test_utils cc_library 对外暴露(test/BUILD:50-61),本次却另起一份,后续 SpecBuildContext 字段变更需改两处。
  • [6.1] Tests — 分布式/跨平台变更有对应覆盖 → issue 平台分支测试复制了生产代码同一个 #if,无法发现门控写错且 ROCm 紧凑布局零执行覆盖
    MLAKVCacheSpecTest.cc:63-72 用与生产代码 MLAKVCacheSpec.h:47 完全相同的 #if USING_ROCM 复制平台判断,因此测试只复述「被编译进来的那一个分支」的算术结果;若平台门控条件本身写错,实现与测试会同步走错分支,测试永远无法暴露。在默认 CUDA CI 下 ROCm 分支既不编译也不执行,本次新增的紧凑布局(576 字节)实际零执行覆盖,#else 期望值退化为与 DenseFp8UsesNativeLayout 完全相同的 656。边界组合也缺:sparse + fp8 + 未对齐 rank(ROCm 应放行、CUDA 应抛错)无用例。
  • [6.1] Tests — 新逻辑有聚焦单测 + 相关集成/smoke 测试 → issue 用例名 test_cli_space_separated_value 与其实际覆盖的输入形态不一致
    该用例名为 space separated,但传入值 "atom.plugin.rtpllm.models,plugin.extra" 是逗号分隔,且 parse_external_model_packages(model_group_args.py:9)只按 , 切分——空格分隔的 "a b" 会被 isidentifier() 判定为非法并拒绝。它真正区别于 test_cli_equals_value_deduplicates_packages 的地方是「--flag value 独立 argv token 形态」而非 --flag=value 形态。名称误导会让后续维护者误以为存在空格分隔语法,也掩盖了这两个用例实际在校验的 argv 形态差异。
  • [6.1] Tests — 边界 case 覆盖(空、单元素、最大值) → issue 未固定 dense fp8 下 k/v 分块字节与总字节不相等这一约束
    测试仅在 ROCm 分支断言 k_block_size_bytes() + v_block_size_bytes() == block_size_bytes()(:66-68)。dense fp8 路径下该等式并不成立:block_size_bytes() 为 656,而 k+v 仍为 512+64=576(MLAKVCacheSpec.h:55 只改了 elems_per_token,k_block_size/v_block_size 沿用 nope/rope)。KVCacheSpecBase.h:39 的 splitKVPartitionBytes 又以 RTP_LLM_CHECK_WITH_INFO 硬校验 k+v == full(已确认 MemoryLayoutStrategy.cc:247 传入的是 kv_block_stride_bytes 与其折半值,非 spec 的 k/v 字节,故当前不触发)。测试把该不变式只在一个平台上断言,读者无法判断 dense fp8 的不相等是有意设计还是遗漏。

RTP-LLM Checklist

  • [I] 代码质量 — 同一功能用统一工具函数 → issue 新测试重复实现了已有的 MLA spec 构造工具函数
    cpp/cache/test/CacheConfigTestUtils.h:116 已有 makeResolvedMlaSpec(dtype, kv_lora_rank, rope_head_dim, seq_size_per_block, tag),逻辑与新增的 makeMlaSpec 几乎一致(同样填 AttentionConfigs、KVCacheSpecDesc、SpecBuildContext 后 dynamic_pointer_cast),差别仅在新函数额外设置 attn.is_sparse 且把 rope_head_dim/seq_size_per_block 硬编码为 64/1。该 helper 已通过 visibility = ["//visibility:public"] 的 cache_config_test_utils cc_library 对外暴露(test/BUILD:50-61),本次却另起一份,后续 SpecBuildContext 字段变更需改两处。

Python Static-First Checklist

  • [P.G] 测试规范 — mock.patch target 是使用处而非定义处 → issue mock.patch 打在全局 importlib 模块属性上,可能把 Mock 结果写进进程级 lru_cache
    import_util.py:1 是 import importlib 后在 :37 直接调用 importlib.import_module,因此 patch target rtp_llm.utils.import_util.importlib.import_module 实际改写的是全局 importlib 模块属性,而非使用处的局部名字。同一模块内 import_optional_internal_source_entrypoint(@lru_cache(maxsize=None),:48-67)与 LazyModuleRegistry.import_module 都调用同一函数:若 patch 窗口内被间接触发,前者会拿到 Mock 并把 True 永久缓存进本进程,污染同一 py_test 内后续测试。当前文件无触发路径,属潜在风险。
  • [P.G] 测试规范 — mock/fake/stub 不得替代本次声称覆盖的生产边界 → issue 外部包加载的两个生产接入点零测试覆盖,单测把 import 边界整体 mock
    全仓 load_external_model_packages 仅两个生产调用点:server_config_setup.py:398(在 _infer_model_type 之前)与 model_factory.py:342(在 get_model_cls 之前),两者均无测试。新增单测三个用例全部 mock.patch(...importlib.import_module),只断言调用次序与异常包装,从未真实 import 过一个包,也未断言「import 后模型确实注册成功」。而该特性的功能本质正是「靠 import 副作用完成 register_model 并写入 _hf_architecture_2_ft」以及「加载必须早于模型类型解析」,这两点当前零回归保护。CLI 侧用例也无法补位:setup_args()(server_args.py:531)并不调用 setup_default_args,故不触发加载。若有人把加载点移到类型推断之后,全部测试仍绿。
  • [P.G] 测试规范 — pytest.raises 带 match 参数 → issue 非法模块名用例只断言 SystemExit,参数改名或拼错也会假通过
    test_invalid_module_path_is_rejected 只有 with self.assertRaises(SystemExit)。argparse 对「未识别的参数」「缺少取值」等任何错误都以 SystemExit(2) 退出,因此该用例无法区分失败原因:一旦 --external_model_packages 被改名或拼错,用例依然通过,而 model_group_args.py:13 中 part.isidentifier() 这条真正要固定的安全校验契约就失去保护——这正是阻断路径穿越写法的唯一防线。

Strengths

  • 安全边界选择正确且工具链自洽:该特性本质是「按名字 import 任意模块并执行其 import-time 代码」,等价于任意代码执行;enable_env=False 把配置面从环境变量(易被间接注入的弱信任通道)收敛为部署方可控的命令行。generate_args_from_env_clean.py:33 按 action.dest in env_mappings 过滤,也不会把该 flag 塞回来,不存在「禁用 env 但工具链绕过」的漏洞。
  • 输入校验下沉到 argparse type 层且足够严格:parse_external_model_packages(model_group_args.py:7)对每个点分段做 isidentifier(),天然拒绝相对导入、路径分隔符与连字符,同时完成去空白与保序去重,脏值不进入运行期。
  • 错误语义显式且 fail-fast:非法路径抛 ArgumentTypeError 由 argparse 收敛为 SystemExit(2);导入失败在 import_util.py:39 以 raise RuntimeError(...) from error 中止启动并附带 sys.path,未静默降级为二段式的「模型类型未注册」。
  • 加载时机与注册语义吻合:server_config_setup.py:398 早于 _infer_model_type(:400-403),使外部包经 register_model(support_architectures=) 写入 _hf_architecture_2_ft 的架构名能参与自动推断,无需强制显式传 --model_type。
  • 跨进程传播完整:model_factory.py:342 在 create_model_config 内统一重新加载,覆盖 spawn 出的 backend / frontend / vit / dash_sc 等入口,不依赖父进程 sys.modules;新字段为纯 List[str],随配置对象 pickle 跨 spawn 边界不引入对外部包类的反序列化依赖。
  • 向后兼容零风险:enable_env 默认 True,约两百个既有参数注册与 env 行为完全不变;ModelArgs 仅追加 slot 且同步维护 __init__ 默认值(model_args.py:30/:60),属加法式局部扩展。
  • MLAKVCacheSpec.h:52 把此前隐藏在 no_pe / 128 * 4 整数除法里的「必须按 128 对齐」隐式前提显式化——改前 rank 不足 128 会把 scale 空间静默算成 0 导致 KV block 少分配,现改为启动期 fail-fast,错误信息带 tag 与实际值。
  • 新增 MLAKVCacheSpecTest 的 SetUp/TearDown(:33-39)正确保存并恢复 StaticConfig::user_ft_core_dump_on_exception,这是 EXPECT_THROW 生效的必要前提(该开关为 true 时 myAssert 直接 abort),与同目录既有测试约定一致且不污染全局状态;Bf16LayoutDoesNotDependOnSparseMode 锁定了「非 fp8 路径不受 is_sparse 影响」这一不变量。
  • 新增 mla_kv_cache_spec_test 只依赖 kv_cache_specs + static_config + torch_deps(),未复用带 CUDA 依赖的 test_deps 也未占用 GPU,与同包纯布局测试一致。
  • test_import_failure_is_fail_fast_and_keeps_context(import_util_test.py:28-36)同时断言异常类型、信息正则、__cause__ 与 assert_called_once_with,把「首个包失败即中断、不吞异常、保留原始异常」三个契约一次钉住。

action = self._optionals.add_argument(*args, **kwargs)

self._register_env_mapping(action, args, env_name)
if enable_env:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] enable_env 在两个同名入口语义分叉,EnvArgumentParser 层因未向委托 group 透传而静默失效

argparse.ArgumentParser.__init__ 通过 self.add_argument_group(...) 创建 _positionals/_optionals,而该方法被重写(:204-211)返回 EnvArgumentGroup,故 :225/:227 的 self._optionals.add_argument(*args, **kwargs) 进入 EnvArgumentGroup.add_argument,其 enable_env 取默认 True 并在 :169-170 无条件注册;enable_env/env_name 是外层 keyword-only 形参、不在 **kwargs 中,不会下传。因此 :229 的 if enable_env: 只是重复写同一映射,无法移除已注册项。旁证:-h/--help 经 parser 层注册后确实进入 _env_mappings,所以 generate_args_from_env_clean.py:130 才需硬编码过滤 --help...

建议: 将 enable_env 与 env_name 显式下传给委托调用(self._optionals.add_argument(*args, enable_env=enable_env, env_name=env_name, **kwargs))并去掉外层重复的 _register_env_mapping;或直接删除 EnvArgumentParser.add_argument 上这个当前无业务调用方的参数(YAGNI),只保留 EnvArgumentGroup 一个可信入口。若保留,请补一条单测:直接在 parser 上注册 enable_env=False 参数,断言其 dest 不出现在 get_env_mappings() 中。

)
model_group.add_argument(
"--external_model_packages",
enable_env=False,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] 仅 CLI 通道对运维完全不可见——无任何告警,env→CLI 生成脚本永不产出该参数,最终报错误导根因

enable_env=False 使该 dest 永不进入 _env_mappings:parse_args 两条 env 回填分支(server_args.py:276、:350)都读不到它,:385 的 [EnvMapping] 调试日志也排除它,generate_args_from_env_clean.py:33 的 action.dest in env_mappings 过滤同样使 env→CLI 生成脚本永不输出该 flag。同组其余参数全部带 env_name,server_config_setup.py:406 的报错文案本身还在引导用户使用 MODEL_TYPE 环境变量。运维按此惯例设置 EXTERNAL_MODEL_PACKAGES 时值被无声丢弃,最终暴露为 model_type is not set and could not be inferred,与真实根因完全脱节。server_args_test.py:603 还把这种静默固化为断言;help 文案只写「仅支持命令行配置」,未说明动机与信任边界。

建议: 在 parse_args 完成后对声明 enable_env=False 的 dest 做显式检查:若 EXTERNAL_MODEL_PACKAGES / RTP_LLM_EXTERNAL_MODEL_PACKAGES 存在于 os.environ 而 CLI 未传,输出 logging.warning 明确提示「该参数出于安全考虑仅支持命令行配置,环境变量已被忽略」,并在 test_environment_variables_are_ignored 中用 assertLogs 断言该告警,把「静默」变为「可观测的拒绝」。help 文案补一句该参数会在启动时 import 并执行指定包的代码。同时在 PR description 或部署文档中说明:纯 env 部署下如何在启动命令追加该参数、回滚手段(去掉该 flag 即完全不生效),并确认 load_external_model_packages 的 INFO 日志在各角色进程都会输出。

self._register_env_mapping(action, args, env_name)
return action

def _register_env_mapping(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

📍 实际位置 rtp_llm/server/server_args/server_args.py:268(不在 diff 展示范围内,就近挂载)

[P2] 采用该仅 CLI 参数会翻转 has_cmd_args 分支,使其他所有 env 参数的畸形值从 fail-fast 退化为静默取默认值

has_cmd_args = args is not None or (len(sys.argv) > 1) 把解析分成两种模式,两者对畸形 env 值并不等价:纯 env 分支(:272-298)把 env 拼成 argv 交给 argparse,int("abc") 失败即经 self.error → SystemExit(2);有 CLI 参数的回填分支虽对 ArgumentTypeError 调 self.error(:371-372),但紧随的 except (ValueError, TypeError): pass(:373-375)会静默丢弃并保留默认值。由于本参数只能从命令行传入,原本完全无 argv 的纯 env 部署一旦启用该特性就被迫引入首个 CLI 参数并整体切到回填分支,于是 MAX_SEQ_LEN=abc(model_group_args.py:105 为 type=int)这类配置从「启动即失败」变为「静默取默认值继续跑」。该分支不对称虽为既有代码,但本 PR 新增了让生产部署普遍触达它的理由。

建议: 把 :373 的 except (ValueError, TypeError): pass 与 :371 的 ArgumentTypeError 分支统一为 self.error(...),让两种解析模式对畸形 env 值都 fail-fast;若为兼容性需保留,至少补 logging.warning 记录被丢弃的 env_name 与原值。并补一个混合场景测试:sys.argv 只带 --external_model_packages,同时用 env 设 MODEL_TYPE 与一个畸形 MAX_SEQ_LEN,断言 env 项正确绑定且畸形值不被静默吞掉。

self._parser._register_env_mapping(action, args, env_name)
return action

def __getattr__(self, name):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

📍 实际位置 rtp_llm/server/server_args/server_args.py:178(不在 diff 展示范围内,就近挂载)

[P2] 仅 CLI 保证依赖类级 _env_mappings 的「缺失」而非显式拒绝

_env_mappings 是 EnvArgumentParser 的类属性(:178),由 _register_env_mapping 以 EnvArgumentParser._env_mappings[action.dest] = ...(:257)写入,进程内所有实例共享且从不清空;get_env_mappings 返回该类字典的拷贝。enable_env=False 只是「不写入」,未记录任何拒绝意图。因此只要任何代码路径以相同 dest 注册一次带 env 的参数(新增别名、或某次重构误删 enable_env=False),这条刻意收敛的安全边界就会静默恢复,且现有测试断言的是结果(值为 None)而非机制(dest 不在映射表中),无法拦住这种回归。新测试类 _setup(:550-553)也未像同文件 ServerArgsGrammarConfigTest(:646-650)那样 importlib.reload,其「env 被忽略」断言实际依赖全局字典恰好未被污染。

建议: 在 EnvArgumentParser 上新增 _env_disabled_dests: Set[str],enable_env=False 时写入该集合;_register_env_mapping 遇到已在集合中的 dest 直接跳过并告警,:276 与 :350 两处 env 读取回路也跳过该集合。这样「仅 CLI」从依赖遗漏变为正向拒绝,不再依赖全局状态的洁净程度。并补一条断言 assertNotIn("external_model_packages", parser.get_env_mappings()) 的单测,对机制而非结果建立护栏。


bool use_compact_fp8_layout = false;
#if USING_ROCM
use_compact_fp8_layout = is_fp8 && attn.is_sparse;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] ROCm 稀疏 fp8 紧凑布局的 576 字节/token 与仓内 fp8 MLA 布局不吻合,且当前无任何读写方可验证

MLAKVCacheSpec.h:46-58:ROCm 下 fp8 且 is_sparse 改走 no_pe + rope。getTypeSize(TYPE_FP8_E4M3) 在 ROCm 为 1(Types.cc:110-113),故 512/64 配置得 576 字节/token,等价于 rope 也按 1 字节存且完全不预留 nope 反量化 scale 区——MLAKVCacheSpec 未重写 scale_block_size_bytes(),该 scale 区原本就靠 no_pe/128*4 这一内联项承载,移除即无处存放,没有 scale 无法做 fp8 反量化。仓内 fp8 MLA 布局为 656 字节:test_dpsk32_fp8.py:70-73 的 entry_size = kv_lora_rank + 4*4 + 2*qk_rope_head_dim,flash_mla_layout_probe_test.py:31 的 ENTRY_BYTES_V32 = 512 + 16 + 128。同时 `model...

建议: 合并前请补充证据:明确目标 ROCm 内核确实按 [512B fp8 nope | 64B fp8 rope] 读写且不需要 scale 区。若 rope 实际仍为 bf16,应写成 no_pe + rope * 2;若需要 scale 区应显式计算而非复用非 fp8 分支的表达式。注意 spec->block_size_bytes() 会直接成为 kv_block_stride_bytes,而 DeepSeek V3.2(deepseek_v2.py:711 设 is_sparse = True,kv_lora_rank=512)在 ROCm 构建下已可触达该分支,一旦有 kernel 沿用 656 字节假设即为越界写。若 ROCm MLA 尚未落地,建议把该分支拆出本 PR、与 ROCm sparse MLA 读写实现一并提交;若保留,请在 MLAKVCacheSpec.h:46 上方注释说明「为何不需要 scale 区、rope 为何按 1 字节存」,并在 build() 成功后按 tag 打一条 INFO 记录最终布局与 elems_per_token。

Checklist: [6.1] 可观测性:日志/指标/超时可操作、非噪声

import_module.assert_not_called()

@mock.patch(
"rtp_llm.utils.import_util.importlib.import_module",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P3] mock.patch 打在全局 importlib 模块属性上,可能把 Mock 结果写进进程级 lru_cache

import_util.py:1 是 import importlib 后在 :37 直接调用 importlib.import_module,因此 patch target rtp_llm.utils.import_util.importlib.import_module 实际改写的是全局 importlib 模块属性,而非使用处的局部名字。同一模块内 import_optional_internal_source_entrypoint(@lru_cache(maxsize=None),:48-67)与 LazyModuleRegistry.import_module 都调用同一函数:若 patch 窗口内被间接触发,前者会拿到 Mock 并把 True 永久缓存进本进程,污染同一 py_test 内后续测试。当前文件无触发路径,属潜在风险。

建议: 优选做法是让 load_external_model_packages 接受可注入的 importer(默认 importlib.import_module),测试传入 fake,彻底避免改写全局模块属性;若维持现状,建议在 tearDown 中显式调用 import_optional_internal_source_entrypoint.cache_clear() 与 has_internal_source.cache_clear(),并加一行注释说明该 patch 的作用域是进程级。

Checklist: [P.G] mock.patch target 是使用处而非定义处

#if USING_ROCM
constexpr size_t expected_bytes = 512 + 64;
EXPECT_EQ(spec->block_size_bytes(), expected_bytes);
EXPECT_EQ(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P3] 未固定 dense fp8 下 k/v 分块字节与总字节不相等这一约束

测试仅在 ROCm 分支断言 k_block_size_bytes() + v_block_size_bytes() == block_size_bytes()(:66-68)。dense fp8 路径下该等式并不成立:block_size_bytes() 为 656,而 k+v 仍为 512+64=576(MLAKVCacheSpec.h:55 只改了 elems_per_token,k_block_size/v_block_size 沿用 nope/rope)。KVCacheSpecBase.h:39 的 splitKVPartitionBytes 又以 RTP_LLM_CHECK_WITH_INFO 硬校验 k+v == full(已确认 MemoryLayoutStrategy.cc:247 传入的是 kv_block_stride_bytes 与其折半值,非 spec 的 k/v 字节,故当前不触发)。测试把该不变式只在一个平台上断言,读者无法判断 dense fp8 的不相等是有意设计还是遗漏。

建议: 在 DenseFp8UsesNativeLayout 中显式断言当前预期(例如断言 k+v == 576 且 < block_size_bytes()),并加一行注释说明 fp8 scale 区不计入 k/v 分块、该等式仅在紧凑布局下成立。若后续 MLA fp8 会以 spec 字节进入 CP 切分路径,应作为独立的正确性问题上报。

Checklist: [6.1] 状态不变量:创建/更新/失败/重试/回滚路径有效;[6.1] 边界 case 覆盖(空、单元素、最大值)

namespace rtp_llm::test {
namespace {

std::shared_ptr<MLAKVCacheSpec>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P3] 新测试重复实现了已有的 MLA spec 构造工具函数

cpp/cache/test/CacheConfigTestUtils.h:116 已有 makeResolvedMlaSpec(dtype, kv_lora_rank, rope_head_dim, seq_size_per_block, tag),逻辑与新增的 makeMlaSpec 几乎一致(同样填 AttentionConfigs、KVCacheSpecDesc、SpecBuildContext 后 dynamic_pointer_cast),差别仅在新函数额外设置 attn.is_sparse 且把 rope_head_dim/seq_size_per_block 硬编码为 64/1。该 helper 已通过 visibility = ["//visibility:public"] 的 cache_config_test_utils cc_library 对外暴露(test/BUILD:50-61),本次却另起一份,后续 SpecBuildContext 字段变更需改两处。

建议: 给 makeResolvedMlaSpec 增加默认为 false 的 is_sparse 参数,新测试改为依赖 :cache_config_test_utils 复用该 helper;seq_size_per_block 也能顺带参数化,便于补齐前述 seq_size_per_block > 1 覆盖。

Checklist: [6.1] DRY:重复非平凡逻辑被抽取或显式复用;[I] 同一功能用统一工具函数

class MLAKVCacheSpecTest: public ::testing::Test {
protected:
void SetUp() override {
old_core_dump_on_exception_ = StaticConfig::user_ft_core_dump_on_exception;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P3] 新增 C++ 测试文件未过 clang-format、缺文件末尾换行,且直接 include 了未声明的依赖头

.clang-format 配置 AlignConsecutiveAssignments: true,.pre-commit-config.yaml 对该目录启用 clang-format(仅排除 rtp_llm/cpp/cutlass/)。最长 LHS 为 StaticConfig::user_ft_core_dump_on_exception,故 :35 与 :38 的 = 前应为单空格,实际各多一个空格;:38 作为独立作用域内的单条语句本不应被补齐对齐。diff 末行显示 \ No newline at end of file。此外 :5 直接 #include "rtp_llm/cpp/utils/Exception.h",但 test/BUILD:91-96 只声明了 kv_cache_specs 与 static_config,该头属 //rtp_llm/cpp/utils:core_utils,目前靠依赖传递生效,一旦启用 layering_check 即断。

建议: 对该文件执行一次 pre-commit run clang-format --files rtp_llm/cpp/cache/test/MLAKVCacheSpecTest.cc 修正 = 对齐并补上文件末尾换行;在 test/BUILD:91 的 deps 中显式加上 //rtp_llm/cpp/utils:core_utils。顺带建议把 MLAKVCacheSpec.h:52-54 中挤在同一行的 desc.tag.c_str(), no_pe 改为每行一个实参,与同函数内既有三处检查保持一致。

Checklist: [6.1] 依赖方向:无循环依赖/跨层惊喜;[6.1] 逻辑变更未混入无关格式化


self.assertIsNone(py_env_configs.model_args.external_model_packages)

def test_cli_space_separated_value(self):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P3] 用例名 test_cli_space_separated_value 与其实际覆盖的输入形态不一致

该用例名为 space separated,但传入值 "atom.plugin.rtpllm.models,plugin.extra" 是逗号分隔,且 parse_external_model_packages(model_group_args.py:9)只按 , 切分——空格分隔的 "a b" 会被 isidentifier() 判定为非法并拒绝。它真正区别于 test_cli_equals_value_deduplicates_packages 的地方是「--flag value 独立 argv token 形态」而非 --flag=value 形态。名称误导会让后续维护者误以为存在空格分隔语法,也掩盖了这两个用例实际在校验的 argv 形态差异。

建议: 改名为能反映 argv 形态的名字(例如 test_cli_separate_token_form_parses_comma_separated_packages),与 equals 形态用例形成「书写形式」维度的对照;并把「去重 / 去空白」的断言从 equals 形态用例中拆出为独立用例,使每个用例只声明一件事。

Checklist: [6.1] 新逻辑有聚焦单测 + 相关集成/smoke 测试

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.

5 participants