2026/4/5 20:41:36
网站建设
项目流程
高明网站制作,域名服务商是什么意思,骏域网站建设专家电话,门户类网站建设大约多少钱LangChain1.0OCRRAG 搭建法务合同审核 Agent#xff08;附源码#xff09;
一、为什么法务场景需要OCR而非VLM#xff1f;
在构建文档智能体#xff08;Agent#xff09;时#xff0c;我们经常面临一个技术选型的难题#xff1a;是直接使用视觉语言模型#xff08;VL…LangChain1.0OCRRAG 搭建法务合同审核 Agent附源码一、为什么法务场景需要OCR而非VLM在构建文档智能体Agent时我们经常面临一个技术选型的难题是直接使用视觉语言模型VLM“看”文档还是采用OCR提取文本结合RAG检索增强生成的技术路线对于政府招投标书RFP、行政公文、法律合同等严格格式文档我们发现OCRRAG方案在落地效果上远超VLM。这些文档通常动辄数十页且对条款的位置、内容规范性有极高要求。核心考量维度如下文档长度与Token成本合同和标书通常是多页长文档。以一份20页的劳动合同为例VLM方案若将PDF转为图像输入每页约消耗 1000-2000 tokens整份文档需2-4万tokens接近许多模型的上下文上限且图像Token价格昂贵通常是文本的5-10倍。OCR方案提取纯文本通常只需 5000-8000 tokens成本降低 80%以上。精确坐标定位与可追溯性法务审核的核心需求是精确定位问题条款。OCR方案如MinerU解析时返回每个文本块的精确坐标bbox: [x1, y1, x2, y2]可精确到字符级支持后续的高亮批注。VLM方案其返回结果中缺乏精确的坐标映射通常只能给出模糊的页码或段落描述无法支持后续的PDF批注、高亮标记等可视化功能。这对于需要生成审核报告并在原文档上标注问题的场景来说是致命缺陷。表格与复杂格式处理对于合同中常包含表格如付款计划表、违约金计算表和复杂格式如条款编号、多级标题OCR方案能将其解析为结构化数据JSON/Markdown便于后续的计算校验如金额汇总、日期逻辑检查。VLM方案VLM 虽然能识别表格但其输出往往是描述性文本“表格中显示…”难以直接用于数值计算和格式校验需要额外的后处理步骤方案对比总结对比维度OCR RAG 方案VLM 方案长文档处理智能切分无token上限受限于上下文窗口成本纯文本token成本低图像token成本高5-10倍坐标定位精确到字符级别缺乏精确坐标映射可追溯性完整的bbox_list仅模糊描述规则灵活性支持动态规则库RAG依赖模型内置知识表格处理结构化解析可计算描述性输出难计算综上对于 合同、标书等长文档审核场景OCR RAG 方案在 成本、精度、可追溯性、灵活性 等多个维度均优于VLM方案。VLM 更适合短文档、强视觉依赖的场景如票据识别、图文混排的宣传册审核法务文档审核这类 重文本、重逻辑、重定位的任务OCRRAG才是最优选择 。本文将带你从零实现一个完整的文档审核系统。核心特点是保留 PDF 文档的坐标信息实现可追溯、可定位的文档审核和修改。核心流程二、效果展示三、核心代码实现这里仅展示核心代码实现流程扫码加入 赋范空间 免费领取完整项目源码还有更多Agent开发、模型微调等项目案例等你来挖掘PDF 解析与坐标提取核心这是系统的基石。MinerU 不仅提取 Markdown 文本还会返回 content_list其中包含每个文本片段在 PDF 中的坐标信息。import requests import json from pathlib import Path def parse_pdf_with_mineru(pdf_path: str, output_dir: str ./temp) - str: 调用 MinerU API 解析 PDF关键参数 return_content_listtrue Path(output_dir).mkdir(exist_ok True ) print( f开始解析 PDF: {pdf_path} ) with open(pdf_path, rb ) as f: files [( files , (Path(pdf_path).name, f, application/pdf ))] data { backend : pipeline , server_url : VLLM_SERVER_URL, parse_method : auto , return_md : true , return_content_list : true , # 关键返回坐标信息 } response requests.post(MINERU_API_URL, filesfiles, datadata, timeout 600 ) response.raise_for_status() result response.json() # 保存结果 file_name Path(pdf_path).stem json_path Path(output_dir) / f{file_name}_output.json with open(json_path, w , encoding utf-8 ) as f: json.dump(result, f, ensure_ascii False , indent 2 ) return str(json_path)扫码加入 赋范空间 免费领取完整项目源码及更多项目案例其中也包括相关的MinerU、PaddleOCR-VL和DeepSeek-OCR的详细介绍以及如何在本地通过vLLM框架启动解析服务带坐标的文档智能切分切分策略按标题层级切分: 优先在 # H1, ## H2, ### H3 处切分控制片段大小: 每个片段不超过 800 tokens分配坐标: 根据文本内容匹配对应的坐标信息关键点切分后的文本片段必须保留其对应的原始坐标信息。切分示例MinerU 返回的原始数据按照行、段落、表格单元格等自然单位切分的。{ content_list : [ { text : 解除劳动合同通知书 , bbox : [ 359 , 95 , 638 , 120 ], page_idx : 0 }, { text : 先生/小姐 , bbox : [ 199 , 164 , 373 , 181 ], page_idx : 0 }, { text : 根据 劳动合同法... , bbox : [ 170 , 200 , 847 , 255 ], page_idx : 0 }, // ... 共 219 个文本块 ] }重新切分 (chunk_size800)核心逻辑一个Chunk → 多个BBox: 每个原始文本块都有自己精确的坐标Chunk 1 ( 831 tokens): 内容: 解除劳动合同通知书\n\n先生/小姐\n\n根据劳动合同法... bbox_lis t: [ {bbox: [ 359 , 95 , 638 , 120 ], tex t: 解除劳动合同通知书 }, {bbox: [ 199 , 164 , 373 , 181 ], tex t: 先生/小姐 }, {bbox: [ 170 , 200 , 847 , 255 ], tex t: 根据... }, // ... 共 86 个原始文本块的坐标 ]后续的审核逻辑issue { original : 年 月 日至 年 月 日 , # 有问题的原文 description : 日期填写不完整 } # 在chunk的bbox_list中查找匹配的坐标 for bbox_item in chunk[ bbox_list ]: if 年 月 日至 年 月 日 in bbox_item[ text ]: problem_bbox bbox_item[ bbox ] # 找到了 problem_page bbox_item[ page_idx ] # 可以在PDF上精确高亮这个位置核心代码实现我们实现一个 split_document_with_coords 函数它会在切分 Markdown 文本的同时遍历原始的 content_list将坐标映射到对应的 Chunk 中。from typing import Dict, Any, List def split_document_with_coords( md_content: str, content_list: List[Dict], chunk_size: int 800 ) - List[Dict[str, Any]]: 切分文档并精确分配坐标核心逻辑 # 1. 简单的按段落切分文本 paragraphs md_content.split( \n\n ) chunks [] current_chunk chunk_start_positions [] # ... (省略部分基础文本拼接代码详见完整源码) ... # 2. 为每个chunk分配坐标 # 逻辑遍历content_list中的每个bbox看它的text属于哪个chunk result [] for i, chunk_text in enumerate(chunks): bbox_list [] for item in content_list: if item.get( type ) text : text item.get( text , ).strip() if not text: continue # 在原文中查找这个text的位置 text_pos md_content.find(text) if text_pos -1 : # 尝试规范化匹配 normalized_text normalize_text(text) normalized_md normalize_text(md_content) text_pos normalized_md.find(normalized_text) # 判断这个text属于哪个chunk if text_pos ! -1 : chunk_start chunk_start_positions[i] chunk_end chunk_start len(chunk_text) # 如果text在当前chunk的范围内 if chunk_start text_pos chunk_end: bbox_list.append({ type : item.get( type ), bbox : item.get( bbox ), page_idx : item.get( page_idx ), text : text, content_preview : text[: 50 ] }) result.append({ content : chunk_text, token_count : estimate_tokens(chunk_text), bbox_list : bbox_list # 实现了文本到坐标的绑定 }) return result构建审核 Agent 的提示词我们将法务审核标准固化为 Prompt 中的 Context。这里仅展示一小部分完整见项目源码也可根据你的场景进行自定义PROFESSIONAL_CONTRACT_AUDIT_RULES # 合同协议书专业审核规则 ## 一、文本规范性审核P1-P2级 ### 1.1 错别字与形近字检查 - 形近字 己 / 已 / 以 、 的 / 地 / 得 、 做 / 作 、 账 / 帐 - 多字、漏字、笔误 - 严重程度medium ### 1.2 标点符号规范性 - 标点符号正确使用句号、逗号、顿号、分号、冒号 - 括号、引号配对 - 合同特殊要求金额数字后不加顿号、条款编号后统一标点 - 严重程度low ...... PROFESSIONAL _USER_ PROMPT 请对以下合同协议书片段进行专业审核 【待审核文本】 {text} 【审核要求】 1. 严格按照《合同协议书专业审核规则》逐条审查 2. 重点关注P0级问题法律风险、权利义务、金额数字、逻辑一致性 3. 对于每个发现的问题 - 精确引用原文位置 - 说明违反的具体规则 - 评估严重程度和法律风险 - 给出专业的修改建议 4. 生成修正后的完整文本 5. 编写审核总结 【特别说明】 1. 如果发现书名号显示为 $ $ 和 $1gt; $ 等符号这是OCR识别错误应归类为【OCR识别问题】而非【法律术语规范性】问题 2. 对于明显的OCR错误如特殊符号、乱码请在modifications中提供正确版本但在issues中标注为OCR识别错误 3. 只有当原文确实使用了错误的标点符号时才归类为【法律术语规范性】问题 请输出审核结果JSON格式。 【输出格式】 以JSON格式返回AuditResult对象确保 - has_issues: 是否发现问题布尔值 - issues: 问题列表按严重程度排序 - modifications: 修改映射列表 - corrected_text: 修正后的完整文本 - summary: 审核总结 - overall _risk_ level: 整体风险等级high/medium/low/none 请开始审核。 基于langChain构建审核 Agentfrom langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate # 创建 LLM llm ChatOpenAI( model qwen3-max , temperature 0.1 , ) # 使用结构化输出 structured_llm llm.with_structured_output(AuditResult) # 定义 Prompt audit_prompt ChatPromptTemplate.from_messages([ ( system , PROFESSIONAL_SYSTEM_PROMPT), ( user , PROFESSIONAL_USER_PROMPT) ]) # 创建审核链 audit_chain audit_prompt | structured_llm执行审核与结果展示执行审核代码将切分好的 Chunk 传入 Agent即可获得包含法律风险分析、修改建议及原文引用的结构化数据。try : print ( \n正在调用专业审核系统... ) result audit_chain.invoke({ rules : PROFESSIONAL_CONTRACT_AUDIT_RULES, text : chunks[ 0 ] })对审核结果进行解析print( \n审核成功 ) print( \n * 80 ) print( 【审核结果概览】 ) print( * 80 ) print( f是否发现问题: {result.has_issues} ) print( f整体风险等级: {result.overall_risk_level} ) print( f问题总数: {len(result.issues)} ) print( f修改总数: {len(result.modifications)} ) print( f\n审核总结: {result.summary} ) if result.has_issues: # 按严重程度分组 high_issues [i for i in result.issues if i.severity high ] medium_issues [i for i in result.issues if i.severity medium ] low_issues [i for i in result.issues if i.severity low ] print( \n * 80 ) print( 【问题详情】 ) print( * 80 ) if high_issues: print( f\n高风险问题 ({len(high_issues)} 个) ) print( - * 80 ) for i, issue in enumerate(high_issues, 1 ): print( f\n{i}. [{issue.rule_category}] {issue.issue_type} ) print( f 描述: {issue.description} ) print( f 原文: {issue.original} ) print( f 建议: {issue.suggestion} ) if issue.legal_risk: print( f ⚠️ 法律风险: {issue.legal_risk} ) if medium_issues: print( f\n中风险问题 ({len(medium_issues)} 个) ) print( - * 80 ) for i, issue in enumerate(medium_issues, 1 ): print( f\n{i}. [{issue.rule_category}] {issue.issue_type} ) print( f 描述: {issue.description} ) print( f 原文: {issue.original} ) print( f 建议: {issue.suggestion} ) if low_issues: print( f\n低风险问题 ({len(low_issues)} 个) ) print( - * 80 ) for i, issue in enumerate(low_issues, 1 ): print( f\n{i}. [{issue.rule_category}] {issue.issue_type} ) print( f 描述: {issue.description} ) print( f 原文: {issue.original} ) print( f 建议: {issue.suggestion} ) if result.modifications: print( \n * 80 ) print( f【修改记录】({len(result.modifications)} 处) ) print( * 80 ) for i, mod in enumerate(result.modifications, 1 ): print( f\n修改 {i}: ) print( f 原文: {mod.original} ) print( f 修改: {mod.modified} ) print( f 原因: {mod.reason} ) if mod.rule_ref: print( f 规则: {mod.rule_ref} ) print( \n * 80 ) print( 【修正后的文本】 ) print( * 80 ) print(result.corrected_text) else : print( \n文档无问题 ) print( \n * 80 ) print( 测试通过数据结构完全兼容 ) print( * 80 ) except Exception as e: print( f\n测试失败 ) print( f\n错误类型: {type(e).__name__} ) print( f错误信息: {e} ) print( \n完整错误堆栈: ) import traceback traceback.print_exc()结果展示正在调用专业审核系统... 审核成功 【审核结果概览】 是否发现问题: True 整体风险等级: high 问题总数: 10 修改总数: 6 审核总结: 本次审核发现该劳动合同相关文书模板存在多项高风险问题 1 ) 法律术语使用不当 通知书 应改为 决定书 2 ) 主体信息缺失未填写员工姓名和身份证号 3 ) 经济补偿金表述不规范且适用情形错误 4 ) 关键日期和金额空白 5 ) 存在严重歧义性表述。此外还有文本重复、标点不规范等中低风险问题。整体风险等级为high建议全面修订后再使用。 【问题详情】 高风险问题 ( 6 个) -------------------------------------------------------------------------------- 1. [法律术语规范性] 法律术语使用不当 描述: 多处使用 解除劳动合同通知书 作为单方通知文件名称但根据《劳动合同法》用人单位单方解除劳动合同应出具 解除劳动合同决定书 或类似具有决定性质的文书 通知书 易被理解为告知而非决定可能影响法律效力。 原文: 解除劳动合同通知书 建议: 建议统一修改为 解除劳动合同决定书 或 关于解除劳动合同的决定 以体现用人单位单方解除行为的法律性质。 2. [权利义务对等性] 主体信息缺失 描述: 所有文书模板中均未填写员工姓名、身份证号等关键身份信息仅以 先生/小姐 或空白代替违反《劳动合同法》关于明确劳动关系主体的要求可能导致文书无效。 原文: 先生/小姐 建议: 应在每份文书开头明确填写员工全名并在乙方信息处完整填写身份证号码确保主体明确。 3. [金额与数字准确性] 经济补偿金表述不规范 描述: 多处经济补偿金条款仅写 计 元 未同时采用大小写金额且未明确计算依据如月工资标准不符合《工资支付暂行规定》关于金额书写规范的要求易引发争议。 原文: 计 元 建议: 应补充为 计人民币【大写】元整¥【小写】 并注明计算基数如 按离职前12个月平均工资计算 。 4. [必备条款完整性] 关键日期缺失 描述: 所有模板中的日期字段如 年 月 日 均为空白未设置默认格式或填写说明不符合合同成立的基本要件可能导致文书无效。 原文: 年 月 日 建议: 应统一格式为 ____年__月__日 并在使用说明中要求必须填写具体日期。 5. [法律合规性] 经济补偿金适用情形错误 描述: 在 劳动合同到期终止通知书 中直接规定 公司需要支付给您相当于 月工资的经济补偿 但根据《劳动合同法》第 46 条劳动合同期满终止时仅在用人单位不同意续订或降低条件续订而劳动者不同意的情况下才需支付经济补偿。此处表述过于绝对可能构成违法承诺。 原文: 2 此种情况下公司需要支付给您相当于 月工资的经济补偿计元。 建议: 应修改为选择项 □ 因公司不同意续订劳动合同需支付经济补偿金...□ 因公司维持或提高原条件续订而您不同意无需支付经济补偿金 。 6. [表述清晰度] 歧义性表述 描述: 协商解除劳动合同协议书 第二条 计 元方支付 方经济补偿金 元 存在严重语病和歧义无法判断支付主体和金额对应关系。 原文: 二、乙方薪资结算至 年 月 日计 元方支付 方经济补偿金 元 建议: 应明确为 乙方薪资结算至____年__月__日共计人民币____元甲方支付乙方经济补偿金人民币____元 。 中风险问题 ( 2 个) -------------------------------------------------------------------------------- 1. [逻辑一致性] 条款重复冗余 描述: 文档中 协商解除劳动合同协议书 、 劳动合同到期终止通知书 等模板重复出现两次内容完全相同属于明显的文本冗余可能造成使用混乱。 原文: 协商解除劳动合同协议书...全文重复 建议: 删除重复的模板保留一份即可。 2. [必备条款完整性] 缺少法律依据引用 描述: 部分解除/终止情形未准确引用法律条款如 过失性解除 选项虽内容正确但未注明对应《劳动合同法》第 39 条不利于员工知悉权利。 原文: 1 过失性解除 口在试用期内证明不符合录用条件的... 建议: 应在每类解除情形后注明法律依据如 依据《劳动合同法》第39条 。 低风险问题 ( 2 个) -------------------------------------------------------------------------------- 1. [文本规范性] 标点符号不规范 描述: 多处顿号、逗号使用不规范如 口不予支付经济补偿金 口公司需要支付... 中分号应为句号或换行且选项间应统一使用顿号或分行排列。 原文: 口不予支付经济补偿金 口公司需要支付... 建议: 每个选项应独立成行末尾不加标点或统一使用顿号分隔。 2. [OCR识别问题] 特殊符号错误 描述: 《劳动合同法》书名号显示正常但部分空格不规范如 《 劳动合同法 》 属OCR识别导致的多余空格。 原文: 《 劳动合同法 》 建议: 修正为 《劳动合同法》 去除多余空格。 【修改记录】( 6 处) 修改 1 : 原文: 解除劳动合同通知书 修改: 原因: 法律术语规范性要求 规则: 2.1 法律术语规范性 修改 2 : 原文: 先生/小姐 修改: 原因: 明确合同主体 规则: 4.3 必备条款完整性 修改 3 : 原文: 计 元 修改: 原因: 金额书写规范 规则: 2.3 金额与数字准确性 修改 4 : 原文: 二、乙方薪资结算至 年 月 日计 元方支付 方经济补偿金 元 修改: 原因: 消除歧义明确支付关系 规则: 5.1 歧义性表述 修改 5 : 原文: 《 劳动合同法 》 修改: 原因: OCR识别错误修正 规则: OCR识别问题 修改 6 : 原文: 2 此种情况下公司需要支付给您相当于 月工资的经济补偿计元。 修改: 原因: 符合法律规定避免违法承诺 规则: 4.1 法律合规性 【修正后的文本】 # 解除劳动合同决定书 【员工姓名】先生/女士 根据《劳动合同法》相关规定公司依法解除此前您与公司订立的劳动合同(合同期限: ____年__月__日至____年__月__日)。解除您的理由是 1 过失性解除依据《劳动合同法》第 39 条 □ 在试用期内证明不符合录用条件的 □ 严重违反公司依法制定的规章制度的 □ 严重失职营私舞弊给用人单位造成重大损害的 □ 以欺诈、胁迫的手段使用人单位违背真实意思签订劳动合同致使劳动合同无效的 □ 员工同时与其他用人单位建立劳动关系对完成本单位的工作任务造成严重影响或者经用人单位提出拒不改正的 □ 被依法追究刑事责任的 2 非过失性解除依据《劳动合同法》第 40 条 □ 劳动合同订立时所依据的客观情况发生重大变化致使原合同无法履行经当事人协商不能就变更合同达成协议的 □ 员工不能胜任工作经过培训或者调整工作岗位仍不能胜任的 □ 员工患病或非因工负伤医疗期满后不能从事原工作也不能从事由公司安排的其他工作 3 经济性裁员依据《劳动合同法》第 41 条 □ 依据企业破产法规定进行重整的 □ 生产经营发生严重困难的 □ 公司转产、重大技术革新或者经营方式调整经变更劳动合同后仍需裁员的 □ 其他因劳动合同订立时所依据的客观经济情况发生重大变化致使劳动合同无法履行的。 您的劳动合同于____年__月__日解除。您需要结算以下薪资和补偿金事项 1 您薪资结算至____年__月__日计人民币【大写】元整¥【小写】 2 此种情况下 □ 不予支付经济补偿金 □ 公司需要支付给您相当于【】个月工资的经济补偿计人民币【大写】元整¥【小写】。 您需要按照公司的离职管理制度规定办理离职手续。 通知单位盖章 通知时间____年__月__日 说明本通知一式二份送达劳动者一份用人单位留存一份涂改无效。 送达记录受送达人签字 签收时间 --- 协商解除劳动合同协议书 甲 方AA公司 乙 方【员工姓名】员工身份证号【身份证号码】 甲、乙双方于____年__月__日签订了有/无固定期限劳动合同现由【甲/乙】方提出协商解除劳动合同要求经甲、乙双方协商一致同意解除劳动合同并达成如下协议 一、解除劳动合同的日期为____年__月__日 二、乙方薪资结算至____年__月__日共计人民币【大写】元整¥【小写】甲方支付乙方经济补偿金人民币【大写】元整¥【小写】 三、【其他约定事项】 四、本协议自甲、乙双方签字盖章后生效 五、本协议一式两份甲、乙双方各执一份具有同等法律效力涂改无效。 甲方盖章 乙方签字 法定代表人或委托代理人签字盖章 签约日期____年__月__日 签约日期____年__月__日 --- 劳动合同到期终止通知书 【员工姓名】先生/女士 公司与您订立的劳动合同____年__月__日至____年__月__日即将届满。根据国家和地方相关法律、法规、政策以及劳动合同相关约定经公司管理层批准依法与您终止劳动合同。 您需要结算以下薪资和补偿金事项 1 您薪资结算至____年__月__日计人民币【大写】元整¥【小写】 2 此种情况下 □ 因公司不同意续订劳动合同需支付经济补偿金相当于【】个月工资计人民币【大写】元整¥【小写】 □ 因公司维持或提高原劳动合同约定条件续订而您不同意不予支付经济补偿金。 您需要按照公司的离职管理制度规定办理离职手续。 通知单位盖章 通知时间____年__月__日 说明本通知一式二份送达劳动者一份用人单位留存一份涂改无效。 送达记录受送达人签字 签收时间 --- [其余文书模板按相同原则修正删除重复内容补充主体信息、规范金额表述、明确法律依据] 测试通过数据结构完全兼容 四、总结通过 MinerU (OCR) Smart Chunking (坐标映射) LLM (Structured Output) 的组合我们成功构建了一个具备企业级能力的法务审核 Agent学AI大模型的正确顺序千万不要搞错了2026年AI风口已来各行各业的AI渗透肉眼可见超多公司要么转型做AI相关产品要么高薪挖AI技术人才机遇直接摆在眼前有往AI方向发展或者本身有后端编程基础的朋友直接冲AI大模型应用开发转岗超合适就算暂时不打算转岗了解大模型、RAG、Prompt、Agent这些热门概念能上手做简单项目也绝对是求职加分王给大家整理了超全最新的AI大模型应用开发学习清单和资料手把手帮你快速入门学习路线:✅大模型基础认知—大模型核心原理、发展历程、主流模型GPT、文心一言等特点解析✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑✅开发基础能力—Python进阶、API接口调用、大模型开发框架LangChain等实操✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经以上6大模块看似清晰好上手实则每个部分都有扎实的核心内容需要吃透我把大模型的学习全流程已经整理好了抓住AI时代风口轻松解锁职业新可能希望大家都能把握机遇实现薪资/职业跃迁这份完整版的大模型 AI 学习资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】