☰
CV+LLM实战:让纸质促销传单自动变成结构化商品数据
2026/10/20 3:52:34 网站建设 项目流程

做杂货配送的团队,几乎都会遇到同一个麻烦:每周各大商超和品牌方都会更新一期纸质促销传单,上面标着折价商品、限时特价、买赠规则,但这些信息本质上是一张图片,不是一条条可查询的结构化数据。平台方既没法让用户在App里直接搜索"哪个超市的鸡胸肉在打折",也没法把线下促销同步到线上购物车,更做不到根据用户偏好做个性化排序。这次要拆解的项目,核心就是把这类纸质传单自动转成结构化的商品促销数据,整个链条里同时用了计算机视觉(CV)和大语言模型(LLM)。CV负责"看懂图",LLM负责"读懂促销逻辑",两者配合,把每周几万张形态各异的传单变成了一条条干净的商品促销记录。这篇文章会从架构设计、CV识别细节、LLM语义解析、数据标注与评测、上线后的问题排查五个方面展开,把我在这类项目里的实操经验一次性讲透。

1. 传单数字化真正要解决的痛点,远不止"把纸变成图片"

1.1 一张纸质传单背后的完整业务链条

很多人以为传单数字化就是把纸扫个描、拍个照、传到网上,其实差远了。一张传单到了用户手里,背后是一整条业务链:商超每周定一次促销计划,设计排版后印刷,再通过人工分发或者随购物袋附送触达到用户。用户看到传单后,可能去店里找对应商品,也可能被价格吸引去线上下单。

问题在于,传统链路里每个环节都是"物理世界"的操作,平台方接不到任何结构化数据。商超给平台传单图片,平台只能靠人工把商品名、原价、折后价、促销条件一条条录进系统里。一家商超一周可能是两三百个商品,平台覆盖几百家商超,录完一遍需要的人力成本非常高,而且容易出错。更关键的是,人工录入的时效性跟不上——传单周五出来,人工录到周一还没录完,那周五到周日这段时间的促销信息就是空白。

1.2 为什么"数字化"不是简单扫描上传

数字化传单的终点不是让人在手机上能翻图片,而是要让促销信息和平台已有的商品库、用户偏好、库存数据打通。举个例子:用户收到App的推送"本周附近3家超市的牛奶有折扣",点进去能看到对比、加入购物车、一键下单——这要求系统不仅识别出传单里有"牛奶"两个字,还要识别出具体是哪个品牌、什么规格、原价多少、现价多少、有没有购买数量限制。

这些信息分散在传单的不同位置:商品图在中间,商品名在图片下方,原价通常标在左上角,现价标在右下角,促销条件可能在最下方一行小字里。要把一张像素组成的图片还原成有逻辑关系的记录,CV和LLM就必须分工配合,而且任何一个环节出错,整条数据就废了。

2. 整体方案设计:五段式流水线,CV和LLM各管一摊

2.1 核心架构:采集、定位、识别、理解、整合

整个系统最终被我拆成了五个环节:

  1. 传单图像采集与质检:接收商超上传的传单图片,检查清晰度、完整性,不合格的自动打回或者通知人工处理。
  2. CV版面分析:把传单按视觉结构切块,定位哪些区域是商品图、哪些是文字、哪些是标价区域。
  3. 图像文字识别与价格数字提取:用OCR能力把文字区域转成文本,同时针对价格数字做专门优化。
  4. LLM促销语义理解:把OCR识别出的文本(加上对应的位置信息)送到大语言模型,让它分析出每一条促销规则的完整结构。
  5. 数据整合与校验:把LLM输出的结构化结果和平台商品库匹配,校验价格逻辑,输出最终的可上线数据。

听起来第四步好像很核心,其实前三步才是地基。OCR识别错了一个字母,后面LLM再聪明也救不回来。所以这套设计里,CV部分重点解决"整张图怎么变成一块块有意义的文字和图像",LLM部分解决"一块块文字怎么拼成一条条完整的促销规则"。

2.2 为什么这个场景非用LLM不可

有人会问:促销规则看起来不就是几个固定模板吗,"现价XX""第二件半价"这些,写正则表达式不就行了?早期我确实试过纯规则方案,结果被现实教育了。

