关于PaddleOCR-VL部署与使用说明

161 阅读7分钟

关于PaddleOCR-VL部署与使用说明

起因是要做一个关于票据OCR识别+LLM的综合应用,在部署PaddleOCR-VL时踩了不少坑,主要是因为GPU显存、计算等级、CUDA版本、选择的部署方案等多维度导致,特此记录。

分享基于NVIDIA RTX PRO 6000 Blackwell (sm_120) 部署 PaddleOCR-VL-1.6 的完整过程与接口调用方法,仅供参考。

参考资料

根据显卡选择部署方案

部署方案说明

访问PaddleOCR项目deploy目录,该目录包含多种部署方案。这里采用Docker部署,因此关注paddleocr_vl_docker目录,其中存放了基于docker不同环境的部署方案

在这里插入图片描述

选择 paddleocr_vl_docker 下的部署方案时,先确认两件事:

  1. GPU 的 CUDA Compute Capability(计算能力),例如 8.69.012.0
  2. 是否需要 HPS 的 Triton 动态批处理和高并发架构。

已验证当前显卡不支持HPS部署,因此不能选择HPS方式部署。应选择nvidia-gpu-sm120方式进行部署

需特别说明的一点是:nvidia-gpu-sm120/.env中提到的镜像标签,其中 sm_120 是 CUDA 编译目标,表示 Compute Capability 12.0

sm_120 -> major = 12, minor = 0 -> Compute Capability 12.0

它不是 CUDA Toolkit 版本,也不是显存容量。例如 nvidia-smi 顶部显示的 CUDA Version: 13.2 表示当前 NVIDIA 驱动最高支持的 CUDA 运行时版本,不能用于判断应选择 sm_120 还是普通 GPU 镜像。

$ nvidia-smi
Wed Aug 12 09:41:06 2026       
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 595.91.07              Driver Version: 595.91.07      CUDA Version: 13.2     |
+-----------------------------------------+------------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA RTX PRO 6000 Blac...    Off |   00000000:16:00.0 Off |                  Off |
| 30%   30C    P8              6W /  600W |   88712MiB /  97887MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

查看 Compute Capability

nvidia-smi 默认不显示 Compute Capability,可通过以下2种方式查看。

1.运行时检查方式:在已部署的 vLLM 容器中执行:

docker exec paddleocr-vlm-server python -c "import torch; print(torch.cuda.get_device_name(0)); print(torch.cuda.get_device_capability(0))"

当前机器预期输出如下,其中 (12, 0)sm_120

NVIDIA RTX PRO 6000 Blackwell Workstation Edition
(12, 0)

2.按照显卡型号在 NVIDIA 的 CUDA GPU Compute Capability 列表 中查询。

在这里插入图片描述

PaddleOCR-VL 部署选择

针对 PaddleOCR 当前仓库中的 PaddleOCR-VL Docker 部署目录。选择前还需确认官方所要求的 NVIDIA 驱动、Docker 和 CUDA 版本。

GPU Compute Capability推荐目录或方式说明
12.0,即 sm_120;例如 RTX PRO 6000 Blackwell、RTX 50 系列deploy/paddleocr_vl_docker/accelerators/nvidia-gpu-sm120/使用 SM120 专用镜像,标签必须包含 -sm120
8.x9.x;例如 RTX 30/40、A10、A100、H100deploy/paddleocr_vl_docker/accelerators/nvidia-gpu/常规 NVIDIA GPU Compose;vLLM 要求 Compute Capability >= 8.0
7.x;例如 T4、V100不建议使用默认 vLLM Compose官方提示 vLLM 容易超时或 OOM;选择 PaddlePaddle 本地推理或手工服务部署
无 NVIDIA GPUCPU 手工部署不使用 NVIDIA GPU Docker Compose
需要 Triton 动态批处理和高并发,且 Compute Capability >= 8.0< 10.0deploy/paddleocr_vl_docker/hps/HPS 架构;需要确认 HPS 基础镜像中的 PaddlePaddle 支持该显卡架构

本机的选择结论

本机显卡为 NVIDIA RTX PRO 6000 Blackwell Workstation Edition,运行时 Compute Capability 是 12.0,因此必须使用:

