2. 工程合同文本的数字化预处理

在把工程合同交给大模型或规则引擎做条款审查之前,必须先完成一件事:把"人看的合同"变成"机器能算的合同"。这一步统称为数字化预处理。它决定了后续所有审查结论的上限——如果OCR把"发包人"识别成"发包入",把"3.5%"识别成"3.5%",再强的模型也会给出错误判断。本节按真实处理链路,讲清四个环节:PDF/扫描件解析、OCR纠错、段落与条款切分、元数据标注。

一、先判断合同是"电子版"还是"扫描版"

工程合同常见的来源有三类:一是Word/PDF导出的原生电子文档,文字层可直接提取;二是纸质合同扫描或手机拍照生成的图片型PDF,只有像素没有文字;三是混合型,正文是电子文字,但盖章页、附件、图纸是扫描图片。处理前必须先分类,否则会做无用功或漏掉关键页。

判断方法很直接:用解析库尝试提取文字,若某页提取出的字符数极少(例如少于20个字符)而页面尺寸正常,基本可判定为图片页。以Python为例:

import fitz  # PyMuPDF
doc = fitz.open("contract.pdf")
for i, page in enumerate(doc):
    text = page.get_text("text").strip()
    imgs = page.get_images(full=True)
    print(f"第{i+1}页 字符数={len(text)} 图片数={len(imgs)}")
    # 字符数少且图片数≥1 → 该页需走OCR

实际工程合同中,专用合同条款、协议书、中标通知书通常是电子版,而盖章页、手写补充条款、附件清单常是扫描件。因此解析策略应是"逐页判定、混合处理",而不是整份文档一刀切。

二、OCR纠错:不是识别完就结束

OCR(光学字符识别)把图片转成文字后,错误集中在几类:形近字("己/已/巳"、"未/末")、数字与单位("1"与"l"、"0"与"O"、"m²"识别成"m2")、表格线干扰导致的串行、以及印章覆盖区域的缺字。工程合同里最致命的是金额、日期、比例、工期天数这几类数字错误。

纠错不能只靠通用词典,要建立领域纠错规则。例如:

  • 金额字段:识别结果若出现"壹拾贰万"与阿拉伯数字"120000"不一致,标记为待人工复核;
  • 日期字段:用正则约束为"YYYY年MM月DD日"格式,非法日期(如2024年13月)直接拦截;
  • 比例字段:百分号前后必须是数字,"3.5%"不能变成"3.5%"以外的形态;
  • 术语表替换:维护"发包人/承包人/监理人/暂列金额/缺陷责任期"等术语白名单,对编辑距离为1的疑似错词做候选替换并记录日志。
纠错结果必须保留"原文—修正—置信度"三元组,便于审查阶段回溯。任何自动修改都不能静默覆盖原文,否则一旦发生争议无法举证。

三、段落与条款切分:让机器找到"第X条"

合同审查的最小单位是条款,而不是整篇文档。切分要做两级:先按版面切段落,再按编号体系切条款。

工程合同普遍采用"第X条 → X.1 → X.1.1"的层级编号。切分时用正则识别编号模式,并记录层级深度。例如:

import re
# 匹配 "第3条"、"3.1"、"3.1.2" 等编号
pat = re.compile(r'^(第[一二三四五六七八九十百]+条|\d+(\.\d+){0,3})\s*')
for line in lines:
    m = pat.match(line.strip())
    if m:
        level = m.group(1).count('.') + 1
        # level=1 为条,level=2 为款,level=3 为项

难点在于:扫描件的编号可能被识别成"第3条"或"第 3 条"或"第三条",需要归一化;跨页条款要合并;表格内的条款不能按行切碎。切分完成后,每条条款应带上条款号、层级、起止位置、所属章节,形成结构化条款列表。

四、元数据标注:给每条条款贴"标签"

元数据是后续检索和审查的索引。工程合同至少应标注以下字段:

元数据字段示例值用途
合同类型施工合同/监理合同/分包合同选择对应审查规则集
条款类别价款/工期/质量/违约/争议解决分类审查
风险关键词无限责任、单方解除、垫资风险预警
金额/比例合同价 12,000,000 元;质保金 3%数值合规校验
来源页/坐标P7, (120,340)-(480,410)定位原文、高亮回显

标注方式建议"规则+模型"结合:先用关键词和正则打底(如出现"违约金"即归入违约类),再用小模型对条款做类别补全。标注结果以JSON存储,每条条款一个对象,便于后续按类别批量审查。

工程合同数字化预处理链路 合同来源 电子PDF / 扫描件 混合型文档 逐页解析判定 文字层提取 图片页标记 OCR识别与纠错 形近字/数字/单位 领域术语白名单 段落与条款切分 第X条 / X.1 / X.1.1 层级与跨页合并 元数据标注(每条条款一个JSON对象) 合同类型 · 条款类别 · 风险关键词 · 金额比例 · 来源页坐标 规则打底 + 小模型补全,保留原文—修正—置信度 结构化条款库(供AI审查调用) 条款号 · 层级 · 正文 · 类别 · 风险标签 · 原文定位 质量校验点 • 字符数异常页 • 金额/日期一致性 • 条款编号连续性 • 印章区域缺字 • 表格串行检测 • 人工复核队列

五、把四步串成可复现的流水线

实际落地时,建议把上述四步封装成一条可重复执行的流水线,每一步都输出中间产物并记录日志:解析阶段输出"页级文字/图片标记表",OCR阶段输出"原文—修正—置信度"记录,切分阶段输出"条款层级树",标注阶段输出"条款JSON库"。这样一旦最终审查结论异常,可以逐级回溯定位是解析漏页、OCR错字,还是切分把两条条款合并了。

常见坑:① 直接对整份PDF做OCR,导致电子版页面被二次识别引入新错误;② 切分时只按"第X条"切,忽略了"X.1"款级编号,导致条款粒度过粗;③ 元数据只标类别不标原文坐标,审查结果无法回显到合同原文,用户无法核对。规避方法就是坚持"逐页判定、层级切分、坐标留痕"三条原则。

完成预处理后,合同就从一份不可计算的文档,变成了带编号、带类别、带坐标、可检索可审查的结构化条款集合。这是后续所有条款分析、风险识别与合规校验的数据基础。