传单促销规则的自由度极高。有的写"买三送一",有的写"满50减8",有的写"第2件五折",有的写"特价29.9/斤",还有更复杂的:"本周末前100名顾客购XX商品立减10元"。不同商超、不同地域、不同节日促销文案五花八门,甚至同一家商超换了个美编,文案风格都变了。用正则和规则的方案需要持续维护规则库,每次遇到没见过的新说法就要补一条规则,周周都在改代码,越到后面越心累。

LLM的优势在于它天然具备语义泛化能力。同样的促销逻辑,不管是"第二件半价"还是"再加一件只花五折",模型都能理解这是在表达同一个意思。把阶段三的文本输出丢给LLM,要求它输出统一的JSON结构,等于把"规则引擎维护"这件事从工程团队手里转移给了模型的语义理解能力。这个选择在实际运行中大大降低了维护成本,也让系统对新版式传单的适应速度从一周缩短到几分钟。

3. CV识别模块:先解决"看得清",才能谈"读得懂"

3.1 输入数据远比想象中脏:透视、反光、褶皱、遮挡

第一个实际碰到的难题,是输入图像的质量参差不齐。从商超拿到的传单,有一部分是扫描件,比较干净;另一部分是门店店员用手机翻拍的,这就麻烦了。

手机翻拍的传单通常是斜着拍的,有透视变形。传单本身是矩形,拍出来变四边形了,直接进后面所有环节,版面信息都会错。这边踩的坑在于:一开始我没有加透视校正,导致OCR的文本行列对齐错误,商品名和价格经常串位。后来加了一个步骤,先用边缘检测找到传单的四条边,再做单应性变换(Homography)把四边形映射成纯矩形,这个问题才基本解决。

因为技术栈的原因,我单开了一个小服务,专门完成"输入图片→找边界→透视校正"的过程。这张中间结果图后续所有环节都复用,而不是每个算法各做各的,统一处理的好处是调试方便,排查问题的时候只查中间结果就能定位到是预处理问题还是下游逻辑问题。

除了透视,还有反光、褶皱、遮挡问题。彩页传单经常有玻璃窗反光,一条亮带正好挡住价格区域;褶皱会让文字发生局部扭曲;偶尔还有水渍污渍叠在商品图上。真实场景里根本没有"完美的传单图像"。我们现在的策略是:图像输入到系统后,先用一套图像质量评估模型判定模糊度、光照异常、遮挡面积,综合评分低的直接进人工队列,不浪费后续算力。

3.2 版面分割:从一整页传单到一个个商品块

传单版面分割是整个CV链路里最隐性但最要命的一环。传单设计师自由发挥的空间太大,有的把商品排成整齐的格子,有的做成锯齿状错落布局,有的跨页大图,有的把十个商品叠在一个区域里。最开始用固定网格切分方法,遇到格子型排版效果还行,遇到复杂创意版式就错得离谱。

后面改成了用目标检测模型做产品块定位。方案是先在真实传单数据上标注出每个商品块的包围框,然后用检测模型去预测。检测完还需要做校正:同一件商品在不同位置被检测出两个框?用非极大值抑制(NMS)去重;检测框把商品切了一半?需要用边缘细化逻辑把框扩展到位。

版面分割的结果决定了后续每一条促销数据的粒度。这块做的不好,后面LLM拿到的是一个"半块商品图+半个价格标签"和另一个"半块商品图+半个名字"的组合,神仙模型也还原不了正确的绑定关系。所以我在产品块检测上花的精力最多,先后试验了多种检测方案的组合,最后采用了一套效果稳定的目标检测方案,代价是推理时长稍长,但换来的是版面切分准确率的大幅提升。产品块切割对了,整条流水线的上限就高了。

3.3 OCR与价格数字识别:商品名能包容错,数字不能错

版面分割之后,每个商品块里有两类关键信息:商品名和价格。商品名识别相对宽容,识别成九成准确率都还能靠LLM去修,"有机纯牛奶"和"有机鲜牛奶"在语义上足够接近,下游可以纠正。但价格数字不能出错——29.9识别成39.9,直接把用户的信任感打没了,促销逻辑也跟着错。

实际测试下来,OCR引擎对印刷体商品名的识别准确率尚可,但对价格数字的识别有三个老大难:

