day33-多模态RAG拓展(PDF图片多模态模型语义理解)

多模态RAG系统进阶:olmOCR工具使用

olmOCR部署与调用流程

olmOCR本质上其实是一个经过特定功能微调的多模态大模型,能够实现明显好于其他普通OCR模型的光学字符识别效果。

项目地址: https://github.com/allenai/olmocr

目前官方已发布 7B 等级模型 权重,微调自 Qwen2.5-VL-7B-Instruct

项目模型:https://huggingface.co/allenai/olmOCR-7B-0825-FP8

image-20251010092209275

实测效果:

image-20251010092229482 image-20251010092236339

1.硬件与系统说明

目前olmOCR只支持本地部署,硬件条件如下:

  • NVIDIA GPU,建议显存 ≥ 15 GB(官方测试过 RTX 4090、L40S、A100、H100;磁盘需约 30 GB)。
  • 操作系统:Linux。

因此,我们下面在autodl云服务器 ( 西北B区 / 963机 ) 进行实操和应用!

autodl云服务器使用流程

  • 官网:https://www.autodl.com/home

  • 注册后进行登录

  • 登录后进入到【控制台】

  • 在个人主页中进行充值:5元

  • 在【容器实例】中租用一个新实例(云服务器)

  • 进行基础镜像配置

2.系统依赖(用于 PDF 渲染/字体)

需要安装相关依赖:下面的两个指令需要在cmd中逐一执行

sudo apt-get update

sudo apt-get install -y poppler-utils ttf-mscorefonts-installer msttcorefonts \
  fonts-crosextra-caladea fonts-crosextra-carlito gsfonts lcdf-typetools

以上为olmOCR官方项目中 README 推荐依赖,用于将 PDF 页渲染为图像、补齐字体

3.创建虚拟环境

接下来继续创建虚拟环境:

conda create -n olmocr python=3.11 -y
#重启cmd切换虚拟环境
conda activate olmocr

4. 安装olmOCR

# GPU 推理(推荐)在olmocr虚拟环境中进行
pip install "olmocr[gpu]" --extra-index-url https://download.pytorch.org/whl/cu128

需要注意的是,真正的 OCR/VLM 推理必须用 GPU。这条安装命令的核心是安装带 GPU 支持的 olmOCR 依赖 和 包含自动安装推理工具vLLM。

安装完成后即可查看实际安装结果:

pip show olmocr
image-20251010094746232

查看vllm作为推理引擎:

pip show vllm
image-20251010094756882

5.下载olmOCR模型权重

需要先安装魔搭社区:在olmocr虚拟环境中执行

pip install modelscope

然后尝试下载olmOCR模型:https://www.modelscope.cn/models/allenai/olmOCR-7B-0825-FP8/

image-20251010094848599

使用如下命令即可开始下载:

#在当前目录下创建一个olmOCR-7B-0825-FP8的文件夹(文件夹名字随便)
modelscope download --model allenai/olmOCR-7B-0825-FP8 --local_dir ./olmOCR-7B-0825-FP8

6.olmOCR模型调用流程

因为,后续我们也需要据此对模型进行提问。这里首先我们需要开启vLLM模型服务:

执行下面指令,autodl不可使用无卡模式开机,一定要有显卡的前提下启动模型服务!该服务一旦关闭,则本地无法进行模型调用!

vllm serve ./olmOCR-7B-0825-FP8 \
  --served-model-name olmocr \
  --max-model-len 16384 --port 8001

顺利启动后如下所示:

image-20251010100135862

然后在命令行中将当前虚拟环境添加到Jupyter kernel中:

conda install ipykernel
python -m ipykernel install --user --name olmocr --display-name "Python (olmocr)"

借助olmOCR实现元素感知OCR

在进行pdf转换md后,olmocr可以实现将md图片进行元素感知和语义解析,即提取图片内容作为md的文字内容和图片语义解析,从而实现更高精度的视觉检索。

实现效果对比:

image-20251010102713855

image-20251010102744752

#传入output.md作为被增强文件
# 需要安装:pip install pdf2image pillow requests tqdm

'''自动分析 Markdown 文档中引用的图片(如图表、公式、流程图等),利用多模态大模型(如 olmOCR)理解图片内容,并将结构化信息以 Markdown 形式插入原文档中,从而提升文档的信息密度和可检索性。'''
import os, re, io, base64, requests, json
from PIL import Image

#指导多模态模型如何解析图片
'''你是OCR与文档理解助手。
分析此图像区域并生成:
1) ALT:非常简短的替代文本(<=12个词)。
2) CAPTION:1-2句简洁的说明。
3) CONTENT_MD:若图像包含表格,输出干净的Markdown表格;若包含公式,输出LaTeX($...$或$$...$$);否则提供3-6个要点总结内容,使用Markdown格式。
严格按以下格式返回:
ALT: <简短替代文本>
CAPTION: <一两句说明>
CONTENT_MD:
<此处为Markdown内容>'''
DEFAULT_PROMPT = (
    "You are an OCR & document understanding assistant.\n"
    "Analyze this image region and produce:\n"
    "1) ALT: a very short alt text (<=12 words).\n"
    "2) CAPTION: a 1-2 sentence concise caption.\n"
    "3) CONTENT_MD: if the image contains a table, output a clean Markdown table;"
    "   if it contains a formula, output LaTeX ($...$ or $$...$$);"
    "   otherwise provide 3-6 bullet points summarizing key content, in Markdown.\n"
    "Return strictly in the following format:\n"
    "ALT: <short alt>\n"
    "CAPTION: <one or two sentences>\n"
    "CONTENT_MD:\n"
    "<markdown content here>\n"
)

