1. 部署目标

客户内网只提供 PaddleOCR-VL-1.6-0.9B 基础 VLM 推理服务,未提供完整的 PaddleOCR-VL 文档解析流水线和 PP-OCRv6 服务。现场需补齐:

  • PaddleOCR-VL:本地完成版面检测、区域裁剪和结果组装,调用客户 VLM 识别区域内容。

  • PP-OCRv6:本地完成文字检测、文本行方向判断和文字识别,对外提供 /ocr。

本方案已在 Windows 11、Docker Desktop/WSL2 和 RTX 4060 8 GB 环境完成容器启动与接口连通验证。

2. 组件关系

flowchart LR
    backend["DTEmpower SPC 后端"]

    subgraph local["本机 Docker / GPU 0"]
        ppapi["PaddleX 服务<br/>POST /ocr"]
        pp["PP-OCRv6<br/>检测 → 方向判断 → 识别"]
        vlapi["PaddleX 服务<br/>POST /layout-parsing"]
        layout["PP-DocLayoutV3<br/>版面检测"]
        paddle["PaddlePaddle GPU"]
        cuda["CUDA / cuDNN"]
        gpu["RTX 4060"]

        ppapi --> pp --> paddle
        vlapi --> layout --> paddle
        paddle --> cuda --> gpu
    end

    subgraph customer["客户内网"]
        vlm["PaddleOCR-VL-1.6-0.9B<br/>VLM 推理服务"]
    end

    backend -->|"30606"| ppapi
    backend -->|"31606"| vlapi
    layout -->|"区域图片 + 提示词"| vlm
    vlm -->|"识别内容"| vlapi

组件

作用

版本或模型

PaddlePaddle

通过 CUDA/cuDNN 执行本地 GPU 推理

3.2.1 GPU

PaddleOCR

提供 OCR 模型和流水线能力

VL 镜像 3.6.0;PP-OCR 镜像 3.7.0

PaddleX

加载配置、组织流水线并发布 HTTP 服务

VL 3.6.1;PP-OCR 3.7.2

PP-OCRv6

文字检测、方向判断和文字识别

medium det + textline ori + medium rec

PaddleOCR-VL

本地版面分析与远程 VLM 组成的文档解析流水线

流水线 1.6;客户 VLM 0.9B

PP-OCRv6 与 PaddleOCR-VL 相互独立。两者都由 PaddleX 发布服务,并通过 PaddlePaddle 使用本机 GPU;客户 VLM 运行在远程服务,不占用本机显存。

3. 环境与目录

3.1 环境要求

  • Windows 11 + Docker Desktop/WSL2,或 Linux Docker Engine + Compose。

  • NVIDIA GPU 和兼容驱动;Linux 还需 NVIDIA Container Toolkit。

  • 客户 VLM 能从 PaddleOCR-VL 容器访问。

  • 端口 30606、31606 可用。

  • Docker 数据盘至少预留 30 GB。

Windows 无需单独安装 CUDA Toolkit,CUDA/cuDNN 已包含在 GPU 镜像中。

3.2 部署目录

D:\study\work\dainqi\
├─ paddleocr-vl\
│  ├─ compose.yaml
│  └─ pipeline_config.yaml
└─ ppocr-paddlex\
   ├─ .dockerignore
   ├─ Dockerfile
   ├─ compose.yaml
   └─ ocr_config.yaml

服务

容器

宿主机接口

PP-OCRv6

ppocr-api-v6

http://<宿主机IP>:30606/ocr

PaddleOCR-VL

paddleocr-vl-api

http://<宿主机IP>:31606/layout-parsing

Compose 未指定宿主机 IP,Docker 会监听所有网卡。其他机器可通过宿主机内网 IP 访问,现场需按网络策略放行 30606 和 31606 端口。

4. 部署 PaddleOCR-VL

4.1 镜像

ccr-2vdh3abv-pub.cnc.bj.baidubce.com/paddlepaddle/paddleocr-vl@sha256:6c735bdf9e758ffdd58ccc067db0c2d84e37e5e6a2cbd47156069d4d7ea5d709

