版本:v25.12

AI推理赫尔墨斯路由插件开发指南

特性介绍

Hermes-router是一个Kubernetes(K8s)原生的AI推理智能路由方案,用于接收用户推理请求并转发至合适的推理服务后端。

作为GIE框架下的EPP插件,Hermes-router仅关注请求的转发过程,本指南介绍开发者如何基于EPP框架进行自定义路由策略开发。

约束与限制

推理引擎限制

Hermes-router对推理引擎的支持与GIE保持一致。 但部分插件依赖cache-indexer计算全局KVCache命中率,而cache-indexer在v25.12版本仅支持vLLM,因此现阶段这些插件间接地仅能在推理引擎为vLLM时使用,插件如下:

  • scorer-aggregate-kv-cache-aware
  • scorer-pd-kv-cache-aware

其他插件在理论上支持多种推理引擎,但目前仅验证了vLLM作为推理引擎的场景。

开发限制

在本文档中,一个EPP实例代表一种路由策略,一个路由策略通常由多个类型的插件组成,插件开发需遵循GIE框架规范

部署限制

  • 仅支持在Kubernetes环境中部署运行。
  • 插件需在本地完成开发,构建为镜像后才可部署运行。
  • 如需变更路由策略配置,需在修改配置后重启EPP方可生效。

环境准备

环境要求

硬件要求

Hermes-router开发环境对硬件无特殊要求,建议按照如下进行配置。

  • CPU:4核及以上
  • 内存:8GB及以上
  • 磁盘:20GB及以上可用空间

软件要求

  • 操作系统:Linux
  • Go环境:Go 1.21或更高版本
  • Docker:Docker 20.10+或兼容的容器运行时(如nerdctl)
  • Kubernetes集群:用于部署和测试
  • kubectl:用于与K8s集群交互
  • Helm:3.0+版本,用于部署Hermes-router

依赖组件

  • 基础依赖

    • 开源网关:需支持Gateway API Inference Extension,如Istio v1.28。
  • 额外依赖

    若要使用Hermes-router提供的KVCache aware相关路由策略进行开发,有如下额外依赖:

    • KVCache全局管理组件:提供全局KVCache感知与命中率计算,如cache-indexer v25.12。

搭建环境

  1. 克隆代码仓库。

    bash
    # 克隆hermes-router主仓库
    git clone https://gitcode.com/openFuyao/hermes-router.git
    cd hermes-router
  2. 配置Go开发环境。

    bash
    # 检查Go版本
    go version
    
    # 设置Go代理(可选,加速依赖下载)
    go env -w GOPROXY=https://goproxy.cn,direct
  3. 安装Istio和GIE框架。

    bash
    # 下载Istio
    curl -L https://istio.io/downloadIstio | sh -
    cd istio-*
    
    # 安装Istio(启用GIE支持)
    istioctl install -y \
    --set tag=<ISTIO_TAG> \
    --set hub=gcr.io/istio-testing \
    --set values.pilot.env.ENABLE_GATEWAY_API_INFERENCE_EXTENSION=true
    
    # 安装Gateway API CRDs
    kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.1/standard-install.yaml
    
    # 安装GIE CRDs(根据实际版本调整)
    kubectl apply -f <GIE_CRDs_YAML>
  4. 构建hermes-router镜像。

    bash
    cd hermes-router
    
    # 构建镜像
    docker build -t hermes-router:dev -f Dockerfile.epp .
    
    # 或使用nerdctl
    nerdctl build -t hermes-router:dev -f Dockerfile.epp .

