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

关于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

text 复制代码
sm_120 -> major = 12, minor = 0 -> Compute Capability 12.0

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

bash 复制代码
$ 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 容器中执行:

bash 复制代码
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

text 复制代码
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、H100 deploy/paddleocr_vl_docker/accelerators/nvidia-gpu/ 常规 NVIDIA GPU Compose;vLLM 要求 Compute Capability >= 8.0
7.x;例如 T4、V100 不建议使用默认 vLLM Compose 官方提示 vLLM 容易超时或 OOM;选择 PaddlePaddle 本地推理或手工服务部署
无 NVIDIA GPU CPU 手工部署 不使用 NVIDIA GPU Docker Compose
需要 Triton 动态批处理和高并发,且 Compute Capability >= 8.0< 10.0 deploy/paddleocr_vl_docker/hps/ HPS 架构;需要确认 HPS 基础镜像中的 PaddlePaddle 支持该显卡架构

本机的选择结论

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

text 复制代码
deploy/paddleocr_vl_docker/accelerators/nvidia-gpu-sm120/
bash 复制代码
# ls -a accelerators/nvidia-gpu-sm120
.  ..  compose.yaml  .env  pipeline.Dockerfile  vllm_config.yaml  vlm.Dockerfile

对应的镜像标签为:

text 复制代码
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-server vLLM VLM 推理服务 8080 默认不暴露
paddleocr-vl-api 完整 PaddleOCR-VL 流水线,含版面检测、阅读顺序和 VLM 调用 8080 8080

数据流:

text 复制代码
客户端 -> paddleocr-vl-api:8080 -> paddleocr-vlm-server:8080

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

vLLM 显存异常说明

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

text 复制代码
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,添加如下参数,需根据实际情况修改。

bash 复制代码
gpu-memory-utilization: 0.12

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

bash 复制代码
#!/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的挂载

bash 复制代码
  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 版本:

bash 复制代码
nvidia-smi

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

获取官方Compose 文件

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

bash 复制代码
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 镜像标签:

dotenv 复制代码
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

yaml 复制代码
gpu-memory-utilization: 0.18

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

yaml 复制代码
  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

启动服务

bash 复制代码
cd /root/paddleocr-sm120
docker compose up -d
docker compose ps
bash 复制代码
# 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

检查日志:

bash 复制代码
docker compose logs -f paddleocr-vlm-server

docker compose logs -f paddleocr-vl-api

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

text 复制代码
Uvicorn running on http://0.0.0.0:8080

服务验证

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

bash 复制代码
curl -i http://<server-ip>:8080/health

验证底层 vLLM 容器:

bash 复制代码
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字符串。

bash 复制代码
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
0 PDF

Python调用

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")

响应结构

成功响应的顶层字段:

json 复制代码
{
  "logId": "...",
  "errorCode": 0,
  "errorMsg": "Success",
  "result": {
    "layoutParsingResults": [],
    "dataInfo": {}
  }
}

常用结果字段:

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

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

常用请求参数

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

参数 类型 作用 使用建议
file string 必填,输入 URL 或 Base64 必填
fileType integer 0 PDF,1 图片/TIFF Base64 输入时建议显式提供
visualize boolean 返回可视化和中间图片 日常调用设为 false
returnMarkdownImages boolean 返回 Markdown 图片数据 无需图片时设为 false
useDocOrientationClassify boolean 文档方向分类 扫描件方向不确定时启用
useDocUnwarping boolean 文档去弯曲/矫正 拍照、变形文档时启用
useLayoutDetection boolean 版面检测与阅读顺序 多栏、表格、公式文档保持 true
useChartRecognition boolean 图表解析 需要识别图表时启用
useSealRecognition boolean 印章识别 需要印章内容时启用
useOcrForImageBlock boolean 对图片块内部文字 OCR 图文混排且图片内有文字时启用
layoutThreshold number/object 版面检测阈值 仅在漏检或误检时调优
layoutNms boolean 版面框 NMS 一般使用默认值
layoutUnclipRatio number/array/object 版面框扩展比例 一般使用默认值
layoutShapeMode string 版面区域几何类型 可选 rectquadpolyauto
temperature number VLM 采样温度 文档解析建议 0
topP number VLM top-p 采样参数 一般使用默认值
repetitionPenalty number 重复惩罚 输出重复时调整
minPixels integer VLM 图片最小像素数 一般使用默认值
maxPixels integer VLM 图片最大像素数 超大图片显存紧张时调低
maxNewTokens integer 最大输出 token 数 长文档输出被截断时调高
prettifyMarkdown boolean 美化 Markdown 默认可保持 true
showFormulaNumber boolean 在 Markdown 中保留公式编号 按需开启
restructurePages boolean 多页 PDF 结果重组 多页 PDF 建议开启
mergeTables boolean 跨页表格合并 restructurePages: true 时生效
relevelTitles boolean 重建多级标题 restructurePages: true 时生效
outputFormats array 附加导出格式 当前可使用 ["docx"]

推荐图片请求

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

推荐 PDF 请求

json 复制代码
{
  "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 中增加端口映射:

yaml 复制代码
ports:
  - "127.0.0.1:8118:8080"

验证:

bash 复制代码
curl http://127.0.0.1:8118/v1/models

CURL调用

bash 复制代码
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

bash 复制代码
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()
相关推荐
众人皆醒我独醉2 小时前
分布式训练与 Ring AllReduce:从单卡绝望到多卡协同
人工智能·面试·llm
Ghost Face...2 小时前
龙芯Docker全流程:安装到离线迁移实战
java·docker·eureka
熊猫钓鱼>_>5 小时前
AI 3D 虚拟盲盒工坊:用腾讯云混元3D + TTS Skills 打造会说话的三维收藏品
人工智能·大模型·llm·agent·tts·混元3d·多skill协同
JavaPub-rodert5 小时前
我又把自己的 Go 后台管理系统升级了一遍:文件管理、2GB 上传、私有文件预览、Docker 镜像全安排上了
开发语言·docker·golang·shiyuadmin
爱码少年6 小时前
嗯,腾讯云个人小站Docker镜像下载功能已下线,压力给到阿里云镜像站
docker
Zhu7586 小时前
在docker环境部署frp
运维·docker·容器
做前端的娜娜子6 小时前
第二个 AI 调用——invoke 阻塞式与 stream 流式生成
人工智能·llm·掘金·金石计划
想要成为糕糕手7 小时前
🐎 从“幻觉”到“可控”:手把手构建一个 LLM 自优化流水线 Harness
前端·llm·agent
艺杯羹8 小时前
LLM越狱与安全护栏攻防大演进:从奶奶漏洞到输入输出双重检测模型
网络·安全·网络安全·ai·llm·大语言模型·ai安全