镜像摘要对应 2026-09-16 查询到的官方 latest-nvidia-gpu-offline 内容,用摘要可避免标签更新导致环境变化。

4.2 配置客户 VLM

修改 pipeline_config.yaml:

genai_config:
  backend: vllm-server
  server_url: "https://customer-vlm.example.internal/v1"
  max_concurrency: 1
  client_kwargs:
    model_name: "paddleocr-vl-1.6"
    api_key: "REPLACE_WITH_CUSTOMER_API_KEY"

server_url 填兼容 OpenAI 接口的 Base URL,即以 /v1 结尾,不填写 /chat/completions。API Key 仅保存在现场受控配置中。使用内部 CA 时,还需把 CA 证书加入容器信任库。

4.3 启动

cd D:\study\work\dainqi\paddleocr-vl
docker compose config --quiet
docker compose pull
docker compose up -d
docker compose logs -f --tail 100

完整 Compose 和流水线配置见附录 A。

5. 部署 PP-OCRv6

5.1 镜像与模型

自定义镜像 local/paddlex-ppocrv6:3.7.0-gpu 基于已固定摘要的官方 VL GPU 镜像构建,安装 PaddleOCR 3.7.0、PaddleX 3.7.2 和 Serving 依赖。复用 VL 镜像只为减少基础镜像下载,PP-OCRv6 运行时不依赖 VL 服务。

流水线加载以下模型:

  • PP-OCRv6_medium_det

  • PP-LCNet_x1_0_textline_ori

  • PP-OCRv6_medium_rec

ocr_config.yaml 中 use_textline_orientation 必须为 true,并与调用参数一致。Serving.extra.max_num_input_imgs: null 取消服务端输入图片数量上限,避免长 PDF 的 VL 与 PP-OCR 处理页数不一致;实际页数仍应按显存和处理时长限制。

5.2 构建与启动

cd D:\study\work\dainqi\ppocr-paddlex
docker compose config --quiet
docker compose build --progress=plain
docker compose up -d
docker compose logs -f --tail 100

模型缓存卷挂载到 /home/paddleocr/.paddlex,容器重建后可复用已下载模型。完整配置见附录 B。

6. 验证

docker ps --filter name=ppocr-api-v6 --filter name=paddleocr-vl-api

Invoke-RestMethod http://127.0.0.1:30606/health
Invoke-RestMethod http://127.0.0.1:31606/health

docker exec ppocr-api-v6 python -c "import paddle,paddleocr,paddlex; print(paddle.__version__); print(paddleocr.__version__); print(paddlex.__version__); print(paddle.device.cuda.device_count())"

nvidia-smi
docker stats --no-stream ppocr-api-v6 paddleocr-vl-api

/health 只验证服务进程存活。验收时还需使用真实图片或 PDF 分别调用 /ocr 和 /layout-parsing,确认模型输出、客户 VLM 鉴权及网络均正常,并检查两个服务同时运行时是否发生显存溢出。

7. 完全内网交付

联网制品机需完成以下工作:

  1. 构建并验证 PP-OCRv6 镜像。

  2. 固定 PaddleOCR-VL 镜像摘要。

  3. 将 PP-OCRv6 模型放入最终镜像,或备份 /home/paddleocr/.paddlex 对应命名卷。

  4. 验证两个容器在无公网环境冷启动。

  5. 通过内网镜像仓库分发,或导出镜像和 SHA-256 校验文件。

docker save -o paddlex-ppocrv6-3.7.0-gpu.tar local/paddlex-ppocrv6:3.7.0-gpu
docker save -o paddleocr-vl-1.6-gpu-offline.tar ccr-2vdh3abv-pub.cnc.bj.baidubce.com/paddlepaddle/paddleocr-vl@sha256:6c735bdf9e758ffdd58ccc067db0c2d84e37e5e6a2cbd47156069d4d7ea5d709
Get-FileHash *.tar -Algorithm SHA256