第一个是价格标签的排版风格混乱。有的传单把"原价¥19.9"标在斜线上,有的把价格放到一个圆形徽章里,OCR很容易把背景的圆形边缘当成文字噪声。

第二个是干扰线。促销传单最爱在价格下面加一条红色的删除线,这线条正好横穿数字,OCR字符分割时经常把"9"和"8"连起来。

第三个是小数点和货币符号的混淆。"¥49.9"里的小数点如果沾上污渍,OCR可能直接识别成"4919"或者"49,9"。

我的做法是做一个独立的价格识别模型,不是单纯依赖通用OCR引擎。准确地说,在通用OCR识别完后,针对检测到的货币符号位置做二次小模型识别,专门识别价格区域的数字串,并且限定输出格式为"数字+小数点+数字"。如果出现多位小数点,就判为低置信度,退回人工。价格数字宁可多退给人工审核,也绝对不冒险自动上线。

比较实用的组合是:商品名用通用OCR识别+LLM语义纠错;价格用专用数字识别模型+格式校验。文字识别差错率高一点可以容忍,价格识别差错率必须压在极低水平。

3.4 SKU映射:产品图像识别也没那么玄

前面识别的都是"图片上的文字",但平台的商品库是一个个SKU。传单上写着"蓝瓶牛奶900ml",怎么和商品库里那条"XX品牌低脂纯牛奶900ml"对应上,这是SKU映射环节的活。

初期我试过直接拿商品名去数据库里做模糊匹配,效果不好。因为传单为了省版面,写名字经常省略品牌:只写"低脂纯牛奶",不写品牌;或者把自家商标图案放上去,文字只写"本牌鲜鸡蛋"。

后面补齐两手:一手是用商品图视觉特征去匹配——把传单商品块的图像做成图像嵌入向量,和商品库里已有的商品主图向量做相似度检索,选出Top候选;另一手拿文字候选和视觉候选做融合打分,文字得分和视觉得分加权合并,最终置信度达标才自动映射。实际完成自动映射的比例大约在七成左右,剩下的三成交给人工打标签。这个比例在后面持续迭代中有所提升,但短期完全自动化并不现实。

3.5 CV模块的效果指标与经验数据

整体而言,CV模块做了大半年后,各项指标大致如下:版面分割的产品块召回率能到95%以上,商品名的OCR字符准确率接近90%,价格数字的识别准确率约98%,SKU映射自动匹配率约70%。这个数据在真实传单数据上的表现,已经能支撑整个业务跑起来了。后面LLM模块再对中间结果做语义补偿,整体准确率还能上一截。

4. LLM理解模块:把一个个文本块变成一条条促销规则

4.1 促销语义解析:同一件事,传单有一千种写法

进入LLM环节之前,每个商品块里已经有了商品名、价格、附加文案。这时候要做的事情就是:用LLM判断这个商品块里到底在表达什么促销规则。

促销规则的类型其实可以穷举成几个大类:

  • 直接折扣:现价XX,或原价XXX折后价XXX
  • 满减:满XX减XX
  • 买赠:买A送B
  • 折扣码/优惠券:输入优惠码享折
  • 积分/返现:返现XX元
  • 限时/限量:前XX名优惠 / 周末限时
  • 组合优惠:第二件XX折、买两件免一件等

每条规则要用统一的字段表达,我定了这套结构:促销类型、适用商品、原价、促销价、优惠力度、参与条件、有效期、备注。LLM做的事情就是"从半结构化文本翻译到全结构化JSON"。

最核心的是"适用商品"字段。很多传单会把一个品牌一排多个商品叠在一张小图里,图上写"所有口味均参与活动"——这时候就要LLM结合商品名、图片标签、文案语义判断出适用对象到底是特定口味,还是全部口味。文本没写全的部分,要结合上下文推导,这种语义推理正是LLM的强项。

4.2 提示词模板和结构化输出的设计思路

我沉淀了一套偏向稳定输出的提示词模板,核心是让LLM始终输出固定结构的JSON,字段缺省弹出来,不允许自由发挥。结构化输出对这个场景的可靠性非常关键,如果不限定JSON结构,LLM很可能输出一段"这句话可能表示……",下游解析就全崩了。

