Chandra OCR详细步骤:vLLM API服务封装为FastAPI微服务,Swagger文档生成
1. 为什么需要把Chandra OCR封装成微服务
你手头有一堆扫描合同、数学试卷、带表格的PDF报表,想快速转成结构化Markdown放进知识库?直接跑CLI命令虽然快,但遇到这些情况就卡住了:
- 团队多人要同时调用,CLI只能单机运行
- 要集成进现有系统(比如内部文档平台、RAG流水线),没有HTTP接口没法对接
- 想监控调用量、加鉴权、做请求限流,CLI完全不支持
- 需要自动生成接口文档给前端或合作方看,CLI连个参数说明都得翻源码
这时候,把Chandra OCR的能力“包装”成一个标准HTTP服务,就成了最自然的选择。而vLLM作为后端推理引擎,配合FastAPI做API层,刚好能兼顾高性能和易用性——它自带Swagger UI,不用额外写文档,接口一跑起来就能点开看、能试用、能生成SDK。
这不是为了炫技,而是让OCR能力真正变成你系统里可调度、可管理、可协作的“基础设施”。
2. 环境准备与vLLM本地部署
2.1 硬件与基础依赖确认
Chandra OCR对显存要求不高,但要注意:它必须用vLLM启动,且至少需要2张GPU(哪怕都是RTX 3060)。官方明确提示“两张卡,一张卡起不来”,这是因为模型在vLLM中启用了多GPU张量并行(tensor parallelism),单卡会报RuntimeError: tensor parallel size must be > 1。
我们以双卡环境为例(如两块RTX 3060 12GB):
# 查看GPU状态 nvidia-smi -L # 输出示例: # GPU 0: NVIDIA GeForce RTX 3060 (UUID: GPU-xxxx) # GPU 1: NVIDIA GeForce RTX 3060 (UUID: GPU-yyyy)确保已安装:
- Python ≥ 3.10
- CUDA 12.1+(vLLM 0.6+要求)
nvidia-driver≥ 535
2.2 安装vLLM与Chandra OCR核心包
不要用pip install chandra-ocr——那是面向终端用户的简化包,不包含vLLM适配逻辑。我们需要从源码安装带vLLM backend的版本:
# 创建干净虚拟环境 python -m venv chandra-env source chandra-env/bin/activate # Linux/macOS # chandra-env\Scripts\activate # Windows # 升级pip并安装基础依赖 pip install --upgrade pip pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 # 安装vLLM(关键:指定CUDA版本) pip install vllm==0.6.3.post1 # 安装Chandra OCR(使用官方GitHub主干,含vLLM backend支持) pip install git+https://github.com/datalab-to/chandra-ocr.git@main#subdirectory=chandra注意:
chandra-ocr的 PyPI 包(pip install chandra-ocr)默认只支持HuggingFace后端,不支持vLLM。必须从GitHub源码安装,并确保chandra子模块被正确加载。
验证安装是否成功:
# test_install.py from chandra import ChandraOCR print("Chandra OCR import OK") print("vLLM backend available:", hasattr(ChandraOCR, 'from_vllm'))运行后应输出vLLM backend available: True。
3. 启动vLLM推理服务
3.1 启动vLLM引擎(非FastAPI,纯推理层)
Chandra OCR的vLLM backend本质是把OCR任务建模为“视觉编码器→文本解码器”的端到端生成,因此需用vLLM的vllm.entrypoints.api_server启动一个标准LLM服务,但加载的是Chandra的视觉语言模型。
先获取模型权重路径(官方提供HuggingFace Hub地址):
- 模型ID:
datalab-to/chandra-ocr-base - 权重协议:OpenRAIL-M(商用需授权,测试免费)
启动命令(双卡并行):
vllm serve \ --model datalab-to/chandra-ocr-base \ --tensor-parallel-size 2 \ --dtype bfloat16 \ --max-model-len 8192 \ --gpu-memory-utilization 0.95 \ --port 8000 \ --host 0.0.0.0参数说明:
--tensor-parallel-size 2:强制启用双卡张量并行(单卡必失败)--max-model-len 8192:Chandra处理长PDF需大上下文--gpu-memory-utilization 0.95:激进但必要,4GB显存卡也能跑满
启动后,你会看到类似日志:
INFO 05-15 14:22:33 [api_server.py:227] vLLM API server started on http://0.0.0.0:8000 INFO 05-15 14:22:33 [engine.py:201] Total number of blocks: 12800此时vLLM服务已在http://localhost:8000运行,但还不是OCR接口——它只是个裸LLM服务,需要上层封装才能理解“上传图片→返回Markdown”。
3.2 测试vLLM原始接口(可选验证)
用curl发一个空请求,确认服务通:
curl http://localhost:8000/health # 返回 {"status":"healthy"}再试一个简单文本生成(非OCR)验证模型加载:
curl http://localhost:8000/generate \ -H "Content-Type: application/json" \ -d '{ "prompt": "OCR任务开始,请输出:", "max_tokens": 10 }'如果返回含"text"字段的JSON,说明vLLM层已就绪。
4. 封装为FastAPI微服务
4.1 设计API接口规范
我们定义一个RESTful接口,符合OCR实际使用习惯:
| 方法 | 路径 | 功能 | 输入格式 |
|---|---|---|---|
| POST | /ocr | 执行OCR识别 | multipart/form-data,含file(图片/PDF)和output_format(markdown/html/json) |
| GET | /health | 健康检查 | 无 |
响应统一为JSON:
{ "success": true, "output": "## 标题\n\n- 列表项\n\n| 表头 | 表头 |\n|---|---|\n| 内容 | 内容 |", "format": "markdown", "page_count": 1, "processing_time_ms": 1240 }4.2 编写FastAPI服务代码
创建app.py:
# app.py import os import tempfile import asyncio from fastapi import FastAPI, File, UploadFile, Form, HTTPException from fastapi.responses import JSONResponse from pydantic import BaseModel from chandra import ChandraOCR import time # 初始化Chandra OCR(指向本地vLLM服务) ocr_engine = ChandraOCR.from_vllm( base_url="http://localhost:8000", # vLLM服务地址 model_name="datalab-to/chandra-ocr-base" ) app = FastAPI( title="Chandra OCR API Service", description="将Chandra OCR封装为标准HTTP微服务,支持图片/PDF转Markdown/HTML/JSON", version="1.0.0" ) class OCRRequest(BaseModel): output_format: str = "markdown" @app.get("/health") async def health_check(): return {"status": "healthy", "service": "chandra-ocr-api"} @app.post("/ocr") async def run_ocr( file: UploadFile = File(...), output_format: str = Form("markdown") ): # 支持格式校验 supported_formats = ["markdown", "html", "json"] if output_format not in supported_formats: raise HTTPException( status_code=400, detail=f"output_format must be one of {supported_formats}" ) # 临时保存上传文件(vLLM backend需要文件路径) try: with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(file.filename)[1]) as tmp: content = await file.read() tmp.write(content) tmp_path = tmp.name start_time = time.time() # 调用Chandra OCR(自动处理PDF/图片,返回结构化结果) result = ocr_engine.run( input_path=tmp_path, output_format=output_format, # 可选:启用表格/公式增强解析 enable_table=True, enable_math=True ) processing_time = int((time.time() - start_time) * 1000) # 清理临时文件 os.unlink(tmp_path) return JSONResponse({ "success": True, "output": result, "format": output_format, "page_count": getattr(ocr_engine, "page_count", 1), "processing_time_ms": processing_time }) except Exception as e: # 清理可能残留的临时文件 if 'tmp_path' in locals(): try: os.unlink(tmp_path) except: pass raise HTTPException(status_code=500, detail=f"OCR processing failed: {str(e)}") if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8001, workers=1)4.3 启动FastAPI服务
# 安装FastAPI依赖 pip install fastapi uvicorn python-multipart # 启动服务(监听8001端口,避免与vLLM的8000冲突) uvicorn app:app --host 0.0.0.0 --port 8001 --reload服务启动后,访问http://localhost:8001/docs即可看到自动生成的Swagger UI界面——所有接口、参数、示例请求、响应结构一目了然,无需手写任何YAML。
5. 实际调用演示与效果验证
5.1 使用curl测试OCR接口
准备一张含表格的扫描件invoice.png,执行:
curl -X POST "http://localhost:8001/ocr" \ -F "file=@invoice.png" \ -F "output_format=markdown" \ -H "accept: application/json" | jq '.output' | head -n 20你会看到类似输出:
## 发票信息 | 项目 | 数量 | 单价 | 金额 | |------|------|------|------| | 服务器租赁 | 1 | ¥12,000.00 | ¥12,000.00 | | 技术支持 | 12月 | ¥2,500.00 | ¥30,000.00 | | **合计** | | | **¥42,000.00** |表格结构完整保留,Markdown语法标准,可直接粘贴进Notion或导入RAG系统。
5.2 Swagger UI交互式测试
打开浏览器访问http://localhost:8001/docs:
- 点击
/ocr接口 → “Try it out” - 在
file字段选择本地图片/PDF - 在
output_format输入框填html或json - 点击 “Execute”
几秒后,右侧实时显示:
- 响应状态码(200)
- 完整JSON响应体(含
output字段) - 请求耗时(通常1–3秒,取决于PDF页数)
无需写一行客户端代码,产品、测试、前端同学都能立刻上手验证。
6. 生产部署建议与避坑指南
6.1 关键配置优化
| 场景 | 推荐配置 | 原因 |
|---|---|---|
| 高并发批量处理 | uvicorn ... --workers 4 --limit-concurrency 100 | 防止单个大PDF阻塞其他请求 |
| 内存敏感环境 | vllm serve ... --max-num-seqs 4 --block-size 16 | 降低KV缓存内存占用 |
| PDF多页处理 | ChandraOCR.run(..., max_pages=5) | 防止超长PDFOOM(默认不限制) |
6.2 常见问题与解决方案
问题:
RuntimeError: tensor parallel size must be > 1
解决:确认vllm serve命令中--tensor-parallel-size 2已设置,且nvidia-smi显示2张GPU均被识别。问题:上传PDF返回空结果或超时
解决:检查PDF是否加密(Chandra不支持加密PDF);增大--max-model-len 16384;添加timeout=300到FastAPI的uvicorn.run()。问题:Swagger UI无法上传文件(422错误)
解决:确保UploadFile参数未设默认值(即file: UploadFile = File(...),不能是File(None));检查浏览器控制台是否有CORS报错(开发时加--cors-allow-all)。问题:中文输出乱码或缺失
解决:vLLM启动时加--tokenizer-mode auto,确保加载正确的分词器;Chandra模型本身已支持40+语种,无需额外配置。
7. 总结:从工具到服务的工程化跃迁
把Chandra OCR从一个pip install就能跑的CLI工具,变成一个带Swagger文档、可监控、可集成的HTTP微服务,看似只是加了一层封装,实则完成了三个关键升级:
- 可用性升级:不再依赖本地Python环境,任何语言(Java/Go/JS)都能通过HTTP调用
- 可观测性升级:FastAPI自动记录请求日志、耗时、错误码,配合Prometheus可做QPS/延迟监控
- 协作效率升级:Swagger UI让前后端无需开会对齐接口,前端直接生成调用代码,测试同学点点鼠标就能压测
你不需要成为vLLM专家,也不用深入Chandra的ViT-Encoder细节。只要记住三步:
1⃣ 用vllm serve启动双卡推理引擎
2⃣ 用ChandraOCR.from_vllm()桥接OCR逻辑
3⃣ 用FastAPI暴露标准REST接口 + 自动Swagger
剩下的,就是把生成的Markdown喂给你的知识库、文档系统或AI助手——让OCR真正成为你数据流水线里沉默但可靠的“排版翻译官”。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。