验证环境

  1. 验证Istio安装。

    bash
    # 检查Istio组件
    kubectl get pods -n istio-system
    
    # 预期输出:所有Pod状态为Running
  2. 验证GIE CRDs。

    bash
    # 检查InferencePool CRD
    kubectl get crd inferencepools.inference.networking.x-k8s.io
  3. 部署hermes-router进行验证。

    bash
    cd hermes-router
    
    # 更新Helm依赖
    helm dependency update examples/1_pd_bucket/charts/hermes-router
    
    # 部署hermes-router(使用最简单的配置)
    helm upgrade --install vllm-qwen-qwen3-8b \
    examples/1_pd_bucket/charts/hermes-router \
    --namespace hermes-test --create-namespace \
    -f examples/profiles/epp-random-pd-bucket.yaml \
    --set inferencepool.provider.name=istio \
    --set image.repository=hermes-router \
    --set image.tag=dev
    
    # 检查部署状态
    kubectl get pods -n hermes-test
    kubectl get svc -n hermes-test

预期结果:

  • Pod状态为Running。
  • Service正常创建。
  • 无错误日志。
bash
[root@master hermes-router]# kd get all
NAME                                          READY   STATUS    RESTARTS   
pod/vllm-pd-decode-5bb99b6764-cs52k           1/1     Running   0          
pod/vllm-pd-prefill-6db4c89f78-f7csp          1/1     Running   0          
pod/vllm-pd-proxy-5f8bfcf495-p5vpj            1/1     Running   0          
pod/vllm-qwen-qwen3-8b-epp-5fd87d6d59-r2xpv   1/1     Running   0          

NAME                             TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)             AGE
service/vllm-pd-proxy            ClusterIP   ******         <none>        8000/TCP,5557/TCP   16h
service/vllm-qwen-qwen3-8b-epp   ClusterIP   ******         <none>        9002/TCP,9090/TCP   83s

NAME                                     READY   UP-TO-DATE   AVAILABLE   
deployment.apps/vllm-pd-decode           1/1     1            1           
deployment.apps/vllm-pd-prefill          1/1     1            1           
deployment.apps/vllm-pd-proxy            1/1     1            1           
deployment.apps/vllm-qwen-qwen3-8b-epp   1/1     1            1           

NAME                                                DESIRED   CURRENT   READY   
replicaset.apps/vllm-pd-decode-5bb99b6764           1         1         1       
replicaset.apps/vllm-pd-prefill-6db4c89f78          1         1         1       
replicaset.apps/vllm-pd-proxy-5f8bfcf495            1         1         1       
replicaset.apps/vllm-qwen-qwen3-8b-epp-5fd87d6d59   1         1         1

开发自定义路由策略

使用场景概述

当预置的路由策略无法满足特定业务需求时,开发者可以通过实现自定义插件来扩展路由能力。典型场景包括:

  • 业务特定路由规则:根据业务标签、用户ID等自定义属性进行路由。
  • 性能优化需求:针对特定硬件或网络环境优化路由算法。
  • 混合架构支持:支持聚合架构和PD分离架构的混合部署。

系统架构

Hermes-router采用插件化架构,通过不同类型的插件协同工作来实现智能路由。插件主要分为四类:Filter插件用于过滤候选端点,Scorer插件用于对端点进行评分,Picker插件用于从评分结果中选择最终端点,PreRequest插件用于在请求转发前修改请求。各类插件的详细说明如下:

表1 Hermes-router插件类型说明

插件类型功能描述示例
Filter插件过滤候选端点列表filter-by-pd-label:根据PD标签过滤。
Scorer插件对端点进行评分scorer-aggregate-kv-cache-aware:基于KV Cache评分。
scorer-pd-bucket:基于Bucket负载评分。
Picker插件从评分结果中选择最终端点picker-min-random:选择评分最低的随机实例
picker-pd-kv-cache-aware:PD架构的智能选择插件。
PreRequest插件在请求转发前修改请求pd-header-handler:添加PD架构所需的请求头。

插件执行流程

插件按照在schedulingProfiles中配置的顺序执行:

  1. Filter阶段:所有Filter插件依次执行,逐步缩小候选端点范围。
  2. Scorer阶段:所有Scorer插件对候选端点进行评分(可配置权重)。
  3. Picker阶段:Picker插件根据评分结果选择最终端点。
  4. PreRequest阶段:PreRequest插件修改请求后转发。