我给LLM的提示词大致包括以下内容:角色定义(你是一名零售促销信息分析助手)、输入格式(从OCR和版面解析得到的文本块列表,每个文本块带有版面坐标)、输出格式要求(JSON列表,每个元素对应一个商品块的促销规则)、字段约束(促销类型从预定义枚举值中选,价格字段必须是数字或null)、少量示例。

让LLM使用示例的方式其实很有讲究。给"错误+正确"的对照示例比只给正确示例效果好得多。比如示例里放一个"传单上标注折扣但实际需要买两件才生效"的情况,让LLM知道这种常见陷阱最容易导错,它后续类似场景就会主动判断"这促销价是否实际附带条件"。

另外,我明确让LLM输出置信度字段。这个字段特别有用,因为置信度低的结果可以自动进入人工审核队列,而不是全盘接受。LLM自评置信度和实际准确率有一定正相关性,虽然不完全精准,但作为分流条件是够用的。

4.3 输出结构示例

最终LLM输出的JSON长这样:

[ { "promo_type": "direct_discount", "product": { "raw_name": "有机纯牛奶 900ml", "matched_sku": "SKU-88211", "quantity_note": "900ml装" }, "original_price": 49.9, "promo_price": 39.9, "condition": null, "deadline": "7月20日", "supplier": "某牧场", "confidence": 0.94, "raw_text_snapshot": "原价49.9 有机纯牛奶 促销价39.9" }, { "promo_type": "buy_more_discount", "product": { "raw_name": "什锦坚果 800g" }, "original_price": 59.0, "promo_price": 89.0, "condition": "第二件半价", "confidenct_fallback": 0.88, "raw_text_snapshot": "任意第二件半价 什锦坚果" } ]

有了JSON结构,下游系统接起来非常轻松,直接落到数据库就行。之前人工录入要一天的工作量,现在几分钟内就能生成几十张传单的结构化数据。

4.4 幻觉与误读的现实对策

用LLM少不了担心幻觉。在这个场景里,幻觉主要表现为三类:

第一类是无中生有:文本里没有促销价,模型凭空补了一个"促销价"出来。对策是提示词里明确要求"价格字段必须来自输入文本,输入中没有则填null",并且在代码层面对比LLM输出的价格是否在OCR识别出的价格集合里,不一致就打回重试。

第二类是过度推理:传单写着"本周特价",模型给补了个"有效期至周日",哪怕原文没写。这种属于脑补,对策是提示词标注"不要推测原文没有的信息"。

第三类是商品名串块:OCR的文本块如果丢边界,上一块商品的文案跑到下一块去了,LLM就会把A商品和B商品的促销绑到一块。这其实不是LLM的问题,是上游CV的缺陷。我处理的办法是:把文本块的坐标信息也传给LLM,让它检查关联性,发现"商品和促销价格坐标相距太远"就主动标记出来。

5. 数据闭环:这个项目最难的不是算法,是标注和评测

5.1 数据标注体系怎么搭

做CV+LLM落地,最痛苦的往往不是训练模型,而是数据标注的质量一致性。传单版面复杂,标注"商品块的边界往左3像素"这类问题很主观,不同标注员的判断会差出半个商品的位置。

我给标注工作定了一套相对明确的标准:第一优先级是价格数字和文字区域的边界;第二优先级是商品图的边界;第三优先级才是装饰性元素(背景、图案、广告标语)。标注工具也需要做了定制,支持"人眼优先看价格、后看商品名"的标注顺序,能加快标注速度。整体统计下来,一张复杂传单平均需要10到15分钟做完全量标注,一个熟练的标注员一天差不多能处理30到40张。

LLM阶段的标注更依赖专家判断。促销规则的类型定义、字段抽取是否准确,需要有一定零售业务背景的人来标注,不是简单外包普工可以完成的。我这边是一个三人小组合力推进:两个人做常规标注,一个核心成员做疑难样本判定和规则迭代。

5.2 效果指标怎么定

传单数字化这个任务的评测指标要分层看,从底往上分别是图像质量、版面分割、文字识别、促销语义解析,每一层都需要独立评测指标,不能只盯着端到端成功率。

