Prhub

#45557 [Bugfix][Rust] Sync EngineCoreReadyResponse with the Python dataclass

原始 PR 作者 wseaton 合并时间 2026-06-15 14:49 文件变更 4 提交数 2 评论 1 代码增减 +54 / -1

执行摘要

同步 Rust 与 Python 的 EngineCoreReadyResponse 字段定义

PR 描述中指出:“The Rust EngineCoreReadyResponse had fallen three fields behind the Python dataclass: block_size (required) plus the optional kv_cache_size_tokens and kv_cache_max_concurrency. Registration is a field-keyed map, so a Rust engine encoding the response omits block_size and the Python frontend rejects it on decode.” 该问题导致 vllm-mock-engine 无法与 Python 前端完成注册。

建议团队在涉及跨语言协议定义时,借鉴本 PR 中 Python→Rust 双向键集合断言的测试方法,防止字段版本漂移。值得精读 python_compat.rs 的测试夹具设计。

讨论亮点

PR 仅有一条 Mergify 自动评论提醒 pre-commit 格式化失败,随后 BugenZhao 提交了格式化修正 commit 并批准。此外无其他技术讨论。

实现拆解

  1. Rust 结构体补全:在 rust/src/engine-core-client/src/protocol/handshake.rs 的 EngineCoreReadyResponse 结构体中增加 block_size: u64(必需)、kv_cache_size_tokens: Option<u64> 和 kv_cache_max_concurrency: Option<f64>(可选),并更新文档注释中的 Python 源码链接。
  2. Mock 引擎默认值:在 rust/src/engine-core-client/src/mock_engine.rs 中添加常量 DEFAULT_MOCK_BLOCK_SIZE = 16,并在 default_ready_response() 函数中为新字段赋默认值(可选字段赋 None)。
  3. Python 测试夹具:新建 rust/src/engine-core-client/src/tests/python_compat.py,用 msgspec 定义与 Python 生产逻辑一致的 EngineCoreReadyResponse dataclass,编码并打印十六进制输出。
  4. Rust 集成测试增强:在 rust/src/engine-core-client/src/tests/client.rs 的 python_msgpack_fixtures_match_rust_encoding 测试中新增一步:解码 Python 输出的 ready_response 键集合,与 Rust default_ready_response() 编码后的键集合做全等断言,若双方字段不匹配则测试失败。
文件 模块 状态 重要度
rust/src/engine-core-client/src/protocol/handshake.rs 协议层 modified 6.17
rust/src/engine-core-client/src/mock_engine.rs 模拟引擎 modified 5.34
rust/src/engine-core-client/src/tests/python_compat.py 兼容测试 modified 5.96
rust/src/engine-core-client/src/tests/client.rs 客户端测试 modified 5.07

关键符号

EngineCoreReadyResponse::new (struct definition) default_ready_response python_msgpack_fixtures_match_rust_encoding

关键源码片段

rust/src/engine-core-client/src/protocol/handshake.rs core-logic

核心修复文件,在 `EngineCoreReadyResponse` 结构体中新增三个字段,确保 Rust 序列化格式与 Python 一致。

/// Post-initialization configuration sent from each engine on the input socket
/// registration message, after the handshake completes.
///
/// Contains values that may differ from the original config (e.g.
/// `max_model_len` after KV cache auto-fitting, `num_gpu_blocks` after
/// profiling).
///
/// Original Python definition:
/// <https://github.com/vllm-project/vllm/blob/c9340e6f35/vllm/v1/engine/__init__.py#L68-L80>
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EngineCoreReadyResponse {
    /// Engine-reported maximum model context length (auto-fitted after
    /// KV cache profiling and may differ from the original config value).
    pub max_model_len: u64,
    /// Number of GPU blocks available for KV cache on this engine.
    pub num_gpu_blocks: u64,
    /// KV cache block size (tokens per block). 此前 Rust 遗漏该必需字段,
    /// 导致 Python 前端解码时抛出 `ValidationError`。
    pub block_size: u64,
    /// DP coordinator stats publish address, if applicable.
    pub dp_stats_address: Option<String>,
    /// Effective model dtype after Python vLLM resolves `--dtype`.
    pub dtype: ModelDtype,
    /// Python vLLM version reported by the engine process.
    pub vllm_version: String,
    /// Total KV cache capacity in tokens, if reported. 新增可选字段,用于
    /// 调度器感知缓存容量。
    pub kv_cache_size_tokens: Option<u64>,
    /// Maximum achievable request concurrency given the KV cache, if reported.
    /// 新增可选字段,用于前端判断并发度。
    pub kv_cache_max_concurrency: Option<f64>,
}
rust/src/engine-core-client/src/tests/python_compat.py test-coverage

新增的 Python 测试夹具,定义 `EngineCoreReadyResponse` dataclass 并输出其 msgpack 十六进制,供 Rust 测试提取键集合进行双向兼容性断言。

from dataclasses import dataclass
# 其余导入略 ...
​
@dataclass
class EngineCoreReadyResponse:
    max_model_len: int
    num_gpu_blocks: int
    block_size: int # 必需字段,Rust 侧之前遗漏导致崩溃
    dp_stats_address: str | None
    dtype: str
    vllm_version: str
    kv_cache_size_tokens: int | None = None # 可选字段,同步添加
    kv_cache_max_concurrency: float | None = None
​
# 构造一个典型实例,用于与 Rust 编码结果对比
ready_response = EngineCoreReadyResponse(
    max_model_len=32768,
    num_gpu_blocks=1000,
    block_size=16,
    dp_stats_address=None,
    dtype="float32",
    vllm_version="0.0.0",
)
​
# 输出 hex 供 Rust 测试解析
print(msgspec.msgpack.encode(ready_response).hex())

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

此修改针对远程 Rust 引擎注册场景,对纯 Python 前端无影响。风险较低,但仍需关注:

  • 若 Python 侧再次新增字段而未同步到 Rust,新增的测试会立即失败,这正是期望的防御效果。
  • 新增两个 Option 字段对下游消费者无破坏性,但若消费者期望这些字段存在而收到 None 可能需调整逻辑。

影响范围:主要影响使用 Rust 引擎客户端(如 vllm-mock-engine)与 Python 前端通过 Data Parallel 协议通信的场景。修复后远程引擎可成功注册,API 服务器能正常启动。影响程度:中等,属于阻塞性 bug 修复。

跨语言序列化一致性 协议漂移(已防御)

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论