资讯动态

0.9B GLM-OCR文档识别生产部署:精度、成本与性能平衡实战

发布时间:2026/10/23 10:52:53 来源:尧图企业网站定制
文档识别这件事过去两年我经手的项目里有个很明显的转折上半年大家还在比谁的模型参数大、谁的榜单分数高下半年开始问得最多的一句话变成了这玩意儿一个月的卡钱是多少。0.9B 级别的 GLM-OCR就是在这个节点上进入视野的——它把文档识别从效果演示往生产级部署推了一步。我最近刚把一套 0.9B 的文档识别服务从测试环境推到生产跑了差不多六周中间踩的坑够写一篇长文。这篇东西主要讲三件事文档识别精度到底该怎么评、成本该怎么算清楚、性能该怎么在不牺牲前面两项的前提下压出来。适合正在做票据、合同、报告、试卷、档案数字化这类业务的同学也适合单纯想搞清楚小模型到底能不能上生产的同行。下面全是我自己实操的记录和判断参数、配置、代码都尽量给到能直接抄的程度。1. 为什么 0.9B 这个尺寸会成为文档识别的甜点区1.1 从参数越大越好到每页多少钱的算账逻辑先说结论文档识别这个任务对模型通用智力的依赖远没有想象中高。它更像是一个高难度的图像到结构化文本的转写任务需要的是视觉分辨率、版式理解、字符级准确性而不是写诗、推理、写代码的能力。这两类能力对参数量的敏感度完全不是一个量级。我做过一个粗略的对照同样一批 2000 页的混合文档扫描合同、带表格的财务报表、含公式的技术手册用 7B 级别的多模态模型和 0.9B 级别的专用 OCR 模型跑字符准确率差距在 3 到 5 个百分点之间但单页成本差了接近一个数量级。这 3 到 5 个点靠后处理、靠置信度路由、靠人工复核补回来成本远低于多花的卡钱。这里有个很关键的思维转变。大模型时代的惯性是先把效果做到 98 分再想成本生产级 OCR 的正确顺序反过来——先确定业务能接受的准确率下限和单页成本上限再倒推模型尺寸和部署方式。一份内部报销单的识别95% 准确率加上人工抽检就够了一份要归档的法律文书可能必须 99.5% 以上。这两个场景根本不该用同一套部署方案。算账的公式其实很朴素单页成本 单卡每小时成本 / 单卡每小时处理页数分母决定了成本的大头。而分母由三件事决定模型权重的显存占用决定能不能大批量、单页的 token 消耗决定解码时间、批处理的效率决定 GPU 利用率。0.9B 这个尺寸的妙处在于它在这三项上都留了很大余量——一张 24GB 的卡就能把并发批大小开到相当可观的程度不用上多卡不用做张量并行运维复杂度直接降一个档。1.2 0.9B 到底能干什么不能干什么我不想把话说得太满。0.9B 的模型有明确的能力边界认清边界比吹效果重要得多。它能稳的印刷体为主的扫描件、电子版 PDF 转图、清晰的票据和表单、常规多栏排版、带线表格、常见数学公式、中英混排。这些场景下只要图像质量不是特别差识别结果基本可以直接入库。它吃力的低质量手机拍摄强反光、阴影、透视变形严重、复杂手写体尤其是连笔中文、无线表格靠空白对齐的那种、超大版面的工程图纸、竖排古籍、印章大面积遮挡正文、极度密集的小字号排版。这些不是不能跑而是错误率会明显抬头需要靠预处理或者路由到更大的模型。我做过一个简单的分层测试把文档按质量分成三档同一套 0.9B 配置下的表现差异非常明显文档质量档位典型来源字符准确率区间是否需要人工复核A 档高质量电子版 PDF 转图、专业扫描仪 300dpi98% 以上抽检 5%B 档中等质量普通扫描仪、复印再扫描、轻微倾斜94% 到 97%抽检 30%C 档低质量手机拍照、光照不均、有遮挡85% 到 93%全量复核或路由注意这张表里的数字是我自己项目里的实测区间不同业务、不同文档类型差异会很大绝对不能直接拿去当验收标准。它的价值在于提示你必须做文档分层而不是告诉你这个模型是多少分。基于这个分层我的建议是把 0.9B 定位成主力通道而不是唯一通道。A 档直接过B 档走轻量后处理加抽检C 档要么进更重的模型要么直接进人工队列。这种分级处理的架构整体成本比全部走大模型低得多准确率又比全部走小模型高得多这才是平衡两个字的真正含义。2. 精度不是玄学先把评测集和指标立起来2.1 三层评测集怎么攒别拿公开榜单当验收依据我见过太多团队犯同一个错拿公开榜单的分数当项目验收标准。榜单是实验室环境下的平均分你的业务是特定分布下的最差情况两者根本不是一回事。上线前必须自建评测集而且是三层结构。第一层回归集200 到 500 页。从历史业务数据里抽样覆盖所有文档大类每一页都有人工标注的标准答案。这批数据的作用是做版本回归——每次调参数、换量化精度、升级模型先跑这一层看分数有没有掉。这层数据要冻结不能随便加新样本否则分数就没法纵向对比了。第二层难例集100 到 200 页。专门收集线上出过错、人工复核过的样本。这批数据的分数通常很难看但它的价值最高因为它反映的是系统最可能崩在哪里。我自己的难例集里光是表格跨页这一类就占了 40 多页——这是 0.9B 模型最容易出问题的地方。第三层抽检集每天动态抽 50 到 100 页。从线上真实流量里随机抽做人工标注。这层的分数是真实水位因为分布会随着业务变化漂移。比如某个月突然来了一批新格式的合同抽检分数会明显下滑这就是信号。三层的关系是回归集看稳定性难例集看短板抽检集看漂移。缺一层你对系统的判断就是残缺的。提示难例集不要只收集模型做错的还要收集模型做对了但置信度很低的。后者往往是快要出错的边缘样本提前纳入评测集能防患于未然。2.2 指标选择与口径统一别被准确率这三个字骗了准确率 96%这句话在文档识别领域基本没有信息量因为口径太多了。你必须把指标拆到任务级别。纯文本部分我用的核心指标是字符错误率CER计算方式是编辑距离除以标准答案的字符总数。这个指标的好处是能反映插入、删除、替换三类错误比简单比对准确率合理得多。对于中文还要额外看标点符号准确率因为标点错乱会直接影响下游的分句和结构化。表格部分字符准确率就没意义了得用表格结构相似度。我的做法是把表格展平成单元格坐标 内容的集合然后比对两个集合的交并比。这个指标能同时反映结构错误和内容错误比单纯看字符准不准靠谱。公式部分最坑。直接比对 LaTeX 字符串几乎必然判错因为同一个公式有无数种等价写法。我的做法是先做LaTeX 规范化统一空格、统一\left \right、统一分式写法再做字符串比对同时统计语义等价但写法不同的比例人工抽检这部分。这个流程麻烦但没办法公式识别的验收就是这么琐碎。阅读顺序也需要单独看。多栏文档里模型可能把两栏内容交错输出字符准确率看着很高但内容完全乱序下游根本没法用。我的做法是给每一页标注阅读顺序正确/错误的二元标签单独统计错误率。指标适用内容计算方式我的验收阈值字符错误率 CER正文段落编辑距离 / 标准字符数A 档 2%B 档 6%标点准确率全部文本正确标点数 / 总标点数 96%表格结构相似度表格单元格集合交并比 92%公式规范化匹配率公式规范化后完全匹配比例 88%阅读顺序错误率多栏文档错误页数 / 总页数 3%这张表不是标准答案是我自己项目里的口径。你要做的是照着这个思路把你自己业务的验收标准写死然后所有版本都用同一套口径跑。口径一变历史数据全部作废这是最消耗团队信任的事情。3. 部署环境与显存预算的精算3.1 硬件选型与显存拆解别拍脑袋买卡选卡这件事我建议先把显存占用算清楚再决定而不是反过来有什么卡就用什么卡。一个 0.9B 参数的模型权重部分很好算FP16 精度下大约 1.8GBINT8 量化后约 0.9GB。但这只是起点真正吃显存的是另外几块KV Cache。这是批处理场景下的大头。计算公式是KV Cache 字节数 2 × 层数 × 隐藏维度 × 序列长度 × 批大小 × 每元素字节数举个具体例子。假设模型 24 层、隐藏维度 1024用 FP16 存储那么每个 token 的 KV Cache 约占2 × 24 × 1024 × 2 98KB。一页 A4 文档渲染成图片后视觉 token 加上输出 token序列长度按 3000 算单个请求就是 0.29GB。批大小开到 8就是 2.3GB。这个数字随着输出变长会线性增长输出 1500 个 token 的长文档单个请求能到 0.5GB 以上。激活与中间张量。高分辨率输入下视觉编码器那一段的峰值显存不容小觑。我实测下来输入分辨率从 1024 提到 1600峰值激活能多出 1GB 左右。这个开销和批大小关系不大主要是单张图内部的计算量。框架开销。CUDA context、推理框架本身的缓存、显存碎片这些加起来给 1 到 1.5GB 的余量比较稳妥。显存碎片这个事吃过亏——理论上够用的配置跑久了因为碎片导致 OOM重启才好非常难受。汇总一下24GB 的卡在 FP16 精度、批大小 8、分辨率 1024 档位下的显存分配大致是这样占用项显存估算说明模型权重 FP161.8GBINT8 可降到约 0.9GBKV Cache批 8序列 30002.3GB随输出长度线性增长视觉编码激活峰值1.0 到 2.0GB与输入分辨率强相关框架与碎片余量1.0 到 1.5GB不要省这一块剩余可用约 13GB可继续提高批大小或分辨率这个余量说明什么说明 24GB 的卡跑 0.9B OCR 是相当宽松的批大小还有很大上调空间。如果你的业务是离线批处理比如整批档案数字化完全可以牺牲延迟换吞吐把批大小开到 16 甚至 24GPU 利用率能干到 80% 以上。如果是在线接口就要留出延迟余量批大小控制在 4 到 8 之间比较稳。我的经验是宁可买两张 24GB 的卡做双实例也不要买一张 48GB 的卡做单实例。前者能做滚动升级、能隔离故障后者一旦挂了整个服务就没了。生产环境的高可用比单卡吞吐重要得多。3.2 推理框架与精度模式选择各有利弊框架选型上我试过三条路。第一条是直接用 transformers 起一个进程自己写批处理逻辑。优点是调试方便任何中间结果都能打出来看缺点是吞吐上不去因为 Python 层的调度开销在并发场景下很明显。我拿它做算法验证和离线批跑线上不用。第二条是用带连续批处理能力的推理服务框架。这类框架的核心价值是连续批处理——不用等一整批都跑完再收下一批而是每生成一步就动态调度把显存利用率拉满。文档识别这种输入长度差异极大的场景一页短文可能 500 token一页密集表格可能 4000 token连续批处理的收益非常明显。我实测下来同等硬件下吞吐能比朴素批处理高 1.5 到 2 倍。第三条是导出成 ONNX 或 TensorRT 做推理。这条路的性能上限最高但代价是灵活性差——模型一动就得重新导出量化精度校准也麻烦。我最后的方案是在线服务用连续批处理框架离线大批量用 TensorRT 引擎两套并行走。精度模式上FP16 是默认选择几乎无损速度比 FP32 快不少。INT8 量化要谨慎我实测下来字符准确率会掉 1 到 2 个百分点掉得最多的是小字号文本和细笔画汉字。如果你的文档以清晰印刷体为主INT8 可以接受如果手写比例高建议老实上 FP16。# 推理服务初始化骨架示意参数需按实际模型调整 from transformers import AutoProcessor, AutoModelForVision2Seq import torch model_path ./local-model-dir processor AutoProcessor.from_pretrained(model_path, trust_remote_codeTrue) model AutoModelForVision2Seq.from_pretrained( model_path, torch_dtypetorch.float16, # FP16 起步INT8 需额外校准 device_mapcuda:0, trust_remote_codeTrue, ) model.eval() # 关键参数限制输入分辨率防止显存尖峰 MAX_PIXELS 1280 * 1280这里的MAX_PIXELS是个关键闸门。不设上限的话遇到一张超大扫描图视觉 token 数量会爆炸直接 OOM。设了上限代价是这张图会被缩放小字号可能糊掉。这个取舍在后面的分辨率章节细讲。4. 服务化实操从单条脚本到能扛并发的接口4.1 图像预处理流水线这一步决定了下限我个人的判断是文档识别项目里预处理的价值被严重低估了。模型再强喂进去一张歪的、暗的、带水印的图结果都不会好。预处理做扎实等于免费提升几个点的准确率。我的流水线按顺序做了这几件事第一格式统一。不管进来的是 PDF、JPG、PNG 还是 HEIC先统一转成 RGB 的三通道图。PDF 要按页渲染渲染 DPI 设 200 到 300 之间——低于 200 小字会糊高于 300 收益递减但计算量线性上涨。我一般用 220 作为默认值实测是个不错的平衡点。第二尺寸归一化。这一步要判断方向不是简单缩放而是看长边。长边超过阈值就等比缩小到阈值短边小于某个下限就适当放大。放大的时候用双三次插值比双线性在文字边缘上更清晰。第三倾斜校正。用霍夫变换或者基于文本行投影的方法估算倾斜角超过 0.5 度就转正。这个动作对扫描件特别有效很多扫描仪走纸会歪一两度不校正的话行切分会出错直接影响阅读顺序。第四对比度增强。用自适应直方图均衡但要限制对比度放大的倍数否则噪点会被放大成黑斑。对于背面透印的文档再加一步背景估计和减除效果很明显。第五去噪与二值化判断。这里有分歧有些方案会把图二值化后再送模型我实测下来不推荐。现代视觉编码器对灰度图更友好二值化会丢掉抗锯齿信息反而让小字识别变差。除非是极低质量的传真件否则保持灰度。预处理步骤关键参数我的默认值不做的后果PDF 渲染DPI220小字糊、笔画粘连尺寸归一长边上限1600px超大图 OOM 或超时倾斜校正触发阈值0.5 度行切分错乱、顺序错对比度增强放大倍数上限2.0噪点放大成黑斑去噪中值滤波核3×3扫描噪点干扰识别注意预处理每一步都会增加耗时。整条流水线跑下来单页大概增加 80 到 150 毫秒。如果你的接口有严格延迟要求可以把倾斜校正和去噪做成异步预计算在文档入库时就处理好查询时直接读缓存。4.2 动态批处理与队列设计吞吐的关键在这里单个请求跑通和能扛并发中间隔着一整个工程。我踩过的最大的坑是接口用同步阻塞方式实现一个请求进来就占住 GPU并发一上来全部排队超时。正确的做法是请求队列 动态批处理。核心逻辑是请求进来先进队列调度器按当前批次累计 token 数和等待时间上限两个条件决定什么时候发车。这样短文档不会因为等长文档而被拖慢长文档也不会被饿死。# 动态批处理调度器骨架示意 import asyncio import time MAX_BATCH_SIZE 8 # 单批最大请求数 MAX_WAIT_MS 50 # 最长等待时间控制尾延迟 MAX_BATCH_TOKENS 24000 # 单批累计 token 上限防 OOM class BatchScheduler: def __init__(self, engine): self.engine engine self.queue asyncio.Queue() async def submit(self, request): fut asyncio.get_event_loop().create_future() await self.queue.put((request, fut, time.time())) return await fut async def run_forever(self): while True: batch, token_sum [], 0 deadline time.time() MAX_WAIT_MS / 1000.0 while len(batch) MAX_BATCH_SIZE and time.time() deadline: try: timeout max(0.0, deadline - time.time()) item await asyncio.wait_for(self.queue.get(), timeout) except asyncio.TimeoutError: break req, fut, _ item est req.estimated_tokens if token_sum est MAX_BATCH_TOKENS and batch: # 超预算先塞回去下一批发 await self.queue.put(item) break batch.append((req, fut)) token_sum est if batch: await self._dispatch(batch)三个参数的作用要说清楚。MAX_BATCH_SIZE控制并发上限太大容易 OOMMAX_WAIT_MS控制尾延迟太小批不起来白费太大用户等得慌50 毫秒是我实测下来比较舒服的值MAX_BATCH_TOKENS是最重要的一道保险因为批大小相同不代表 token 数相同一页密集表格的 token 可能是一页短文的五六倍只看批大小必然会出现显存尖峰。estimated_tokens怎么估我用的是输入图像像素数除以一个经验系数再加上输出长度的历史中位数。这个估算不需要太准只要量级对就行它的作用是防止一个超长请求混进一批短文里这种灾难。4.3 后处理与结构化输出别把原始输出直接丢给下游模型吐出来的是一段带 Markdown 结构的文本直接入库会出各种问题。后处理这一步是看起来能跑和真的能用的分界线。我做的后处理主要有这么几件去掉重复行。文档识别有个典型故障是同一行被输出两遍尤其是页眉页脚区域。我的做法是检测连续重复行和近似重复行编辑距离小于阈值只保留一份。页码和页眉剔除。可以用规则也可以用位置信息。规则做法是识别形如第 X 页 共 Y 页、纯数字行、页眉位置上重复出现的固定字符串。这一步对有严格模板的业务文档特别有效。表格结构修复。模型输出的 Markdown 表格经常列数对不齐。我的做法是解析成二维数组按出现次数最多的列数做基准短行补空、长行截断同时记录修复次数用于监控。修复次数突然飙升说明模型在表格上开始飘了。公式校验。把输出的 LaTeX 丢给一个轻量解析器解析失败就标记为可疑走人工。这一步能拦住大部分公式乱码。置信度打分与路由。这个是最有价值的一步。我不依赖模型输出的概率而是用一组启发式信号做综合打分输出长度是否异常短、是否包含大量连续重复字符、表格修复次数、LaTeX 解析失败数、是否触发了截断。综合分低于阈值直接路由到人工或者更大的模型。# 后处理与置信度路由骨架示意 def postprocess(raw_text, meta): issues 0 lines dedupe_lines(raw_text.splitlines()) lines drop_headers_footers(lines) lines, n_fixed fix_markdown_tables(lines) issues n_fixed if in raw_text or raw_text.count($) % 2 ! 0: issues 2 # 结构不闭合高度可疑 if meta[output_tokens] meta[max_tokens] - 8: issues 3 # 触发截断几乎必然丢内容 if meta[char_count] 20 and meta[image_area] 500_000: issues 2 # 大图出短文本异常 return \n.join(lines), issues def route(issues): if issues 4: return human if issues 2: return large_model return accept这套路由上线后人工复核量降了大概六成因为大部分明显有问题的输出被自动拦下来了剩下进人工的都是真的疑难件。5. 成本、精度、性能三角的调参手册5.1 分辨率档位的取舍这是最有效的旋钮在所有可调参数里输入分辨率对精度—性能—成本三角的影响最直接也最容易量化。我的做法是设三档按文档质量动态选。1024 档适合 A 档文档正文清晰、字号正常。单页耗时最短吞吐最高。这一档我实测下来对于 300dpi 扫描的标准 A4 文档字符错误率已经很接近更高档位了性价比最高。1280 档默认档位覆盖大部分 B 档文档。相比 1024 档单页耗时增加约 30% 到 40%但小字号和密集排版的识别明显改善。1600 档只给 C 档和疑难件用。耗时是 1024 档的两倍以上显存峰值也高不少。但对手写、印章遮挡、极小字号这几类提升是实打实的。分辨率档适用场景相对耗时相对显存峰值字符错误率改善1024A 档清晰印刷件1.0×1.0×基准1280B 档常规扫描件1.35×1.3×相对基准降低约 25%1600C 档劣质件、疑难件2.1×1.9×相对基准降低约 40%关键在于动态选择而不是全量上高档。怎么判断该用哪档我用的是一个很土但很有效的办法先算图像的清晰度指标拉普拉斯方差再结合 DPI、文档类型标签做一个规则映射。规则映射比训一个分类器省事得多而且可解释出了问题好排查。这里有个反直觉的发现把分辨率往上堆收益是有天花板的。我试过 2048 档对大部分文档的改善已经很小但耗时继续线性上涨。真正制约准确率的变成了模型本身的能力而不是输入信息的丰富度。所以不要无脑上高分辨率找到一个拐点就够了。5.2 量化和加速的实测边界哪些能碰哪些别碰量化这块我把实测结论摆出来省得你重复踩坑。FP16几乎无损必选没有讨论空间。INT8 权重量化字符准确率掉 1 到 2 个点速度提升明显显存降一半。适合 A 档文档的大批量离线处理。但要注意掉点主要集中在小字号和细笔画如果你的文档字号偏小慎用。INT8 激活量化这个我建议不要碰。视觉编码器那部分的激活分布很宽量化后细节丢失严重实测曲线边缘和文字笔画会出现明显退化。省下的那点显存不值得。投机解码文档识别任务输出高度结构化重复模式多理论上适合投机解码。我试过用一个小草稿模型加速实测吞吐提升 20% 到 30%但需要额外显存放草稿模型而且草稿模型和主模型的输出风格差异会导致偶尔的格式错乱。收益不算特别突出我最后没上。前缀缓存如果你的业务有大量请求共享相同的前缀提示词比如固定的任务指令前缀缓存能省掉这部分 prefill 开销。文档识别场景下前缀通常不长收益有限但实现简单顺手加上不亏。真正把性能压出来的其实是另外两件事而且都不在模型层面。第一件是图像解码的并行化。PDF 渲染和图像预处理是 CPU 密集的如果串行做GPU 有大量时间在等数据。我把它拆成独立进程池做成预取队列GPU 利用率从 50% 出头提到了 75% 以上。这个优化比任何模型层的量化都值钱。第二件是输出长度控制。0.9B 模型的解码速度和输出长度几乎线性相关。如果你的下游只需要正文不需要版式可以在提示词里明确要求只输出纯文本不要 Markdown 标记能把输出 token 砍掉两三成。这一招零成本收益立竿见影。把这几项加起来我最终的配置是FP16 权重、1280 默认分辨率、连续批处理、CPU 预取并行、输出精简提示词。单卡 24GB 在混合负载下每小时能处理 2500 到 4000 页取决于文档复杂度单页成本算下来是纯人工录入的百分之一量级比 7B 方案便宜差不多一个数量级。6. 上线后的坑问题排查速查表6.1 典型故障与定位路径上线六周我整理了一份故障速查表。这里面的每一条都是我实际遇到过的不是编的。故障现象最可能原因定位方法处理方式整页输出为空图像预处理后变成纯白/纯黑保存预处理中间图肉眼确认修正对比度增强的边界条件输出重复行页眉页脚区域被反复识别统计重复行出现位置加去重规则页眉区加掩码表格列数错乱无线表格或无表头表格看表格修复次数监控曲线该类型路由到大模型长文档尾部丢失输出 token 触顶被截断检查输出长度是否接近上限提高上限或分段识别中文夹杂乱码字符图像分辨率过低导致笔画粘连对比高低分辨率结果提高该文档的分辨率档位并发升高后超时批处理队列积压看队列深度和 P99 延迟扩实例或调批处理参数跑几小时后 OOM显存碎片累积看显存占用随时间曲线定期重启 worker 或换分配器公式大量解析失败输出 LaTeX 语法不规范统计解析失败样本后处理加括号闭合修复表格里最值得说的是跑几小时后 OOM这一条。这个坑非常隐蔽因为压测的时候跑十分钟就结束了根本发现不了。我是在生产环境跑了七八个小时之后才遇到的现象是显存占用缓慢爬升最后 OOM。根本原因是长序列请求和短序列请求混合时显存分配器会产生大量碎片。解决办法有两个一是定期比如每处理 5000 页重启 worker 进程简单粗暴但有效二是换用更激进的显存分配策略代价是启动时预留更多显存。另一个隐蔽的坑是输出重复行和页眉剔除打架。有些文档的页眉本身就是正文的一部分比如每页顶部都有一个条款编号粗暴剔除会丢内容。我的做法是先统计这个字符串在全文档中的重复次数只在重复次数超过总页数 80% 时才判定为页眉。6.2 监控指标该盯哪几个别什么都想监控监控面板容易做成什么都想看结果什么都看不过来。我的做法是只盯五个核心指标每个都有明确的告警阈值。第一P95 单页延迟。这个指标直接反映用户体验。超过 3 秒就该看队列了。注意看 P95 而不是平均值平均值会被大量快速请求拉低掩盖长尾问题。第二队列深度。队列持续增长说明处理能力不足要么扩实例要么降精度。这个指标是容量规划的核心输入。第三GPU 利用率。低于 50% 说明预处理是瓶颈高于 90% 且队列在涨说明要扩容了。这个指标要配合队列深度一起看单看没意义。第四低置信度路由比例。这个比例突然上升要么是模型飘了要么是进来的文档变了。这是最早能发现分布漂移的信号。第五OOM 与重启次数。不为零就要查哪怕只是偶发。# 监控告警配置示意 alerts: - name: high_p95_latency expr: ocr_page_latency_p95_seconds 3 for: 5m - name: queue_backlog expr: ocr_queue_depth 200 for: 3m - name: low_conf_route_spike expr: rate(ocr_low_confidence_total[10m]) / rate(ocr_requests_total[10m]) 0.15 for: 10m - name: oom_restart expr: increase(ocr_worker_restarts_total[1h]) 0low_conf_route_spike这条告警我最看重。它不直接反映故障但它是所有故障的先兆。出现过一次某天上午这个比例从 6% 跳到 22%查下来是上游系统换了 PDF 导出工具生成的图片分辨率整体降了一半。如果没有这条告警可能要等到客户投诉才发现。7. 灰度与回滚生产环境的最后一道保险7.1 分层灰度策略别一次性全量切换文档识别服务的灰度不能简单按流量百分比切那样切出来的样本分布是乱的验证不出真实效果。我用的策略叫分层灰度按文档类型和来源通道切。具体做法分三步走。第一步只放一个文档大类比如报销单的 5% 流量跑三天对比新旧方案在这个类上的准确率和延迟。第二步扩大到这个大类的全部流量同时加一个新大类比如合同继续观察。第三步全部大类逐步放开每个大类都单独看指标。这种灰度的好处是任何一个类别出问题都能立刻定位到具体的文档分布而不是面对一堆混合指标猜。代价是上线周期长从灰度到全量我花了差不多三周。回滚机制必须做到一键且无状态。我的做法是新旧两套服务同时在线用路由层控制流量回滚就是改一个配置项秒级生效。绝对不能设计成新服务替换老服务的模式那样回滚要重新部署故障窗口太长。7.2 我个人踩过的几个坑写出来给同行省点时间第一个坑是提示词的隐式假设。模型对提示词里的措辞非常敏感。我早期用的是请识别图片中的所有文字结果模型有时候会把图片里的水印、装饰性文字也识别出来。改成请按阅读顺序输出正文内容忽略页眉页脚、水印和装饰性元素输出干净了很多。这种细节不实测根本想不到。第二个坑是批处理对结果的影响。同一张图单独跑和放在一个批次里跑输出可能有细微差异。原因是浮点运算的批次内归约顺序不同。大部分情况下差别可以忽略但在阈值边缘的样本上可能导致路由结果不一致。我的应对是把路由阈值设得离边界远一点留出缓冲。第三个坑是过度依赖量化省钱。我一度为了压成本把离线批处理通道全量切到 INT8结果那批档案里有大量手写批注准确率掉得很难看返工重跑的成本远超省下的卡钱。教训是量化前一定要在用真实难例集上测别看平均指标。第四个坑是忽略了下游的消费方式。我最初输出的 Markdown 表格下游系统解析不了因为他们只认 HTML 表格。这个错误很低级但确实发生了原因是需求沟通时谁也没提这个细节。后来我在后处理里加了一层格式转换问题解决。这件事提醒我OCR 服务的验收标准应该由下游消费者来定不是由算法同学自己定。第五个坑是评测集污染。有一次我用线上抽检数据调了提示词然后又拿同一批数据当评测集分数虚高得离谱。从那以后我定了规矩调参用的数据绝对不能进评测集两边的数据来源要物理隔离。回头看这六周最大的体会是0.9B 这个尺寸的 OCR 模型技术本身已经很成熟了真正决定项目成败的是工程细节——预处理做不做细、后处理严不严、灰度切得稳不稳、监控盯得准不准。模型选型只占整个工作量的一小部分剩下的全是脏活累活。如果让我给准备上同类项目的同行一句建议那就是先把评测口径和成本模型写清楚再动第一行部署代码。这两件事想明白了后面的路会顺很多。

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

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

免费获取报价 →
↑