部署初始化#

serve.llm 部署的初始化阶段涉及多个步骤,包括模型权重准备、引擎(vLLM)初始化以及 Ray Serve 副本自动扩缩容的开销。下面详细介绍了使用 serve.llm 和 vLLM 的步骤。

启动分解#

  • 配置节点:如果 GPU 节点不可用,则必须配置新实例。

  • 镜像下载:将镜像下载到目标实例会产生与镜像大小相关的延迟。

  • 固定 Ray/节点初始化:Ray/vLLM 在启动新进程以处理新副本时会产生一些固定开销,包括导入大型库(如 vLLM)、准备模型和引擎配置等。

  • 模型加载:从 Hugging Face 或云存储检索模型,包括下载模型并将其移至 GPU 内存所花费的时间。

  • Torch 编译:Torch 编译是 vLLM 设计不可或缺的一部分,默认启用。

  • 内存分析:vLLM 对模型运行一些推理,以确定可用于 KV 缓存的可用内存量。

  • CUDA 图捕获:vLLM 会提前捕获不同输入大小的 CUDA 图。更多详细信息请参见此处

  • 预热:初始化 KV 缓存,运行模型推理。

本文档将概述自定义部署初始化的多种方法。

从 Hugging Face 加载模型#

默认情况下,Ray Serve LLM 从 Hugging Face Hub 加载模型。使用 model_source 指定模型来源。

from ray import serve
from ray.serve.llm import LLMConfig, build_openai_app

llm_config = LLMConfig(
    model_loading_config=dict(
        model_id="llama-3-8b",
        model_source="meta-llama/Meta-Llama-3-8B-Instruct",
    ),
    accelerator_type="A10G",
)

app = build_openai_app({"llm_configs": [llm_config]})
serve.run(app, blocking=True)

加载受限模型#

受限的 Hugging Face 模型需要身份验证。通过 runtime_env 传递您的 Hugging Face 令牌。

from ray import serve
from ray.serve.llm import LLMConfig, build_openai_app
import os

llm_config = LLMConfig(
    model_loading_config=dict(
        model_id="llama-3-8b-instruct",
        model_source="meta-llama/Meta-Llama-3-8B-Instruct",
    ),
    deployment_config=dict(
        autoscaling_config=dict(
            min_replicas=1,
            max_replicas=2,
        )
    ),
    accelerator_type="A10G",
    runtime_env=dict(
        env_vars={
            "HF_TOKEN": os.environ["HF_TOKEN"]
        }
    ),
)

app = build_openai_app({"llm_configs": [llm_config]})
serve.run(app, blocking=True)

您也可以通过传递给 ray.init 的方式在整个集群范围内设置环境变量。

import ray

ray.init(
    runtime_env=dict(
        env_vars={
            "HF_TOKEN": os.environ["HF_TOKEN"]
        }
    ),
)

从 Hugging Face 快速下载#

使用 Hugging Face 的 hf_transfer 库启用快速下载。

  1. 安装库

pip install hf_transfer
  1. 设置 HF_HUB_ENABLE_HF_TRANSFER 环境变量。

from ray import serve
from ray.serve.llm import LLMConfig, build_openai_app

llm_config = LLMConfig(
    model_loading_config=dict(
        model_id="llama-3-8b",
        model_source="meta-llama/Meta-Llama-3-8B-Instruct",
    ),
    accelerator_type="A10G",
    runtime_env=dict(
        env_vars={
            "HF_HUB_ENABLE_HF_TRANSFER": "1"
        }
    ),
)

app = build_openai_app({"llm_configs": [llm_config]})
serve.run(app, blocking=True)

从远程存储加载模型#

从 S3 或 GCS 存储桶加载模型,而不是从 Hugging Face 加载。这对于以下情况很有用:

  • 未在 Hugging Face 上托管的私有模型

  • 在同一区域从云存储更快地加载

  • 自定义模型格式或微调模型

S3 存储桶结构#

您的 S3 存储桶应包含 Hugging Face 兼容结构中的模型文件。