deploy/paddleocr_vl_docker/accelerators/nvidia-gpu-sm120/
# ls -a accelerators/nvidia-gpu-sm120
.  ..  compose.yaml  .env  pipeline.Dockerfile  vllm_config.yaml  vlm.Dockerfile

对应的镜像标签为:

API_IMAGE_TAG_SUFFIX=latest-nvidia-gpu-sm120-offline
VLM_BACKEND=vllm
VLM_IMAGE_TAG_SUFFIX=latest-nvidia-gpu-sm120-offline

架构与端口

正确的 sm120 Compose 方案包含两个容器:

容器职责容器端口宿主机端口
paddleocr-vlm-servervLLM VLM 推理服务8080默认不暴露
paddleocr-vl-api完整 PaddleOCR-VL 流水线,含版面检测、阅读顺序和 VLM 调用80808080

数据流:

客户端 -> paddleocr-vl-api:8080 -> paddleocr-vlm-server:8080

paddleocr-vl-api 是完整 OCR 服务,使用 /layout-parsing。它不是 OpenAI API,因此访问 /v1/models 会返回 404

vLLM 显存异常说明

部署过程中需要特别注意的是vLLM 显存异常,例如 vLLM 启动错误:

Free memory on device (26.34/94.97 GiB) on startup is less than desired GPU memory utilization (0.5, 47.49 GiB)

含义如下:

  • GPU 总显存约 94.97 GiB
  • 当时可用显存约 26.34 GiB
  • 默认 gpu-memory-utilization: 0.5 需要约 47.49 GiB,因此 vLLM 拒绝启动。

基于HPS方案部署特别说明

访问HPS目录,其中README.md有提及如何部署,按照文档部署问题不大,但无关于VLLM显存调整的说明,可参考以下步骤完成HPS部署方案的VLLM显存配置。

1.基于hps/compose.yaml同级路径,创建vllm_config.yaml,添加如下参数,需根据实际情况修改。

gpu-memory-utilization: 0.12

2.编辑genai_server_entrypoint.sh,添加VLLM_CONFIG变量与--backend_config参数,用于指定vllm配置,手动分配显存分配。

#!/usr/bin/env sh

set -eu

CONFIG="${PIPELINE_CONFIG:-/config/pipeline_config.yaml}"
VLLM_CONFIG="${VLLM_CONFIG:-/config/vllm_config.yaml}"

VLM_NAME=$(
    grep -A5 'module_name: vl_recognition' "$CONFIG" \
        | grep 'model_name:' \
        | head -1 \
        | awk '{print $2}'
)

if [ -z "$VLM_NAME" ]; then
    echo "Failed to read VLM name from ${CONFIG}" >&2
    exit 1
fi

exec paddleocr genai_server \
    --model_name "$VLM_NAME" \
    --host 0.0.0.0 \
    --port 8080 \
    --backend vllm \
    --backend_config "$VLLM_CONFIG" 

3.修改hps/compose.yaml,添加vllm_config.yaml的挂载

  paddleocr-vlm-server:
    image: ccr-2vdh3abv-pub.cnc.bj.baidubce.com/paddlepaddle/paddleocr-genai-vllm-server:latest-nvidia-gpu
    container_name: paddleocr-vlm-server
    volumes:
      - ./${HPS_SDK_DIR:-paddlex_hps_PaddleOCR-VL-1.6_sdk}/server/pipeline_config.yaml:/config/pipeline_config.yaml:ro
      - ./genai_server_entrypoint.sh:/entrypoint.sh:ro
      - ./vllm_config.yaml:/config/vllm_config.yaml:ro

部署

前置条件

  • NVIDIA RTX Blackwell 架构 GPU,例如 RTX PRO 6000 Blackwell。
  • NVIDIA 驱动支持 CUDA 12.9 或更高版本。
  • Docker 19.03 或更高版本。
  • Docker Compose 2.x

检查驱动支持的 CUDA 版本:

nvidia-smi

输出顶部的 CUDA Version 应为 12.9 或更高。

获取官方Compose 文件

创建目录并下载Compose、env文件

