
干电商平台审核或者运营的同学一定遇到过这种场景商家提交一整套入驻资料包里面是营业执照、法人身份证、食品经营许可证、品牌授权书、质检报告五六张图堆在一起。人工核验时先看证照齐不齐再看日期过没过期还要比对公司名和统一社会信用代码是不是同一个主体碰到授权链路还得翻半天聊天记录确认代理关系。这一套下来文件顺的时候十分钟遇到模糊、缺页、经营范围对不上的二十分钟打底心累不说还容易看走眼。我这次做的事简单说就是把自己从这套“看图找茬”的流程里解放出来用蓝耘元生代的 MaaS 服务搭建了一个电商资料包合规体检的小应用。商家把资料包传上来系统自动识别证照类型、抽取出关键字段、跑规则做硬校验最后生成一份体检报告标注每项检查的结果和不通过原因。整套流程从人工核验的 20 分钟压缩到实测 1 分半左右出结果。本文就把完整的思路、代码和踩坑过程都展开讲讲给同样被资质审核折磨的朋友一个可直接参考的模板。1. 项目背景与方案设计1.1 人工审核到底慢在哪里先拆解一下人工审核的耗时构成。以一份常见的食品类目入驻资料包为例通常包含营业执照、食品经营许可证、法人身份证正反面、品牌授权书、近一年质检报告。审核员要做的事看文件数量对不对缺不缺件逐张看图确认是否为对应证照比如把身份证当成营业执照传上来的情况并不少见提取关键字段公司名、统一社会信用代码、法定代表人、有效期、经营范围、发证机关做交叉核验执照上的主体名称是否和授权书的被授权方一致执照经营范围里有没有包含“食品销售”或“餐饮服务”等关键类目判断有效期证照是否过期以及是否在即将过期的边缘比如有效期还剩不到 30 天风控严格的平台会要求商家先换证检查图片质量是否清晰、是否缺角、是否反光、是否有明显 PS 痕迹这些动作看起来简单但每张图都要反复放大、对比、确认。一个熟练的审核员单份资料包平均耗时 15 到 20 分钟是常态高峰期堆积几十个待审队列加班就成了家常便饭。1.2 为什么选用蓝耘元生代的 MaaS 而不是本地模型当时考虑过两条技术路线。一条是自建模型服务。用开源的视觉语言模型再自己封装批量推理接口。优势是数据不出内网但问题也明显要准备 GPU 资源要处理模型部署、版本管理、并发调度还要面对开源模型在细粒度 OCR 抽取上准确率不够稳的坑。对一个内部提效工具来说前期的工程投入太重了。另一条就是现在采用的方案接入蓝耘元生代的 MaaS 平台。从开发者的视角看元生代就是一个统一的模型 API 入口上面同时提供视觉理解、文本生成、逻辑推理等多个模型而且接口是 OpenAI 兼容的形式之前写过 GPT 接口的同学基本零成本切换。我用下来最直接的体感是三点视觉模型对证件类图片的字段抽取很稳结构化输出可以直接拿到 JSON 而不是靠正则硬抠平台侧把并发和鉴权都管好了不用自己运维费用按调用量算内部小规模用成本非常可控。选择 MaaS 的核心逻辑是把“调模型”当做一个外部能力来调用把有限的开发精力全部放在业务规则和审核流程上。毕竟对合规体检来说模型只是负责“看懂图”的眼睛真正做决策的应该是我们自己的规则引擎。1.3 整体方案视觉抽取 规则硬校验的双引擎架构整个系统的处理链路如下商家上传资料包可以是一个 zip也可以是多张图片Flask 后端接收文件按文件名或读取顺序整理文件列表逐张调用蓝耘元生代的视觉语言模型传入图片和审核 Prompt让模型输出标准化的 JSON 结构证照类型、关键字段、置信度和风险提示汇总所有图片的结构化结果交给规则引擎做业务校验规则引擎负责硬性判断日期是否过期、证照类型是否匹配、经营范围是否包含必需类目、不同文件间的公司主体是否一致输出体检报告接口返回给前端或直接写入审核后台为什么用双引擎而不是全部交给大模型判断因为业务合规中有大量场景需要零容错。模型可以帮我识别出“营业期限为 2025 年 1 月 1 日”但“今天是否超过这个日期”这种判断必须由代码来做精确到秒不能存在任何随机性。规则引擎就是用来兜底的保险丝。2. 合规体检规则集与 Prompt 设计2.1 体检到底查什么五类核心规则在设计规则之前我把人工审核手册里的检查项重新归纳成了五个维度。这五个维度几乎覆盖了大多数电商平台的入驻资质审核场景。第一是完整性检查。不同类目对证照的要求不同食品类目需要营业执照、食品经营许可证、质检报告美妆类目需要特殊化妆品注册证数码类目可能需要 3C 认证证书。规则引擎里维护一张类目和必需证照的映射表检查上传资料缺不缺件。第二是有效性检查。证照的有效期是硬指标。判断逻辑很简单如果截止日期已经小于当前日期直接不通过如果距离截止日期小于 30 天标记为“预警”转人工确认商家是否在走续期流程。第三是一致性检查。这是人工审核中耗时最长、最容易出错的环节。典型场景包括营业执照上的公司名与授权书中的被授权方是否一致法人身份证上的姓名与营业执照的法定代表人是否一致授权书中的品牌名与申请入驻的品牌是否一致。第四是经营范围覆盖检查。营业执照的经营范围是一段长文本需要判断是否包含与入驻类目对应的关键词。比如食品销售类目需要包含“食品销售”“预包装食品销售”“食品经营”等词如果执照上只有“服装服饰批发”那这个商家卖食品就属于超范围经营。第五是图片可用性检查。模型在识别时如果发现图片模糊、缺边、反光、拍摄角度倾斜过大需要返回对应的风险标签。这类检查属于人工复核优先级最高的信号。2.2 从审核手册到 Prompt把人工经验翻译成机器指令要让视觉模型稳定输出Prompt 的设计比想象中更重要。我第一版 Prompt 写得很简单——“帮我识别这张营业执照的信息”结果模型输出格式千奇百怪字段名一会儿是 company_name 一会儿是 enterpriseName甚至有时直接把经营范围一长段原样返回不拆分。后来改成强约束的结构化 Prompt准确率才真正稳定下来。我目前用的 Prompt 大概长这样你是一名电商平台资质审核专家。我将给你一张电商入驻资质材料的图片请你完成以下任务 1. 判断图片中的证照类型可选值营业执照、食品经营许可证、品牌授权书、质检报告、法人身份证正面、法人身份证反面、其他 2. 提取该证照上的关键信息输出为 JSON 对象字段要求如下 - license_type: 证照类型 - company_name: 企业/个体工商户名称票据类证照填 null - credit_code: 统一社会信用代码无则 null - legal_person: 法定代表人/经营者姓名无则 null - valid_from: 有效期开始日期格式 YYYY-MM-DD未标注则 null - valid_to: 有效期截止日期格式 YYYY-MM-DD如果文本写的是“长期”输出字符串 long_term - business_scope: 经营范围原文无则 null - issuer: 发证机关无则 null - brand_name: 品牌名仅品牌授权书需要提取其他证照输出 null - extracted_text: 图片中与上述字段相关的原文摘要用于人工复核溯源 3. 给出图片质量风险标签可选值模糊、缺角、反光、遮挡、倾斜、无风险 4. 输出格式严格按以下 JSON 结构返回不要输出任何解释文字 {license_type: , company_name: , credit_code: , legal_person: , valid_from: , valid_to: , business_scope: , issuer: , brand_name: , extracted_text: , quality_risks: []}有几个细节值得强调。字段名必须全英文、固定命名方便后端直接反序列化。日期格式在 Prompt 里强制约定否则模型可能输出“2025年01月01日”或者“2025/01/01”这样千奇百怪的格式。extracted_text字段是我后面加上的目的很简单让模型把关键判断依据的原文摘出来一旦规则判定不通过审核员可以直接看模型摘出的原文来确认是否是误判而不是重新打开原图满屏找。还有一个比较隐蔽的经验不要要求模型在提取信息的同时做合规判断。也就是说不要让模型回答“这张执照是否过期”。模型擅长抽取和归纳但日期比对这种确定性逻辑应该交给规则引擎。模型一旦开始“判断”就引入了幻觉和随机性的空间反而不可控。2.3 结构化输出与置信度控制蓝耘元生代的接口支持 JSON Output Mode也就是强制模型按 JSON 格式输出。这个功能很关键它从根上解决了响应解析的问题。在没有结构化输出能力的时候模型偶尔会在 JSON 前后加一段“好的我识别到了以下信息”之类的废话解析时要写一堆异常处理去剥离。开启 JSON 模式后返回体干净很多。有一个例外情况需要单独处理如果上传的图片根本不是证照模型无法提取任何字段强行要求 JSON 输出会导致模型编造一个结果。我的做法是在 Prompt 里加了“如果图片内容不是证照或无法识别license_type 输出 other其余字段全部输出 null”同时要求模型在quality_risks里带上“无法识别”的标签。这样规则引擎看到license_type other且extracted_text为空直接判定为文件无效转人工。3. Flask 应用从零到上线3.1 工程结构一个服务多模型编排这是整个项目的骨架部分。我参考了蓝耘元生代常见的使用方式把应用搭成了一个轻量的 Flask Web 服务。整个工程划分成几个模块app.pyFlask 入口负责接收上传、调用处理链路、返回报告llm_client.py封装蓝耘元生代的 API 调用统一处理鉴权、超时、重试、JSON 解析rules_engine.py规则引擎包含日期校验、经营范围匹配、主体一致性校验等report.py生成体检报告的数据结构config.py配置文件存放类目映射、经营范围关键词表、API Key 等选 Flask 而不是 FastAPI说实话没有特别复杂的理由就是团队之前的技术栈以 Flask 为主迁移成本低。这个项目真正有意思的地方在于“多模型编排”的思路视觉模型负责看图抽取字段文本模型负责生成给商家的退回原因说明逻辑推理模型负责处理特殊情况下的复杂判断。三种模型通过同一个 MaaS 网关接入业务侧不需要关心每个模型部署在哪里只需要调用统一的客户端接口。这和从零搭建 DevOps 智能助手的思路本质上是同一个套路——一个 Flask 应用作为编排层底层挂多个模型服务。3.2 关键代码接收文件、调用 VLM、规则校验下面把核心代码片段贴出来。先看大模型客户端的封装。这套代码风格是通用的 OpenAI 兼容调用方式密钥和模型名称需要替换成蓝耘元生代控制台里对应的配置。import os import base64 import json import time import requests class LLMClient: def __init__(self, api_key, base_url, model_name): self.api_key api_key self.base_url base_url self.model_name model_name self.headers { Authorization: fBearer {self.api_key}, Content-Type: application/json } def _encode_image(self, image_path): with open(image_path, rb) as f: return base64.b64encode(f.read()).decode(utf-8) def chat(self, messages, temperature0.1): payload { model: self.model_name, messages: messages, temperature: temperature, response_format: {type: json_object} } for attempt in range(3): try: resp requests.post(f{self.base_url}/chat/completions, headersself.headers, jsonpayload, timeout60) resp.raise_for_status() data resp.json() return data[choices][0][message][content] except Exception as e: if attempt 2: raise e time.sleep(2 * (attempt 1)) def analyze_image(self, image_path, prompt_text): img_base64 self._encode_image(image_path) messages [ {role: system, content: 你是一个严谨的电商资质审核专家只输出 JSON。}, {role: user, content: [ {type: text, text: prompt_text}, {type: image_url, image_url: {url: fdata:image/jpeg;base64,{img_base64}}} ]} ] content self.chat(messages) try: return json.loads(content) except json.JSONDecodeError: return {license_type: other, quality_risks: [模型输出解析失败]}再来看 Flask 路由接收上传文件后逐张调用模型汇总后交给规则引擎。from flask import Flask, request, jsonify import os, uuid app Flask(__name__) client LLMClient(api_keyyour-api-key, base_urlhttps://your-endpoint.blueuan.com/v1, model_namevision-model-name) # 从文件读取 prompt 模板 PROMPT_TEMPLATE open(prompt_template.txt, encodingutf-8).read() app.route(/api/compliance_check, methods[POST]) def compliance_check(): files request.files.getlist(files) material_id request.form.get(material_id, str(uuid.uuid4())) category request.form.get(category, food) tmp_dir f/tmp/{material_id} os.makedirs(tmp_dir, exist_okTrue) file_results [] for f in files: file_path os.path.join(tmp_dir, f.filename) f.save(file_path) # 调用视觉模型抽取信息 result_json client.analyze_image(file_path, PROMPT_TEMPLATE) result_json[origin_filename] f.filename file_results.append(result_json) # 交给规则引擎 report rules_engine.check(file_results, categorycategory) return jsonify(report)规则引擎是核心我重点写了三个函数日期有效性判断、经营范围匹配、主体一致性校验。from datetime import datetime def check_validity(license_info): warnings [] errors [] valid_to license_info.get(valid_to) if valid_to long_term or valid_to is None: warnings.append(证照为长期有效请人工确认发证机关情况) else: try: end_date datetime.strptime(valid_to, %Y-%m-%d) days_left (end_date - datetime.now()).days if days_left 0: errors.append(f证照已过期 {abs(days_left)} 天) elif days_left 30: warnings.append(f证照即将过期剩余 {days_left} 天需商家补充续期证明) except ValueError: warnings.append(f日期格式无法解析: {valid_to}需要人工核对) return {errors: errors, warnings: warnings} def check_business_scope(business_scope, required_keywords): if not business_scope: return [经营范围无法识别] matched [kw for kw in required_keywords if kw in business_scope] if not matched: return [f经营范围未包含以下关键词之一: {, .join(required_keywords)}] return [] def check_company_consistency(extracted_list): company_names set() credit_codes set() for item in extracted_list: if item.get(company_name): company_names.add(item[company_name].strip()) if item.get(credit_code): credit_codes.add(item[credit_code].strip()) errors [] if len(credit_codes) 1: errors.append(资料包中出现多个不同统一社会信用代码) elif len(company_names) 1: errors.append(资料包中出现多个不同公司主体名称) return errors这些规则都相当直接没有任何花哨的机器学习。但正是这些确定性的逻辑和大模型抽取能力配合起来才构成了完整的审核闭环。3.3 并发与耗时从 20 分钟到 1 分半是怎么算出来的很多人关心 1 分半这个数字怎么来的我直接上一组实测数据。以一份 7 张图的食品资料包为例串行调用视觉模型平均每张图响应时间在 4 到 6 秒7 张图大约 35 秒。规则引擎纯本地运行处理时间可以忽略不计。但这里有个速度瓶颈图片 base64 编码后体积较大上传文件到 API 的传输时间占了不小比例。后来我做了两个优化把单份资料包的总耗时压到了 90 秒以内。第一个优化是并行调用。7 张图之间没有依赖关系用线程池并发请求可以压缩掉一半以上的等待时间。第二个优化是控制图片体积。手机拍摄的图片动辄 5MB 以上分辨率远超证件识别所需。我在后端先用 Pillow 把图片统一缩放到最长边 1600 像素、质量压缩到 80%再转 base64。图片从 6MB 降到 300KB 左右传输时间大幅缩短。优化后的耗时情况如下环节串行耗时并行压缩后耗时图片预处理约 8 秒约 3 秒VLM 逐张识别约 35 秒约 12 秒规则引擎校验 1 秒 1 秒报告生成与入库约 2 秒约 2 秒总计约 46 秒约 18 秒这里 18 秒是针对 7 张图的纯计算耗时。实际业务里商家上传文件、服务器排队、网络传输这些环节也会计入总时长所以线上实测一份资料包从点击上传到看到报告普遍在一分半左右。相比人工 20 分钟效率提升是数量级的。另外说一句如果资料包里包含 PDF 格式的质检报告需要先转成图片再送模型。我在代码里预留了 PyMuPDF 的转换逻辑PDF 每页渲染成 PNG然后走同样的识别链路。市面上大部分入驻资料包都支持 PDF这一步是必须做的。4. 常见问题与排查实录4.1 模型“看错字”怎么兜底视觉语言模型在证件识别上确实很强但偶尔会在某些字符上出错尤其是营业执照上的统一社会信用代码数字“0”和字母“O”数字“1”和字母“I”非常容易混淆。这类错误如果不处理直接落到规则引擎里就会导致一致性校验不通过。我试过的方法有两种。第一是 Prompt 里强制要求“统一社会信用代码如难以分辨请结合证件字体特征判断不要猜测”这能降低一部分错误率。第二更可靠——在规则引擎里加入校验位检查。统一社会信用代码本身有 GB 32100-2015 规定的校验算法用最后一位校验码验证前面 17 位的正确性校验不通过时标记为“信用代码校验不通过需人工核实”。这样即使模型偶尔认错字规则层也能识别出异常不会静默通过。还有一个小技巧对于高风险字段信用代码、法人姓名可以让模型把对应文本的局部截图区域描述出来。比如“代码中最后一个字符是 X 还是 8”模型给出判断依据审核员在后台复核时能快速定位到问题位置。4.2 长期、缺页、模糊这些边界情况证件有效期经常出现“长期”两个字不同模型对这两个字的理解可能不一致。有些模型会输出 null有些会输出“长期”。我在 Prompt 中明确约定输出字符串long_term同时在后端兼容了 null 的情况。规则引擎遇到这两种情况都不会直接判过期而是标记为人工确认。图片缺角是另一个高频问题。商家拍照时身份证或者营业执照的四个角经常被手挡住或者跑出镜头导致关键信息残缺。模型会对缺角图片输出质量风险标签。这里有个值得一提的处理逻辑缺角不一定等于不通过。如果缺掉的部分恰好是经营范围区域以外的空白位置且其他字段全部齐整规则引擎可以给出“通过但建议重新上传更清晰副本”的提示如果缺角导致法人姓名或统一社会信用代码无法识别则直接判不通过。模糊图片的处理也类似。我设了一个阈值逻辑模型返回quality_risks包含“模糊”标签时如果同一份资料包中其他证照识别结果都正常只允许模糊图对应字段存在 null 的情况下转人工复核如果多张图都模糊直接判定资料包整体质量不合格要求商家重新拍摄。这一条规则能避免大量低质量图片进入人工队列。4.3 隐私、日志与合规红线电商资质资料包含有大量敏感信息身份证号、统一社会信用代码、法人姓名、经营地址。这些数据在调用第三方 MaaS 平台的时候相当于把数据送出了内网。虽然我用的平台明确承诺了数据传输加密和数据不落地存储但作为业务系统负责人必须自己做好几层防护。第一层上传文件只保存在临时目录审核完成后立即删除。第二层日志一律脱敏只记录文件哈希值和处理状态不记录图片内容或抽取出的明文敏感字段。第三层调用 MaaS 时图片传输使用平台提供的私有化或者专有加密通道不经过公网明文传输。这些内容我没有在代码里写死而是放到了部署文档里保证运维同学在配置环境时不会遗漏。这个环节说句实在话比模型选型和 Prompt 调优更值得重视。合规体检应用本身是为了降风险如果自己的数据链路反而存在泄露风险那就本末倒置了。5. 从合规体检到运维助手的扩展5.1 同一套 MaaS 网关还能做什么做完合规体检之后我最大的感触是蓝耘元生代这种 MaaS 平台的价值不在于某一个模型有多强而在于它把“接入多个模型”的成本降到了极低。我这边 Flask 应用里的LLMClient完全不需要改只要换一个 model_name就可以把视觉模型换成文本模型做另外一类任务。比如我后续接了一个类似 DevOps 助手的小工具用同一个 Flask 服务接收报警信息调用文本模型做日志摘要遇到无法判断的问题再调用一个推理能力更强的模型分析根因。从架构上看这与合规体检是完全一样的套路——一个 Web 入口一个统一的模型网关多个模型按任务类型灵活路由。合规体检用到的并发调用、JSON 模式、重试机制在运维助手里直接复用省掉了大量重复工程。这个模式对中小团队尤其友好。不需要懂模型部署不需要管 GPU 集群只需要关注业务本身定义清楚要模型做什么、输出什么格式、哪些环节必须用代码兜底。剩下的复杂度交给 MaaS 平台。5.2 后续迭代方向当前版本已经满足内部提效需求但还有明显的迭代空间。一个是把规则配置化。现在类目和必需证照的映射关系写在配置文件里每次新增类目都要改代码。下一步打算提供一个管理后台让运营同学自己配置类目对应的证照清单和经营范围关键词做到零代码调整审核规则。另一个是引入人工反馈闭环。现在审核员在后台处理转人工的案例时最终的判定结果没有被收集。如果能将人工判定结果反哺到 Prompt 示例或者规则库整个系统的准确率会越用越高。大模型的幻觉问题不可能完全消除但只要“机器初筛 规则兜底 人工抽检”的闭环转起来系统的可靠性在业务层面就是可接受的。6. 一些实操中的个人体会项目上线之后我复盘了整个流程最想分享的一点是不要把大模型当成人来用而是当成一个“阅读理解能力很强但偶尔会走神的实习生”。你得给它一个明确的表单让它填空它填完以后你还得安排另一个人规则引擎去检查它填得对不对。所以这个项目中质量最高的部分反而不是模型调用代码而是那些用朴素 if-else 写出来的日期判断和经营范围比对逻辑。另一个体会和耗时有关。很多人一听“20 分钟压到 1 分半”就以为是模型推理足够快实际上模型的响应速度和人工比起来并没有数量级上的碾压真正的提速来自并行、图片压缩、自动规则替代人工逐字比对这三点组合拳。单纯换大模型不会带来效率革命围绕业务场景把流程重新编排一遍才是关键。最后留一个小技巧不要把所有希望寄托在单一模型上。我在蓝耘元生代平台上测过多个不同的视觉模型同一个 Prompt 在不同模型上的抽取准确率差异明显。上线前务必拿一批有标注的测试集做横向对比挑准确率最高的那个作为主模型剩下一个当备用。多模型配一条网关的好处在这里就体现出来了——切换模型只是改一个配置项的事。如果有同行也在做类似的自动化审核工具欢迎按照本文的思路先搭一个最小可行版本跑通一遍真实的资料包再逐步迭代。那 1 分半的体验确实比人工盯屏 20 分钟舒服太多了。