以下链接提供了开发自定义路由策略所需的相关文档:

  • hermes-router代码仓库:Hermes-router的源代码仓库,包含所有插件实现示例和开发框架,开发者可参考现有插件代码进行开发。
  • GIE框架规范:Gateway API Inference Extension(GIE)的官方规范文档,定义了EPP插件的接口规范和开发标准,是开发EPP插件必须遵循的规范。
  • EPP Architecture Proposal:Endpoint Picker Plugin(EPP)架构提案,详细说明了EPP插件的架构设计、执行流程和扩展机制,帮助开发者深入理解插件工作原理。

开发步骤

  1. 设计路由策略。

    开发者自行设计路由策略与具体的插件,本指南略过此步骤。

  2. 开发路由插件。

    开发者在完成路由策略的设计后,需要将处理流程拆分为若干EPP规范的插件并实现,主要插件类型为Filter、Scorer、Picker、PreRequest等。

    下面以用于过滤Pod的Filter插件为例,展示EPP插件开发流程:

    2.1. 创建Filter代码文件。

    Hermes-router将EPP插件分类存放,建议在pkg/plugins/filter下创建新的Filter插件。

    2.2. 定义Filter插件结构体。

    go
    type MyFilter struct {  
       typedName plugins.TypedName  
       // ... 其他成员变量 
     }

    2.3. 实现结构体构造函数。

    go
    func NewMyFilter(...){
       // ... 初始化成员变量
       return &MyFilter{...}
    }

    2.4. 实现工厂函数。

    go
    func ByMyFilterFactory(...){
       // ... 根据GIE传入参数初始化Filter成员变量
       return NewMyFilter(...)
     }

    2.5. 实现Filter接口中的Filter()方法。

    go
     func (m *MyFilter) Filter(_ context.Context, _ *types.CycleState, _ *types.LLMRequest, pods []types.Pod) []types.Pod {}

    2.6. 在pkg/plugins/register.go中注册新增Filter。

    go
    func RegisterAllPlugins() {  
       plugins.Register(filter.MyFilter, filter.ByMyFilterFactory)  
       // ... 其他插件  
     }

    至此一个Filter插件开发完成,开发者可以按照相同流程开发其他类型的EPP插件。

  3. 定义路由策略。

    为应用路由策略,开发者需要在资源类型为InferencePool的yaml文件中进行配置:

    • 在inferenceExtension.pluginsConfigFile字段声明路由策略名称。
    • 在inferenceExtension.pluginsCustomConfig字段声明路由策略具体配置。
    yaml
    # example-strategy 路由策略的配置示例
    inferencepool:
    inferenceExtension:
       pluginsConfigFile: "example_strategy.yaml"
       pluginsCustomConfig:
       exaexample_strategymple.yaml: |
          apiVersion: inference.networking.x-k8s.io/v1alpha1
          kind: EndpointPickerConfig
          plugins:
          # ... plugins

至此开发者已完成路由策略的开发。

调测验证

使用kubectl port-forward进行端口转发。

  1. 执行如下命令,查找Gateway Service名称。

    shell
    kubectl get svc -n <NAMESPACE> -l gateway.networking.k8s.io/gateway-name=inference-gateway
  2. 执行如下命令,设置端口转发。

    shell
    kubectl port-forward -n <NAMESPACE> service/<gateway-service-name> 8000:80
  3. 执行如下命令,发送请求。

    shell
    curl -X POST http://localhost:8000/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{
       "model": "Qwen/Qwen3-8B",
       "messages": [
          {"role": "user", "content": "你好"}
       ],
       "max_tokens": 100,
       "temperature": 0.7,
       "stream": false
    }'

开发完成后,请参照《用户指南》中的安装章节进行部署及验证工作。