南向接口实现方式

实现方式

南向实现方式如图1所示,分别设计了五个核心接口E、F、G、H、I,实际上是五个回调函数,分别负责从ModelState存储队列中读取请求、将推理响应回传给Tritonserver、发送完成推理的请求ID队列、发送LlmManager推理状态和发送异常请求的状态。在ModelState构造函数内部定义并且传参给LlmManager完成初始化。LlmManager作为MindIE LLM与Backend对接的唯一核心接口类,提供模型推理和请求调度的能力,支持Continuous Batching动态调度。首先通过上层Backend传递的这五个回调函数和配置文件完成构造和初始化,接着创建线程来循环读取ModelState中接收到的请求队列,并传递给MindIE LLM进行处理。最后利用回调函数把响应Response直接传递给Tritonserver,并且在完成全部推理后释放请求任务。

图1 南向实现方式

接口描述

表1 接口E

参数

描述

接口函数

std::function<std::vector<std::shared_ptr<mindie_llm::InferRequest>>()>。

接口功能

GetRequestsCallback回调函数,负责从ModelState存储队列InferRequests中读取出所有请求,将由LlmManager调用。

输入参数

N/A。

输出参数

推理请求队列。

表2 接口F

参数

描述

接口函数

std::function<void(mindie_llm::InferRequestId, const mindie_llm::TensorMap&, bool, const std::string&)>。

接口功能

SendResponsesCallback回调函数,负责将推理响应回传给Tritonserver,定义了MindIE LLM将推理出的单个Token响应回传给Tritonserver的行为,首先由Reqid对应的响应工厂responseFactory创建一个triton response,并使用convertResponse函数将tensorMap中所有推理张量依次附加至该response中,最后使用TRITONBACKEND_ResponseSend函数将该响应回传给Triton侧。值得一提的是,如果参数isEnd为true,代表该请求的推理全部完成,需要在回调函数中释放该请求。

输入参数

请求Id,包含推理响应信息的张量,end标志位,响应自身的状态。

输出参数

N/A。

表3 接口G

参数

描述

接口函数

std::function<std::vector<std::pair<mindie_llm::InferRequestId, mindie_llm::Operation>>()>。

接口功能

ControlSignalCallback回调函数,发送停止推理的请求id队列。

输入参数

N/A。

输出参数

完成推理的请求id队列。

表4 接口H

参数

描述

接口函数

std::function<void(const std::string&)>。

接口功能

LlmManagerStatsCallback回调函数,发送LlmManager推理状态,包括slaves_status、remain_blocks、remain_prefill_slots等。

输入参数

LlmManager推理状态status字符串。

输出参数

N/A。

表5 接口I

参数

描述

接口函数

std::function<void(mindie_llm::InferRequestId, mindie_llm::Status, mindie_llm::StatusResponseType)>。

接口功能

SendStatuslResponseCallback回调函数,发送异常请求的状态。

输入参数

请求Id,请求状态,响应状态。

输出参数

N/A。

表6 LlmManager接口类

参数

描述

接口类构造函数

LlmManager::LlmManager(const std::string& llmConfigPath, GetRequestsCallback getRequest, SendResponsesCallback sendResponse, ControlSignalCallback controlCallback, LlmManagerStatsCallback statusCallback, SendStatuslResponseCallback statusResponseCallback)。

接口类功能

LlmManager作为MindIE LLM暴露给backend的唯一核心接口类,提供模型推理和请求调度的能力,支持Continuous Batching动态调度。首先通过上层Backend传递的这五个回调函数和配置文件完成初始化,在构造函数中创建了一个线程循环读取ModelState中接收到的请求队列,并传递给MindIE LLM进行处理。最后利用回调函数把响应response直接传递给Tritonserver,并且在完成全部推理后摧毁请求任务。

输入参数

模型配置文件,五个ModelState中定义的回调函数。

输出参数

N/A。

适配流程

ModelState初始化,在构造函数中主要做以下三点:

  1. 初始化BackendModel并将配置文件engineConfigPath透传给MindIE LLM,其中包含了模型推理所需的配置信息和调度策略等。
  2. 定义五个接口回调函数,是Triton和MindIE LLM之间收发请求和响应的关键。定义了从ModelState存储队列中读取请求的动作、将推理响应回传给Tritonserver的动作、发送完成推理的请求ID队列的动作、发送LlmManager推理状态的动作及发送异常请求的状态的动作。
  3. 使用engineConfigPath和五个Callback函数给每个模型实例构造出LlmManager对象,该对象在初始化后创建了线程循环读取ModelState中接收到的请求队列,并传递给LLM进行推理和调度,代码如下:
    ModelState::ModelState(TRITONBACKEND_Model *triton_model) : BackendModel(triton_model), shape_initialized_(false)
    {
        // 验证模型的配置参数都被backend支持
        THROW_IF_BACKEND_MODEL_ERROR(ValidateModelConfig());
        // 获取mindie配置文件路径
        std::string configPath = MindIEUtils::GetEngineConfigPath(this);
        // 获取llm-manager初始化时必须的模型实例个数和对应的npu设备号
        auto initConfig = GetInitConfig();
        uint32_t modelInstanceNumber = initConfig.first;
        std::vector<std::set<size_t>> npuDeviceIds = initConfig.second;
        LOG_MESSAGE(TRITONSERVER_LOG_ERROR,
                    (std::string("modelInstanceNumber: ") + std::to_string(modelInstanceNumber)).c_str());
        // mindie-llm从modelstate存储队列中获取request的回调函数
        auto getRequestsFunc = CreateGetRequestsCallback();
        // mindie-llm推理出的响应发送回tritonserver的回调函数
        auto sendResponsesFunc = CreateSendResponsesCallback();
        
        // mindie-llm接收triton侧发来的停止推理请求Id的回调函数
        auto controlSignalFunc = CreateControlSignalCallback();
        
        // mindie-llm发送推理状态的回调函数
        auto llmManagerStatsFunc = CreateLlmManagerStatsCallback();
        
        // mindie-llm发送推理过程中异常请求的状态
        auto sendStatusResponseCallback = CreateSendStatusResponseCallback();
        
        // 给每个模型实例构造并初始化一个llm_manager接口类,负责mindie中请求的调度推理
        mindie_llm::LlmManager* llm_manager = nullptr;
        for (uint32_t modelInstanceId = 0; modelInstanceId < modelInstanceNumber; ++modelInstanceId) {
            llm_manager = new mindie_llm::LlmManager(configPath,
                getRequestsFunc, sendResponsesFunc, controlSignalFunc, llmManagerStatsFunc, sendStatusResponseCallback);
            llmManagers_.emplace_back(llm_manager);
            auto status = llm_manager->Init(modelInstanceId, npuDeviceIds[modelInstanceId]);
            if (!status.IsOk()) {
                LOG_MESSAGE(TRITONSERVER_LOG_ERROR,
                    "Failed to init llm_manager");
                break;
            }
        }
    }