这次我们来看一个很现实的场景:手头有一份 PDF,字看得见,但复制不出来;或者是一张截图,里面全是表格,想直接丢给 LLM 让它总结,结果模型要么读不到内容,要么回得七零八落。OCR It 要解决的就是这类问题——从无法复制的文档中提取文本,然后把结果变成 LLM 能直接吃掉的输入。
这个项目最值得关注的有三点:第一,面向扫描版 PDF、截图、图片这类“看得见但拿不到”的文本来源;第二,输出不只是纯文本,还能生成 Markdown 或结构化文本,方便直接塞进 LLM 上下文,或者喂给 RAG 管道;第三,部署方式灵活,既能本地离线跑,也能封装成接口服务,对已有工具链做集成。
如果你是做 LLM 应用开发的,你会发现大多数 RAG 项目卡在第一公里:让模型在读文档之前,先把文档里的字“拿出来”。OCR It 就是这一公里的解决方案。本文会带你把核心能力、环境准备、部署启动、功能测试、API 调用和批量任务整体过一遍,最后给一份常见问题排查清单。
1. OCR It 核心能力速览
从项目定位看,OCR It 是一个面向 LLM 数据预处理的文档文本提取工具。下面这张表先把关键规格列出来,方便你快速判断它适不适合自己的环境。
| 能力项 | 说明 |
|---|---|
| 项目类型 | OCR 文档文本提取工具,面向 LLM 预处理场景 |
| 输入类型 | 图片、扫描 PDF、不可复制的 PDF、截图 |
| 输出格式 | 纯文本、Markdown、结构化文本(按实际版本确认) |
| 识别引擎 | 可选用 Tesseract、PaddleOCR、百度 OCR API 等方案 |
| 硬件门槛 | 轻量 OCR 模型 CPU 可跑;GPU 可加速,显存占用与模型规模相关 |
| 启动方式 | 命令行、Python 脚本、HTTP 服务 |
| 批量任务 | 支持目录批量处理,建议自行设计队列与日志 |
| API 集成 | 可封装为接口供 LLM / RAG 调用 |
| 适合场景 | 论文、合同、报表、聊天截图等 LLM 数据预处理 |
这里需要说明一点:不同的 OCR 引擎识别质量差异很大,建议先拿自己的真实文档打样,再决定用哪个方案。Tesseract 胜在免费轻量,PaddleOCR 胜在中文场景和排版还原,云端 API 胜在省事但要注意费用和合规。
2. 适用场景与使用边界
OCR It 能解决的问题很明确:内容看得见、但文本拿不出来的文档。典型场景包括:
- 扫描版 PDF,整页都是图片,复制后全是空白。
- 政府文件、合同扫描件、传真件,文字糊但不至于读不出来。
- 网页长截图、聊天记录截图、会议白板照片。
- PPT 导出成图片后,不能直接选中文本。
- 加密 PDF 或选择不提供文本层的 PDF,无法直接复制。
这些材料如果要进入 LLM 的处理流程,必须先做 OCR。OCR It 的思路就是把这些材料统一转成“LLM 友好”的文本。
但也要说清楚边界。OCR 不是万能的,以下几类场景不建议硬上:
- 手写体识别。除非专门训练过,否则通用 OCR 对手写体、花体字的识别率会明显下降。
- 强调版式精确还原的文档。OCR 输出的是文本流和简单结构,不是 PDF 版式重现。
- 涉及个人隐私、商业机密、版权内容的处理。需要先确认你有权使用这些材料。
合规问题必须放在前面:抓取他人网站内容做 OCR、识别未授权文档、处理包含个人信息的图片,都可能涉及版权和隐私风险。自用工具也建议只处理你有使用权的文件。
3. OCR It 本地部署环境准备
无论用哪种 OCR 引擎,环境准备的核心是四件事:Python 运行环境、OCR 引擎本体、模型或语言数据包、输出目录。
3.1 操作系统与 Python
Windows、Linux、macOS 都可以跑。建议使用 Python 3.10 或更高版本,并用虚拟环境隔离依赖,避免污染系统 Python。
# Linux / macOS python3 -m venv .venv source .venv/bin/activate # Windows PowerShell python -m venv .venv .venv\Scripts\activate3.2 Tesseract 路线
Tesseract 是老牌 OCR 引擎,适合英文和文本结构简单的文档。Windows 用户需要下载 Tesseract 5 的 Windows 64 位安装包,安装时勾选需要的语言包,尤其是简体中文chi_sim。
安装完成后,做两步检查:
tesseract --version echo %TESSDATA_PREFIX% # Windows如果 TESSDATA_PREFIX 没有设置,识别中文时会报 “Failed loading language ‘chi_sim’”。可以把 Tesseract 安装目录下的tessdata路径加入环境变量。
3.3 PaddleOCR 路线
PaddleOCR 在中文场景里识别效果更稳,对表格、印章、倾斜文字的鲁棒性也更好。安装 PaddlePaddle 和 PaddleOCR:
pip install paddlepaddle paddleocr如果你的机器有 NVIDIA GPU,并且确认 CUDA 环境正常,可以安装 GPU 版 PaddlePaddle:
pip install paddlepaddle-gpuGPU 版具体安装命令会根据 CUDA 版本变化,建议到 PaddlePaddle 官方安装页复制对应的 wheel 地址。
3.4 百度 OCR API 路线
走 API 方案不需要本地模型。去百度智能云创建 OCR 应用,拿到 API Key 和 Secret Key,然后通过 Access Token 调用。
这里顺带回应一个搜索热词:“百度 OCR 怎么在 RK3588 运行”。要区分两种方式:
- 如果你在 RK3588 上跑本地 OCR,比如 Tesseract 或 PaddleOCR,那是本地推理,关注的是 CPU/GPU/NPU 性能和推理框架的支持情况。
- 如果你只是调用百度 OCR 的 HTTP API,那和芯片基本没关系,只要设备能联网发请求就能用。
很多嵌入式场景会混这两者。OCR It 的接口模式走的是后者,本地只负责发请求、收结果、整理文本。
4. OCR It 安装部署与启动方式
OCR It 的启动方式可以从简单到复杂分成三档:命令行、Python 脚本、HTTP 服务。先跑通最简单的,再决定要不要封装。
4.1 命令行快速识别
如果只是偶尔识别一两张图,Tesseract 命令行最直接:
tesseract data/sample.png output -l chi_sim+eng --psm 6--psm 6表示把图片当成一个文本块处理,适合大部分截图。output是输出文件前缀,结果会保存为output.txt。
PaddleOCR 也提供命令行入口,但不同版本的参数差异比较大。新版可以用:
paddleocr --image_dir data/sample.png --lang ch如果命令报参数错误,优先看当前版本帮助:
paddleocr --help4.2 Python 脚本调用
推荐用 Python 方式,因为后面无论是批量任务还是接入 LLM,都需要在代码里拿到 OCR 结果对象。
from paddleocr import PaddleOCR ocr = PaddleOCR( lang='ch', use_gpu=False, # 有 GPU 且安装 GPU 版时可以改成 True ocr_version='PP-OCRv4' # 以实际安装版本为准 ) result = ocr.predict('./data/sample.png') for line in result: texts = line.get('rec_texts', []) for text in texts: print(text)跑通这段后,你就有了一个可控的 OCR 提取函数。后面所有批量任务、接口封装都可以围着这个函数展开。
4.3 HTTP 服务启动
如果要把 OCR 能力暴露给其他服务调用,最简单的方式是包一个 Flask 接口。下面是一个通用模板,端口和路由需要按实际项目调整:
# app.py from flask import Flask, request, jsonify from paddleocr import PaddleOCR app = Flask(__name__) ocr = PaddleOCR(lang='ch', use_gpu=False) @app.route('/ocr', methods=['POST']) def ocr_image(): if 'file' not in request.files: return jsonify({'error': 'no file'}), 400 file = request.files['file'] file.save('/tmp/ocr_input.png') result = ocr.predict('/tmp/ocr_input.png') texts = [] for line in result: texts.extend(line.get('rec_texts', [])) return jsonify({'texts': texts}) if __name__ == '__main__': app.run(host='127.0.0.1', port=8000)启动:
python app.py然后另开一个终端测试:
curl -X POST -F "file=@data/sample.png" http://127.0.0.1:8000/ocr返回 JSON 包含识别出来的文本数组,这个接口就可以接入你现有的 LLM 应用了。
5. OCR It 功能测试与效果验证
部署完成不等于能直接用于生产。我建议按下面几个维度逐项验证,每个都记录结果,方便后续调优。
5.1 单张图片识别测试
测试目的:确认基础识别链路是否正常。
输入:一张包含中文和英文的截图。
curl -X POST -F "file=@data/sample.png" http://127.0.0.1:8000/ocr预期结果:返回 JSON 中包含中文和英文文本,顺序与图片内容一致。
判断标准:文字没有大面积缺行、乱码,数字和字母没有明显串行。
常见失败:返回空数组,先检查图片是否太暗、太小;中文识别出乱码,优先检查语言包是否完整。
5.2 PDF 提取测试
PDF 无法直接 OCR,需要先把每一页渲染成图片,再走识别流程。用 pypdfium2 可以做这一层转换:
import pypdfium2 as pdfium from pathlib import Path pdf = pdfium.PdfDocument('data/demo.pdf') output_dir = Path('data/pages') output_dir.mkdir(exist_ok=True) for i in range(len(pdf)): page = pdf[i] bitmap = page.render(scale=2) # 2 倍分辨率,提升小字号文本识别率 img = bitmap.to_pil() img.save(output_dir / f'page_{i:03d}.png')渲染完成后,把每张页面图循环送入 OCR。实际测试时,建议先取 2 到 3 页试跑,确认时间成本和识别质量,再处理整份文档。
5.3 表格和图文混排测试
表格是 OCR 最容易翻车的地方。常见问题是:多列表格被识别成一行,列与列之间无法区分。
Tesseract 有专门处理表格的--psm 6和 TSV 输出模式,但效果有限。PaddleOCR 对简单表格的识别更可靠。如果表格结构比较复杂,建议先做图像预处理,比如用 OpenCV 检测表格线、切分成单元格再逐一识别。
判断成功标准:表格数据每一列都能落到对应的文本字段里,而不是一行糊过去。如果这一步达不到要求,后续做 LLM 结构化分析会非常吃力。
5.4 Markdown 输出测试
LLM 友好的输出,Markdown 比纯文本更好。一个简单的策略:先用 OCR 得到文本块和坐标,然后按坐标做段落到 Markdown 的映射。
def to_markdown(result): lines = [] for line in result: texts = line.get('rec_texts', []) lines.extend(texts) return '\n\n'.join(lines)这是最简版本。实际项目中可以根据坐标把标题、列表、表格分别标记,输出更规范的 Markdown。测试时用一个带标题和列表的文档,看看输出结构与原文差异有多大。
5.5 批量目录测试
批量任务最怕的是“跑了一半卡住”。建议先把批处理脚本写好,再加日志和失败重试。下面是一个可运行的目录遍历模板:
import pathlib from paddleocr import PaddleOCR image_dir = pathlib.Path('./inputs') output_dir = pathlib.Path('./outputs') output_dir.mkdir(exist_ok=True) ocr = PaddleOCR(lang='ch', use_gpu=False) for img_path in sorted(image_dir.glob('*.png')): try: result = ocr.predict(str(img_path)) texts = [] for line in result: texts.extend(line.get('rec_texts', [])) out_file = output_dir / f'{img_path.stem}.md' out_file.write_text('\n'.join(texts), encoding='utf-8') print(f'[OK] {img_path.name}') except Exception as exc: print(f'[FAIL] {img_path.name}: {exc}')先放 3 到 5 张图跑一遍,确认输出文件完整,再放整个目录。
5.6 LLM 消费测试
OCR 文本最终要给 LLM 用。测试时把识别结果直接作为上下文发给 LLM,看是否可理解:
from openai import OpenAI client = OpenAI( base_url='http://127.0.0.1:8000/v1', # 本地 LLM 服务地址 api_key='not-needed', ) ocr_text = open('outputs/合同第一页.md', encoding='utf-8').read() resp = client.chat.completions.create( model='local-model', messages=[ {'role': 'system', 'content': '你是一个文档助理,请根据用户提供的 OCR 文本回答问题。'}, {'role': 'user', 'content': ocr_text + '\n\n请提取这份文档中的金额和日期。'} ] ) print(resp.choices[0].message.content)如果这一步能稳定提取出金额、日期、甲方乙方名称,说明 OCR 质量足够支撑 LLM 的下游任务。
6. OCR It 接口 API 与批量任务设计
把 OCR 能力接口化之后,可以很方便地接进 LLM Agent、RAG 流程或自动化脚本。这里给出三套典型代码:本地 OCR 封装、百度 OCR API 调用、LLM 消费链路。
6.1 百度 OCR API 调用示例
使用云端 API 前需要准备 API Key 和 Secret Key:
import base64 import requests API_KEY = 'your_api_key' SECRET_KEY = 'your_secret_key' def get_access_token(): url = 'https://aip.baidubce.com/oauth/2.0/token' resp = requests.post(url, params={ 'grant_type': 'client_credentials', 'client_id': API_KEY, 'client_secret': SECRET_KEY, }) return resp.json().get('access_token') def ocr_by_api(image_path, access_token): with open(image_path, 'rb') as f: image_data = base64.b64encode(f.read()).decode() url = 'https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic' resp = requests.post(url, params={'access_token': access_token}, data={ 'image': image_data, }) words = [item['words'] for item in resp.json().get('words_result', [])] return '\n'.join(words) token = get_access_token() print(ocr_by_api('data/contract.jpg', token))云端 API 的好处是本地不需要装 OCR 模型,网络请求返回结构化文本;坏处是费用、请求频率限制,以及图片内容会经过第三方服务。敏感数据要谨慎使用。
6.2 批量任务队列设计
批量处理的工程化建议是:输入目录、输出目录、日志目录三分离。每次处理都记录文件状态,避免重复处理和中断后重新开始。
import json import pathlib input_dir = pathlib.Path('./inputs') output_dir = pathlib.Path('./outputs') state_file = pathlib.Path('./tasks.json') if state_file.exists(): tasks = json.loads(state_file.read_text(encoding='utf-8')) else: tasks = {p.name: 'pending' for p in input_dir.glob('*.png')} for name, status in tasks.items(): if status == 'done': continue try: # 执行 OCR 并保存结果 tasks[name] = 'done' except Exception as exc: tasks[name] = f'error: {exc}' state_file.write_text( json.dumps(tasks, ensure_ascii=False, indent=2), encoding='utf-8' )通过 state 文件记录状态,进程中断后重启可以跳过已完成任务,只处理失败和未开始的文件。
6.3 OCR It 接入 LLM 的完整链路
一个典型的“OCR + LLM”管道有三步:识别、清洗、交给 LLM。识别得到文本后,先处理掉 OCR 常见的噪声,比如多余空格、页脚、页码:
import re def clean_ocr_text(text): text = re.sub(r'\s+', ' ', text) text = re.sub(r'第\s*\d+\s*页', '', text) return text.strip()清洗后的文本再交给 LLM。如果文本过长,先做 chunk 切分,按段落分块,避免超过 LLM 上下文窗口。
7. OCR It 资源占用与性能观察
OCR It 的资源占用取决于选择哪个引擎、跑在什么硬件上。这里给一套观察方法,具体数字要以本机测试为准。
- 显存观察:Windows 用任务管理器,Linux 用
nvidia-smi -l 1,重点看 OCR 进程占用。 - 模型加载时机:PaddleOCR 首次调用需要加载模型,启动阶段耗时明显,后续单张图片处理更快。生产环境建议服务启动后就预热模型。
- CPU 推理:PP-OCR mobile 这类轻量模型在 CPU 上可跑,速度取决于图片尺寸和 CPU 核数。处理 1080P 截图时,单张可能在 1 到 3 秒之间,具体以实测为准。
- GPU 推理:显存占用与模型大小、批量大小、图片分辨率相关。如果显存不够,把批量数降到 1,或者换更小的模型。
- 内存:处理大 PDF 时分页渲染再识别,避免整份文档一次性加载到内存。
降低资源占用的几个实用技巧:
- 图片预处理:灰度化、二值化、去噪。
- 适当降低渲染分辨率,非关键页面可以
scale=1而不是scale=2。 - 限制 OCR 多线程数量,避免多个任务同时跑导致内存峰值过高。
- 批量任务控制在 2 到 4 个并发,优先保证稳定而不是速度。
8. OCR It 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 中文识别出一堆乱码 | 语言包缺失或未设置 TESSDATA_PREFIX | 查看 tesseract 日志 | 安装 chi_sim 语言包并配置环境变量 |
| PaddleOCR 下载模型失败 | 网络问题或模型地址变更 | 查看模型缓存目录 | 手动下载模型文件放到缓存目录 |
| PaddlePaddle 安装失败 | Python 版本或 CUDA 不匹配 | 检查 Python 版本和 CUDA 版本 | 按官网 wheel 表选择对应版本 |
| GPU 跑不起来,总是 CPU 在算 | 安装的是 CPU 版 PaddlePaddle | 打印 paddle 版本信息 | 安装 paddlepaddle-gpu |
| OCR 返回空数组 | 图片太暗、太小或压缩过度 | 打开图片检查质量 | 提高分辨率,做图像增强 |
| 大 PDF 处理内存溢出 | 一次性加载所有页面 | 观察内存占用曲线 | 分页渲染后再逐页识别 |
| OCR 文本串行、表格错乱 | 表格线干扰识别 | 检查原图表格结构 | 先做表格线检测和单元格切割 |
| 接口服务启动后访问不到 | 端口被占用或服务未启动 | 检查日志和端口监听 | 更换端口或重启服务 |
| LLM 上下文超长 | OCR 文本未做切分 | 查看单次文本 token 数 | 按段落切分,分块调用 |
| 批量任务中途卡住 | 单张图片耗时过长或死锁 | 查看任务状态文件 | 加超时控制,记录失败原因后继续 |
排查原则很朴素:先看日志,再看状态文件,最后看资源占用。不要一上来就重启服务,先确定是哪个环节卡住了。
9. OCR It 最佳实践与使用建议
从工程化角度,以下几个建议能明显减少踩坑次数。
第一,第一次使用不要直接跑全量。先拿 5 到 10 张有代表性的图片做验证,确认识别质量和速度满足需求,再上批量。
第二,保留一套最小可运行配置。不管是命令行还是 Python 脚本,把环境依赖和启动命令写进 README,换机器时能快速复现。
第三,目录分开管理。输入文件、输出文件、模型缓存、日志目录不要混在一起。批量任务一定要加任务状态文件。
第四,OCR 文本必须做后处理清洗。页脚、页码、多余空行都是噪声,直接给 LLM 会浪费 token 并影响效果。
第五,接口服务要限制访问范围。启动时绑定127.0.0.1,不要无脑绑到0.0.0.0。如果有多台机器需要访问,再加认证层。
第六,涉及人脸、签名、身份证、合同金额等敏感信息时,先确认你是否有权处理。本地 OCR 比云端 API 更可控,但同样要注意数据安全。
第七,LLM 输出的结果要复核。OCR 识别错误会传递到 LLM 的最终答案中,尤其是金额、日期、编号这类关键字段,建议加一道规则校验。
10. 总结与下一步
OCR It 最值得尝试的点,是把“看得见但拿不到”的文档文本快速变成 LLM 可消费的输入。整个链路并不复杂:图片或 PDF 进入 OCR 引擎,得到文本,清洗后交给 LLM。真正决定效果的不是选哪个框架,而是你对输入质量的管控和输出文本的清洗程度。
拿到项目后,建议最先验证三件事:一张中文截图能不能正确识别、扫描版 PDF 能否分页提取、识别结果丢给 LLM 后能不能稳定抽取关键字段。这三项跑通,项目就已经能用起来了。
最容易踩的坑集中在两个地方:一是语言包和模型文件没下全,二是批量任务缺少状态管理。前者会导致乱码或空输出,后者会让长任务中断后无从下手。
后续可以扩展的方向很多:把 OCR 结果接入 RAG 做知识库问答、用视觉大模型对复杂版面做二次理解、把批量任务改成异步队列,甚至加一个 WebUI 让非技术同学直接上传文件拿结果。先把 OCR 到 LLM 这条主链路跑稳,后面的想象空间会很大。