资讯动态

智谱开源GLM-OCR实战:基于GLM-V编码器-解码器架构的多模态OCR模型部署与验证

发布时间:2026/10/9 13:43:02 来源:尧图企业网站定制
1. 为什么我要在本地跑 GLM-OCR从一次票据识别翻车说起先说结论GLM-OCR 是智谱开源的一个多模态 OCR 模型基于 GLM-V 编码器-解码器架构参数量只有 0.9B能识别文字、公式、表格还能按你给的 JSON 结构做信息抽取。它适合谁适合手头有一堆扫描件、发票、合同、代码截图又不想把图片传到别人服务器上的开发者也适合想在边缘设备或本地工作站上跑文档理解流水线的人。我最初盯上它是因为一个很具体的需求手上有几百张格式不统一的采购单据字段位置飘忽传统 OCR 出来是一堆散字还得自己写正则去拼。试过几个方案要么表格线一多就串行要么公式直接变乱码。后来看到 GLM-OCR 在 OmniDocBench V1.5 上综合分 94.62公式、表格、信息抽取都是 SOTA而且只有 0.9B就决定在本地部署验证一下。这篇文章不聊虚的直接交付三样东西可复制的环境配置、能跑通的模型加载脚本、以及图片识别的测试用例和输出解析方法。你跟着做半小时内应该能看到第一张图的识别结果。中间我会把踩过的坑标出来尤其是编码器-解码器结构下输出解析容易出错的地方。需要说明的是GLM-OCR 的架构分三块视觉侧是 CogViT 编码器用大规模图文数据预训练过中间是一个轻量级跨模态连接器做令牌降采样解码器是 GLM-0.5B 语言模型。训练时用了多令牌预测MTP损失和全任务强化学习所以它在复杂版面上的泛化比一般 OCR 稳。理解这个结构对后面调 prompt 和解析输出很关键——编码器负责“看”连接器负责“压缩对齐”解码器负责“按指令生成文本或 JSON”。2. 部署前的准备TaoToken 接入与 GLM-OCR 环境依赖梳理在本地跑 GLM-OCR 之前有个现实问题模型权重下载、依赖版本冲突、以及如果你还想同时调用其他大模型做后处理怎么统一管理密钥。我的做法是把模型推理和 API 调用分开GLM-OCR 本地跑后处理或对比验证走 TaoToken 的 API。TaoToken 在这里的角色是统一接入层。官网是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口是 https://taotoken.net/api 。你可以在控制台创建 API Key然后用于模型对话、Coding Plan 或接入文档里的各种场景。对于这篇 OCR 教程来说它的用处是当你识别完图片想把结果丢给语言模型做字段校验或结构化清洗时不用再单独配一套密钥。具体操作路径先到 API Keys 页面生成一个 Key地址是 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 。生成后保存好后面在环境变量里引用。如果你只是想先验证 GLM-OCR 本身这一步可以跳过但建议还是配一下因为后面做信息抽取的 JSON 校验时会用到。环境依赖这块GLM-OCR 官方给了四种部署方案vLLM、SGLang、Ollama、Transformers。我实测下来如果你只是做验证Transformers 方案最直接不用起服务如果要高并发或生产用vLLM 更合适。Ollama 最省事但版本更新可能滞后。基础环境建议Python 3.10 或 3.113.12 在某些依赖上会有编译问题CUDA 12.1 以上显卡显存至少 8GB0.9B 模型 fp16 大概 2GB 权重但视觉编码器吃显存磁盘预留 10GB 以上模型权重和缓存先装基础依赖pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 pip install githttps://github.com/huggingface/transformers.git pip install accelerate pillow requests注意 transformers 必须从 GitHub 装最新版因为 GLM-OCR 用了AutoModelForImageTextToText这个较新的接口PyPI 上的稳定版可能还没有。我踩过的坑是直接用pip install transformers装完导入AutoModelForImageTextToText报 ImportError折腾了半小时才发现要装 git 版。如果你要用 vLLM 方案额外装pip install -U vllm --extra-index-url https://wheels.vllm.ai/nightlyvLLM 的 nightly 源在国内下载可能慢可以配个镜像。Docker 方案也行docker pull vllm/vllm-openai:nightlyOllama 方案最简单装完 Ollama 后直接ollama run glm-ocr然后把图片拖进终端它会自动识别路径。但 Ollama 的模型版本可能不是最新的做严谨验证还是建议 Transformers 或 vLLM。关于 TaoToken 的接入配置如果你要在代码里调用它的 API 做后处理可以这样设环境变量export TAOTOKEN_API_KEY你的Key export TAOTOKEN_BASE_URLhttps://taotoken.net/api然后在 Python 里用 requests 调用即可。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有完整的请求格式说明。这样你的 OCR 流水线就是本地 GLM-OCR 出原始文本 → TaoToken API 做结构化校验两边解耦互不影响。3. 可复制配置GLM-OCR 的 Transformers 加载脚本与 settings 片段这一节直接给可复制的代码和配置。我按 Transformers 方案写因为最容易验证也方便你改参数。先建一个工作目录比如glm-ocr-test然后在里面放测试图片。我用的测试图是一张包含表格和公式的文档截图命名为test_image.png。核心加载脚本run_ocr.pyfrom transformers import AutoProcessor, AutoModelForImageTextToText import torch MODEL_PATH zai-org/GLM-OCR messages [ { role: user, content: [ {type: image, url: test_image.png}, {type: text, text: Text Recognition:}, ], } ] processor AutoProcessor.from_pretrained(MODEL_PATH) model AutoModelForImageTextToText.from_pretrained( pretrained_model_name_or_pathMODEL_PATH, torch_dtypeauto, device_mapauto, ) inputs processor.apply_chat_template( messages, tokenizeTrue, add_generation_promptTrue, return_dictTrue, return_tensorspt, ).to(model.device) inputs.pop(token_type_ids, None) generated_ids model.generate(**inputs, max_new_tokens8192) output_text processor.decode( generated_ids[0][inputs[input_ids].shape[1]:], skip_special_tokensFalse, ) print(output_text)这段代码有几个关键点。第一inputs.pop(token_type_ids, None)必须加否则某些 transformers 版本会报 unexpected key。第二max_new_tokens8192对长文档够用但如果你只识别短文本可以降到 2048 省时间。第三skip_special_tokensFalse是为了看到完整输出调试时有用生产环境可以设 True。如果你要用 vLLM 起服务配置如下pip install githttps://github.com/huggingface/transformers.git vllm serve zai-org/GLM-OCR --allowed-local-media-path / --port 8080注意--allowed-local-media-path /这个参数不加的话本地图片路径会被拒绝。起完服务后用 OpenAI 兼容接口调用from openai import OpenAI client OpenAI(base_urlhttp://localhost:8080/v1, api_keydummy) response client.chat.completions.create( modelzai-org/GLM-OCR, messages[ { role: user, content: [ {type: image_url, image_url: {url: file:///path/to/test_image.png}}, {type: text, text: Text Recognition:}, ], } ], max_tokens8192, ) print(response.choices[0].message.content)这里有个 settings 片段值得单独说如果你用 Cline 或 Claude Code 这类工具做辅助开发需要配 Base URL、Key、Model ID 三件套。以 Cline 的 MCP 配置为例在settings.json里{ mcpServers: { glm-ocr-local: { command: python, args: [-m, glm_ocr_server], env: { GLM_OCR_BASE_URL: http://localhost:8080/v1, GLM_OCR_API_KEY: dummy, GLM_OCR_MODEL_ID: zai-org/GLM-OCR } } } }如果你用 Codex 的auth.json格式类似{ base_url: http://localhost:8080/v1, api_key: dummy, model: zai-org/GLM-OCR }三件套缺一不可Base URL 指向本地 vLLM 服务Key 随便填本地服务不校验Model ID 必须是zai-org/GLM-OCR。我见过有人只填 URL 不填 Model ID结果请求发出去报 model not found。另外如果你要把 TaoToken 作为后处理接入可以在同一个 settings 里加一组{ taotoken: { base_url: https://taotoken.net/api, api_key: 你的Key, model: 你选的模型ID } }这样 OCR 和清洗两条链路就都配好了。Coding Plan 适合长期做这类流水线的场景地址是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 有需要可以看看。4. 验证请求图片识别测试用例与编码器-解码器输出解析配置写完跑起来看结果。我用一张包含标题、段落、一个三线表和一条公式的文档截图做测试。执行python run_ocr.py第一次跑会下载模型权重大概 2GB 左右取决于网速。下载完后输出类似Text Recognition: # 2024年度采购汇总 | 项目 | 数量 | 单价 | 金额 | |------|------|------|------| | 服务器 | 2 | 12000 | 24000 | | 交换机 | 5 | 800 | 4000 | 合计金额28000 元 公式E mc^2实测下来表格结构保留得不错公式也正确识别成了 LaTeX 风格。这就是编码器-解码器架构的好处编码器把图像切成 patch 后提取视觉特征连接器做令牌降采样压缩序列长度解码器再按 prompt 指令自回归生成文本。因为解码器是语言模型它天然会把表格转成 Markdown把公式转成 LaTeX不需要你额外写后处理规则。但输出解析有几个坑。第一skip_special_tokensFalse时输出里会带特殊 token比如|endoftext|或|assistant|你需要自己 strip 掉。第二如果图片里有多个区域模型可能按阅读顺序输出但复杂版面下顺序可能乱建议配合 PP-DocLayout-V3 做两阶段先版面分析切块再逐块识别。第三max_new_tokens设太小会截断长文档建议 8192 起步。信息抽取的 prompt 要严格按 JSON 格式。比如提取票据信息messages [ { role: user, content: [ {type: image, url: invoice.png}, { type: text, text: 请按下列JSON格式输出图中信息: { invoice_number: , date: , total_amount: , items: [ {name: , quantity: , price: } ] }, }, ], } ]注意 prompt 里的 JSON 结构必须和你想拿到的完全一致模型会照着填。如果结构里有嵌套它也能处理但层级太深容易漏字段。我试过三层嵌套准确率还行但四层以上就开始丢数据了。验证成功的标志输出文本和图片内容对得上表格没串行公式没乱码JSON 能被json.loads()解析。如果 JSON 解析失败先检查输出里有没有多余的解释性文字模型有时会在 JSON 前后加“好的以下是识别结果”之类的话需要你在 prompt 里明确说“只输出 JSON不要任何其他文字”。另外如果你用 vLLM 服务模式可以用 curl 快速验证curl http://localhost:8080/v1/chat/completions \ -H Content-Type: application/json \ -d { model: zai-org/GLM-OCR, messages: [ {role: user, content: [ {type: image_url, image_url: {url: file:///abs/path/test_image.png}}, {type: text, text: Text Recognition:} ]} ], max_tokens: 4096 }返回的 JSON 里choices[0].message.content就是识别结果。这一步能通说明服务正常。5. 常见报错排查401、local proxy failed、reading choices 与 OAuth 问题这一节列我实际遇到过的报错和解法你大概率会碰到其中几个。报错一401 Unauthorized如果你调 TaoToken API 或本地 vLLM 服务时看到 401先检查 Key 和 Base URL。本地 vLLM 的 Key 是 dummy但有些客户端会强制校验格式填个非空字符串就行。TaoToken 的 Key 要去 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 生成注意不要有多余空格。Base URL 本地是http://localhost:8080/v1TaoToken 是https://taotoken.net/api两者不要混。报错二local proxy failed这个通常出现在你配了系统代理但本地服务不走代理。解法是在请求库里显式禁用代理import os os.environ[NO_PROXY] localhost,127.0.0.1或者在 requests 里proxies {http: None, https: None} requests.post(url, jsondata, proxiesproxies)注意这里说的是本地回环地址不走代理不是让你去配什么网络工具。本地服务本来就在本机直连即可。报错三reading choices 相关错误如果你用 OpenAI SDK 调本地 vLLM报KeyError: choices或reading choices多半是服务返回了错误信息而不是正常响应。先看原始返回response client.chat.completions.create(...) print(response)常见原因是 Model ID 写错或者图片路径不对。vLLM 要求图片用file://绝对路径相对路径会失败。另外--allowed-local-media-path要设成/或你的图片目录否则会被安全策略拦掉。报错四OAuth 或 token 过期如果你用 Claude Code 或类似工具接入可能会遇到 OAuth 相关报错。这类工具通常有自己的认证流程和 GLM-OCR 本身无关。解法是检查工具的配置文件确保 Base URL 指向正确的服务。Claude Code 的接入文档在 https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaude_codeutm_campaignrewrite 里面有完整的配置说明。如果你只是跑 GLM-OCR不需要 OAuth直接用本地服务即可。报错五显存不足0.9B 模型听起来小但视觉编码器处理高分辨率图片时显存占用会飙升。如果报 CUDA out of memory两个解法一是把图片先缩放到 1024 宽以内二是用device_mapauto让 accelerate 自动分配或者降到 fp16。我试过 4K 截图直接喂进去16GB 显存都不够缩到 1080p 就正常了。报错六输出 JSON 解析失败前面提过模型可能在 JSON 外加文字。解法是在 prompt 末尾加一句“只输出 JSON不要 markdown 代码块不要解释”。如果还不行用正则提取第一个{到最后一个}之间的内容再解析。排查顺序建议先确认服务能通curl 测试再确认图片路径对再看 Model ID最后看显存和 prompt。大部分问题出在前两步。6. 把 GLM-OCR 接进你的工作流从验证到日常使用跑通单张图片后下一步是把它接进日常流程。我的做法是写一个批量脚本遍历目录下所有图片逐张识别结果存成 JSON 或 Markdown。如果要做信息抽取就在识别后调 TaoToken API 做字段校验和清洗。批量脚本的核心逻辑import os import json from transformers import AutoProcessor, AutoModelForImageTextToText import torch MODEL_PATH zai-org/GLM-OCR processor AutoProcessor.from_pretrained(MODEL_PATH) model AutoModelForImageTextToText.from_pretrained( MODEL_PATH, torch_dtypeauto, device_mapauto ) def ocr_image(image_path, promptText Recognition:): messages [ { role: user, content: [ {type: image, url: image_path}, {type: text, text: prompt}, ], } ] inputs processor.apply_chat_template( messages, tokenizeTrue, add_generation_promptTrue, return_dictTrue, return_tensorspt, ).to(model.device) inputs.pop(token_type_ids, None) generated_ids model.generate(**inputs, max_new_tokens8192) return processor.decode( generated_ids[0][inputs[input_ids].shape[1]:], skip_special_tokensTrue, ) results {} for fname in os.listdir(images): if fname.lower().endswith((.png, .jpg, .jpeg)): path os.path.join(images, fname) results[fname] ocr_image(path) print(fdone: {fname}) with open(ocr_results.json, w, encodingutf-8) as f: json.dump(results, f, ensure_asciiFalse, indent2)这个脚本跑完你会得到一个 JSONkey 是文件名value 是识别文本。如果要做结构化抽取把 prompt 换成你的 JSON 模板即可。日常使用中有几个实用技巧。第一图片预处理很重要灰度化、二值化、去噪能显著提升识别率尤其是扫描件。第二如果文档有固定版面先用 PP-DocLayout-V3 切块再逐块识别比整图识别准。第三长文档分段处理避免max_new_tokens截断。第四结果一定要人工抽检OCR 再强也有边界情况尤其是手写体和印章遮挡。如果你需要长期跑这类任务Coding Plan 可能比按次调用更划算地址是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 。模型对话功能可以用来做识别结果的二次校验入口在 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 。最后说个我踩过的坑GLM-OCR 的许可证是 MIT但它整合的 PP-DocLayout-V3 是 Apache 2.0商用时要同时遵守两个协议。如果你只是内部验证问题不大如果要打包成产品记得把两个许可证都带上。整套流程跑下来从环境配置到批量识别大概一个下午能搞定。关键是把 Transformers 版本、图片路径、Model ID 这三样对齐剩下的就是调 prompt 和抽检结果。GLM-OCR 在复杂表格和公式上的表现确实比传统 OCR 稳0.9B 的体量也让它能在消费级显卡上跑这是我愿意把它留在工具链里的原因。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