1664 字
8 分钟
PaddleOCR-VL 模型部署备忘录
WARNING
吐槽
PaddleOCR 的文档从 2021 年写得稀巴烂,到 2026 年了,依旧他妈的稀巴烂。各种依赖冲突、版本不兼容、文档和实际代码对不上,浪费了我整整 4 个小时。写这篇文章就是为了让后来者少踩坑,因为指望百度更新文档是不可能的。
架构说明
PaddleOCR-VL 的部署需要两个独立的服务配合运行:
- vLLM 后端服务(端口 8118):负责 VL 模型的高性能推理
- PaddleX Serving 前端服务(端口 8000):负责文档预处理、版面分析,并调用 vLLM 后端
用户请求 → PaddleX Serving (8000) → vLLM Backend (8118) ↓ 返回 OCR 结果前置条件
- Linux 服务器(本文以 Ubuntu 为例)
- NVIDIA GPU(需要 CUDA 支持)
- 足够的显存(建议 8GB+)
Step 1:安装 uv 包管理器
为什么用 uv?因为 pip 在处理 Paddle 这种依赖地狱的时候慢得要死,uv 至少能让你在绝望中少等一会儿。
# 下载并安装 uv# ⚠️ 替换:版本号 0.9.27 可根据需要更换为最新版本wget https://speed.oo9.dpdns.org/gh/astral-sh/uv/releases/download/0.9.27/uv-x86_64-unknown-linux-gnu.tar.gztar -zxf uv-x86_64-unknown-linux-gnu.tar.gzmv uv-x86_64-unknown-linux-gnu/* /usr/local/bin
# 创建工作目录mkdir -p /paddleStep 2:部署 vLLM 后端服务(端口 8118)
必须先启动这个服务,因为 PaddleX Serving 依赖它。
cd /paddle
# 创建 vLLM 专用虚拟环境# ⚠️ 替换:Python 版本可根据需要调整,推荐 3.10-3.12uv venv .venv_vllm --python 3.12source .venv_vllm/bin/activate
# 先装 pip(是的,uv 环境里还得装 pip,因为后面的脚本依赖它)uv pip install pip
# 安装 PaddleOCRuv pip install -U "paddleocr[doc-parser]"
# 安装 Flash Attention(加速推理的关键)# ⚠️ 替换:根据你的 CUDA 和 PyTorch 版本选择对应的 wheel# 这里是 CUDA 12.8 + PyTorch 2.8 + Python 3.12 的版本# 其他版本请去 https://github.com/mjun0812/flash-attention-prebuild-wheels/releases 找uv pip install https://speed.oo9.dpdns.org/gh/mjun0812/flash-attention-prebuild-wheels/releases/download/v0.3.14/flash_attn-2.8.2+cu128torch2.8-cp312-cp312-linux_x86_64.whl
# 安装 vLLM 依赖paddleocr install_genai_server_deps vllm
# 安装 transformers(版本很重要,不要乱改)uv pip install transformers==4.57.6
# 安装 Python 开发头文件(编译某些依赖需要)# ⚠️ 替换:python3.12-dev 根据你的 Python 版本调整apt update && apt install -y python3.12-dev
# 启动 vLLM 服务# ⚠️ 替换:# - --model_name → 可选模型:PaddleOCR-VL-0.9B、PaddleOCR-VL-2B 等# - --port 8118 → vLLM 后端端口,需要和 PaddleOCR-VL.yaml 中的配置一致paddlex_genai_server --model_name PaddleOCR-VL-0.9B --backend vllm --port 8118WARNING
Flash Attention 的坑
Flash Attention 的预编译 wheel 对 CUDA、PyTorch、Python 版本有严格要求。如果版本不匹配,要么安装失败,要么运行时 segfault。
百度的文档?不存在的。他们只会告诉你 pip install flash-attn,然后让你自己编译 2 小时,最后还可能失败。
建议直接去 mjun0812 的预编译仓库 找对应版本。
Step 3:部署 PaddleX Serving 前端服务(端口 8000)
新开一个终端,部署前端服务。
cd /paddle
# 创建 PaddleX 专用虚拟环境(不要和 vLLM 环境混用!)# ⚠️ 替换:Python 版本可根据需要调整uv venv .venv_paddle --python 3.12source .venv_paddle/bin/activate
# 安装 PaddlePaddle GPU 版本# ⚠️ 替换:cu126 表示 CUDA 12.6,根据你的 CUDA 版本选择对应的包# 可选:cu118(CUDA 11.8)、cu120(CUDA 12.0)、cu126(CUDA 12.6)uv pip install paddlepaddle-gpu==3.2.1 -i https://www.paddlepaddle.org.cn/packages/stable/cu126/
# 安装 PaddleOCRuv pip install -U "paddleocr[doc-parser]" pip
# 安装 PaddleX Serving 组件paddlex --install serving
# 启动服务# ⚠️ 替换:# - gpu:0 → 改为你的 GPU 设备号,多卡可用 gpu:0,1# - --port 8000 → 改为你想要的端口号paddlex --serve --device gpu:0 --pipeline PaddleOCR-VL --port 8000NOTE
关于 CUDA 版本
查看你的 CUDA 版本:nvcc --version 或 nvidia-smi
百度的文档根本不会告诉你这些,你得自己去 PaddlePaddle 官网 找对应的安装命令。而且官网的安装命令还经常和实际的包名对不上,真是谢谢您嘞。
Step 4:配置 PaddleOCR-VL.yaml(可选)
如果你需要自定义配置(比如调整 batch_size、阈值等),可以覆盖默认的配置文件。
# ⚠️ 替换:路径中的 python3.12 根据你的 Python 版本调整# 如果你用的是 uv venv,路径类似:/paddle/.venv_paddle/lib/python3.12/site-packages/paddlex/configs/pipelines/cp /root/PaddleOCR-VL.yaml /paddle/.venv_paddle/lib/python3.12/site-packages/paddlex/configs/pipelines/ -r配置文件内容如下:
# ⚠️ 替换:server_url 中的端口需要和 vLLM 服务端口一致
pipeline_name: PaddleOCR-VL
batch_size: 64
use_queues: True
use_doc_preprocessor: Trueuse_layout_detection: Trueuse_chart_recognition: Falseformat_block_content: False
SubModules: LayoutDetection: module_name: layout_detection model_name: PP-DocLayoutV2 model_dir: null batch_size: 8 threshold: 0: 0.5 # abstract 1: 0.5 # algorithm 2: 0.5 # aside_text 3: 0.5 # chart 4: 0.5 # content 5: 0.4 # formula 6: 0.4 # doc_title 7: 0.5 # figure_title 8: 0.5 # footer 9: 0.5 # footer 10: 0.5 # footnote 11: 0.5 # formula_number 12: 0.5 # header 13: 0.5 # header 14: 0.5 # image 15: 0.4 # formula 16: 0.5 # number 17: 0.4 # paragraph_title 18: 0.5 # reference 19: 0.5 # reference_content 20: 0.45 # seal 21: 0.5 # table 22: 0.4 # text 23: 0.4 # text 24: 0.5 # vision_footnote layout_nms: True layout_unclip_ratio: [1.0, 1.0] layout_merge_bboxes_mode: 0: "union" # abstract 1: "union" # algorithm 2: "union" # aside_text 3: "large" # chart 4: "union" # content 5: "large" # display_formula 6: "large" # doc_title 7: "union" # figure_title 8: "union" # footer 9: "union" # footer 10: "union" # footnote 11: "union" # formula_number 12: "union" # header 13: "union" # header 14: "union" # image 15: "large" # inline_formula 16: "union" # number 17: "large" # paragraph_title 18: "union" # reference 19: "union" # reference_content 20: "union" # seal 21: "union" # table 22: "union" # text 23: "union" # text 24: "union" # vision_footnote VLRecognition: module_name: vl_recognition model_name: PaddleOCR-VL-0.9B model_dir: null batch_size: 2048 genai_config: backend: vllm-server # ⚠️ 替换:这里的端口必须和 Step 2 中 vLLM 服务的端口一致 server_url: http://127.0.0.1:8118/v1
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: nullStep 5:测试服务
两个服务都启动后,可以用以下 Python 代码测试:
import requestsimport base64from concurrent.futures import ThreadPoolExecutor, as_completed
# ⚠️ 替换:改为你的 PaddleX Serving 地址和端口API_URL = "http://localhost:8000/layout-parsing"
# ⚠️ 替换:改为你的 PDF 文件路径with open('xxxx.pdf', 'rb') as f: data = f.read()
content = base64.b64encode(data).decode("ascii")
def test_ocr(file_data, file_type=0): headers = { "Content-Type": "application/json" } payload = { "file": file_data, "fileType": file_type, "useDocOrientationClassify": True, "useLayoutDetection": True, "useDocUnwarping": True, "useChartRecognition": True, "repetitionPenalty": 1, "temperature": 0.1, "topP": 1, "minPixels": 147384, "maxPixels": 2822400, "layoutNms": True, "visualize": False } response = requests.post(API_URL, json=payload, headers=headers) return response.json()
# 并发测试with ThreadPoolExecutor(max_workers=4) as executor: futures = [executor.submit(test_ocr, content, 0) for _ in range(10)] for future in as_completed(futures): try: result = future.result() print("OCR 处理完成") except Exception as e: print(f"OCR 处理失败: {e}")需要根据实际情况替换的部分汇总
| 参数 | 说明 | 示例值 |
|---|---|---|
| uv 版本 | uv 包管理器版本号 | 0.9.27 |
| Python 版本 | 虚拟环境 Python 版本 | 3.12 |
| CUDA 版本 (PaddlePaddle) | PaddlePaddle 对应的 CUDA 版本 | cu126(CUDA 12.6) |
| Flash Attention wheel | 预编译的 FA 包 URL | 根据 CUDA/PyTorch/Python 版本选择 |
| python-dev 包名 | Python 开发头文件包 | python3.12-dev |
| vLLM 端口 | vLLM 后端服务端口 | 8118 |
| PaddleX Serving 端口 | 前端服务端口(对外暴露) | 8000 |
| GPU 设备号 | 使用的 GPU 编号 | gpu:0 或 gpu:0,1 |
| 模型名称 | PaddleOCR-VL 模型版本 | PaddleOCR-VL-0.9B |
| YAML 配置路径 | PaddleOCR-VL.yaml 的位置 | 根据 Python 环境路径调整 |
| server_url | YAML 中 vLLM 服务地址 | http://127.0.0.1:8118/v1 |
最后
如果你按照这篇文章还是跑不起来,那大概率是版本又变了。去骂百度吧,反正他们也不会改文档的。
祝你好运。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
PaddleOCR-VL 模型部署备忘录
https://blog.useforall.com/posts/paddleocr-vl-deployment-memo/
Lim's Blog