#正则匹配 Markdown文件内容中 图片链接的语法
IMG_PATTERN = re.compile(r'!\[[^\]]*\]\(([^)]+)\)')

#调用多模态模型解析单张图片
def call_olmocr_image(vllm_url, model, img_path,
                      temperature=0.2, max_tokens=2048,
                      prompt=DEFAULT_PROMPT):
    #读取并编码图片为 Base64,目的是为了在vllm请求参数中使用
    with Image.open(img_path) as im:
        bio = io.BytesIO()
        im.save(bio, format="PNG")
        img_bytes = bio.getvalue()
        
    #构造 vLLM API 请求(兼容 OpenAI 多模态格式)
    payload = {
        "model": model,
        "messages": [{
            "role": "user",
            "content": [
                {"type": "text", "text": prompt},
                {"type": "image_url",
                 "image_url": {"url": f"data:image/png;base64,{base64.b64encode(img_bytes).decode()}", "detail": "auto"}} #detail: "auto" 让模型自动选择分辨率。
            ]
        }],
        "temperature": temperature,
        "max_tokens": max_tokens,
    }
    
    #发送 HTTP POST 请求
    r = requests.post(vllm_url, json=payload, timeout=180)
    r.raise_for_status()
    text = r.json()["choices"][0]["message"]["content"].strip()

    #解析模型返回的结构化文本,对其按行扫描,识别 ALT:、CAPTION:、CONTENT_MD: 标记,提取对应内容,组装为字典
    alt, caption, content_md_lines = "", "", []
    mode = None
    for line in text.splitlines():
        l = line.strip()
        if l.upper().startswith("ALT:"):
            alt = l.split(":", 1)[1].strip()
            mode = None
        elif l.upper().startswith("CAPTION:"):
            caption = l.split(":", 1)[1].strip()
            mode = None
        elif l.upper().startswith("CONTENT_MD:"):
            mode = "content"
        else:
            if mode == "content":
                content_md_lines.append(line.rstrip())
    #提取对应内容,组装为字典
    return {
        "alt": alt or "Figure",
        "caption": caption or alt or "",
        "content_md": "\n".join(content_md_lines).strip()
    }

#主流程——增强整个 Markdown 文档
def augment_markdown(md_path, out_path,
                     vllm_url="http://localhost:8001/v1/chat/completions",
                     model="olmocr",
                     temperature=0.2, max_tokens=2048,
                     image_root=".",
                     cache_json=None):
    #读取原始 Markdown 行数据
    with open(md_path, "r", encoding="utf-8") as f:
        md_lines = f.read().splitlines()
	#加载缓存(避免重复解析同一张图)
    cache = {}
    if cache_json and os.path.exists(cache_json):
        try:
            cache = json.load(open(cache_json, "r", encoding="utf-8"))
        except Exception:
            cache = {}

    #逐行处理,识别并增强图片
    out_lines = []
    for line in md_lines:
        out_lines.append(line)
        m = IMG_PATTERN.search(line)
        if not m:
            continue

        img_rel = m.group(1).strip().split("?")[0]
        img_path = img_rel if os.path.isabs(img_rel) else os.path.join(image_root, img_rel)

        if not os.path.exists(img_path):
            out_lines.append(f"<!-- WARN: image not found: {img_rel} -->")
            continue

        if cache_json and img_path in cache:
            result = cache[img_path]
        else:
            result = call_olmocr_image(vllm_url, model, img_path,
                                       temperature, max_tokens)
            if cache_json:
                cache[img_path] = result

        alt, cap, body = result["alt"], result["caption"], result["content_md"]

        if cap:
            out_lines.append(f"*{cap}*")
        if body:
            out_lines.append("<details><summary>解析</summary>\n")
            out_lines.append(body)
            out_lines.append("\n</details>")

    with open(out_path, "w", encoding="utf-8") as f:
        f.write("\n".join(out_lines))

    if cache_json:
        with open(cache_json, "w", encoding="utf-8") as f:
            json.dump(cache, f, ensure_ascii=False, indent=2)

    print(f"✅ 已写入增强后的 Markdown:{out_path}")
    
augment_markdown(
    md_path="output.md",                     # 第一步生成的 md
    out_path="output_augmented.md",          # 增强后的 md
    vllm_url="http://localhost:8001/v1/chat/completions",  # 你的 vLLM 服务
    model="olmocr",
    image_root=".",                          # 图片路径相对根目录
    cache_json="image_cache.json"            # 可选,缓存文件
)

agent(steamlit)

RAG(chat ui )

deepseek-ocr

工具调用

代码开发

posted @ 2025-12-21 10:42  凫弥  阅读(3)  评论(0)    收藏  举报