Prhub

#49491 [Rust Frontend][gRPC] Add server and model discovery

原始 PR 作者 connorcarpenter15 合并时间 2026-07-28 00:53 文件变更 18 提交数 8 评论 4 代码增减 +615 / -269

执行摘要

Rust gRPC 前端新增服务与模型发现 API

为 Rust gRPC 前端添加服务发现能力,使客户端(如负载均衡器、监控组件)能够通过控制 API 获取服务器运行时信息和模型详情,满足生产环境对 vLLM 实例自动化管理和可见性的需求。

该 PR 是 Rust 前端 gRPC 架构演进的重要一步,值得负责部署和可观测性的工程师精读。特别应关注以下设计决策:

  • 服务拆分与重命名的时机(在客户采用前完成 breaking change);
  • 握手协议字段的扩展方式,包括如何在不破坏兼容性的前提下添加新字段;
  • 字段编号 gap 的处理,体现了 protobuf 演进的经验。
讨论亮点
  1. 提取 ready response 构建逻辑:njhill 建议将 EngineCoreReadyResponse 的构建抽取为独立方法,以提升代码组织和可测试性。作者接受并实现,在后续提交中引入 _make_ready_response。

  2. protobuf 字段编号 gap 处理:njhill 注意到 ParallelismInfo 和 ModelInfo 中存在字段编号跳变。作者回应:ParallelismInfo 因实际不需要某字段而主动删除并重新编号以消除 gap;ModelInfo 中 supports_lora 字段被临时移除但计划将来恢复,故保留 gap 作为占位。

实现拆解

  1. 拆分 gRPC 服务模块:将 grpc/mod.rs 中的 Generate 和 Control 实现分别独立到 inference.rs 和 control.rs;同时将 protobuf 服务从 vllm.Generate 重命名为 vllm.Inference,并定义新的 vllm.Control 服务,生成对应的 Rust 客户端和服务端代码。mod.rs 精简为只负责重导出和子模块声明。

  2. 扩展 Python–Rust 握手协议:在 EngineCoreProc 中提取 _make_ready_response 方法,构造 EngineCoreReadyResponse。新增字段包括 data_parallel_size、tensor_parallel_size、pipeline_parallel_size、decode_context_parallel_size、instance_id、max_num_seqs、max_num_batched_tokens 等。Rust 端 client.rs 添加 ready_response() 方法以访问这些值。

  3. 实现 Control 服务:在 control.rs 中实现 get_server_info 和 get_model_info。前者从 AppState 和 EngineCoreClient 获取引擎版本、实例 ID、并行度(parallelism_info)、最大模型长度、KV 块大小和总量、最大运行请求数和批处理 token 数;后者从 ChatLlm 获取模型 ID、服务名称、别名,并查询多模态支持、推理和工具调用解析器名称。

  4. 扩充 ChatLlm 能力:在 chat/src/lib.rs 中添加 supports_multimodal、tool_call_parser_name、reasoning_parser_name 三个公有方法。supports_multimodal 通过检查 processor.backend.multimodal_model_info() 是否存在来判断;解析器名称方法根据当前配置的 ParserSelection 返回全局注册名称或显式名称。

  5. 更新测试与配置:更新 tests.rs 为新的服务类型(InferenceClient 替代 GenerateClient),并添加两个控制服务集成测试:control_reports_server_and_model_info 验证单引擎下返回正确信息;control_aggregates_multi_engine_capacity 验证多引擎场景下总 KV 块数被正确聚合。同时引入 mock_engine 模块中的默认常量和 spawn_mock_engine_task_with_ready 辅助函数。

文件 模块 状态 重要度
rust/src/server/src/grpc/control.rs 控制服务 added 8.86
rust/src/server/src/grpc/inference.rs 推理服务 added 9.03
rust/src/server/src/grpc/mod.rs 服务入口 modified 8.82
rust/src/server/src/grpc/tests.rs 服务测试 modified 8.22
rust/src/chat/src/lib.rs 会话层 modified 7.61
vllm/v1/engine/core.py 引擎核心 modified 7.22
rust/src/engine-core-client/src/client.rs 引擎客户端 modified 6.31

