
简介这份资源面向破产管理人、清算律师、法务与司法信息化技术人员围绕破产债权申报环节的真实性核验与优先权认定难题给出了一套可落地的智能审核方案。内容从债权申报材料的结构化抽取切入结合OCR识别、自然语言语义解析与银行流水关联比对构建债权真实性验证体系并针对虚假债权特征库、申报金额与合同金额逻辑校验、时间线连贯性核查、信息冲突检测等维度逐层展开。资源共1个PDF文件674页、63个大章节压缩包约13.87MB文档支持目录跳转与左侧书签大纲定位图表文字显示完整便于按章节检索查阅。后半部分重点落在优先权自动分级涵盖破产法优先权知识图谱、职工债权与税款债权优先级判定规则、担保债权顺位排序及普通债权动态调整机制等算法实现。目前已有61人学习适合作为该领域系统研读与工程落地的参考材料。1. 破产债权申报审核为什么需要一套可复核的智能流水线一个中等规模的破产重整案件管理人要在申报期内处理上百份债权申报材料其中单份卷宗就有 674 页里面夹着合同、补充协议、对账单、银行流水、生效裁判文书、债权转让通知和催收函。人工审核的真实瓶颈从来不是看不懂某一页而是要把散落在不同页码、不同附件、不同格式里的金额、日期、主体名称逐一勾稽起来再判断这笔债权是否真实、金额是否成立、有没有优先受偿的顺位。这套智能审核方案瞄准的就是三段流水线用 DeepSeek 把非结构化材料读成结构化字段用规则加语义模型完成债权真实性验证与申报材料逻辑一致性检查最后给每笔债权自动打上优先权分级的标签。适合破产管理人团队、律所清算业务线以及在做司法与金融文档智能审核的工程师参考。2. 用 DeepSeek 抽取债权申报要素从 674 页 PDF 到结构化字段2.1 申报卷宗的版面差异与预处理策略破产债权申报材料基本没有统一模板。同一批材料里有的是扫描件有的是带文本层的 PDF还有的是 Excel 明细加 Word 说明的组合。直接整本丢给模型是最常见的误用既浪费额度也让页码溯源失效。我一般先做一次版面体检判断哪些页需要走 OCR哪些页可以直接抽文本。# 用 PyMuPDF 快速判断每页是否带文本层决定 OCR 分流 python - PY import fitz # PyMuPDF doc fitz.open(claim_674p.pdf) scan_pages [] for idx, page in enumerate(doc): text page.get_text(text).strip() # 少于 30 个字符基本可判定为无文本层多为扫描图 if len(text) 30: scan_pages.append(idx 1) print(总页数:, doc.page_count) print(疑似扫描页数量:, len(scan_pages)) print(前 20 页页码:, scan_pages[:20]) PY逻辑说明这份体检脚本不做任何识别只负责分流。带文本层的页走pdfplumber或 PyMuPDF 直接抽扫描页转图片后走 OCR避免整本都走 OCR 带来的成本和错字率。参数上阈值 30 是个经验值遇到页眉页脚字很多的扫描件可以提到 80先跑一遍看分布再定。真正的切块不是按固定页数切而是按证据清单切先用目录页或首部清单定位合同流水对账单各自的起止页再按证据单元切。证据类型页区间定位方式建议切块粒度主合同与补充协议关键词合同协议 目录页每份合同一块附条款编号银行流水与对账单表头重复检测 页码连续性每 20 到 30 行一块保留账号与日期列生效裁判文书页首民事判决书裁定书整份不切长文单独请求债权转让与催收记录关键词转让催收通知每次转让事件一块这样切完每个块都带着evidence_type、page_start、page_end、chunk_id四个元字段后面无论做抽取还是回溯原文都能直接跳回页码。2.2 借 DeepSeek API 做要素抽取的提示词与结构化输出抽取这一步的关键不是提示词写得多花哨而是强制结构化输出。DeepSeek 开放平台兼容 OpenAI 风格的接口用官方 SDK 就能调如果案卷涉密不允许出内网就把base_url换成本地部署的推理服务地址其余代码不用改这也是本地化部署在这类场景里最常见的动机。import json import os from openai import OpenAI client OpenAI( api_keyos.environ[DEEPSEEK_API_KEY], base_urlhttps://api.deepseek.com/v1, # 本地化部署时改内网地址 ) EXTRACT_SYSTEM 你是破产债权申报材料的信息抽取器。 只输出 JSON不要输出任何解释文字。 遇到材料中没有的信息字段值填 null不要猜测。 金额一律输出为数字单位元日期输出为 YYYY-MM-DD。 SCHEMA_HINT { creditor_name: 债权人名称, debtor_name: 债务人名称, claim_amount: 申报本金元, interest_amount: 申报利息元, claim_basis: 债权形成依据如买卖合同/借款合同/判决书, contract_no: 合同编号, contract_date: 合同签订日期, debt_due_date: 债务到期日, has_judgment: 是否附生效裁判文书true/false, has_assignment: 是否涉及债权转让true/false, collateral_desc: 担保物描述无则 null, evidence_pages: 该字段所在页码数组, } def extract_fields(chunk_text: str, chunk_id: str) - dict: user_prompt ( f请从下面的材料片段中抽取字段字段定义如下\n f{json.dumps(SCHEMA_HINT, ensure_asciiFalse, indent2)}\n\n f材料片段chunk_id{chunk_id}\n{chunk_text} ) resp client.chat.completions.create( modeldeepseek-chat, messages[ {role: system, content: EXTRACT_SYSTEM}, {role: user, content: user_prompt}, ], response_format{type: json_object}, # 强制 JSON省掉解析容错 temperature0, # 抽取任务不要随机性 max_tokens1500, ) return json.loads(resp.choices[0].message.content)逻辑说明response_format设为json_object后模型输出一定是合法 JSON省掉了正则兜底的麻烦。temperature0是抽取类任务的默认选择追求同一份材料多次调用结果一致。系统提示里专门写了填 null 不要猜因为申报材料缺项极多模型一旦开始合理推断后面的一致性检查就全是假阳性。参数上max_tokens按单个块的最大字段量估1500 对大多数证据块够用遇到长合同可提到 3000但要注意块本身别切太大。2.3 抽取字段的校验与置信度标记抽取结果不能直接进审核队列。我会先过一遍确定性校验再给每个字段打上置信度标记低置信度的字段不参与后续自动判定直接进人工复核。校验项规则失败处理金额格式正则^\d(\.\d{1,2})?$且大于 0标记LOW转人工日期合法性可被datetime.strptime解析且不晚于申报截止日标记LOW转人工名称一致性债权人名称与营业执照或身份证明文本相似度 ≥ 0.9标记MID提示核对页码可溯源evidence_pages非空且页码在实际范围内标记LOW重新抽取金额勾稽本金 利息与申报总额偏差 ≤ 1 元标记MID进一致性检查校验脚本本身很轻关键是evidence_pages这道卡没有页码的字段无法回溯原文人工复核时等于白干所以宁可重抽也不放过。这几步跑完674 页卷宗会收敛成一张字段表字段表才是后面真实性验证和优先权分级的输入。3. 债权真实性验证申报金额、合同、流水三方勾稽的落地写法3.1 三类证据的对账规则设计债权真实性验证最容易走偏的地方是把它当成模型判断真假。实际业务里真实性体现为一组可复现的勾稽关系申报金额能不能被合同金额解释合同约定的付款义务有没有对应的流水流水的对手方是不是申报人。把这些关系写成规则比让模型直接回答这笔债权是否真实可靠得多。勾稽维度参与证据判定口径不通过含义金额勾稽申报表 合同 流水流水累计入账 ≥ 合同金额 × 0.95出借或交付事实存疑时间勾稽合同签订日 放款日 到期日三者在合理时序内无倒挂材料可能拼接主体勾稽合同相对方 流水对手方 申报人名称归一化后一致债权转让或主体错位凭证勾稽申报表 裁判文书文书金额与申报本金偏差 ≤ 5%申报金额超出文书确认范围金额勾稽里的 0.95 是容忍系数用于吸收手续费、部分回款等情况具体取值按案件类型调。主体勾稽必须先做名称归一化因为同一主体在合同里写全称、在流水里是简称、在申报表里可能少个有限公司直接字符串比较必然误判。3.2 用 DeepSeek 补全证据链的语义判断规则能覆盖金额和日期覆盖不了这份催收函能不能构成诉讼时效中断这类语义判断。我一般把规则跑出的疑点整理成小批次问题交给 DeepSeek 做定向回答而不是让它通读全文。CHECK_TEMPLATE 下面是同一笔债权申报的两段材料摘录请回答三个问题 1) 两段材料描述的是否为同一笔债务 2) 是否存在金额、日期或主体上的冲突如有指出冲突点。 3) 材料是否能支撑申报表中的债权金额 每个问题用一句话回答并在句末给出 [依据页码]。 材料A页码{p1}{text_a} 材料B页码{p2}{text_b} def semantic_cross_check(item: dict) - str: prompt CHECK_TEMPLATE.format( p1item[page_a], text_aitem[text_a][:3000], p2item[page_b], text_bitem[text_b][:3000], ) resp client.chat.completions.create( modeldeepseek-chat, messages[{role: user, content: prompt}], temperature0, max_tokens600, ) return resp.choices[0].message.content逻辑说明模板把两段材料限长到 3000 字符只保留最相关的段落避免模型被无关内容带偏。要求句末给依据页码是为了让结论可回溯——模型说冲突审核员点开页码就能核对。参数上temperature0保持一致max_tokens600对应三个短答足够。这一步的产出不是最终结论而是给规则引擎补充疑似冲突点的结构化条目。3.3 逻辑一致性检查的规则引擎实现把规则和语义结果合并成一张问题清单是这套方案里最该写扎实的一段。规则引擎不追求复杂输出要统一每条问题带类型、严重级、涉及页码。def run_consistency_check(claim: dict, rules_result: list, semantic_result: list) - list: issues [] # 规则层金额、时间、主体的硬性冲突 for r in rules_result: if not r[passed]: issues.append({ code: r[code], # 如 AMOUNT_MISMATCH level: r[level], # HIGH / MID / LOW detail: r[detail], pages: r.get(pages, []), }) # 语义层模型给出的冲突点降一级处理需人工确认 for s in semantic_result: if 冲突 in s and 不存在 not in s: issues.append({ code: SEMANTIC_CONFLICT, level: MID, detail: s.strip(), pages: extract_pages(s), # 从 [依据页码] 里回捞 }) # 去重同页码同 code 只保留严重级最高的 dedup {} for it in issues: key (it[code], tuple(it[pages])) if key not in dedup or level_rank(it[level]) level_rank(dedup[key][level]): dedup[key] it return sorted(dedup.values(), keylambda x: -level_rank(x[level]))逻辑说明规则层的结论直接采信语义层的结论统一降为MID因为模型判断只是线索不能当作结论。去重按问题类型 页码集合做键避免同一处金额冲突被规则和模型各报一次。level_rank把 HIGH/MID/LOW 映射成可比数值排序后清单第一条就是最该先看的。跑完这一步每笔债权会得到一份问题清单清单为空或只剩 LOW 的才进入自动通过区间。4. 优先权自动分级给每笔债权打顺位标签4.1 优先权的分类口径与边界条件优先权分级的难点不在分类本身而在口径要和业务方给定的规则表严格对齐。类别边界、顺位关系、例外情形通常是管理人团队在案件启动阶段就确认好的模型只负责把材料映射到这套口径上不负责解释口径。落到实现里我一般把口径整理成一张配置表而不是写死在提示词里。标签典型判定依据边界条件优先-担保材料中存在有效担保约定与登记凭证担保物已灭失或未登记的降级优先-职工申报人为职工且申报工资、社保类款项需与职工名册交叉核对优先-税款申报主体为税务机关附完税凭证滞纳金部分单独标注普通无担保、无优先依据的普通合同债权默认兜底类别劣后材料显示关联关系或约定劣后需人工二次确认边界条件这一列才是真正决定准确率的部分。担保物是否灭失、登记凭证是否在卷这些信息往往埋在附件里所以分级必须在第 2 章的字段抽取之后跑不能独立做。4.2 提示词驱动的分级标签输出分级提示词要把口径表直接喂进去让模型做的是匹配而不是发挥。GRADE_SYSTEM 你是破产债权优先权分级器。严格按给定口径表分级。 只输出 JSON{grade: ..., reason: ..., confidence: 0.0-1.0, pages: [...]} 口径表之外的类别一律归入普通。 置信度低于 0.7 时必须说明不确定的具体字段。 def grade_claim(claim: dict, rule_table: list) - dict: prompt ( f分级口径表\n{json.dumps(rule_table, ensure_asciiFalse)}\n\n f债权要素\n{json.dumps(claim, ensure_asciiFalse)}\n\n f材料摘要\n{claim.get(summary, )[:2000]} ) resp client.chat.completions.create( modeldeepseek-chat, messages[ {role: system, content: GRADE_SYSTEM}, {role: user, content: prompt}, ], response_format{type: json_object}, temperature0, max_tokens500, ) return json.loads(resp.choices[0].message.content)逻辑说明口径表以 JSON 形式传入改口径只需改配置不用动代码。系统提示里口径表之外归入普通是防止模型自创类别分级结果必须能落进有限枚举。confidence不是模型自评的装饰而是分流依据低于 0.7 的结果一律进人工队列并要求模型指出不确定字段方便复核时直接定位。pages字段同样用于回溯分级理由和页码一起存库后续出审核底稿时可以直接引用。4.3 分级结果与人工复核队列的衔接自动分级的结果不能直接出结论必须按置信度和问题清单分流。我用的分流规则如下落到数据库里就是一张审核任务表。条件处理动作队列置信度 ≥ 0.85 且无 HIGH 问题自动通过生成底稿免复核置信度 0.7 到 0.85复核分级标签常规队列置信度 0.7 或存在 MID复核分级 关键字段优先队列存在 HIGH 问题挂起退回补充材料待补正队列分流后复核人员看到的不是原始 674 页而是标签 理由 冲突点 页码。这套流程跟我们平时把审核结果推送到企业微信审批流是同一套接口思路模型出结构化结果人在熟悉的界面里做最终确认。真正省时间的不是让模型替人决策而是把定位页码这件事自动化掉。5. 674 页卷宗跑得动的工程技巧切片、缓存与漂移核对5.1 按证据单元切片并保留页码锚点长卷宗跑不动八成是切片策略的问题。按固定字数硬切会切断合同条款按固定页数切会把一份判决书劈成两半。我的做法是两级切片第一级按证据单元切第二级在单元内按语义段落切。每个切片都带chunk_id、evidence_type、page_start、page_end四个锚点抽取结果里必须回填这些锚点缺锚点的结果直接丢弃重抽。这样做还有个副作用好处同一份材料里反复出现的表头、页码、骑缝章说明会被切分策略天然隔离不会污染字段抽取。5.2 抽取结果缓存与增量重跑一份 674 页卷宗全量跑一次抽取耗时主要在请求往返上。我会按hash(chunk_text)建缓存命中缓存的切片直接返回上次的 JSON只有内容变化的切片才重新请求。补充材料进来时只需对新切片和受影响的证据单元重跑其余沿用缓存。缓存键里不含页码因为同一段文字换页后结论不变含页码反而会降低命中率。这里有个容易踩的坑调了提示词或换了模型版本后缓存必须整体失效否则新旧结果混在一张表里一致性检查会报出一堆假冲突。我一般把提示词版本号和模型标识拼进缓存键。import hashlib, sqlite3 def cache_key(chunk_text: str, prompt_ver: str, model: str) - str: raw f{prompt_ver}|{model}|{chunk_text}.encode(utf-8) return hashlib.sha256(raw).hexdigest() def get_or_extract(conn: sqlite3.Connection, chunk: dict, prompt_ver: str) - dict: key cache_key(chunk[text], prompt_ver, deepseek-chat) row conn.execute(SELECT result FROM cache WHERE key?, (key,)).fetchone() if row: return json.loads(row[0]) # 命中缓存跳过请求 result extract_fields(chunk[text], chunk[chunk_id]) conn.execute(INSERT OR REPLACE INTO cache VALUES (?, ?), (key, json.dumps(result))) conn.commit() return result逻辑说明缓存键里带prompt_ver和model任何一端变化都会让旧缓存自然失效不用手动清库。用 SQLite 存就够了单机一次案件几千个切片查询压力很小。注意INSERT OR REPLACE只在键相同时覆盖不会污染其他版本的缓存。5.3 抽样核对定位模型漂移模型行为不是恒定的同一批材料隔一段时间再跑个别字段的抽取口径可能悄悄变了。我会固定抽 20 份历史已复核的债权每次全量跑完后重抽一遍比对两轮的字段差异率。差异率超过 5% 就说明口径漂移先查提示词和模型标识有没有被动过再决定是否重跑全量。核对输出建议直接生成一张对照表chunk_id、字段名、上一轮值、本轮值、涉及页码。开发阶段在 VSCode 里接 DeepSeek 调试提示词时也可以把这张表做成一个快捷任务改一次提示词就自动跑一遍抽样比人工翻页快得多。本文还有配套的精品资源点击获取