docker load -i paddlex-ppocrv6-3.7.0-gpu.tar
docker load -i paddleocr-vl-1.6-gpu-offline.tar

docker save 不包含命名卷数据。若模型仍在卷中,必须单独备份卷。

8. 常见故障

现象

处理

use_textline_orientation ... not initialized

流水线未加载方向模型。保持 YAML 与请求参数一致,当前目标值为 true。

VL 日志出现 Connection error

检查客户 VLM URL、容器 DNS/路由、TLS CA、API Key、模型名和服务状态。

/health 正常但业务请求失败

/health 不调用模型;使用真实 /ocr 或 /layout-parsing 请求,并检查响应中的错误信息。

容器重建后重新下载模型

确认命名卷挂载到 /home/paddleocr/.paddlex,或使用镜像内离线模型目录。

两个服务无法同时运行

检查端口占用和 8 GB 显存;降低并发或只启动当前需要的服务。

9. 验收与参考

验收至少覆盖:

  • 图片和多页 PDF 的 /ocr、/layout-parsing 请求。

  • 客户 VLM 的网络、证书、鉴权和模型名。

  • 两个服务同时运行时的显存峰值。

  • 容器重建和无公网冷启动。

官方文档:

附录 A. PaddleOCR-VL 完整配置

目录:D:\study\work\dainqi\paddleocr-vl

A.1 compose.yaml

services:
  paddleocr-vl-api:
    image: ccr-2vdh3abv-pub.cnc.bj.baidubce.com/paddlepaddle/paddleocr-vl@sha256:6c735bdf9e758ffdd58ccc067db0c2d84e37e5e6a2cbd47156069d4d7ea5d709
    container_name: paddleocr-vl-api
    ports:
      - "31606:8080"
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              device_ids: ["0"]
              capabilities: [gpu]
    shm_size: "2g"
    user: root
    restart: unless-stopped
    volumes:
      - ./pipeline_config.yaml:/home/paddleocr/pipeline_config.yaml:ro
    command:
      - paddlex
      - --serve
      - --pipeline
      - /home/paddleocr/pipeline_config.yaml
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:8080/health || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 300s

A.2 pipeline_config.yaml

pipeline_name: PaddleOCR-VL-1.6
batch_size: 64
use_queues: True
use_doc_preprocessor: False
use_layout_detection: True
use_chart_recognition: False
use_seal_recognition: False
format_block_content: False
merge_layout_blocks: True
markdown_ignore_labels:
  - number
  - footnote
  - header
  - header_image
  - footer
  - footer_image
  - aside_text

SubModules:
  LayoutDetection:
    module_name: layout_detection
    model_name: PP-DocLayoutV3
    model_dir: null
    batch_size: 8
    threshold: 0.3
    layout_nms: True
    layout_unclip_ratio: [1.0, 1.0]
    layout_merge_bboxes_mode:
      0: "union"
      1: "union"
      2: "union"
      3: "large"
      4: "union"
      5: "large"
      6: "large"
      7: "union"
      8: "union"
      9: "union"
      10: "union"
      11: "union"
      12: "union"
      13: "union"
      14: "union"
      15: "large"
      16: "union"
      17: "large"
      18: "union"
      19: "union"
      20: "union"
      21: "union"
      22: "union"
      23: "union"
      24: "union"
  VLRecognition:
    module_name: vl_recognition
    model_name: PaddleOCR-VL-1.6-0.9B
    model_dir: null
    batch_size: 4096
    genai_config:
      backend: vllm-server
      server_url: "REPLACE_WITH_CUSTOMER_VLM_URL"
      max_concurrency: 1
      client_kwargs:
        model_name: "paddleocr-vl-1.6"
        api_key: "REPLACE_WITH_CUSTOMER_API_KEY"

