多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

用DeepSeek实现仲裁与调解文书智能生成:要素抽取与条款审查

用DeepSeek实现仲裁与调解文书智能生成:要素抽取与条款审查 简介法律文书是高度结构化的专业文本传统人工起草耗时且易错。大模型技术为文书生成提供了新路径其核心在于将案情要素抽取、结构化模板回填与段落润色分工处理。通过设定低温参数、JSON输出约束和角色边界模型可以作为起草助手在固定骨架内辅助完成事实整理、请求表述和证据清单构建。争议解决条款审查同样遵循此逻辑先列出风险清单再基于约束条件优化措辞确保管辖与终局性表述无冲突。这类智能文书生成流程可覆盖仲裁申请书、调解协议及合同条款审查等场景将分钟级初稿与人工复核相结合显著提升批量案件处理效率。借助DeepSeek的实际工程演示可完整看到从要素抽取到条款优化的落地路径。1. 用 DeepSeek 做仲裁与调解文书智能生成先把话说死它是起草助手不是裁判官我见过太多团队拿到 DeepSeek 后的第一反应是丢一句“帮我写一份仲裁申请书”然后拿着结果直接交差。这恰恰是最危险的用法。仲裁与调解文书和普通公文不一样它有明确的法定要素、固定的行文结构、以及一眼就能看出的逻辑断点。DeepSeek 这类大模型真正的价值不在于替你“无中生有”而在于把案情要素抽取、文书初稿生成、争议解决条款审查优化这些重复劳动压缩到分钟级——一份三千字的仲裁申请书人工起草通常要两个小时以上用智能文书生成流程可以把初稿时间压到五分钟左右。但前提是你得把流程拆对要素抽取、结构化输出、条款审查、人工复核一个都不能少。这篇笔记写给两类人一类是被批量案件反复改稿折磨的法务和律师另一类是想把大模型落进法律科技产品的工程师。适合你的才是好方案不适合的再炫也没用。2. 智能文书生成不是“把模板交给大模型”五段式结构与要素抽取先行2.1 为什么直接让 DeepSeek 写文书会翻车法律文书的“结构化约束”和普通问答不一样先看一个现象。你让 DeepSeek“写一份劳动仲裁申请书”它大概率能产出一份看起来像模像样的东西有申请人、被申请人、仲裁请求、事实与理由、证据清单。但你再让它写十份不同案由的问题就出来了——仲裁请求的序号可能有歧义事实与理由里混进了法律分析证据清单缺了证明目的。原因不复杂法律文书是高度结构化的文体而通用大模型在自由对话模式下倾向于“流畅地发挥”不会自动遵守你脑子里的那份文书规范。仲裁与调解文书的基本骨架一般是五段首部文书名称、案号、当事人信息名称、住所、法定代表人、正文仲裁请求、事实与理由、证据清单、尾部仲裁员签署、日期、附注送达地址、联系方式。调解文书还会多出“调解协议内容”和“履行方式”两段。让模型直接写等于把结构约束完全托付给模型的“即兴发挥”——偶尔对上长期靠不住。我一般会这样处理把文书生成拆成两步。第一步先做案情要素抽取用结构化输出锁定所有事实字段第二步把字段回填进一个经过校验的骨架模板再让 DeepSeek 只做段落级润色。这样模型从头到尾没有机会“自由发挥结构”它能发挥的只是语序和衔接——这部分它确实擅长。下面两节就按这个思路展开。2.2 用 DeepSeek 做案情要素抽取的最小实现JSON 输出与字段约束以最常见的劳动仲裁申请场景为例。我们在一个 Python 脚本里调用 DeepSeek 的对话补全接口要求它从一段案情描述里抽出固定字段。注意 DeepSeek 的 API 兼容 OpenAI 格式所以直接用 openai 库指定 base_url 就能调通。from openai import OpenAI import json client OpenAI( api_key你的key, base_urlhttps://api.deepseek.com/v1 # DeepSeek 兼容 OpenAI 接口 ) def extract_case_facts(case_text: str) - dict: system_prompt 你是一个仲裁文书要素抽取器。只允许从用户输入中抽取事实信息禁止补充任何法律意见。 必须输出 JSON字段严格限定如下 { applicant: {name: , type: 自然人/法人, address: }, respondent: {name: , type: 自然人/法人, address: }, claims: [仲裁请求1, 仲裁请求2], facts: [事实要素1, 事实要素2], evidence: [{name: 证据名, purpose: 证明目的}], missing: [缺失信息列表] } 如果输入中没有对应信息字段填 null 或空列表不要编造。 resp client.chat.completions.create( modeldeepseek-chat, messages[ {role: system, content: system_prompt}, {role: user, content: case_text} ], temperature0.1, # 抽取任务用低温减少幻觉 max_tokens2048, response_format{type: json_object} # 强制 JSON 输出 ) return json.loads(resp.choices[0].message.content) case_text 张三于2023年3月入职杭州某网络科技有限公司任前端开发岗 月薪12000元。2024年7月公司以业务调整为由单方面解除劳动合同 未支付经济补偿金。张三主张公司违法解除要求支付赔偿金24000元 并补发2024年5月被克扣的绩效工资3000元。公司注册地为杭州市西湖区文三路138号。 result extract_case_facts(case_text) print(json.dumps(result, ensure_asciiFalse, indent2))这段代码的关键有三处。第一system_prompt里明确写了“禁止补充任何法律意见”这是防止模型在抽取阶段就擅自定性——比如把“业务调整”直接解读成“违法辞退”那是仲裁庭该做的事不是抽取器该做的事。第二temperature0.1是用于事实抽取的基准参数抽取任务要的是确定性不是创造性温度越高越容易在事实里混入推测。第三response_format{type: json_object}强制模型输出 JSON但注意它不能保证字段名完全符合你的预期——个别情况下模型会自己改名或嵌套所以下游最好加一层 schema 校验比如用jsonschema库不校验的话后面回填模板时会翻车。抽取完成后你应该拿到一份干净的结构化事实。一个实用的习惯把missing字段里的空缺项整理成人话反馈给经办人——“缺申请人出生日期”“缺被申请人法定代表人”——让人去补而不是让模型猜。法律文书的字段猜一次就是一份错误文书。2.3 从要素到文书初稿把抽取结果回灌模板再让模型做段落级润色字段拿到之后不要急着让模型“写全文”。我惯用的做法是先用一段带占位符的文书骨架做字符串格式化把抽取结果填进去生成一份没有语病但略显生硬的“机械稿”然后只把“事实与理由”这一段交给 DeepSeek 润色。template 劳动仲裁申请书 申请人{applicant_name}{applicant_type}住所{applicant_address} 被申请人{respondent_name}{respondent_type}住所{respondent_address} 仲裁请求 {claims_block} 事实与理由 {facts_block} 证据清单 {evidence_block} 此致 {arbitration_committee} def build_claims_block(claims: list, applicant: str) - str: lines [] for i, c in enumerate(claims, 1): # 每一项请求单独成行便于后续逐项核对 lines.append(f{i}. 请求裁决被申请人向{applicant}{c}) return \n.join(lines) def polish_facts(facts: list, respondent: str) - str: # 只润色衔接和语序不新增事实 resp client.chat.completions.create( modeldeepseek-chat, messages[ {role: system, content: 把用户给的事实要点改写成一段通顺的叙述文字。要求不得新增事实不得删除事实不得出现法律定性结论控制在300字以内。}, {role: user, content: .join(facts) f。被申请人系{respondent}。} ], temperature0.3, max_tokens1024 ) return resp.choices[0].message.content.strip() # 假设上一节已经拿到了 result doc template.format( applicant_nameresult[applicant][name], applicant_typeresult[applicant][type], applicant_addressresult[applicant][address], respondent_nameresult[respondent][name], respondent_typeresult[respondent][type], respondent_addressresult[respondent][address], claims_blockbuild_claims_block(result[claims], result[applicant][name]), facts_blockpolish_facts(result[facts], result[respondent][name]), evidence_block\n.join(f- {e[name]}{e[purpose]} for e in result[evidence]), arbitration_committeeXX仲裁委员会 ) print(doc)这轮润色的temperature我通常设在 0.3 左右比抽取高一点能给文字留出自然的改写余地但又不能太高否则模型会“顺手”把“被申请人拖欠工资”扩写成“被申请人恶意拖欠工资”——一个字的差别就是两种性质。注意 prompt 里那句“不得出现法律定性结论”这就是在给模型画边界。你回头会发现段落级润色比全文生成的翻车率低一个量级因为结构已经被模板锁死了模型没有机会改变段落顺序和文书框架。3. 争议解决条款优化从“能写到”到“能执行、不打架”3.1 仲裁条款审查的四个必查点仲裁机构、仲裁地、仲裁语言、裁决终局性文书生成只是前半场真正考验功力的在争议解决条款。合同里的仲裁条款和调解条款问题通常不出在“写不出来”而出在“写出来没法执行”。我处理过的条款缺陷里高频的就四类第一仲裁机构名称不完整。合同中写“提交北京市仲裁委员会”但官方名称是“北京仲裁委员会”——一字之差法院可能认定仲裁协议无效。第二仲裁地和仲裁机构混为一谈。约定了“在上海仲裁”却指定了外地仲裁机构。第三仲裁语言缺失。涉外合同里不约定仲裁语言到时候程序语言争议比实体争议还麻烦。第四漏掉裁决终局性表述。仲裁裁决是终局的对双方都有约束力但这个“终局性”需要在条款里写明不然当事人心里没底还会额外生出一轮确认之诉。调解条款里还有一类典型问题把调解设为仲裁的前置条件却没有写明“调解期限届满未达成一致任何一方可申请仲裁”。结果是双方在调解阶段互相拖延仲裁程序启动不了。DeepSeek 能在这里做什么它能快速从条款文本里把上述要素逐项抽查出来尤其是当你把检查清单写成结构化 prompt 之后。3.2 结合 DeepSeek 做条款风险扫描的提示词设计常见的做法是把审查逻辑做成“一条 prompt 一份示例输出”让模型逐条对合同文本做合规预审。这里给出一个可以直接用的最小实现。clause_review_prompt 你是资深争议解决律师负责审查合同中的争议解决条款。 对输入的条款文本逐项检查以下8项存在风险则输出风险描述无风险输出null。 检查项 1. 仲裁机构名称是否完整准确对照标准全称 2. 仲裁地/开庭地是否明确 3. 仲裁语言是否有约定涉外合同必查 4. 是否写明裁决终局性和约束力 5. 调解前置程序是否设定期限或退出机制 6. 仲裁/诉讼路径是否同时出现且冲突 7. 送达地址是否完整决定后续程序文书能否有效送达 8. 条款是否覆盖合同全部争议如漏掉知识产权争议 输出JSON结构 {risks: [{check_item: 序号, risk_level: high/medium/low, description: 问题描述, suggestion: 修改建议}], overall: 通过/需修改} def review_clause(text: str) - dict: resp client.chat.completions.create( modeldeepseek-chat, messages[ {role: system, content: clause_review_prompt}, {role: user, content: text} ], temperature0.1, max_tokens2048, response_format{type: json_object} ) return json.loads(resp.choices[0].message.content) sample_clause 因本合同引起的或与本合同有关的任何争议双方应友好协商解决 协商不成的任何一方均可向上海仲裁委员会申请仲裁。 仲裁裁决是终局的对双方均有约束力。 仲裁费用由败诉方承担。 print(review_clause(sample_clause))参数上要注意两点。一是temperature0.1审查任务本质是“找错”低温是为了让模型不过度推断——不然它会把一个本来规范的条款脑补出风险。二是max_tokens2048对单条款够用但对整份合同的争议解决章节经常两三页就不够了这时需要分块处理。分块的方式按条款编号切而不是按字符数硬切否则一个跨页的完整条款会被拦腰截断漏检率猛增。检查项的设计上是刻意写成 8 项的。为什么不是 5 项因为实际翻车场景里“送达地址缺失”和“调解前置无期限”这两项最容易被模型忽略而它们恰恰是后期执行阶段的高频纠纷点。你可以在自己的检查清单里增删但建议保留一个原则宁可多查一项显示“无风险”也别少查一项漏掉真问题。3.3 条款优化生成给模型“三份输入”而不是“一句指令”条款审查发现问题之后下一步是改写优化。很多人会直接说“帮我改一下这个条款”结果模型给出一版完全重写的漂亮条款但改掉了当事人已经谈好的商业条件比如把仲裁改成了诉讼。这是条款改写里最容易踩的坑。我一般会让模型同时接收三份输入原条款全文、审查发现的风险清单、以及改写约束哪些内容不能动。改写约束里写明“不得变更争议解决方式、不得变更管辖地、不得新增当事人义务、其他部分可优化”。improve_prompt 根据风险清单优化下列争议解决条款。 原文 {original} 风险清单 {risks} 约束 1. 不得将仲裁改为诉讼或将诉讼改为仲裁 2. 不得变更仲裁机构 3. 不得新增当事人实体义务 4. 保持条款编号不变 5. 被优化处用【修改说明】标注理由 输出格式完整条款文本附修改说明。 risks review_clause(sample_clause) improved client.chat.completions.create( modeldeepseek-chat, messages[ {role: system, content: 你是合同条款修订专家严格按约束条件修改。}, {role: user, content: improve_prompt.format( originalsample_clause, risksjson.dumps(risks, ensure_asciiFalse) )} ], temperature0.2, max_tokens2048 ) print(improved.choices[0].message.content)这样生成出来的优化稿比单次指令“帮我优化条款”的可用性高很多。原因在于“三份输入”把模型的自由度限制在了“文本表达层”而不是“商业决策层”——商业条件已经在原条款里定好了模型只负责让它更严密、更可执行。另外建议在优化后加一层差量检查用 diff 工具对比原文和优化稿人工只需阅读变化部分而不是从头通读全文。这能大大缩短复核时间也方便向当事人解释改了什么、为什么改。4. 全流程落地把“生成文书→优化条款→人工复核”串成一条可审计链路4.1 整条流水线的模块划分与文件流转设计前面两章解决了“单点怎么做”这一章把串起来的问题讲清楚。一个可用于真实业务的智能文书生成全流程至少需要四个模块要素抽取模块、初稿生成模块、条款审查模块、人工复核台。整套链路的核心设计原则是每个模块的输出都落盘为结构化中间产物而不是只存在于内存里。这样任何一个环节出问题都能从磁盘上捡回上一步结果重跑不用整条链从头再来。文件流转我一般这样设计案件原始材料进来 →01_extracted_facts.json→02_draft_doc.md→03_review_report.json→04_final_doc.docx/pdf。中间每一步都由脚本生成一份带时间戳的产物文件文件命名格式统一为序号_模块_案号_时间。这个习惯初期看着啰嗦但一旦遇到“生成的文书里有一项请求金额错了”这种事故你能立刻定位是抽取阶段错了还是模板回填阶段错了而不是把整条链重新跑一遍看运气。4.2 用脚本把 DeepSeek 输出自动转成排版干净的 PDF文书最终要交到仲裁委或当事人手里格式不能是 Markdown 源码。我的落地做法是先用 python-docx 生成规范的 Word 文档再由 LibreOffice 无头模式转 PDF。这样既保留了后续人工在 Word 里微调的可能又能得到定稿的 PDF 版本。from docx import Document from docx.shared import Pt, Cm from docx.enum.text import WD_ALIGN_PARAGRAPH import subprocess def generate_doc_from_markdown(doc_md: str, output_docx: str, output_pdf: str): doc Document() # 页边距设置为上下2.54cm、左右3.17cm符合公文习惯 for section in doc.sections: section.top_margin Cm(2.54) section.bottom_margin Cm(2.54) section.left_margin Cm(3.17) section.right_margin Cm(3.17) title doc.add_paragraph() title.alignment WD_ALIGN_PARAGRAPH.CENTER run title.add_run(劳动仲裁申请书) run.font.name 黑体 run.font.size Pt(22) body_lines doc_md.split(\n) for line in body_lines[1:]: # 跳过已写入标题的首行 p doc.add_paragraph() run p.add_run(line) run.font.name 仿宋 run.font.size Pt(14) # 三号仿宋中文公文常用字号 p.paragraph_format.line_spacing 1.5 doc.save(output_docx) # LibreOffice 无头模式转PDF适合批量任务 subprocess.run([libreoffice, --headless, --convert-to, pdf, output_docx, --outdir, .], checkTrue) # doc_md 来自上一章的模板输出 generate_doc_from_markdown(doc, 仲裁申请书_张三_20240701.docx, 仲裁申请书_张三_20240701.pdf)这段代码里值得注意的不是 python-docx 本身而是两个容易忽略的细节。第一中文公文中正文字体通常用仿宋标题用黑体或宋体加粗直接沿用模板里的默认字体一般是 Calibri会让中文排版在转 PDF 后非常难看。第二libreoffice --headless转换时如果源 docx 里中文字体没有嵌入目标 PDF 在别人电脑上打开可能缺字所以务必要在 Word 里装好常用中文字体再从脚本调转换不要直接裸奔。4.3 为企业法务做本地/私有化部署时的取舍外部 API 调用在数据合规上有一个绕不过去的问题案情描述属于敏感信息很多企业不允许把这类文本发到外部服务。这时就要考虑本地部署 DeepSeek 模型。常见做法是用 vLLM 部署量化版本的模型显存能够吃下 7B/14B 的档位就够用了。这里有一个务实的建议如果只是做要素抽取和条款审查这类中短文本任务14B 量化模型配合 8K 上下文窗口能覆盖绝大多数场景但如果要处理整份合同全文建议先按条款拆分再分段调用而不是硬上大上下文——上下文窗口拉长后模型对中段信息的注意力会下降这不是玄学是实测共识。本地部署还有一个隐性好处你可以针对自己的文书模板做微调或持续收集 few-shot 样本让模型越用越贴合本单位的语言习惯。但代价也很实际——GPU 显存占用、推理速度下降、运维成本上来。我的取舍建议是涉密案件和日常大风控场景走本地批量标准文书的去隐私化初稿可以走 API两者并行而不是二选一。5. 避坑DeepSeek 生成法律文书的 5 个典型翻车现场5.1 编造“仲裁规则”和“法条序号”幻觉条文怎么拦现象生成的文书里出现“根据《中华人民共和国仲裁法》第57条规定……”看着严谨实际该条内容与上下文不匹配甚至根本不存在。 原因大模型在生成“看起来合理”的引用时会基于训练数据里的高频法条序号做概率拼接而不是在查法条库。 解决所有引用类内容一律走检索增强先用法条库检索出真实条文再让模型基于检索结果改写而不是让它凭记忆生成。对不接检索的场景就在 prompt 里加一条硬指令禁止引用具体法条序号如确需引用用“根据相关法律规定”代替。5.2 输出 JSON 偶发截断导致下游解析失败现象抽取要素时返回内容在 JSON 末尾突然断了只到facts: [事实要素1, 事实要素json.loads 直接抛异常。 原因max_tokens 用尽长输入或复杂案件描述会耗尽生成额度输出被硬截断。 解决两个对策同时用。第一max_tokens 设到输出预期值的 1.5 倍以上第二在解析失败后不要重跑全量生成而是把截断的尾部文本重新送入模型让它“续写并闭合 JSON”。重跑全量很可能得到一份和上次不完全一致的结果而续写保持了前半段信息的一致性。5.3 条款优化改出了“自相矛盾”同一案由下管辖与争议解决方式冲突现象原条款约定“提交北京仲裁委员会仲裁”优化稿里出现了“任何一方均可向合同签订地人民法院提起诉讼”的表述两种争议解决路径同时存在。 原因模型在改写时把其他合同模板里的诉讼条款“缝合”了进来且审查清单里没有覆盖“仲裁与诉讼互斥”这一项。 解决优化稿生成后强制过一次结构性检查——把争议解决方式仲裁/诉讼提取出来和原条款做比对不一致直接判失败。我在第三章的检查清单里把“仲裁/诉讼路径是否同时出现且冲突”列了进去就是这个原因。5.4 “当事人信息”张冠李戴多人多组织案件里的指代混淆现象一份案件中申请人是公司、被申请人是法定代表人个人生成文书里把法定代表人的姓名填到了申请人名称栏。 原因抽取阶段模型对“谁是被申请人”的指代消解出错尤其是“张三系该公司法定代表人”这种句式模型容易把“张三”归到公司实体上去。 解决在抽取 prompt 里显式要求输出每个实体的“角色标注”并且人工复核时优先检查当事人信息行的字段回填。如果案件涉及多个自然人/法人可以考虑让模型先输出实体关系表再抽取要素不要一步到位。5.5 长文档处理超时或丢上下文中间结果没有及时落盘现象一份几十页的合同中第二次调用的模型“忘记”了第一次审查时发现的某个高风险条款。 原因整份合同塞进一个上下文窗口超过模型有效注意力范围后中间部分条款被“漏看”。也可能单次请求超时整条链返回失败。 解决按条款块切分后用会话保持上下文但每个条款块的审查结果立即写回 JSON 文件。宁可多几步文件读写也不要把全部状态都放在模型上下文里——上下文是易失的磁盘是可靠的。6. 验证模型输出质量的“反向抽取回测法”流程搭好之后怎么证明这套方案真的靠谱我的习惯是做一个“反向抽取回测”——拿已经生效的仲裁裁决书和调解协议书作为测试集把文书全文喂给 DeepSeek让它反向抽取案件要素并重建文书骨架再和原始文书逐字段比对。这个方法的巧妙之处在于你不是在验证模型“写得好不好看”而是在验证它“抓得准不准、漏没漏、幻觉多不多”。回测的维度我一般取三个字段级准确率、结构完整性、条款一致性。字段级准确率看当事人信息和金额数字是否与原始文书完全一致结构完整性看抽取结果是否覆盖原始文书的全部段落类型条款一致性针对争议解决条款看模型重建的版本与原条款在管辖地和争议解决方式上是否冲突。自建一个几十份样本的小测试集就够把失败样本按原因归类回填进 few-shot 示例里——哪些字段容易抓错、哪些句子结构会触发幻觉都收集起来下次新版本模型或新提示词上生产环境前先跑一遍这批回归样本。我自己的一个小习惯是维护一个“条款黑名单样本库”里面有十来份从真实业务里收集的带病条款机构名不全、管辖冲突、送达地址缺失等。每次换模型版本、调整提示词都先用这批样本过一遍。如果新版模型在旧样本上的风险发现率下降说明有倒退那就需要回滚提示词或补 few-shot。这个方法花不了多少时间但它是避免“换了个更强模型结果条款审查反而漏了”这种怪事的最好办法。这个方向值得投入吗如果你的业务里存在批量案件、标准化文书、高频条款审查答案是值得。把重复劳动交给 DeepSeek把判断和责任留给人这是我认为最健康的落地姿势。希望帮到你。本文还有配套的精品资源点击获取
返回列表