关键符号

ControlServiceImpl::get_server_info ControlServiceImpl::get_model_info ControlServiceImpl::parallelism_info ControlServiceImpl::ready InferenceServiceImpl::generate InferenceServiceImpl::generate_stream ChatLlm::supports_multimodal ChatLlm::tool_call_parser_name ChatLlm::reasoning_parser_name EngineCoreProc._make_ready_response

关键源码片段

rust/src/chat/src/lib.rs core-logic

ChatLlm 新增三个查询方法:supports_multimodal、tool_call_parser_name、reasoning_parser_name,供控制服务填充 ModelInfo。

/// 检查加载的模型后端是否注册了多模态处理器。
pub fn supports_multimodal(&self) -> bool {
    self.processor.backend.multimodal_model_info().is_some()
}
​
/// 返回当前生效的工具调用解析器名称。
/// 当解析器未启用时返回 `None`,否则根据配置返回自动解析结果或显式名称。
pub fn tool_call_parser_name(&self) -> Option<&str> {
    match &self.tool_call_parser {
        ParserSelection::Auto => {
            ToolParserFactory::global().resolve_name_for_model(self.model_id())
        }
        ParserSelection::None => None,
        ParserSelection::Explicit(name) => Some(name),
    }
}
​
/// 返回当前生效的推理解析器名称。
/// 逻辑与 `tool_call_parser_name` 类似,返回自动或显式设置的解析器名称。
pub fn reasoning_parser_name(&self) -> Option<&str> {
    match &self.reasoning_parser {
        ParserSelection::Auto => {
            ReasoningParserFactory::global().resolve_name_for_model(self.model_id())
        }
        ParserSelection::None => None,
        ParserSelection::Explicit(name) => Some(name),
    }
}

评论区精华

提取 ready_response 构建逻辑为独立方法 设计

njhill 建议将 EngineCoreReadyResponse 的构建抽取为独立方法,以提升代码组织和可测试性。作者随后实现。

结论:已解决,通过提交 7426168 引入 `_make_ready_response`。 · 已解决

protobuf 字段编号 gap 处理 设计

njhill 询问 ParallelismInfo 和 ModelInfo 中字段编号跳变的原因。作者解释 ParallelismInfo 因删除无用字段后重编号消除 gap;ModelInfo 保留 gap 作为未来 supports_lora 的占位。

结论:已达成一致,ParallelismInfo 无 gap,ModelInfo 保留 gap。 · 已解决

风险与影响

  1. 协议兼容性风险:将 vllm.Generate 重命名为 vllm.Inference 是破坏性变更,但 Rust 前端服务尚处早期,影响可控。后续升级需协调客户端。
  2. 字段缺失风险:新增的 supports_multimodal 等字段依赖 Python 端正确初始化,Rust 端通过 unwrap_or_default 安全处理,不会 panic。
  3. 信息泄露风险:GetServerInfo 暴露 instance_id、engine_version 等元信息,若控制 API 未做访问控制,可能泄露内部拓扑。建议使用 TLS 或网络隔离保护该端口。
  4. 测试覆盖风险:控制服务测试覆盖了单引擎和多引擎场景,但缺少异常路径(如握手失败、空参请求)的测试。
  1. 对用户(运维/平台开发者):新增 gRPC 控制接口,可直接查询 vLLM 实例的状态和能力,便于集成到负载均衡、自动扩缩容、监控面板等系统。
  2. 对系统:拆分服务后,Inference 和 Control 可以使用不同的 TLS 证书或独立端口,有利于安全隔离。Python 端握手协议字段增加,要求 Python 和 Rust 保持同步更新。
  3. 对团队:后续可沿着 Control 服务继续添加 KV 卸载状态、请求统计等管理 RPC,形成完整的运营 API。
gRPC 服务兼容 握手协议同步 实例信息暴露

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论