SubPipelines:
  DocPreprocessor:
    pipeline_name: doc_preprocessor
    batch_size: 8
    use_doc_orientation_classify: True
    use_doc_unwarping: True
    SubModules:
      DocOrientationClassify:
        module_name: doc_text_orientation
        model_name: PP-LCNet_x1_0_doc_ori
        model_dir: null
        batch_size: 8
      DocUnwarping:
        module_name: image_unwarping
        model_name: UVDoc
        model_dir: null

Serving:
  extra:
    max_num_input_imgs: null

附录 B. PP-OCRv6 完整配置

目录:D:\study\work\dainqi\ppocr-paddlex

B.1 Dockerfile

# 复用已有官方 PaddleOCR-VL GPU 镜像,避免重复下载超大基础镜像。
FROM ccr-2vdh3abv-pub.cnc.bj.baidubce.com/paddlepaddle/paddleocr-vl@sha256:6c735bdf9e758ffdd58ccc067db0c2d84e37e5e6a2cbd47156069d4d7ea5d709

USER root

ARG PADDLEOCR_VERSION=3.7.0
ARG PADDLEX_VERSION=3.7.2

RUN python -m pip install --no-cache-dir --upgrade \
      "paddleocr==${PADDLEOCR_VERSION}" \
      "paddlex[ocr-core]==${PADDLEX_VERSION}" \
    && paddlex --install serving

WORKDIR /app

CMD ["paddlex", \
     "--serve", \
     "--pipeline", "/app/ocr_config.yaml", \
     "--device", "gpu:0", \
     "--host", "0.0.0.0", \
     "--port", "8080"]

B.2 compose.yaml

services:
  ppocr-api:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        PADDLEOCR_VERSION: "3.7.0"
        PADDLEX_VERSION: "3.7.2"
    image: local/paddlex-ppocrv6:3.7.0-gpu
    container_name: ppocr-api-v6
    ports:
      - "30606:8080"
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              device_ids: ["0"]
              capabilities: [gpu]
    shm_size: "2gb"
    user: root
    restart: unless-stopped
    environment:
      PADDLE_PDX_MODEL_SOURCE: BOS
    volumes:
      - ./ocr_config.yaml:/app/ocr_config.yaml:ro
      - ppocr-v6-model-cache:/home/paddleocr/.paddlex
    command:
      - paddlex
      - --serve
      - --pipeline
      - /app/ocr_config.yaml
      - --device
      - gpu:0
      - --host
      - 0.0.0.0
      - --port
      - "8080"
    healthcheck:
      test:
        - CMD-SHELL
        - >-
          python -c "import urllib.request;
          urllib.request.urlopen('http://127.0.0.1:8080/health', timeout=5)"
      interval: 20s
      timeout: 10s
      retries: 10
      start_period: 600s

volumes:
  ppocr-v6-model-cache:

B.3 ocr_config.yaml

pipeline_name: OCR
text_type: general

use_doc_preprocessor: false
use_textline_orientation: true

SubPipelines:
  DocPreprocessor:
    pipeline_name: doc_preprocessor
    use_doc_orientation_classify: false
    use_doc_unwarping: false
    SubModules:
      DocOrientationClassify:
        module_name: doc_text_orientation
        model_name: PP-LCNet_x1_0_doc_ori
        model_dir: null
      DocUnwarping:
        module_name: image_unwarping
        model_name: UVDoc
        model_dir: null

SubModules:
  TextDetection:
    module_name: text_detection
    model_name: PP-OCRv6_medium_det
    model_dir: null
    limit_side_len: 64
    limit_type: min
    max_side_limit: 4000
    thresh: 0.3
    box_thresh: 0.6
    unclip_ratio: 1.5

  TextLineOrientation:
    module_name: textline_orientation
    model_name: PP-LCNet_x1_0_textline_ori
    model_dir: null
    batch_size: 6

  TextRecognition:
    module_name: text_recognition
    model_name: PP-OCRv6_medium_rec
    model_dir: null
    batch_size: 6
    score_thresh: 0.0

Serving:
  visualize: false
  extra:
    max_num_input_imgs: null

B.4 .dockerignore

.git
.idea
.vscode
*.log
models