Prhub

#24167 [gateway] Align /v1/loads and /model_info with sglang server; drop dead /rerank

原始 PR 作者 Kangyan-Zhou 合并时间 2026-05-03 02:43 文件变更 6 提交数 3 评论 2 代码增减 +10 / -275

执行摘要

对齐网关端点并删除死代码 /rerank

SGLang 服务器规范路径为 /v1/loads/model_info,而网关之前使用了非规范的 /get_loads/get_model_info;此外网关暴露的 /rerank 端点没有对应的后端服务,属于死代码。本次变更加以对齐并清理。

值得精读,学习 API 版本迁移和废弃端点的管理模式。建议在后续 PR 中补充 /v1/rerank 的更多测试用例以弥补覆盖损失。

讨论亮点

Gemini Code Assist bot 指出删除 5 个 rerank 测试后,损失了对成功、top_kreturn_documents 等场景的覆盖,建议将这些测试迁移到 /v1/rerank 端点。PR 保留了 test_v1_rerank_compatibility 作为 /v1/rerank 的兼容性测试,但未补充其他场景。作者未回复,PR 已合并。

实现拆解

  1. 路由注册调整server.rs):在 build_app() 中添加 /v1/loads/model_info 路由,并将 /get_loads/get_model_info 标记为废弃别名(带 TODO 注释);删除 /rerank 路由及其处理函数 rerank,移除不再需要的 RerankRequest 导入。
  2. 上游代理路径更新router.rspd_router.rs):将 RouterTrait::get_model_infoPDRouter::get_model_info 中代理请求的路径从 "get_model_info" 改为 "model_info"
  3. 测试配套更新mock_worker.rstest_pd_routing.rs):将 mock worker 的路由名更新为 /model_info;将 PD 路由覆盖测试矩阵中的 /get_model_info 改为 /model_info/get_loads 改为 /v1/loads
  4. 测试用例清理api_endpoints_test.rs):移除 5 个覆盖 /rerank 的测试用例(test_rerank_successtest_rerank_with_top_ktest_rerank_without_documentstest_rerank_worker_failuretest_rerank_invalid_request),仅保留 test_v1_rerank_compatibility 以验证 /v1/rerank 的正确性。
文件 模块 状态 重要度
sgl-model-gateway/src/server.rs 网关核心 modified 7.28
sgl-model-gateway/src/routers/http/router.rs HTTP 路由 modified 5.1
sgl-model-gateway/src/routers/http/pd_router.rs PD 路由 modified 4.93
sgl-model-gateway/tests/api/api_endpoints_test.rs API 测试 modified 7.73
sgl-model-gateway/tests/routing/test_pd_routing.rs PD 路由测试 modified 3.64
sgl-model-gateway/tests/common/mock_worker.rs Mock 服务 modified 3.46

关键符号

rerank v1_rerank get_model_info get_loads build_app RouterTrait::get_model_info PDRouter::get_model_info

关键源码片段

sgl-model-gateway/src/server.rs data-contract

核心路由注册,新增 /v1/loads 和 /model_info 规范路径,删除 /rerank 死代码

// 在 build_app() 中注册网关公开的路由
// 规范路径 /v1/loads 和 /model_info 被添加为主路径
// 遗留的 /get_loads 和 /get_model_info 作为废弃别名保留
let app = Router::new()
    .route("/health", get(health))
    .route("/health_generate", get(health_generate))
    .route("/v1/models", get(v1_models))
    .route("/model_info", get(get_model_info)) // 规范路径
    // TODO: 一个发布周期后移除 /get_model_info 别名
    .route("/get_model_info", get(get_model_info)) // 废弃别名
    .route("/server_info", get(get_server_info))
    .route("/get_server_info", get(get_server_info)) // 废弃别名
    .route("/flush_cache", post(flush_cache))
    .route("/v1/loads", get(get_loads)) // 规范路径
    // TODO: 一个发布周期后移除 /get_loads 别名
    .route("/get_loads", get(get_loads)) // 废弃别名
    // ... 其他路由
    .route("/v1/rerank", post(v1_rerank)); // 已删除旧的 /rerank 路由
sgl-model-gateway/tests/api/api_endpoints_test.rs test-coverage

删除 5 个 /rerank 测试,保留 /v1/rerank 兼容性测试

#[tokio::test]
async fn test_v1_rerank_compatibility() {
    let ctx = AppTestContext::new(vec![MockWorkerConfig {
        port: 18110,
        worker_type: WorkerType::Regular,
        health_status: HealthStatus::Healthy,
        response_delay_ms: 0,
        fail_rate: 0.0,
    }])
    .await;    let app = ctx.create_app().await;    // 使用规范路径 /v1/rerank 发送请求
    let payload = json!({
        "query": "machine learning algorithms",
        "documents": [
            "Introduction to machine learning concepts",
            "Deep learning neural networks tutorial",
            "Statistical learning theory basics"
        ]
    });    let req = Request::builder()
        .method("POST")
        .uri("/v1/rerank")
        .header(CONTENT_TYPE, "application/json")
        .body(Body::from(serde_json::to_string(&payload).unwrap()))
        .unwrap();    let resp = app.oneshot(req).await.unwrap();
    assert_eq!(resp.status(), StatusCode::OK);    let body = axum::body::to_bytes(resp.into_body(), usize::MAX).await.unwrap();
    let body_json: serde_json::Value = serde_json::from_slice(&body).unwrap();    assert!(body_json.get("results").is_some());
    assert!(body_json.get("model").is_some());
    // V1 API 应使用默认模型名
    assert_eq!(body_json["model"], "unknown");    let results = body_json["results"].as_array().unwrap();
    assert_eq!(results.len(), 3); // 所有文档应被返回    assert!(results[0]["score"].as_f64().unwrap() >= results[1]["score"].as_f64().unwrap());
    assert!(results[1]["score"].as_f64().unwrap() >= results[2]["score"].as_f64().unwrap());    // V1 API 默认返回文档
    for result in results {
        assert!(result.get("document").is_some());
    }    ctx.shutdown().await;
}

评论区精华

测试覆盖损失 测试

Gemini Code Assist bot 指出删除 5 个 /rerank 测试后,损失了对成功、top_k、return_documents 等场景的覆盖,建议将这些测试迁移到 /v1/rerank 端点。PR 保留了 test_v1_rerank_compatibility 作为兼容性测试,但未补充其他场景。

结论:作者未回复,PR 已合并,可能认为现有的单个兼容性测试足够,或计划后续补充。 · 已解决

风险与影响

  1. 废弃端点移除:虽然保留了 /get_loads/get_model_info 作为别名,但若用户直接依赖未公开的 /rerank 将收到 404,不过该端点从未正常工作,影响有限。
  2. 测试覆盖减少:删除了 5 个 rerank 测试,仅保留 1 个兼容性测试,若后续对 /v1/rerank 逻辑有改动,可能遗漏边界情况。
  3. 代理路径变更router.rspd_router.rsget_model_info 调用的上游路径从 "get_model_info" 改为 "model_info",如果后端 sglang server 未同步更新(但 PR 基于的服务器已支持此路径),可能导致代理失败。

用户影响:使用 /get_loads/get_model_info 的用户不受影响,但建议迁移到规范路径;从未可用的 /rerank 移除无实际影响。
系统影响:路由更加统一,内部代理通信一致,降低维护成本。
团队影响:需要在文档中声明废弃路径的移除时间线,并考虑后续补全 /v1/rerank 测试。

废弃端点移除隐患 测试覆盖减少 代理路径一致性

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论