Unlimited-OCR 部署运行(13/13):长文档验证 + 端口冲突坑 + 完整使用指南

这是部署运行篇的终篇,也是整个 14 篇系列的收尾。它做三件事:(1) 用
long-horizon-ocr.gif验证长文档 OCR 在修复后依然正确;(2) 记下两个 Windows 特有的运维坑(本机网络环境变量干扰 health check、端口 10000 被遗留服务占用);(3) 给你一份完整使用指南——怎么用 OpenAI 兼容 API 真正调用这个服务。如果你只想知道"我怎么用",直接跳到第四节。
一、长文档 OCR 验证(修复在长输入上依旧成立)
assets/long-horizon-ocr.gif 是 280 帧、1916×954 的长文档动画。验证脚本 test_long_horizon.py 用两种输入测 第 10 篇 的乱码修复在长文档上是否仍成立:
- (A) 单帧(frame 0):
elapsed=54.5s, out_len=2610,头部header [8,20,79,40]Unlimited-OCR header...连贯。 - (B) 12 帧均匀采样拼接长图(resize 宽 1280 → 1280×7644,模拟长文档):
elapsed=313.7s, out_len=42571,头部header [0,0,999,11]Unit 1 Unit 2 Unit 3...连贯长文档,无乱码 / 崩溃。
两者均输出结构化 OCR,证明第 10 篇的"3 文件还原"修复在长文档 / 多区域输入上依旧成立。
gundam图像模式:base_size=1024, image_size=640, crop=True;处理器用 PIL 单图解码(GIF 只取 frame 0),多图仅 tiny/small/base 支持,模型本身不接受 GIF 多帧。所以长文档建议用"多帧拼接成一张高图"的方式,而不是把 GIF 多帧当多图。
二、运维坑①:本机网络环境变量干扰 health check(HTTP 000)

本机若设了 HTTPS_PROXY 指向某个本地转发端口,urllib / curl 会把 127.0.0.1:10000 也路由到该端口 → health 检查返回 HTTP 000(但 raw socket 能连、服务实际在跑)。排查时极易误判"服务没起来"。
解决:所有请求脚本开头必须清理该网络环境变量
import os
os.environ.pop("HTTPS_PROXY", None)
os.environ.pop("HTTP_PROXY", None)
os.environ.pop("ALL_PROXY", None)
os.environ["no_proxy"] = "127.0.0.1,localhost"
test_long_horizon.py / smoke_moe.py 已内置这段。哪怕你用 curl 手动测,也要先 set HTTPS_PROXY= 清空。
三、运维坑②:端口 10000 被遗留服务占用

多次启动会出现 [Errno 10048] address already in use——旧 worker 由 base conda python 启动且会重生,占着 10000。启动前先清理:
:: 定位占用 10000 的 PID
netstat -ano | findstr ":10000 " | findstr "LISTENING"
:: 杀掉(/T 连子进程一起杀)
taskkill /F /T /PID <占用PID>
infer.py 的 start_server() 已内置这段:启动时自动 netstat 找占用 PID 并 taskkill,再启动单一干净服务(详见 第 09 篇)。
冷服务首请求极慢:triton 对所有 kernel 做 JIT 编译,首请求可能 >300s。客户端超时要放宽(如 600s);服务不是卡死,是在编译 + 生成。热身后的请求回到 ~50–60s 级。
四、使用指南:怎么用这个 OCR 服务

