PaddleOCR-VL 高性能服务化部署(HPS):FastAPI 网关 + Triton + vLLM 的三容器并发推理方案
【免费下载链接】PaddleOCRTurn any PDF or image document into structured data for your AI. A powerful, lightweight OCR toolkit that bridges the gap between images/PDFs and LLMs. Supports 100+ languages.项目地址: https://gitcode.com/GitHub_Trending/pa/PaddleOCR
本文基于 PaddleOCR 仓库中 deploy/paddleocr_vl_docker/hps/README.md 撰写,系统讲解 PaddleOCR-VL 系列模型(PaddleOCR-VL、PaddleOCR-VL-1.5、PaddleOCR-VL-1.6)的高稳定性服务化部署(High Performance Serving,HPS)方案:三容器架构的组成与职责、Docker Compose 启动流程、全部环境变量配置项、Triton 动态批处理与实例数的调优权衡,以及故障排查方法。读完本文,你可以直接在 NVIDIA GPU 机器上拉起一套支持并发请求处理的 PaddleOCR-VL 文档解析服务,并针对吞吐或时延目标调整并发、Worker 数与 Triton 批处理参数。
注意:该方案目前只支持 NVIDIA GPU,对其他推理设备的支持仍在完善中;环境要求为 x64 CPU、Compute Capability >= 8.0 且 < 10.0 的 NVIDIA GPU(即 A 系/RTX 系等 Ampere 及以上架构,Blackwell 等 sm_120 平台需另行查阅 docs/version3.x/pipeline_usage/PaddleOCR-VL-NVIDIA-Blackwell.md)、支持 CUDA 12.6 的 NVIDIA 驱动、Docker >= 19.03、Docker Compose >= 2.0。
架构:三个容器各司其职
HPS 方案的请求链路为:
客户端 → FastAPI 网关 → Triton 服务器 → vLLM 服务器| 组件 | 说明 |
|---|---|
| FastAPI 网关 | 统一访问入口、简化客户端调用、并发控制 |
| Triton 服务器 | 运行版面分析模型(如 PP-DocLayoutV3)及产线串联逻辑,负责模型管理、动态批处理、推理调度 |
| vLLM 服务器 | 承载 VLM(视觉语言模型),进行连续批处理推理 |
Triton 服务器内部注册了两个模型:
| 模型 | 设备 | 说明 |
|---|---|---|
layout-parsing | 推理设备(如 GPU) | 版面解析推理 |
restructure-pages | CPU | 多页结果后处理(跨页表格合并、标题层级重分配) |
这个双模型设计是理解整套并发控制策略的钥匙:版面解析是占用 GPU 的重推理操作,而多页重组是纯 CPU 的轻量后处理,二者对资源的需求完全不同,因此网关对它们采用独立的两套并发上限(详见后文"性能调优")。
从源码结构看,方案对 PaddleX 高稳定性服务化部署 SDK 的复用关系在 prepare.sh 中有清晰体现:该脚本从 PaddleX 的发布目录下载对应版本的 SDK 压缩包并解压,SDK 提供 Triton 服务的基础模型仓库(server/目录)与 Python 客户端依赖(client/目录),而 PaddleOCR 在此之上增加了专用的 FastAPI 网关和 vLLM 服务编排。
三个容器与依赖顺序
compose.yaml 定义了三个服务及其启动依赖关系(depends_on+condition: service_healthy,即前序服务健康检查通过后才会启动后序服务):
| 服务 | 说明 | 端口 |
|---|---|---|
paddleocr-vl-api | FastAPI 网关(对外入口) | 8080 |
paddleocr-vl-pipeline | 运行产线的 Triton 推理服务器 | 8000(内部 HTTP 健康检查)、8001(内部 gRPC,供网关调用) |
paddleocr-vlm-server | 基于 vLLM 的 VLM 推理服务 | 8080(内部,不对外发布) |
几个值得注意的编排细节(均可在 compose.yaml 中核对):
paddleocr-vlm-server使用官方镜像paddleocr-genai-vllm-server:latest-nvidia-gpu,将 SDK 中的pipeline_config.yaml与 genai_server_entrypoint.sh 以只读方式挂载进容器;paddleocr-vl-pipeline与paddleocr-vlm-server均通过deploy.resources.reservations.devices绑定同一张 GPU(device_ids由HPS_DEVICE_ID指定,默认 0),即版面分析模型与 VLM 共享同一块推理卡;paddleocr-vl-pipeline设置了shm_size: 4gb,用于 Triton 进程间共享内存;- 三个服务都配置了
healthcheck(curl 探测,间隔 10 秒),其中 VLM 服务的start_period设为 300 秒(VLM 加载耗时较长),Triton 为 60 秒。
VLM 服务容器的入口脚本 genai_server_entrypoint.sh 会先从挂载的pipeline_config.yaml中解析vl_recognition模块对应的model_name,然后执行:
paddleocr genai_server \ --model_name "$VLM_NAME" \ --host 0.0.0.0 \ --port 8080 \ --backend vllm即 vLLM 后端由 PaddleOCR 的genai_server命令统一拉起,网关侧则通过HPS_VLM_URL访问它。
快速开始
- 拉取 PaddleOCR 源码并切换到部署目录:
git clone https://gitcode.com/GitHub_Trending/pa/PaddleOCR cd PaddleOCR/deploy/paddleocr_vl_docker/hps- 准备必要文件:
cp .env.example .env # 按需修改 .env 中的 HPS_PIPELINE_NAME bash prepare.sh- 启动服务:
docker compose up首次启动会自动下载并构建镜像,耗时较长;从第二次启动起将直接使用本地镜像,启动速度更快。
prepare.sh 具体做了什么
prepare.sh 是连接"选择哪个版本"与"容器内容"的关键脚本,其执行逻辑如下:
- 读取
.env(如存在),并以环境变量形式生效,随后对未设置的变量回落到默认值:HPS_PIPELINE_NAME(默认PaddleOCR-VL-1.6)、HPS_PADDLEX_VERSION(默认3.6)、HPS_SDK_DIR(默认paddlex_hps_${HPS_PIPELINE_NAME}_sdk)、HPS_VLM_URL(默认http://paddleocr-vlm-server:8080); - 从 PaddleX 的 SDK 发布目录按
v${HPS_PADDLEX_VERSION}版本号下载paddlex_hps_${HPS_PIPELINE_NAME}_sdk.tar.gz并解压; - 检查 SDK 内
server/pipeline_config.yaml:若vl_recognition模块配置为backend: native,则改写为backend: vllm-server并写入server_url: ${HPS_VLM_URL%/}/v1——这一步把 VLM 推理从"进程内原生推理"切换为"外挂独立 vLLM 服务"; - 从
pipeline_config.yaml中提取 VLM 模型名,校验失败则直接报错退出; - 将最终确定的
HPS_PIPELINE_NAME、HPS_SDK_DIR、HPS_VLM_URL回写进.env,保证后续docker compose up时构建参数与实际下载的 SDK 目录一致。
因此修改产线版本后必须重新执行prepare.sh并重建镜像(例如docker compose build --no-cache后重新docker compose up)。
两个镜像的构建内容
- 网关镜像 gateway.Dockerfile:基于
python:3.10-slim,拷贝 gateway/ 应用代码,并通过 build 参数HPS_SDK_DIR把 SDK 的client/目录绑定进构建上下文,安装requirements.txt、SDK 客户端依赖以及paddlex_hps_client-*.whl客户端包;容器最终以uvicorn --host 0.0.0.0 --port 8080 --workers ${HPS_UVICORN_WORKERS} app:app启动。 - 产线镜像 pipeline.Dockerfile:以
paddlex/hps:paddlex${HPS_PADDLEX_VERSION}-gpu为基座镜像,把 SDK 的server/目录拷入/app并执行server.sh启动 Triton。
两个镜像都通过HPS_SDK_DIR构建参数引用同一个 SDK 目录,这就是HPS_SDK_DIR必须与HPS_PIPELINE_NAME严格对应(paddlex_hps_${HPS_PIPELINE_NAME}_sdk)的原因——目录名对不上,构建阶段就会找不到 SDK 文件。
配置说明:环境变量全表
复制 .env.example 为.env后按需修改:
cp .env.example .env除了通过.env文件设置,也可以直接设置环境变量,如:
export HPS_MAX_CONCURRENT_INFERENCE_REQUESTS=8产线与 SDK 配置
以下变量决定使用 PaddleOCR-VL 系列中的哪个版本(修改后需重新执行prepare.sh并重建镜像):
| 变量 | 默认值 | 说明 |
|---|---|---|
HPS_PIPELINE_NAME | PaddleOCR-VL-1.6 | 产线名称 |
HPS_PADDLEX_VERSION | 3.6 | PaddleX 版本(仅填 major.minor,如3.6),同时决定 Triton 基础镜像标签(paddlex${HPS_PADDLEX_VERSION}-gpu)和 SDK 发布目录(v${HPS_PADDLEX_VERSION}),二者保持一致 |
HPS_SDK_DIR | paddlex_hps_PaddleOCR-VL-1.6_sdk | 解压后的 SDK 目录,须遵循paddlex_hps_${HPS_PIPELINE_NAME}_sdk |
常见配置示例:
| 目标版本 | HPS_PIPELINE_NAME | HPS_SDK_DIR |
|---|---|---|
| PaddleOCR-VL-1.6 | PaddleOCR-VL-1.6 | paddlex_hps_PaddleOCR-VL-1.6_sdk |
| PaddleOCR-VL-1.5 | PaddleOCR-VL-1.5 | paddlex_hps_PaddleOCR-VL-1.5_sdk |
| PaddleOCR-VL (v1) | PaddleOCR-VL | paddlex_hps_PaddleOCR-VL_sdk |
HPS_PADDLEX_VERSION的"双向一致性"体现在 compose.yaml 中:它既是paddleocr-vl-pipeline的基座镜像标签.../hps:paddlex3.6-gpu,也是prepare.sh下载 SDK 时使用的发布目录v3.6,保证 Triton 基础镜像与 SDK 版本配套。
网关与设备配置
| 变量 | 默认值 | 说明 |
|---|---|---|
HPS_MAX_CONCURRENT_INFERENCE_REQUESTS | 16 | 推理操作(版面解析)最大并发请求数 |
HPS_MAX_CONCURRENT_NON_INFERENCE_REQUESTS | 64 | 非推理操作(多页重组)最大并发请求数 |
HPS_INFERENCE_TIMEOUT | 600 | 请求超时时间(秒) |
HPS_HEALTH_CHECK_TIMEOUT | 5 | 健康检查超时时间(秒) |
HPS_VLM_URL | http://paddleocr-vlm-server:8080 | VLM 服务器地址 |
HPS_LOG_LEVEL | INFO | 日志级别(DEBUG, INFO, WARNING, ERROR) |
HPS_FILTER_HEALTH_ACCESS_LOG | true | 是否过滤健康检查的访问日志 |
HPS_UVICORN_WORKERS | 4 | 网关 Worker 进程数 |
HPS_DEVICE_ID | 0 | 使用的推理设备 ID |
这些变量的真实消费点在网关 gateway/app.py 中可以逐一核对:启动时通过os.getenv读取(如HPS_TRITON_URL、HPS_MAX_CONCURRENT_INFERENCE_REQUESTS、HPS_INFERENCE_TIMEOUT等),其中两个并发上限分别初始化为独立的asyncio.Semaphore(见 app.py#L107-L119),并在生命周期结束时关闭 Triton gRPC 异步客户端。HPS_FILTER_HEALTH_ACCESS_LOG的实现是给uvicorn.access日志器挂一个过滤/health字样的logging.Filter,避免探针请求刷满访问日志。.env.example中还给出了 Worker 数的经验值注释:每 CPU 核心建议 2~4 个 Worker。
产线配置调整
如需调整产线相关配置(如模型路径、批处理大小、部署设备等),请参考 PaddleOCR-VL 使用教程 中的产线配置调整说明章节。在 HPS 方案中,产线配置即 SDK 内的${HPS_SDK_DIR}/server/pipeline_config.yaml——prepare.sh的backend改写和 VLM 服务入口的模型名解析都基于该文件,vLLM 服务容器也将其只读挂载到/config/pipeline_config.yaml。
API 使用
文档解析
请参考 PaddleOCR-VL 使用教程 中的客户端调用相关章节。服务支持 PDF 或图像文件(含 TIFF,多页时按页处理);多页 TIFF 请使用fileType=1。
从网关源码看,客户端实际面对的是两个 POST 端点(见 gateway/app.py):
POST /layout-parsing:版面解析推理,受推理信号量(默认 16 并发)约束;POST /restructure-pages:多页重组后处理,受非推理信号量(默认 64 并发)约束。
请求体为 JSON,网关会为其补充/沿用logId用于日志串联,并调用 SDK 提供的triton_request_async转发到对应 Triton 模型。响应采用 AIStudio 标准格式(logId/errorCode/errorMsg+ 结果数据):下游(Triton)返回的errorCode非 0 时,网关原样透传该错误码作为 HTTP 状态码;JSON 解析失败返回 400,参数校验失败返回 422,推理超时(含 gRPC 层 "Deadline Exceeded")返回 504,Triton 未就绪或模型未加载返回 503,其余异常返回 500。
健康检查
# 存活检查 curl http://localhost:8080/health # 就绪检查(验证 Triton 和 VLM 服务是否已准备好处理请求) curl http://localhost:8080/health/ready/health只表示网关进程存活;/health/ready则做完整链路探测(见 app.py#L159-L218):依次检查 Triton 服务器is_server_ready()、两个模型layout-parsing与restructure-pages的is_model_ready(),最后请求 VLM 服务的/health端点,任何一环不通过即返回 503 并说明具体原因(如Model 'layout-parsing' not ready),单项检查超时由HPS_HEALTH_CHECK_TIMEOUT控制。这个端点适合作为负载均衡或 K8s 的就绪探针。
性能调优
并发设置
网关对推理操作和非推理操作各自独立地进行并发控制(两个独立信号量,见前文源码分析):
HPS_MAX_CONCURRENT_INFERENCE_REQUESTS(默认 16):控制layout-parsing(版面解析)等推理操作的并发数- 过低(4):推理设备利用率不足,请求不必要地排队;
- 过高(64):可能导致 Triton 过载,出现 OOM 或超时;
- 默认值 16 允许在当前批次处理时有足够请求排队形成下一批次;
- 如推理设备资源有限,建议适当降低此值。
HPS_MAX_CONCURRENT_NON_INFERENCE_REQUESTS(默认 64):控制restructure-pages(多页重组)等非推理操作的并发数- 非推理操作不占用推理设备资源,可以设置更高的并发数;
- 可根据 CPU 核数和内存情况调整。
高吞吐配置示例:
# .env HPS_MAX_CONCURRENT_INFERENCE_REQUESTS=32 HPS_MAX_CONCURRENT_NON_INFERENCE_REQUESTS=128 HPS_UVICORN_WORKERS=8低延迟配置示例:
# .env HPS_MAX_CONCURRENT_INFERENCE_REQUESTS=8 HPS_MAX_CONCURRENT_NON_INFERENCE_REQUESTS=32 HPS_INFERENCE_TIMEOUT=300 HPS_UVICORN_WORKERS=2Worker 进程数
每个 Uvicorn Worker 是独立的进程,有自己的事件循环(gateway.Dockerfile 中以 shell 形式展开--workers ${HPS_UVICORN_WORKERS}):
- 1 个 Worker:简单,但受限于单进程;
- 4 个 Worker:适合大多数场景;
- 8+ 个 Worker:适用于高并发、大量小请求的场景。
需要注意的是,每个 Worker 进程都会各自维护到 Triton 的 gRPC 连接和独立信号量,因此 Worker 数影响的是网关侧的连接与事件循环规模,而不是 Triton 侧的批处理能力。
Triton 动态批处理
Triton 自动将请求批处理以提高推理设备利用率。最大批处理大小通过模型配置文件中的max_batch_size参数控制(默认:8),配置文件位于模型仓库目录下的config.pbtxt(如model_repo/layout-parsing/config.pbtxt,该文件随 SDK 的server/目录提供,并经由 pipeline.Dockerfile 的COPY ${HPS_SDK_DIR}/server .进入容器)。
Triton 实例数
每个 Triton 模型的并行推理实例数通过config.pbtxt中的instance_group配置(默认:1)。增加实例数可以提高并行处理能力,但会占用更多设备资源:
# model_repo/layout-parsing/config.pbtxt instance_group [ { count: 1 # 实例数,增大可提高并行度 kind: KIND_GPU gpus: [ 0 ] } ]实例数与动态批处理之间存在权衡:
- 单实例(
count: 1):动态批处理会将多个请求合并为一个批次并行执行,但同批次的请求需等待最慢的那个完成后才能一起返回,可能导致部分请求的时延升高。同时,单实例同一时刻只能处理一个批次,当前批次未完成时后续请求只能排队等待。适合显存有限或请求耗时较均匀的场景; - 多实例(
count: 2+):多个实例可以同时各自处理不同的批次,能够同时处理更多请求,减少排队等待时间,单个请求的时延也会有所改善。但需注意,同一实例内的批次仍然遵循动态批处理的行为(批内请求一起开始、一起结束)。每增加一个实例会额外占用一份版面分析模型的显存,同时也会增加对 VLM 推理服务的负载以及内存和 CPU 的使用,需根据推理设备的资源情况酌情设置。
非推理模型(如restructure-pages)运行在 CPU 上,可根据 CPU 核数适当增加实例数。
故障排查与解决
服务无法启动
查看各服务的日志以定位问题:
docker compose logs paddleocr-vl-api docker compose logs paddleocr-vl-pipeline docker compose logs paddleocr-vlm-server常见原因包括端口被占用、推理设备不可用或镜像拉取失败。结合编排细节排查时,可留意两点:一是paddleocr-vl-api依赖paddleocr-vl-pipeline健康、paddleocr-vl-pipeline依赖paddleocr-vlm-server健康,VLM 容器start_period为 300 秒,加载期内的探针失败属正常现象;二是 prepare.sh 若无法从pipeline_config.yaml解析出 VLM 模型名会直接以非零码退出,此时.env不会完成回写,需要检查 SDK 是否下载完整。
超时错误
- 增加
HPS_INFERENCE_TIMEOUT(针对复杂文档); - 如果推理设备过载,减少
HPS_MAX_CONCURRENT_INFERENCE_REQUESTS。
对应到网关行为:超时既包括triton_request_async抛出的asyncio.TimeoutError,也包括 gRPC 的 "Deadline Exceeded" 异常,两者统一映射为 504 Gateway timeout 响应。
内存/显存不足
- 减少
HPS_MAX_CONCURRENT_INFERENCE_REQUESTS; - 确保每个推理设备只运行一个服务(本方案中版面解析与 VLM 默认共同绑定
HPS_DEVICE_ID指定的同一张卡,多实例instance_group会进一步放大显存占用,显存紧张时应优先回调实例数与推理并发); - 检查 compose.yaml 中的
shm_size(默认:4GB,见 compose.yaml#L48)。
小结
PaddleOCR 的 HPS 部署方案把文档解析服务拆分为"网关—产线—VLM"三层:FastAPI 网关负责统一入口与分级并发控制,Triton 承载版面分析与跨页后处理两个模型并通过动态批处理提升 GPU 利用率,vLLM 独立容器专注 VLM 连续批处理推理。版本选择、SDK 下载与产线改写收敛在prepare.sh一个入口中,全部运行时行为由.env中一组带明确默认值的HPS_*变量驱动;在此基础上按吞吐/时延目标调整推理并发、Worker 数、max_batch_size与instance_group,即可在不同显存与并发规模下获得可预期的服务能力。若需扩展到其他硬件平台,可参考同目录 accelerators/ 下各加速器的适配说明。
【免费下载链接】PaddleOCRTurn any PDF or image document into structured data for your AI. A powerful, lightweight OCR toolkit that bridges the gap between images/PDFs and LLMs. Supports 100+ languages.项目地址: https://gitcode.com/GitHub_Trending/pa/PaddleOCR
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考