mkdir -p /root/paddleocr-sm120
cd /root/paddleocr-sm120

curl -fsSL -o compose.yaml https://raw.githubusercontent.com/PaddlePaddle/PaddleOCR/main/deploy/paddleocr_vl_docker/accelerators/nvidia-gpu-sm120/compose.yaml
curl -fsSL -o .env https://raw.githubusercontent.com/PaddlePaddle/PaddleOCR/main/deploy/paddleocr_vl_docker/accelerators/nvidia-gpu-sm120/.env

.env 必须使用 SM120 镜像标签:

API_IMAGE_TAG_SUFFIX=latest-nvidia-gpu-sm120-offline
VLM_BACKEND=vllm
VLM_IMAGE_TAG_SUFFIX=latest-nvidia-gpu-sm120-offline

说明:

  • -offline 镜像包含模型,首次拉取较大,但启动不依赖模型下载。
  • 有网络且希望首次启动时下载模型时,可去掉两个标签中的 -offline
  • 无论是否使用离线镜像,两个标签都必须保留 -sm120

配置vLLM显存使用量

需要根据实际情况配置vLLM显存使用量,默认使用显存50%是不合理的,具体操作方式是:在Compose文件所在目录创建 vllm_config.yaml

gpu-memory-utilization: 0.18

compose.yamlpaddleocr-vlm-server 服务中,加入 volumescommand。保留其原有的配置:

  paddleocr-vlm-server:
    image: ccr-2vdh3abv-pub.cnc.bj.baidubce.com/paddlepaddle/paddleocr-genai-${VLM_BACKEND}-server:${VLM_IMAGE_TAG_SUFFIX}
    container_name: paddleocr-vlm-server
	volumes:
      - ./vllm_config.yaml:/home/paddleocr/vlm_server_config.yaml:ro
    command:
      - paddleocr
      - genai_server
      - --model_name
      - PaddleOCR-VL-1.6-0.9B
      - --host
      - 0.0.0.0
      - --port
      - "8080"
      - --backend
      - vllm
      - --backend_config
      - /home/paddleocr/vlm_server_config.yaml

启动服务

cd /root/paddleocr-sm120
docker compose up -d
docker compose ps
# docker compose ps
NAME                   IMAGE                                                                                                           COMMAND                   SERVICE                CREATED        STATUS                  PORTS
paddleocr-vl-api       ccr-2vdh3abv-pub.cnc.bj.baidubce.com/paddlepaddle/paddleocr-vl:latest-nvidia-gpu-sm120-offline                  "/bin/bash -c 'paddl…"   paddleocr-vl-api       17 hours ago   Up 17 hours (healthy)   0.0.0.0:8080->8080/tcp, [::]:8080->8080/tcp
paddleocr-vlm-server   ccr-2vdh3abv-pub.cnc.bj.baidubce.com/paddlepaddle/paddleocr-genai-vllm-server:latest-nvidia-gpu-sm120-offline   "paddleocr genai_ser…"   paddleocr-vlm-server   17 hours ago   Up 17 hours (healthy)   8080/tcp

检查日志:

docker compose logs -f paddleocr-vlm-server

docker compose logs -f paddleocr-vl-api

成功后,paddleocr-vl-api 会出现:

Uvicorn running on http://0.0.0.0:8080

服务验证

paddleocr-vl-api的健康检查接口如下,应返回 HTTP 200

curl -i http://<server-ip>:8080/health

验证底层 vLLM 容器:

docker exec paddleocr-vlm-server curl -i http://127.0.0.1:8080/health

OCR API使用

Docs信息

访问http://IP:8080/docs查看接口文档信息 在这里插入图片描述

接口作用何时调用
GET /health存活检测。确认 API 容器进程正在运行。 Docker 健康检查、负载均衡探针、部署验证。
POST /layout-parsing核心 OCR 接口。对图片/PDF 做版面检测、阅读顺序分析、文字/表格/公式识别,并返回 Markdown与结构化结果。每次提交新的票据、图片或 PDF 时调用。
POST /restructure-pages对已完成的多页解析结果做跨页重组,例如合并跨页表格、重建多级标题、拼接多页 Markdown。多页 PDF 的第二步。单张票据通常不需要。

