跳转到主要内容
博客

使用 TorchServe + vLLM 部署 LLM

作者: 2024 年 10 月 31 日2025 年 5 月 5 日暂无评论

vLLM 引擎是目前执行大型语言模型 (LLM) 的最佳方式之一。它提供了 vllm serve 命令,作为在单机上部署模型的简便选项。虽然这很方便,但要在生产环境中大规模地服务这些 LLM,还需要一些高级功能。

flow diagram

TorchServe 提供了这些基本的生产功能(如自定义指标和模型版本控制),并通过其灵活的自定义处理程序设计,使得集成检索增强生成 (RAG) 或像 Llama Guard 这样的安全防护功能变得非常容易。因此,将 vLLM 引擎与 TorchServe 结合起来,创建一套完整的生产级 LLM 服务解决方案是很自然的。

在深入探讨集成细节之前,我们将演示如何使用 TorchServe 的 vLLM Docker 镜像部署 Llama-3.1-70B-Instruct 模型。

在 TorchServe + vLLM 上快速开始使用 Llama 3.1

首先,我们需要通过检出 TorchServe 仓库并在主文件夹中执行以下命令来构建 新的 TS LLM Docker 容器镜像

docker build --pull . -f docker/Dockerfile.vllm -t ts/vllm

该容器使用我们新的 LLM 启动脚本 ts.llm_launcher,该脚本接受一个 Hugging Face 模型 URI 或本地文件夹,并启动一个本地 TorchServe 实例,后台运行 vLLM 引擎。要在本地服务模型,您可以使用以下命令创建容器实例

#export token=<HUGGINGFACE_HUB_TOKEN>
docker run --rm -ti --shm-size 10g --gpus all -e HUGGING_FACE_HUB_TOKEN=$token -p 
8080:8080 -v data:/data ts/vllm --model_id meta-llama/Meta-Llama-3.1-70B-Instruct --disable_token_auth

您可以使用此 curl 命令在本地测试端点

curl -X POST -d '{"model":"meta-llama/Meta-Llama-3.1-70B-Instruct", "prompt":"Hello, my name is", "max_tokens": 200}' --header "Content-Type: application/json" "https://:8080/predictions/model/1.0/v1/completions"

docker 将模型权重存储在本地文件夹“data”中,该文件夹在容器内部挂载为 /data。要服务您的自定义本地权重,只需将其复制到 data 中,并将 model_id 指向 /data/<您的权重>。

在内部,容器使用我们新的 ts.llm_launcher 脚本来启动 TorchServe 并部署模型。该启动器将 LLM 与 TorchServe 的部署简化为一个命令行,也可以在容器外部用作实验和测试的有效工具。要在 Docker 外部使用启动器,请遵循 TorchServe 安装步骤,然后执行以下命令启动一个 8B Llama 模型

# after installing TorchServe and vLLM run
python -m ts.llm_launcher --model_id meta-llama/Meta-Llama-3.1-8B-Instruct  --disable_token_auth

如果有多张 GPU 可用,启动器将自动占用所有可见设备并应用张量并行(请参阅 CUDA_VISIBLE_DEVICES 以指定要使用的 GPU)。

虽然这非常方便,但重要的是要注意它不包含 TorchServe 提供的所有功能。对于那些希望利用更高级功能的人来说,需要创建一个模型存档。虽然这个过程比发出单个命令稍微复杂一些,但它具有自定义处理程序和版本控制的优势。前者允许在预处理步骤中实现 RAG,而后者允许您在更大规模部署之前测试不同版本的处理程序和模型。

在我们提供创建和部署模型存档的详细步骤之前,让我们深入了解 vLLM 引擎集成的细节。

TorchServe 的 vLLM 引擎集成

作为最先进的服务框架,vLLM 提供了大量高级功能,包括 PagedAttention、连续批处理、通过 CUDA 图快速执行模型,以及支持各种量化方法,如 GPTQ、AWQ、INT4、INT8 和 FP8。它还提供了对 LoRA 等重要的参数高效适配器方法的集成,并支持包括 Llama 和 Mistral 在内的多种模型架构。vLLM 由 vLLM 团队和活跃的开源社区维护。

为了方便快速部署,它提供了一个基于 FastAPI 的服务模式,通过 HTTP 提供 LLM 服务。为了更紧密、更灵活的集成,该项目还提供了 vllm.LLMEngine,它提供了持续处理请求的接口。我们利用其 异步变体 集成到 TorchServe 中。