$ aws s3 ls air-example-data/rayllm-ossci/meta-Llama-3.2-1B-Instruct/
2025-03-25 11:37:48       1519 .gitattributes
2025-03-25 11:37:48       7712 LICENSE.txt
2025-03-25 11:37:48      41742 README.md
2025-03-25 11:37:48       6021 USE_POLICY.md
2025-03-25 11:37:48        877 config.json
2025-03-25 11:37:48        189 generation_config.json
2025-03-25 11:37:48 2471645608 model.safetensors
2025-03-25 11:37:53        296 special_tokens_map.json
2025-03-25 11:37:53    9085657 tokenizer.json
2025-03-25 11:37:53      54528 tokenizer_config.json

配置 S3 加载 (YAML)#

model_loading_config 中使用 bucket_uri 参数。

# config.yaml
applications:
- args:
    llm_configs:
        - accelerator_type: A10G
          engine_kwargs:
            max_model_len: 8192
          model_loading_config:
            model_id: my_llama
            model_source:
              bucket_uri: s3://anonymous@air-example-data/rayllm-ossci/meta-Llama-3.2-1B-Instruct
  import_path: ray.serve.llm:build_openai_app
  name: llm_app
  route_prefix: "/"

使用以下命令部署

serve deploy config.yaml

配置 S3 加载 (Python API)#

您还可以使用 Python 配置 S3 加载。

from ray import serve
from ray.serve.llm import LLMConfig, build_openai_app

llm_config = LLMConfig(
    model_loading_config=dict(
        model_id="my_llama",
        model_source=dict(
            bucket_uri="s3://my-bucket/path/to/model"
        )
    ),
    accelerator_type="A10G",
    engine_kwargs=dict(
        max_model_len=8192,
    ),
)

app = build_openai_app({"llm_configs": [llm_config]})
serve.run(app, blocking=True)

配置 GCS 存储桶加载 (YAML)#

对于 Google Cloud Storage,使用 gs:// 协议。

model_loading_config:
  model_id: my_model
  model_source:
    bucket_uri: gs://my-gcs-bucket/path/to/model

S3 凭证#

对于私有 S3 存储桶,请配置 AWS 凭证。

  1. 选项 1:环境变量

llm_config = LLMConfig(
    model_loading_config=dict(
        model_id="my_model",
        model_source=dict(
            bucket_uri="s3://my-private-bucket/model"
        )
    ),
    runtime_env=dict(
        env_vars={
            "AWS_ACCESS_KEY_ID": os.environ["AWS_ACCESS_KEY_ID"],
            "AWS_SECRET_ACCESS_KEY": os.environ["AWS_SECRET_ACCESS_KEY"],
        }
    ),
)
  1. 选项 2:IAM 角色(生产环境推荐)

使用具有适当 S3 读取权限的 EC2 实例配置文件或 EKS 服务账户。

S3 和 RunAI Streamer#

S3 可以与 RunAI Streamer 结合使用,RunAI Streamer 是 vLLM 中的一个扩展,可实现直接从远程云存储流式传输模型权重到 GPU 内存,从而提高模型加载延迟。更多详细信息请参见此处

llm_config = LLMConfig(
    ...
    model_loading_config={
        "model_id": "llama",
        "model_source": "s3://your-bucket/Meta-Llama-3-8B-Instruct",
    },
    engine_kwargs={
        "tensor_parallel_size": 1,
        "load_format": "runai_streamer",
    },
    ...
)

模型分片#

现代 LLM 模型的大小通常会超出单个 GPU 的内存容量,需要使用张量并行在多个设备之间分割计算。在此范例中,每个 GPU 仅存储一部分权重,模型分片可确保每个设备仅加载模型的相关部分。通过提前分片模型文件,我们可以显着减少加载时间,因为 GPU 避免加载不必要的权重。vLLM 为此目的提供了一个实用脚本:save_sharded_state.py

保存分片权重后,将其上传到 S3,并使用带有新标志的 RunAI Streamer 来加载分片权重。

llm_config = LLMConfig(
    ...
    engine_kwargs={
        "tensor_parallel_size": 4,
        "load_format": "runai_streamer_sharded",
    },
    ...
)

附加优化#

Torch 编译缓存#