服务按 第 09 篇 启动后,对外暴露 OpenAI 兼容的 /v1/chat/completions 接口(端口 10000)。你不需要懂 sglang 内部,像调 GPT 一样调它即可。
4.1 最小 Python 调用(单图 OCR)
import os, base64, json, urllib.request
# 关键:清掉会把 127.0.0.1 路由到本地转发端口的环境变量
os.environ.pop("HTTPS_PROXY", None); os.environ.pop("HTTP_PROXY", None); os.environ.pop("ALL_PROXY", None)
os.environ["no_proxy"] = "127.0.0.1,localhost"
def ocr(image_path: str, prompt: str = "document parsing.") -> str:
with open(image_path, "rb") as f:
b64 = base64.b64encode(f.read()).decode()
payload = {
"model": "Unlimited-OCR",
"messages": [
{"role": "user", "content": [
{"type": "image_url", "image_url": {"url": f"data:image/png;base64,{b64}"}},
{"type": "text", "text": prompt},
]}
],
"temperature": 0,
"stream": False,
"images_config": {"image_mode": "gundam"}, # Unlimited-OCR 专用图模式
}
req = urllib.request.Request(
"http://127.0.0.1:10000/v1/chat/completions",
data=json.dumps(payload).encode(),
headers={"Content-Type": "application/json"},
)
with urllib.request.urlopen(req, timeout=600) as r: # 首请求放宽到 600s
return json.load(r)["choices"][0]["message"]["content"]
print(ocr("assets/baidu.png"))
输出示例:<|det|>title [14, 0, 999, 999]<|/det|>Baidu 百度
4.2 curl 调用
curl http://127.0.0.1:10000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Unlimited-OCR",
"messages": [{"role":"user","content":[
{"type":"image_url","image_url":{"url":"data:image/png;base64,'"$B64"'"}},
{"type":"text","text":"document parsing."}
]}],
"temperature": 0, "stream": false,
"images_config": {"image_mode": "gundam"}
}'
4.3 用项目自带脚本
# 单图
.venv\Scripts\python.exe infer.py --image_path "你的图片.jpg"
# 文件夹批量
.venv\Scripts\python.exe infer.py --image_dir "你的图片文件夹"
# 流式推理测试
.venv\Scripts\python.exe test_inference.py assets/baidu.png "document parsing."
infer.py 会自动:复用已有服务 / 清理占用端口 / 启动服务 / 发请求 / 停止服务。
4.4 长文档 / 多页建议
- 把多页或长图拼接成一张高图(宽统一 resize 到 ~1280,高度按需),用
gundam模式一次送进去(见第一节验证)。 --context-length 32768已为长文档留足上下文;更长的文档可调大,但注意--mem-fraction-static要相应留足 KV cache。- 首请求慢属正常,把客户端超时设 600s,之后请求会快很多。
五、系列结语
14 篇写到这,整件事讲完了:
- 编译移植篇(01–08):一个被广泛认为"Windows 装不了、只能上 WSL/Docker"的高性能推理框架,我们拒绝逃生,在原生 Windows 上从源码把它编译并跑通——横跨 FlashInfer 前置编译、环境、GCC→MSVC 方言、MSVC 语义严格性、架构裁剪、链接收尾,以及支撑这一切不散架的工程方法论。
- 部署运行篇(09–13):编出来之后怎么真正跑起来——正确启动、两个经典排障(乱码根因 / 环境变量块崩溃)、MoE 性能调优、长文档验证,以及本篇的使用指南。
如果这个系列只留下一句话,我希望是:“官方没有提供”,从来不等于"做不到"。 缺的往往不是可能性,而是有没有人愿意、并且有方法,把那条没人走过的路,一步一个脚印、留着可复现的记录,走到底。
愿它对你自己的那场硬仗,有用。
系列导航(全 14 篇)
编译移植篇(怎么把 sglang 从源码编出来)
- 00 · 系列总览
- 01 · EPGF 环境地基与岔路口
- 02 · 结论与可行性:三铁证 + --no-deps
- 03 · 编译篇·前置:FlashInfer Windows 源码编译
- 04 · 编译篇·环境关
- 05 · 移植篇(上):GCC 方言
- 06 · 移植篇(下):语义严格与崩溃
- 07 · 编译篇·收尾:架构裁剪与 LNK2019
- 08 · 方法论
部署运行篇(怎么跑起来并排障)
参考资料与延伸阅读
以下为本文涉及的官方仓库、文档与规格站,建议发布前点一遍确认可达:
- Unlimited-OCR 官方仓库(模型与项目源码)
- SGLang 官方仓库
- SGLang 官方文档(启动参数 / OpenAI 兼容 API)
- flashinfer-windows(Windows 兼容 fork,编译前置)
- vllm-windows(同作者,可对照的 Windows 移植思路)
- PyTorch Windows CUDA 预编译索引(cu130)
- NVIDIA CUDA Toolkit 下载
- uv 官方文档(Python 环境治理)
- MSVC /Zc:preprocessor 标准预处理器
- MSVC 致命错误 C1001(编译器内部错误)
- nvcc -Xcompiler 转发 host 编译器选项
- CMake 生成器(Visual Studio / Ninja)
- RTX 3090 规格(GA102 / sm_86,共享内存 100KB)
- CUDA 共享内存上限与 dynamic_shared_memory 限制
- Windows 子进程环境变量块限制(CreateProcess / ~32KB)
- OpenAI 兼容 API 参考(推理调用)
2268

被折叠的 条评论
为什么被折叠?



