概述: 本文介绍如何在阿里云 EMR Serverless Ray 集群上,使用 Ray Serve LLM 部署 Qwen3.5 系列模型,并通过 Ray Data 的 ai_query API 实现集群内高吞吐批量推理。其他自建模型可按同样的方式提供模型服务
适用场景:
- 大规模文本标注、分类、摘要等离线批量推理任务
- RAG 管道中的批量生成环节
- 模型评估与数据合成
架构设计

核心组件说明
Ray Serve LLM(模型服务层)
Ray Serve LLM 是 Ray 引入的高层 LLM 部署 API。它在内部编排了以下组件:
-
OpenAI Ingress:HTTP 入口,提供
/v1/chat/completions、/v1/models等标准端点,内置 SSE streaming 和 token 用量统计。 -
LLMServer:编排层,管理推理引擎生命周期(加载配置转换、引擎启停),将请求路由到 EngineCore。
-
vLLM EngineCore:运行在 GPU 节点上的推理引擎 Worker,负责模型加载、KV Cache 管理和 continuous batching。
-
CompiledDAG(通信机制):在 LLMServer 与 EngineCore 之间建立零拷贝 IPC 通道(共享内存/NCCL),绕过常规 Ray task 调度的序列化和 GCS 查找开销。
请求路径:HTTP → OpenAiIngress → LLMServer → (CompiledDAG) → EngineCore
这种分层设计使得模型服务可以独立扩缩(通过autoscaling_config),而 Ingress 层自动负载均衡。
Ray Data ai_query(批量推理层)
ray.data.ai.ai_query是 Ray Data 提供的声明式批量推理 API:
-
将数据集按
batch_size分片,分发给concurrency个 Actor 并行处理 -
每个 Actor 内部使用 OpenAI SDK 异步并发请求模型服务
-
内置 AIMD(加性增/乘性减)流控算法,根据服务端响应延迟动态调节并发度
-
自动处理请求失败重试和 Actor 故障恢复
两层解耦的好处是:模型服务的副本数和推理任务的并发数可以独立调优,互不影响。
前置条件
| 项目 | 要求 |
|---|---|
| EMR Serverless Ray 集群 | err-1.3.0(ray llm镜像) |
| GPU 节点 | 至少 1 张 A10/A100/V100等 |
| 模型 | Qwen3.5 系列,可放在OSS上挂载到集群可访问路径(如/mnt/Qwen3.5-4B) |
| Python 依赖 | 无,镜像已涵盖 |
步骤一:部署模型服务
1.1 编写模型配置
创建serve_app.py:
python
from ray.serve.llm import LLMConfig, build_openai_app
llm_config = LLMConfig(
model_loading_config=dict(
model_id="Qwen3.5-4B",
model_source="/mnt/Qwen3.5-4B", # 集群上的模型路径(需集群启动时挂载)
),
deployment_config=dict(
ray_actor_options={"num_cpus": 1},
),
engine_kwargs=dict(
trust_remote_code=True,
tensor_parallel_size=1,
gpu_memory_utilization=0.9,
max_model_len=4096,
),
)
app = build_openai_app({"llm_configs": [llm_config]})
重要: ray_actor_options 中不要设置 num_gpus。Ray Serve LLM 内部的 vLLM EngineCore 会根据 tensor_parallel_size 自动申请 GPU 资源。如果同时设置了 num_gpus,两者会相加,导致单卡集群因资源不足而无法调度。
1.2 编写 Serve 配置
创建serve_config.yaml:
makefile
http_options:
host: 0.0.0.0
port: 8000
applications:
- name: default
import_path: serve_app:app
route_prefix: /
1.3 提交部署
python
from ray.job_submission import JobSubmissionClient
client = JobSubmissionClient(
"https://<your-gateway>",
headers={"ray-token": "<your-token>"},
)
job_id = client.submit_job(
entrypoint="serve run serve_config.yaml",
runtime_env={"working_dir": "."}, # 打包上传 serve_app.py / serve_config.yaml
)
部署成功后,集群内可通过http://<head-node-ip>:8000/v1访问 OpenAI 兼容 API。
1.4 验证服务
nginx
ray job submit -- python -c "
from openai import OpenAI
client = OpenAI(base_url='http://<head-node-ip>:8000/v1', api_key='dummy')
resp = client.chat.completions.create(
model='Qwen3.5-4B',
messages=[{'role': 'user', 'content': '你好'}],
max_tokens=64,
)
print(resp.choices[0].message.content)
"
步骤二:批量推理
2.1 基本用法
python
import ray
import ray.data.ai # 注册 .ai accessor
ray.init()
# 构造数据集(实际场景中可从 OSS/HDFS/数据库读取)
ds = ray.data.from_items([
{"text": "解释什么是分布式计算"},
{"text": "比较 MapReduce 和 Spark 的优劣"},
# ... 更多数据
])
result_ds = ds.ai.ai_query(
"Qwen3.5-4B", # 模型 ID(与 LLMConfig 中一致)
prompt_col="text", # 输入列
base_url="http://<serve-nlb-ip>:8000/v1", # 模型服务地址
api_key="dummy",
output_col="generated_text", # 输出列
options={
"temperature": 0.7,
"max_tokens": 256,
"extra_body": {
"chat_template_kwargs": {"enable_thinking": False}
},
},
concurrency=32, # 推理 Actor 数量
batch_size=8, # 每个 Actor 的异步并发度
)
# 消费结果
for row in result_ds.iter_rows():
print(row["generated_text"]["content"])
2.2 Qwen3.5 Thinking 模式控制
Qwen3.5 系列支持"思考模式"(thinking),模型会先输出推理链再给出最终答案。在批量推理场景中,关闭 thinking 可以大幅减少 token 消耗及节省 GPU 资源,同时提高吞吐。
传参方式因服务端而异:
| 服务端 | 写法 |
|---|---|
| 自建 vLLM(本文方案) | "extra_body": {"chat_template_kwargs": {"enable_thinking": False}} |
| ray ai_query内置模型 | "enable_thinking": False直接放 options |
2.3 结果写入外部存储
php
# 写入 Parquet(OSS)
result_ds.write_parquet("oss://<bucket>/inference_results/")
# 或逐行处理
result_ds.map_batches(
lambda batch: [post_process(row) for row in batch],
batch_format="pandas",
).write_parquet(...)
性能调优
关键参数
| 参数 | 作用 | 调优建议 |
|---|---|---|
concurrency |
推理 Actor 数量,每个占 1 CPU | 设为集群可用 CPU 数的 50%~70% |
batch_size |
每个 Actor 内部的异步并发请求数 | 按需调整 |
max_tokens |
最大生成 token 数 | 按业务需要设置,越小吞吐越高 |
enable_thinking |
是否开启思考模式 | 批量场景建议关闭 |
gpu_memory_utilization |
vLLM KV Cache 显存占比 | 0.9(单模型部署时) |
总结
通过 EMR Serverless Ray + Ray Serve LLM + Ray Data ai_query 的组合,可以在 10 行代码内完成 Qwen 模型的生产级部署,并以声明式 API 实现高吞吐批量推理。上述方案也再次验证ServerlessRay以下价值:
-
极简部署:Ray极简API 封装了 vLLM 引擎管理、OpenAI 协议适配和 streaming 支持
-
自动流控:Serverless Ray AIMD 算法动态调节并发,无需手动调参即可逼近硬件极限
-
架构解耦:模型服务与推理管道独立扩缩,适配从单机到多节点的弹性需求
-
生态兼容:标准 OpenAI API 接口,可无缝对接现有 OpenAI SDK 生态