Torch.compile 在初始化期间会产生一些延迟。可以通过保留 torch 编译缓存来缓解此问题,该缓存由 vLLM 自动生成。要检索 torch 编译缓存,请运行 vLLM 并查找类似以下的日志。

(RayWorkerWrapper pid=126782) INFO 10-15 11:57:04 [backends.py:608] Using cache directory: /home/ray/.cache/vllm/torch_compile_cache/131ee5c6d9/rank_1_0/backbone for vLLM's torch.compile

在此示例中,缓存文件夹位于 /home/ray/.cache/vllm/torch_compile_cache/131ee5c6d9。将此目录上传到您的 S3 存储桶。现在可以在启动时检索缓存文件夹。我们提供了一个自定义实用程序,用于从云存储下载编译缓存。在 LLMConfig 中指定 CloudDownloader 回调,并提供相关参数。确保在 compilation_config 中正确设置 cache_dir

llm_config = LLMConfig(
    ...
    callback_config={
        "callback_class": "ray.llm._internal.common.callbacks.cloud_downloader.CloudDownloader",
        "callback_kwargs": {"paths": [("s3://samplebucket/llama-3-8b-cache", "/home/ray/.cache/vllm/torch_compile_cache/llama-3-8b-cache")]},
    },
    engine_kwargs={
        "tensor_parallel_size": 1,
        "compilation_config": {
            "cache_dir": "/home/ray/.cache/vllm/torch_compile_cache/llama-3-8b-cache",
        }
    },
    ...
)

检索编译缓存的其他选项(分布式文件系统、块存储)也可以使用,只要将缓存路径设置在 compilation_config 中即可。

自定义初始化行为#

我们提供了通过 CallbackBase 定义的 API 来创建自定义节点初始化行为的能力。该类中定义的 callback 函数会在初始化过程的特定部分被调用。一个例子是上面提到的 CloudDownloader,它会重写 on_before_download_model_files_distributed 函数,将下载任务分布到各个节点。要启用您的自定义 callback,请在 LLMConfig 中指定类名。

from user_custom_classes import CustomCallback
config = LLMConfig(
    ...
    callback_config={
        "callback_class": CustomCallback, 
        # or use string "user_custom_classes.CustomCallback"
        "callback_kwargs": {"kwargs_test_key": "kwargs_test_value"},
    },
    ...
)

注意: Callbacks 是一个新功能。随着我们继续开发此功能,我们可能会更改 callback API 并整合用户反馈。

最佳实践#

模型来源选择#

  • 使用 Hugging Face 获取公开可用的模型和快速原型开发。

  • 使用远程存储存储私有模型、自定义微调模型,或在与计算资源共置时使用。

  • 启用快速下载以从 Hugging Face 下载大型模型。

安全性#

  • 切勿将令牌提交到版本控制。使用环境变量或秘密管理。

  • 在 AWS 上进行生产部署时,请使用 IAM 角色而不是访问密钥。

  • 将权限范围限定为只读访问以加载模型。

性能#

  • 将存储和计算资源共置于同一云区域,以减少延迟和出口成本。

  • 对于大于 10GB 的模型,使用快速下载HF_HUB_ENABLE_HF_TRANSFER)。

  • 如果您反复部署相同的模型,请将模型缓存在本地。

  • 请参见基准测试此处,了解有关优化的详细信息。

故障排除#

从 Hugging Face 下载速度慢#

  • 安装 hf_transferpip install hf_transfer

  • runtime_env 中设置 HF_HUB_ENABLE_HF_TRANSFER=1

  • 考虑将模型移动到您云区域中的 S3/GCS 并使用 RunAI Streamer,并对大型模型使用分片。

S3/GCS 访问错误#

  • 验证存储桶 URI 格式(例如,s3://bucket/pathgs://bucket/path)。

  • 检查 AWS/GCP 凭证和区域是否已正确配置。

  • 确保您的 IAM 角色或服务账户具有 s3:GetObjectstorage.objects.get 权限。

  • 验证存储桶是否存在且可从您的部署区域访问。

未找到模型文件#

  • 验证模型结构是否与 Hugging Face 格式匹配(必须包含 config.json、分词器文件和模型权重)。

  • 检查存储桶中是否包含所有必需文件。

另请参阅#