公司动态

构建OpenAI兼容OCR API:统一GLM-OCR、DeepSeek-OCR-2等多模型调用接口

📅 2026/9/2 13:45:32
构建OpenAI兼容OCR API:统一GLM-OCR、DeepSeek-OCR-2等多模型调用接口
1. 先搞清楚这个方案到底解决什么问题如果你正在找一种方法能让你在本地或自己的服务器上像调用 OpenAI 的 ChatGPT API 一样去调用 GLM-OCR、DeepSeek-OCR-2、Dots.mocr 这些 OCR 模型那这个主题就值得你看下去。它解决的核心痛点很直接统一接口。现在各种 OCR 模型层出不穷每个都有自己的调用方式、输入格式和输出结构。开发一个应用如果想同时支持多个模型做备选或对比就得写好几套适配代码非常麻烦。这个方案的目标就是给这些不同的 OCR 模型套上一个“OpenAI 兼容 API”的壳子。这样一来你只需要学会一种 API 调用方式就是 OpenAI 那种就能以几乎相同的方式去使用背后不同的 OCR 引擎。这特别适合几类人应用开发者想在自己的产品里集成 OCR 功能但不想被某个特定厂商或模型绑定死。算法研究者/工程师需要快速对比不同 OCR 模型在自家数据上的效果但又不想为每个模型单独写测试脚本。有私有化部署需求的企业或团队数据敏感不能上传到公网 API需要在本地或内网部署 OCR 服务并希望接口标准化。最关键的价值不是某个模型多厉害而是降低了集成和切换的成本。你可以今天用 GLM-OCR明天发现 DeepSeek-OCR-2 对某种字体识别更好只需要在配置里改个模型名业务代码几乎不用动。下面我就以一个实际部署者的角度带你走一遍从理解到落地的全过程。我会重点讲清楚环境怎么配、服务怎么起、API 怎么调以及最重要的——跑起来之后怎么验证效果、怎么排查那些看起来像模型问题但其实是环境或参数问题的坑。2. 部署前环境、模型与兼容层选择在动手敲命令之前得先把“地基”打好。这里的环境准备比单纯跑一个模型 Demo 要复杂一点因为它涉及三部分模型本身、API 兼容层、以及你的运行环境。2.1 核心组件拆解OCR 模型本体GLM-OCR智谱的 OCR 模型通常以仓库形式提供需要克隆、安装依赖、可能还需要下载预训练权重。DeepSeek-OCR-2深度求索的 OCR 模型同样需要从其官方渠道获取模型文件或代码。Dots.mocr这可能是一个特定项目或仓库的 OCR 实现需要找到其源码。关键点你必须先确保能在本地独立运行起来这个模型最基本的推理功能。比如给你一张图能用模型自带的脚本或例子跑出识别结果。这是后续所有工作的前提。OpenAI 兼容 API 层这是本方案的核心。你需要一个“适配器”它能够接收标准 OpenAI 格式的请求特别是 Chat Completion 那种然后将其转换成对应 OCR 模型所需的输入调用模型推理最后再将结果包装成 OpenAI 格式的响应返回。常见的实现方式有专门为某个模型写的兼容服务比如glm-ocr-openai-server。通用模型服务框架比如vLLM、TGI(Text Generation Inference)它们原生或通过配置支持 OpenAI 兼容接口。但 OCR 模型通常是多模态图像文本的需要确认框架是否支持视觉模型。使用openai库的v1/chat/completions端点模拟一些项目会利用 FastAPI 等框架自己实现这个端点的处理逻辑。我们的目标就是部署这样一个服务让它监听一个端口比如8000等着接收请求。你的客户端任何能发送 HTTP POST 请求的工具或代码库。最方便的就是直接使用openai这个 Python 库把base_url指向你本地服务的地址api_key可以随便填一个如果服务端没做鉴权的话。这样你的调用代码和调用真正的 OpenAI API 几乎一模一样。2.2 环境与资源评估这不是一个轻量级的 Web 应用对资源有一定要求。操作系统LinuxUbuntu/CentOS是首选macOS 也可行Windows 可能需要更多配置尤其是 GPU 支持。Python版本通常是 3.8具体看模型和兼容层的要求。强烈建议使用虚拟环境venv或conda隔离依赖。深度学习框架PyTorch 是主流。需要根据你的 CUDA 版本如果有 GPU安装对应的 PyTorch。GPU强烈推荐OCR 推理尤其是处理高分辨率图片或批量处理时GPU 能带来数量级的速度提升。需要检查CUDA 版本nvidia-smi查看驱动支持的 CUDA 最高版本。显存这是硬约束。模型加载就要占用一部分每张图片推理再占用一部分。GLM-OCR、DeepSeek-OCR-2 这类模型建议准备8GB 以上显存会比较从容。处理大批量或大图时需要更多。CPU 内存如果没有 GPU 或显存不够可以回退到 CPU 模式但速度会慢很多。内存建议16GB 以上因为模型权重和图片数据都会加载到内存。磁盘空间模型文件尤其是大语言模型基座视觉编码器可能很大几个 G 到几十个 G 不等。预留充足空间。我的建议先别急着部署全套。第一步先去每个 OCR 模型的官方仓库按照它们的 README在本地跑通一个最简单的图片识别示例。这能帮你提前解决掉 80% 的依赖和环境问题。3. 实战部署以 GLM-OCR 为例搭建服务假设我们已经选定了 GLM-OCR 作为第一个部署的模型。这里我给出一个通用的、分步走的部署思路具体命令可能因项目更新而微调但流程是共通的。3.1 第一步搞定模型本体# 1. 克隆模型仓库假设仓库地址 git clone https://github.com/THUDM/GLM-OCR.git cd GLM-OCR # 2. 创建并激活虚拟环境 python -m venv venv_glm_ocr source venv_glm_ocr/bin/activate # Linux/macOS # venv_glm_ocr\Scripts\activate # Windows # 3. 安装依赖。仔细看 requirements.txt可能需要特定版本的 torch pip install -r requirements.txt # 4. 下载预训练模型权重。通常仓库会提供下载脚本或说明。 # 例如bash download_models.sh 或从 Hugging Face 下载 # 将权重文件放到指定的目录比如 ./model_weights/ # 5. 运行官方示例验证模型能正常工作 python examples/run_demo.py --image_path ./test_image.jpg如果这一步能成功输出图片中的文字恭喜你最难关卡之一已过。记下这个成功运行所必需的环境Python 版本、PyTorch 版本、其他关键库版本。3.2 第二步引入 OpenAI 兼容层现在需要让 GLM-OCR 能够通过 HTTP API 被调用。我们需要一个“服务化”的包装。情况 A项目自带或社区有现成的兼容服务。这是最理想的情况。去 GLM-OCR 的仓库 Issues、Discussions 或者 GitHub 上搜索glm-ocr openai api server之类的关键词。如果找到就按照它的文档部署。它可能是一个额外的api_server.py文件。情况 B需要自己基于通用框架搭建。如果没有现成的我们可以用 FastAPI 快速构建一个。思路是创建一个 FastAPI 应用。加载 GLM-OCR 模型复用第一步已验证的代码。定义一个/v1/chat/completions的 POST 接口。在接口中从请求中提取图片数据可能是 base64、URL 或文件路径调用 GLM-OCR 模型推理。将识别出的文本按照 OpenAI Chat Completion 的响应格式包装返回。下面是一个极度简化的概念性代码框架用于说明逻辑# server.py (概念示例不可直接运行) from fastapi import FastAPI, HTTPException from pydantic import BaseModel import uvicorn # 导入你第一步中验证可用的 GLM-OCR 推理函数 from your_glm_ocr_inference_module import process_image app FastAPI() class ChatMessage(BaseModel): role: str content: str # 这里可能包含图片信息需要约定格式如 [image:base64_data] class ChatCompletionRequest(BaseModel): model: str glm-ocr # 客户端指定的模型名 messages: list[ChatMessage] # 可以添加其他参数但需处理 app.post(/v1/chat/completions) async def create_chat_completion(request: ChatCompletionRequest): # 1. 从 messages 中解析出图片信息。 # 通常用户消息 content 可能是一个列表包含文本和图片。 # 这里需要你定义一种协议例如图片是 base64 字符串。 image_data extract_image_from_messages(request.messages) if not image_data: raise HTTPException(status_code400, detailNo image found in request) # 2. 调用 GLM-OCR 核心函数 try: ocr_result_text process_image(image_data) # 这是关键调用 except Exception as e: raise HTTPException(status_code500, detailfOCR processing failed: {str(e)}) # 3. 包装成 OpenAI 格式的响应 response { id: chatcmpl-123, object: chat.completion, created: 1677652288, model: request.model, choices: [{ index: 0, message: { role: assistant, content: ocr_result_text # 识别出的文本作为助手回复 }, finish_reason: stop }], usage: { prompt_tokens: 0, # OCR模型可能不计算token可设为0或估算 completion_tokens: len(ocr_result_text.split()), total_tokens: 0 } } return response def extract_image_from_messages(messages): # 实现你的图片提取逻辑 # 例如约定最后一条用户消息的 content 是图片 base64 for msg in reversed(messages): if msg.role user: # 这里需要解析 content可能是纯 base64也可能是复杂结构 # 假设 content 直接就是 base64 图片字符串 if msg.content.startswith(data:image): return msg.content return None if __name__ __main__: # 在启动前确保你的 GLM-OCR 模型已经加载好 # init_model() ... uvicorn.run(app, host0.0.0.0, port8000)这个框架的重点是process_image函数它需要你从第一步能运行的 GLM-OCR 示例代码中抽象出来。真正的难点在于设计请求格式如何把图片和可能的文本指令例如“只识别中文”一起传给 API。OpenAI 的视觉模型 API 是一个很好的参考。3.3 第三步启动服务并测试启动服务cd /path/to/your/api_server_directory source venv_glm_ocr/bin/activate python server.py看到服务在0.0.0.0:8000启动成功的日志。使用curl进行最简测试 假设你的接口接收 base64 图片。# 将图片转为 base64 (Linux/macOS) IMAGE_BASE64$(base64 -i test_image.jpg | tr -d \n) curl http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer fake-key \ -d { model: glm-ocr, messages: [ {role: user, content: $IMAGE_BASE64} ] }检查返回的 JSON 中choices[0].message.content是否为识别出的文本。使用openaiPython 库测试推荐 这更能体验“兼容”的效果。# test_client.py from openai import OpenAI client OpenAI( base_urlhttp://localhost:8000/v1, # 指向你的本地服务 api_keyfake-key # 如果服务端不需要鉴权任意字符串即可 ) # 读取图片为二进制然后转为 base64 import base64 with open(test_image.jpg, rb) as image_file: image_data base64.b64encode(image_file.read()).decode(utf-8) # 构造请求。注意这里需要根据你的服务端实现的协议来构造 messages。 # 以下是一种可能的格式你需要调整以匹配你的 server.py 的 extract_image_from_messages 逻辑。 completion client.chat.completions.create( modelglm-ocr, messages[ { role: user, content: [ {type: text, text: 识别这张图片中的文字}, { type: image_url, image_url: { url: fdata:image/jpeg;base64,{image_data} } } ] } ] ) print(completion.choices[0].message.content)如果这段代码能成功打印出识别结果那么你的 OpenAI 兼容 API 服务就基本搭建成功了。4. 关键细节、参数与生产化考量服务能跑通只是第一步。要真正可用尤其是支持 DeepSeek-OCR-2、Dots.mocr 等多个模型还需要处理很多细节。4.1 统一的请求响应协议这是实现“兼容”的关键。你需要为所有模型定义一套统一的输入输出格式。输入格式如何通过messages字段传递图片和文本指令方案一类 OpenAI Vision使用content数组包含type: “text”和type: “image_url”的对象。image_url可以是data:image/...;base64,格式。这是目前比较主流和清晰的方式。方案二自定义文本标记在content文本字符串中嵌入特殊标记如[IMAGE:base64_data]。解析起来稍复杂但结构简单。方案三多部分表单不使用messages而是用文件上传。但这偏离了 OpenAI Chat Completion 的格式。建议优先采用方案一因为它最接近标准且被越来越多的多模态模型 API 采用。你的server.py中的extract_image_from_messages函数就需要按照这个格式来解析。输出格式严格遵循 OpenAI Chat Completion 的响应 JSON 结构。重点是choices[0].message.content必须包含识别出的纯文本或结构化文本如 JSON。如果需要返回文本框位置、置信度等信息可以放在content的一个 JSON 字符串里或者通过响应中的其他自定义字段返回但这样会降低兼容性。4.2 服务端核心参数与配置在你的兼容层服务中需要考虑以下配置通常可以通过环境变量或配置文件管理参数说明示例/建议MODEL_PATH不同 OCR 模型权重文件的路径。GLM_OCR_WEIGHTS/path/to/glm-ocr-weightsDEVICE推理设备。cuda:0,cpu。CUDA_VISIBLE_DEVICES0MAX_IMAGE_SIZE服务端允许处理的图片最大尺寸宽*高。防止内存/显存溢出。1024*1024BATCH_SIZE如果支持批量推理一次处理多少张图。GPU 下可调大以提高吞吐。1(默认) 或4,8TIMEOUT单次推理超时时间。30(秒)LOG_LEVEL日志级别。调试时用DEBUG生产用INFO。INFOAPI_KEYS如果启用鉴权有效的 API Key 列表。sk-xxx,sk-yyy生产环境建议使用进程管理器不要直接用python server.py跑在前台。用gunicorn(配合uvicornworker) 或supervisor来管理进程实现崩溃重启、日志轮转。gunicorn -w 2 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000 server:app启用鉴权在服务端简单校验请求头中的Authorization: Bearer api_key是否在你允许的列表中。健康检查端点添加一个/health的 GET 接口返回服务状态和模型加载情况方便监控。请求限流根据你的服务器性能使用中间件对接口进行限流防止被刷。4.3 客户端调用最佳实践对于调用方你的业务代码使用 OpenAI SDK 是最佳选择。import openai from openai import OpenAI client OpenAI( base_urlhttp://your-server-ip:8000/v1, # 你的 OCR API 服务地址 api_keyyour-secret-api-key-here # 如果服务端启用了鉴权 ) def ocr_with_openai_api(image_path, model_nameglm-ocr, prompt识别文字): import base64 with open(image_path, rb) as f: image_b64 base64.b64encode(f.read()).decode() response client.chat.completions.create( modelmodel_name, # 通过此参数切换不同模型服务端路由 messages[ { role: user, content: [ {type: text, text: prompt}, { type: image_url, image_url: { url: fdata:image/jpeg;base64,{image_b64} } } ] } ], max_tokens1024, # 控制返回文本的最大长度 temperature0.0, # OCR通常不需要创造性设为0 ) return response.choices[0].message.content # 使用 result ocr_with_openai_api(invoice.jpg, model_namedeepseek-ocr-2) print(result)关键点model参数是你的“路由键”。服务端根据这个值决定加载哪个 OCR 模型。你可以在服务端维护一个模型名称到实际模型加载句柄的映射。max_tokens需要根据 OCR 结果的可能长度设置一个足够大的值。temperature设为 0保证输出确定性。5. 多模型管理与常见问题排查当你把 GLM-OCR 的服务搭起来后集成 DeepSeek-OCR-2 或 Dots.mocr 就变成了模式化的操作。核心是设计一个模型路由管理器。5.1 实现模型路由在服务端初始化时根据配置加载所有需要的模型。# model_manager.py class OCRModelManager: def __init__(self): self.models {} def load_model(self, model_name, model_path, devicecuda:0): if model_name glm-ocr: from glm_ocr_integration import load_glm_ocr self.models[model_name] load_glm_ocr(model_path, device) elif model_name deepseek-ocr-2: from deepseek_ocr_integration import load_deepseek_ocr self.models[model_name] load_deepseek_ocr(model_path, device) elif model_name dots-mocr: from dots_mocr_integration import load_dots_mocr self.models[model_name] load_dots_mocr(model_path, device) else: raise ValueError(fUnsupported model: {model_name}) def infer(self, model_name, image_data): if model_name not in self.models: raise ValueError(fModel {model_name} not loaded) model self.models[model_name] # 调用对应模型的推理函数统一返回文本 return model.process(image_data) # 在 server.py 中初始化 manager OCRModelManager() manager.load_model(glm-ocr, config.GLM_MODEL_PATH, device) manager.load_model(deepseek-ocr-2, config.DEEPSEEK_MODEL_PATH, device) # 在 API 端点中调用 ocr_result_text manager.infer(request.model, image_data)这样客户端只需要在请求中指定不同的model参数就可以调用不同的 OCR 引擎。5.2 系统性排查清单当你的 API 服务出现问题时不要第一时间怀疑模型能力按以下顺序排查服务是否存活curl http://localhost:8000/health(如果你实现了健康检查)。查看服务进程日志是否有崩溃信息。请求格式是否正确这是最常见的问题。用最简单的curl命令或 Python 脚本发送一个最小请求确保你的messages结构、图片编码方式base64 格式是否正确是否包含data:image/...前缀完全符合服务端解析逻辑。建议在服务端extract_image_from_messages函数开始处打印接收到的messages原始内容确认解析无误。模型加载是否成功查看服务启动日志确认每个模型都打印了加载成功的消息。检查模型文件路径是否正确权限是否足够。资源是否够用GPU 显存不足服务能启动但一推理就崩溃或卡住。用nvidia-smi观察推理时的显存占用。解决方案减小MAX_IMAGE_SIZE降低BATCH_SIZE或者换用更小的模型变体。CPU 内存不足处理大图或批量时被系统杀死。观察htop或free -m。请求超时图片太大或模型在 CPU 上推理太慢超过客户端或服务端设置的超时时间。调整超时参数或优化图片预处理如缩放。依赖版本冲突不同模型可能依赖不同版本的 PyTorch、Transformers 或其他库。这是多模型部署的最大挑战。终极方案为每个模型创建独立的虚拟环境然后通过子进程调用或HTTP 微服务的方式隔离。即每个 OCR 模型作为一个独立的服务运行在不同的端口你的主 API 网关兼容层根据model参数将请求转发到对应的后端微服务。这样彻底解决了环境隔离问题但架构复杂度增加。输出格式错误服务端返回了 200但客户端解析失败。检查服务端返回的 JSON 结构是否严格符合 OpenAI 格式特别是choices[0].message.content字段是否存在且为字符串。5.3 性能与稳定性优化启用批处理如果单个请求处理一张图GPU 利用率可能很低。修改服务端支持将短时间内收到的多个请求的图片合并成一个批次进行推理能极大提升吞吐量。这需要设计一个简单的请求队列和批量调度器。异步处理使用async/await防止 IO 操作如图片解码、网络传输阻塞整个服务。FastAPI 本身支持异步。结果缓存如果同一张图片可能被重复识别可以增加一个基于图片哈希的缓存层避免重复计算。监控与告警记录请求量、响应时间、错误率。当错误率飙升或响应时间变长时触发告警。6. 总结从“跑通”到“用好”搭建一个 OpenAI 兼容的 OCR API 服务技术上的核心是协议适配和模型路由。GLM-OCR、DeepSeek-OCR-2、Dots.mocr 只是几个具体的实现例子这套方法可以扩展到任何你需要的 OCR 或 AI 模型上。我个人的实践建议是分而治之先集中精力让一个模型比如 GLM-OCR在裸环境下跑通其原生示例。这是所有工作的基石。搭建桥梁再基于这个可运行的模型编写或寻找一个最简单的 OpenAI 兼容 API 包装层。用单张图片测试确保“进图-出文”的链路通畅。完善协议设计好稳定、清晰的请求响应格式强烈建议模仿 OpenAI Vision API。这个格式一旦定好所有客户端和后续模型都要遵守。逐个集成用同样的模式去集成第二个、第三个模型。此时你会遇到环境冲突问题根据严重程度决定是依赖调和还是进程隔离。生产加固最后考虑鉴权、限流、日志、监控、部署方式Docker 化等生产级需求。不要一开始就追求大而全的、支持所有模型的生产级系统。从单个模型的兼容 API 开始跑通一个完整的用例你就能掌握其中的所有关键环节和坑点。之后无论是扩展模型数量还是提升服务性能都有了可靠的抓手。最终你会发现最大的挑战往往不是模型本身的精度而是如何让这些模型在你的技术栈里稳定、高效、易用地跑起来。