API调用

这里调用/layout-parsing接口,该接口是完整的 PaddleOCR-VL 流水线,不采用 OpenAI 的 messages 请求格式。

file 可以是服务端能够访问的文件 URL,或图片、PDF内容的Base64字符串。

curl -sS -X POST "http://<server-ip>:8080/layout-parsing" \
  -H "Content-Type: application/json" \
  -d '{
    "file": "https://paddle-model-ecology.bj.bcebos.com/paddlex/imgs/demo_image/paddleocr_vl_demo.png",
    "fileType": 1
  }' 

fileType 的取值:

含义
1图片或 TIFF
0PDF

Python调用

import base64
from pathlib import Path

import requests

file_path = Path("./demo.jpg")

# 对本地图像进行Base64编码
with open(file_path, "rb") as file:
    image_bytes = file.read()
    image_data = base64.b64encode(image_bytes).decode("ascii")


payload = {
    "file": image_data,
    "fileType": 1,
    "visualize": False,
    "returnMarkdownImages": False
}

response = requests.post(
    "http://IP:8080/layout-parsing",
    json=payload,
    timeout=600,
)
response.raise_for_status()

page = response.json()
Path("result.md").write_text(str(page), encoding="utf-8")

响应结构

成功响应的顶层字段:

{
  "logId": "...",
  "errorCode": 0,
  "errorMsg": "Success",
  "result": {
    "layoutParsingResults": [],
    "dataInfo": {}
  }
}

常用结果字段:

字段说明
markdown.text可直接保存为 .md 的文本结果
prunedResult结构化识别结果
outputImages可视化/中间图片,默认可能为 Base64
inputImage输入图片,默认可能为 Base64
markdown.imagesMarkdown 引用图片的 Base64 映射
exports.docx.content请求 DOCX 导出时的 Base64 文件内容

visualize: falsereturnMarkdownImages: false 可以减少图片 Base64 数据。部分镜像版本仍可能返回图片字段,因此客户端应优先读取 markdown.textprunedResult

常用请求参数

仅发送实际需要的参数。没有特殊需求时,保留默认值通常更稳定。

参数类型作用使用建议
filestring必填,输入 URL 或 Base64必填
fileTypeinteger0 PDF,1 图片/TIFFBase64 输入时建议显式提供
visualizeboolean返回可视化和中间图片日常调用设为 false
returnMarkdownImagesboolean返回 Markdown 图片数据无需图片时设为 false
useDocOrientationClassifyboolean文档方向分类扫描件方向不确定时启用
useDocUnwarpingboolean文档去弯曲/矫正拍照、变形文档时启用
useLayoutDetectionboolean版面检测与阅读顺序多栏、表格、公式文档保持 true
useChartRecognitionboolean图表解析需要识别图表时启用
useSealRecognitionboolean印章识别需要印章内容时启用
useOcrForImageBlockboolean对图片块内部文字 OCR图文混排且图片内有文字时启用
layoutThresholdnumber/object版面检测阈值仅在漏检或误检时调优
layoutNmsboolean版面框 NMS一般使用默认值
layoutUnclipRationumber/array/object版面框扩展比例一般使用默认值
layoutShapeModestring版面区域几何类型可选 rectquadpolyauto
temperaturenumberVLM 采样温度文档解析建议 0
topPnumberVLM top-p 采样参数一般使用默认值
repetitionPenaltynumber重复惩罚输出重复时调整
minPixelsintegerVLM 图片最小像素数一般使用默认值
maxPixelsintegerVLM 图片最大像素数超大图片显存紧张时调低
maxNewTokensinteger最大输出 token 数长文档输出被截断时调高
prettifyMarkdownboolean美化 Markdown默认可保持 true
showFormulaNumberboolean在 Markdown 中保留公式编号按需开启
restructurePagesboolean多页 PDF 结果重组多页 PDF 建议开启
mergeTablesboolean跨页表格合并restructurePages: true 时生效
relevelTitlesboolean重建多级标题restructurePages: true 时生效
outputFormatsarray附加导出格式当前可使用 ["docx"]

推荐图片请求