TorchServe 是一个易于使用的开源解决方案,用于在生产环境中服务 PyTorch 模型。作为经过生产验证的服务解决方案,TorchServe 提供了许多有益的功能,用于大规模部署 PyTorch 模型。通过将其与 vLLM 引擎的推理性能相结合,现在这些优势也可以用于大规模部署 LLM。

Torchserve highlights and integrations

为了最大化硬件利用率,通常将来自多个用户的请求进行批处理是一个好习惯。历史上,TorchServe 只提供了同步模式来收集来自不同用户的请求。在此模式下,TorchServe 会等待预定义的时间(例如,batch_delay=200ms)或直到足够的请求(例如,batch_size=8)到达。当这些事件之一被触发时,批处理数据会被转发到后端,模型会应用于该批次,然后模型输出通过前端返回给用户。这对于传统视觉模型特别有效,因为每个请求的输出通常同时完成。

对于生成式用例,特别是文本生成,请求同时准备好的假设不再成立,因为响应的长度会有所不同。尽管 TorchServe 支持连续批处理(动态添加和删除请求的能力),但此模式只能容纳静态的最大批处理大小。随着 PagedAttention 的引入,即使是最大批处理大小的假设也变得更加灵活,因为 vLLM 可以高度适应地组合不同长度的请求,以优化内存利用率。

为了实现最佳内存利用率,即填补内存中未使用的空白(想象一下俄罗斯方块),vLLM 需要完全控制在任何给定时间处理哪些请求的决定。为了提供这种灵活性,我们必须重新评估 TorchServe 处理用户请求的方式。我们没有采用以前的同步处理模式,而是引入了一种异步模式(见下图),其中传入的请求直接转发到后端,使其可供 vLLM 使用。后端将请求馈送给 vllm.AsyncEngine,后者现在可以从所有可用请求中进行选择。如果启用了流式传输模式并且请求的第一个 token 可用,后端将立即发送结果并继续发送 token,直到生成最后一个 token。

flow diagram

我们对 VLLMHandler 的实现 使您能够使用配置文件快速部署任何与 vLLM 兼容的模型,同时仍通过自定义处理程序提供相同级别的灵活性和可定制性。您可以自由地添加例如自定义的 预处理后处理 步骤,方法是继承 VLLMHandler 并重写相应的类方法。

我们还支持单节点、多 GPU 分布式推理,其中我们将 vLLM 配置为使用模型的张量并行分片,以增加小型模型的容量或启用不适合单个 GPU 的大型模型,例如 70B Llama 变体。以前,TorchServe 只支持使用 torchrun 进行分布式推理,其中会启动多个后端工作进程来分片模型。vLLM 在内部管理这些进程的创建,因此我们 向 TorchServe 引入了新的“custom”并行类型,它启动一个后端工作进程并提供分配的 GPU 列表。然后,后端进程可以在必要时启动自己的子进程。

为了方便将 TorchServe + vLLM 集成到基于 Docker 的部署中,我们提供了一个单独的 Dockerfile,该文件基于 TorchServe 的 GPU docker 镜像,并将 vLLM 添加为依赖项。我们选择将两者分开,以避免增加非 LLM 部署的 docker 镜像大小。

接下来,我们将演示在具有四个 GPU 的机器上使用 TorchServe + vLLM 部署 Llama 3.1 70B 模型所需的步骤。

分步指南

对于本分步指南,我们假设 TorchServe 的安装 已成功完成。目前,vLLM 不是 TorchServe 的硬依赖项,因此我们使用 pip 安装该软件包

$ pip install -U vllm==0.6.1.post2

在接下来的步骤中,我们将(可选地)下载模型权重,解释配置,创建模型存档,然后部署和测试它

1. (可选) 下载模型权重

此步骤是可选的,因为 vLLM 也可以在模型服务器启动时处理权重的下载。然而,预先下载模型权重并在 TorchServe 实例之间共享缓存文件,可以在存储使用和模型 worker 启动时间方面受益。如果您选择下载权重,请使用 huggingface-cli 并执行

# make sure you have logged into huggingface with huggingface-cli login before
# and have your access request for the Llama 3.1 model weights approved