版面分割用的是IoU:块与块之间的交并比,阈值卡在0.7以上算命中。文字识别用准确率,但需要区分"商品名准确率"和"价格数字准确率",权重不同。促销语义解析用F1值:促销类型对不对、字段值对不对、整个JSON结构对不对,三档拆分统计。

最关键的是端到端"条目标准确率":一条促销记录最终和人工标注完全一致的比例。这个指标初期大概只有40%多,经过多轮迭代逐步到80%以上,单类传单(如格式固定的超市周报)能到90%以上。复杂品牌联动页数字会低一些,需要人工兜底的部分始终存在。

5.3 长尾传单:模型最有意思的考验

模型处理正式格子排版传单很稳,但总有些"设计鬼才"——有的传单用荧光色背景,有的文字是深底白字,有的字挤在二维码旁边,有的把价格竖排。这些长尾情况是真实世界里不可避免的部分。

我的处理思路是用一个抵抗力强的CV主干模型,再叠加一套"异常识别"逻辑。如果某个商品块OCR出来的文字可信度极低,或者LLM输出的置信度低于阈值,系统会自动标记并降级到人工处理。这套机制保障了系统在长尾传单面前不会爆出一堆错误数据,最多是"效率下降",不会"质量崩盘"。

6. 上线后实际遇到的问题与解法

6.1 每周传单更新带来的概念漂移

上线之前我以为"模型训练完"就万事大吉了。真实情况是:每周商超换新传单,促销风格和商品排版跟着变。有些商超在换季大促时会把整张传单的模板都改掉,之前训练集里完全没见过这种版式。

这会直接导致版面分割性能下降。做过在线监控之后,我会留意"每周产品块分割准确率"这个指标,一旦跌出阈值,就会立即拉取当周的新数据进行增量调优。频率上,基本一个月迭代一次模型,日常用一批校准数据持续做灰度验证。

6.2 多门店传单的差异

同一个品牌在不同城市的商超,传单内容可能不一样,甚至同一城市不同商圈店的促销价也不一样。平台方拿到的传单是按门店维度提供的,这带来一个分配问题:识别完的促销记录要落到具体门店,不能笼统覆盖到全品牌。我们在数据整合模块做了门店维度隔离,每条数据都带上"门店ID+传单期数"作为唯一键,避免不同店的促销价互相覆盖。

6.3 端到端兜底机制必须存在

无论CV和LLM做到多好,千万不能指望100%全自动。系统从设计之初就留了"人工校验池"的入口:置信度低于阈值、或者系统内部校验失败的打回人工队列。人工处理界面我做得比较顺手,操作员打开后能看到完整截图、OCR原文、LLM解析结果,只需要一键确认或者改几个字段。整个校验流程可以做到平均每条记录20秒处理完。

6.4 成本控制的一些心得

这套系统的成本大头在OCR和LLM推理。传单高峰期(周四周五集中上传)的算力消耗是平时的两三倍。为了控制成本,我做了两件事:高峰期不读全部传单,按门店和用户需求优先级挑重点传单先处理;LLM只用中等规模的模型,因为传单语义不算复杂,没必要开最大的模型。成本算下来,一张传单的数字化处理成本不到人工录入成本的十分之一,业务上完全能接受。

7. 复盘与个人体会

这个项目给我最深的感触是:CV和LLM不是竞争关系,而是链条上下游的通力配合。CV解决的是"物理世界的图像还原成结构化中间结果",LLM解决的是"中间结果还原成业务语义"。中间任何一层质量不好,下游就受苦。所以做这类系统,最需要下功夫的地方往往不是模型算法本身,而是数据闭环、评测机制和人工兜底的工程细节。

另一个体会是:不要迷信任何一个模型的输出。CV会漏、OCR会错、LLM会幻觉,只有把每一层的置信度都管控住,叠加人工审核的兜底,整个系统才敢在真实业务环境里放开跑。很多团队做这种项目失败,不是因为单个模型选得不够好,而是因为整个链路的容错设计没做好。

最后分享一个实用小技巧:在传单数字化链路的每个环节都保留中间结果的快照(原始图、校正图、版面框、OCR文本、LLM JSON)。排查线上问题时,沿着快照一路看下去,基本十几分钟就能定位到具体是哪个环节出了偏差。这个习惯救了我很多次,算是这个项目里最值得保持的工程实践了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询