{
  "file": "https://example.com/document.png",
  "fileType": 1,
  "visualize": false,
  "returnMarkdownImages": false,
  "useLayoutDetection": true,
  "temperature": 3
}

推荐 PDF 请求

{
  "file": "https://example.com/document.pdf",
  "fileType": 0,
  "visualize": false,
  "returnMarkdownImages": false,
  "restructurePages": true,
  "mergeTables": true,
  "relevelTitles": true,
  "temperature": 3
}

OpenAI兼容的底层vLLM接口

完整OCR服务没有官方的 /v1/chat/completions 接口。若只需要访问底层 VLM,可在 paddleocr-vlm-server 中增加端口映射:

ports:
  - "127.0.0.1:8118:8080"

验证:

curl http://127.0.0.1:8118/v1/models

CURL调用

curl http://IP:8118/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "PaddleOCR-VL-1.6-0.9B",
    "messages": [
      {
        "role": "user",
        "content": [
          {
            "type": "image_url",
            "image_url": {
              "url": "https://paddle-model-ecology.bj.bcebos.com/paddlex/imgs/demo_image/paddleocr_vl_demo.png"
            }
          },
          {
            "type": "text",
            "text": "OCR:"
          }
        ]
      }
    ],
    "temperature": 0.0,
    "max_tokens": 16000
  }'

此接口可供 OpenAI SDK 使用,但它只执行 VLM 推理,不包含完整的版面检测、裁切、阅读顺序和结果整合。复杂页面、表格和多栏文档应优先调用 /layout-parsing

Python调用

具体查阅 PaddleOCR-VL-1.6 on Hugging Face

import base64
import mimetypes
from pathlib import Path

from openai import OpenAI


# 将本地图片转换为 OpenAI 多模态接口支持的 Data URL
def local_image_to_data_url(image_path: str) -> str:
    path = Path(image_path)

    if not path.is_file():
        raise FileNotFoundError(f"图片文件不存在: {image_path}")

    # 根据图片扩展名推断 MIME 类型,例如 image/png、image/jpeg
    mime_type, _ = mimetypes.guess_type(str(path))

    if not mime_type or not mime_type.startswith("image/"):
        raise ValueError(f"不支持的图片格式: {path.suffix}")

    # 读取图片并编码为 Base64
    image_base64 = base64.b64encode(path.read_bytes()).decode("utf-8")

    # 拼接为 data URL,发送给 OpenAI 兼容接口
    return f"data:{mime_type};base64,{image_base64}"


# 当前 vLLM 服务地址。
# 如果通过 Docker 映射为宿主机 8118:8080,应使用:
VLLM_BASE_URL = "http://127.0.0.1:8118/v1"

# 从 /v1/models 返回结果中确认实际模型名。
# SM120 官方镜像通常使用这个模型名。
MODEL_NAME = "PaddleOCR-VL-1.6-0.9B"

IMAGE_PATH = "Screenshot 2025-11-13 100012.png"

# 初始化 OpenAI 兼容客户端
client = OpenAI(
    api_key="EMPTY",  # 本地 vLLM 通常不校验 API Key
    base_url=VLLM_BASE_URL,
    timeout=3600,
)

# 根据任务选择提示词
TASKS = {
    "ocr": "OCR:",
    "table": "Table Recognition:",
    "formula": "Formula Recognition:",
    "chart": "Chart Recognition:",
}

task_type = "ocr"
data_url = local_image_to_data_url(IMAGE_PATH)

# 构造多模态消息:
# 一部分是图片,一部分是任务提示词
messages = [
    {
        "role": "user",
        "content": [
            {
                "type": "image_url",
                "image_url": {
                    "url": data_url,
                },
            },
            {
                "type": "text",
                "text": TASKS[task_type],
            },
        ],
    }
]

# stream=True 表示流式返回,需要逐块读取结果
stream = client.chat.completions.create(
    model=MODEL_NAME,
    messages=messages,
    temperature=0,
    stream=True,
)

# 输出模型返回的文本
print("OCR 结果:")

for chunk in stream:
    if not chunk.choices:
        continue

    content = chunk.choices[0].delta.content

    if content:
        print(content, end="", flush=True)

print()