huggingface-cli download meta-llama/Meta-Llama-3.1-70B-Instruct --exclude original/*

这会将文件下载到 $HF_HOME 下,如果您想将文件放在其他位置,可以更改此变量。请确保您在运行 TorchServe 的任何地方更新该变量,并确保它有权访问该文件夹。

2. 配置模型

接下来,我们创建一个 YAML 配置文件,其中包含模型部署所需的所有参数。配置文件的第一部分指定前端如何启动后端 worker,该 worker 最终将在处理程序中运行模型。第二部分包含后端处理程序的参数,例如要加载的模型,然后是 vLLM 本身的各种参数。有关 vLLM 引擎可能配置的更多信息,请参阅此 链接

echo '
# TorchServe frontend parameters
minWorkers: 1            
maxWorkers: 1            # Set the number of worker to create a single model instance
startupTimeout: 1200     # (in seconds) Give the worker time to load the model weights
deviceType: "gpu" 
asyncCommunication: true # This ensures we can cummunicate asynchronously with the worker
parallelType: "custom"   # This lets TS create a single backend prosses assigning 4 GPUs
parallelLevel: 4

# Handler parameters
handler:
    # model_path can be a model identifier for Hugging Face hub or a local path
    model_path: "meta-llama/Meta-Llama-3.1-70B-Instruct"
    vllm_engine_config:  # vLLM configuration which gets fed into AsyncVLLMEngine
        max_num_seqs: 16
        max_model_len: 512
        tensor_parallel_size: 4
        served_model_name:
            - "meta-llama/Meta-Llama-3.1-70B-Instruct"
            - "llama3"
'> model_config.yaml

3. 创建模型文件夹

创建模型配置文件 (model_config.yaml) 后,我们现在将创建一个模型存档,其中包含配置和附加元数据,例如版本信息。由于模型权重较大,我们不会将其包含在存档中。相反,处理程序将通过 model_path 访问权重,该路径在模型配置中指定。请注意,在此示例中,我们选择了“无存档”格式,它创建了一个包含所有必要文件的模型文件夹。这使我们能够轻松修改配置文件以进行实验,而不会遇到任何摩擦。稍后,我们还可以选择 mar 或 tgz 格式来创建更易于传输的工件。

mkdir model_store
torch-model-archiver --model-name vllm --version 1.0 --handler vllm_handler --config-file model_config.yaml --archive-format no-archive --export-path model_store/

4. 部署模型

下一步是启动 TorchServe 实例并加载模型。请注意,为了本地测试,我们已禁用令牌身份验证。强烈建议在公开部署任何模型时实施某种形式的身份验证。

要启动 TorchServe 实例并加载模型,请运行以下命令

torchserve --start --ncs  --model-store model_store --models vllm --disable-token-auth

您可以通过日志语句监控模型加载的进度。模型加载完成后,您可以继续测试部署。

5. 测试部署

vLLM 集成使用 OpenAI API 兼容格式,因此我们可以使用专门的工具或 curl。我们在此处使用的 JSON 数据包括模型标识符和提示文本。其他选项及其默认值可以在 vLLMEngine 文档中找到。

echo '{
  "model": "llama3",
  "prompt": "A robot may not injure a human being",
  "stream": 0
}' | curl --header "Content-Type: application/json"   --request POST --data-binary @-   https://:8080/predictions/vllm/1.0/v1/completions

请求的输出如下所示

{
  "id": "cmpl-cd29f1d8aa0b48aebcbff4b559a0c783",
  "object": "text_completion",
  "created": 1727211972,
  "model": "meta-llama/Meta-Llama-3.1-70B-Instruct",
  "choices": [
    {
      "index": 0,
      "text": " or, through inaction, allow a human being to come to harm.\nA",
      "logprobs": null,
      "finish_reason": "length",
      "stop_reason": null,
      "prompt_logprobs": null
    }
  ],
  "usage": {
    "prompt_tokens": 10,
    "total_tokens": 26,
    "completion_tokens": 16
  }

当流式传输为 False 时,TorchServe 将在生成最后一个 token 后收集完整的答案并一次性发送。如果我们切换流式参数,我们将收到包含单个 token 的分段数据。

结论

在这篇博客文章中,我们探讨了 vLLM 推理引擎与 TorchServe 的全新原生集成。我们演示了如何使用 ts.llm_launcher 脚本在本地部署 Llama 3.1 70B 模型,以及如何创建模型存档以在任何 TorchServe 实例上进行部署。此外,我们讨论了如何构建和在 Docker 容器中运行解决方案,以便在 Kubernetes 或 EKS 上进行部署。在未来的工作中,我们计划启用 vLLM 和 TorchServe 的多节点推理,并提供预构建的 Docker 镜像以简化部署过程。

我们衷心感谢 Mark Saroufim 和 vLLM 团队在撰写本博客文章之前提供的宝贵支持。