
简介这份PDF文档面向法律从业者、法律科技研究者及希望借助大模型提升文书效率的团队系统讲解如何用提示词工程驱动DeepSeek完成法律文书自动化。内容围绕合同审查、起诉状起草、答辩状生成、法律意见书等12大核心场景展开覆盖风险条款识别、条款合规校验、当事人信息结构化提取、诉讼请求规范化、证据清单关联匹配、反驳逻辑构建、法规检索关联等100余个高频模板并配套法律术语库交互设计与语义、逻辑、规范三层适配原理。资源共1个PDF文件约13.33MB460页、60个大章节支持目录跳转与左侧书签大纲快速定位图表、目录等元素显示完整。已有109人学习。读者可据此掌握从架构设计到模板落地的完整方法直接复用15合同类型、20案由及10典型纠纷的提示词实例快速搭建可迁移的法律文书自动化流程。1. 法律文书自动化从460页模板到可复现的提示词工程一份460页的PDF12大核心场景100高频模板——这个体量放在任何一家律所或法务部门都意味着一件事日常文书工作里存在大量高度重复、结构固定、但措辞要求精确的内容。合同审查意见、律师函、起诉状、答辩状、尽职调查报告、合规备忘录这些文书的骨架大同小异真正消耗时间的往往是措辞的反复推敲和格式的来回调整。DeepSeek法律文书自动化方案的核心思路就是用提示词工程把这100模板变成可调用、可组合、可迭代的生成规则让模型承担初稿输出和格式填充人只负责关键判断和最终把关。这套方案适合两类人一是手头有大量文书模板但不知道怎么让AI稳定输出的法务从业者二是想用DeepSeek API搭建内部文书工具的技术人员。接下来我会把提示词工程怎么设计、模板怎么组织、API怎么调、坑在哪里一层层拆开讲清楚。2. 提示词工程在法律文书场景的落地逻辑2.1 为什么法律文书不能直接丢给模型自由发挥法律文书的特殊性在于格式必须合规措辞必须精确逻辑链条必须完整而且不同场景对语气、立场、引用规范的要求差异极大。一份律师函和一份内部合规备忘录虽然都是法律文书但结构、语气、引用方式完全不同。如果直接给DeepSeek一句“帮我写一份律师函”输出结果大概率是结构松散、措辞随意、缺少必要法律要素的泛泛之谈。提示词工程在这里的作用不是让模型“更聪明”而是把法律文书的隐性规则显性化。具体来说需要把以下要素固化到提示词里文书类型对应的标准结构比如起诉状必须包含当事人信息、诉讼请求、事实与理由、证据清单、必须出现的法律要素比如律师函中的委托人授权声明、合规备忘录中的法规依据、语气和立场约束比如代理词需要偏向己方当事人审查意见需要中立客观、以及输出格式要求比如是否需要Markdown表格、是否需要编号、是否需要留空待填项。我一般会把一个场景的提示词拆成四层角色定义层、任务描述层、约束条件层、输出格式层。角色定义层告诉模型“你是一名有十年经验的商事诉讼律师”任务描述层说明“根据以下案件事实生成一份起诉状初稿”约束条件层列出“诉讼请求必须分项编号、事实部分按时间线组织、引用法条必须写明全称和条款号”输出格式层规定“用Markdown输出当事人信息用表格诉讼请求用有序列表”。这四层缺一不可少了任何一层输出稳定性都会明显下降。2.2 12大场景的提示词模板怎么拆460页的模板库不可能一次性全部塞进提示词必须按场景拆分。常见的12大场景大致可以归为几类诉讼类起诉状、答辩状、代理词、证据清单、非诉类合同审查意见、律师函、尽职调查报告、合规备忘录、内部类法律意见书、风险提示函、制度审查报告、培训材料。每个场景对应一套独立的提示词模板模板之间共享一些通用组件比如法条引用格式、当事人信息占位符、日期格式规范。拆模板的关键原则是一个场景一个模板文件模板内部用变量占位符标记需要动态填入的内容。比如合同审查意见模板里{{contract_type}}、{{party_a}}、{{party_b}}、{{key_clauses}}、{{risk_points}}这些变量由调用方传入模型只负责根据变量内容生成审查意见正文。这样做的好处是模板本身可以版本化管理修改模板不影响调用逻辑也方便后续做A/B测试对比不同模板版本的输出质量。下面是一个合同审查意见的提示词模板示例用Python字符串表示CONTRACT_REVIEW_PROMPT 你是一名有十五年经验的商事合同律师擅长买卖合同、服务合同、租赁合同的审查。 ## 任务 根据以下合同基本信息生成一份合同审查意见初稿。 ## 合同信息 - 合同类型{{contract_type}} - 甲方{{party_a}} - 乙方{{party_b}} - 合同金额{{amount}} - 关键条款摘要{{key_clauses}} ## 审查要求 1. 逐条审查关键条款指出对甲方不利的条款并说明风险等级高/中/低 2. 对每个风险点给出修改建议修改建议必须具体到条款措辞 3. 引用相关法条时必须写明法律全称和条款号 4. 最后给出总体结论建议签署 / 建议修改后签署 / 不建议签署 ## 输出格式 用Markdown输出风险点用表格呈现表格列包括条款位置、风险描述、风险等级、修改建议。 总体结论单独一段加粗显示。 这段模板的逻辑是先锁定角色和专业范围再给出任务和输入变量然后用审查要求约束输出内容的深度和精度最后用输出格式约束可读性。参数说明方面{{contract_type}}建议限定在模板支持的合同类型范围内超出范围的类型模型可能给出不准确的审查意见{{key_clauses}}建议传入原文摘录而非概括概括会丢失关键措辞细节风险等级的高/中/低定义需要在模板外部统一否则不同调用之间没有可比性。2.3 模板字符串与变量注入的工程实现模板字符串的处理方式直接影响调用效率和可维护性。常见做法有两种一种是用Python的string.Template或str.format()做简单替换另一种是引入Jinja2这类模板引擎做条件渲染和循环。对于法律文书场景我倾向于用Jinja2因为很多模板需要根据条件决定是否包含某些段落。比如律师函模板里如果委托人不是自然人而是公司需要额外包含法定代表人信息段落如果涉及金额超过某个阈值需要包含特别提示段落。这些条件逻辑用Jinja2的{% if %}写起来很自然用str.format()就很难处理。from jinja2 import Template LAWYER_LETTER_TEMPLATE Template( 你是一名执业律师根据以下信息生成一份律师函。 委托人{{ client_name }} {% if client_type company %} 法定代表人{{ legal_representative }} 统一社会信用代码{{ credit_code }} {% endif %} 对方当事人{{ opposing_party }} 事由{{ matter }} 诉求{{ demand }} {% if amount 1000000 %} 特别提示本案涉及金额较大建议在函件中明确保留进一步采取法律措施的权利。 {% endif %} 要求 1. 函件格式符合律师函规范 2. 语气正式、克制避免情绪化表述 3. 诉求部分分项列明每项独立成段 4. 结尾注明律师事务所名称和律师签名栏 ) # 调用示例 prompt LAWYER_LETTER_TEMPLATE.render( client_name某某科技有限公司, client_typecompany, legal_representative张三, credit_code91110000XXXXXXXXXX, opposing_party某某贸易有限公司, matter买卖合同货款纠纷, demand1. 支付拖欠货款人民币120万元2. 支付逾期利息3. 承担本案全部诉讼费用, amount1200000 )这段代码的关键点在于条件渲染让模板可以覆盖同一场景下的不同子情况避免为每种情况单独写一个模板。参数说明方面amount用数值类型而非字符串方便做数值比较demand传入的是已经格式化好的诉求文本模型只负责将其融入函件正文不负责生成诉求内容本身——诉求内容必须由人工确认这是法律文书自动化的底线。提示模板中的条件判断逻辑建议保持简单超过三层嵌套的条件逻辑会让模板难以维护也容易让模型困惑。复杂条件应该在调用方处理模板只接收处理好的变量。3. 用DeepSeek API跑通文书生成的最小链路3.1 API调用参数怎么设才稳定DeepSeek API的调用方式和OpenAI兼容核心参数包括model、messages、temperature、max_tokens、top_p。法律文书场景对稳定性的要求高于创意性所以temperature建议设在0.1到0.3之间top_p设在0.8到0.9之间。temperature越低输出越确定但过低会导致措辞僵硬0.2左右是一个比较平衡的值既能保证结构稳定又能让措辞有一定自然度。max_tokens需要根据文书类型设置。律师函一般800到1200字起诉状可能到2000字以上合同审查意见取决于合同条款数量建议设在4000以上留足空间。如果输出被截断模型会在末尾突然中断这时候需要检查max_tokens是否够用或者把长文书拆成多个段落分别生成再拼接。import openai client openai.OpenAI( api_keyyour-deepseek-api-key, base_urlhttps://api.deepseek.com ) def generate_legal_doc(prompt: str, max_tokens: int 4000) - str: response client.chat.completions.create( modeldeepseek-chat, messages[ {role: system, content: 你是一名严谨的法律文书助手输出内容必须准确、格式规范。}, {role: user, content: prompt} ], temperature0.2, top_p0.85, max_tokensmax_tokens ) return response.choices[0].message.content这段代码的逻辑是用system message锁定模型的输出风格用user message传入具体的提示词模板渲染结果。参数说明方面base_url指向DeepSeek的API端点model用deepseek-chat即可如果需要更强的推理能力可以换deepseek-reasoner但推理模型的响应时间更长、成本更高法律文书生成场景一般不需要。temperature0.2和top_p0.85是经过多次测试后比较稳定的组合如果发现输出格式经常跑偏可以进一步降低temperature到0.1。3.2 批量生成时的并发与限流处理100模板如果逐个串行调用效率很低。实际使用中通常需要批量生成比如一次性为多个案件生成律师函或者为多份合同生成审查意见。DeepSeek API有速率限制具体限制取决于账户等级常见做法是用concurrent.futures做并发控制同时加一个简单的重试机制。import time from concurrent.futures import ThreadPoolExecutor, as_completed def generate_with_retry(prompt: str, max_retries: int 3) - str: for attempt in range(max_retries): try: return generate_legal_doc(prompt) except Exception as e: if attempt max_retries - 1: raise wait 2 ** attempt # 指数退避 time.sleep(wait) return def batch_generate(prompts: list, max_workers: int 3) - list: results [None] * len(prompts) with ThreadPoolExecutor(max_workersmax_workers) as executor: future_map { executor.submit(generate_with_retry, p): i for i, p in enumerate(prompts) } for future in as_completed(future_map): idx future_map[future] results[idx] future.result() return results这段代码的关键设计是max_workers3控制并发数避免触发API限流指数退避重试在遇到临时错误时自动等待后重试避免立即重试导致连续失败。参数说明方面max_workers建议从3开始测试如果API响应稳定再逐步提高但一般不建议超过5法律文书生成不是高并发场景稳定性优先于吞吐量。max_retries3意味着最多重试3次如果3次都失败说明可能是提示词本身有问题或者API账户异常需要人工介入排查。3.3 输出后处理从模型输出到可交付文档模型输出的Markdown文本不能直接交付需要做几步后处理检查必填字段是否完整、检查法条引用格式是否规范、检查是否有明显的占位符残留、把Markdown转换成Word或PDF格式。这些步骤可以用脚本自动化但关键检查项建议保留人工确认环节。import re def validate_output(text: str, required_sections: list) - dict: 检查模型输出是否包含必要段落 missing [] for section in required_sections: if section not in text: missing.append(section) # 检查是否有未替换的占位符 placeholders re.findall(r\{\{.*?\}\}, text) # 检查法条引用格式示例匹配《XX法》第X条 law_refs re.findall(r《[^》]》第[一二三四五六七八九十百千\d]条, text) return { missing_sections: missing, unresolved_placeholders: placeholders, law_reference_count: len(law_refs), is_valid: len(missing) 0 and len(placeholders) 0 }这段代码做的是基础校验required_sections传入该文书类型必须包含的段落标题列表比如律师函必须包含“委托人信息”“事由”“诉求”“结尾”四个段落unresolved_placeholders检查是否有变量没被替换这通常意味着调用方传参有遗漏law_reference_count统计法条引用数量数量为0可能意味着模型没有引用法条需要人工复核。参数说明方面required_sections需要根据文书类型动态传入不同场景的必填段落不同校验结果中的is_valid为False时建议把输出退回人工处理不要直接交付。注意法条引用格式检查只能验证格式不能验证引用内容是否正确。模型可能会引用不存在的法条或引用错误条款这一步必须由人工复核。我一般会把法条引用单独提取出来让法务人员逐条核对。4. 100模板的组织、检索与版本管理4.1 模板文件目录结构怎么设计100模板如果全部放在一个目录里查找和维护都会很痛苦。我一般按“场景大类/文书类型/版本”三级目录组织。场景大类分为诉讼、非诉、内部三类文书类型是具体的文书名称比如起诉状、答辩状、律师函版本用日期或语义化版本号标记比如v1.0、v1.1。每个模板文件包含两部分提示词模板正文和元数据适用场景、必填变量、输出格式要求、最后修改日期。templates/ ├── litigation/ │ ├── complaint/ │ │ ├── v1.0.jinja2 │ │ └── meta.yaml │ ├── defense/ │ │ ├── v1.0.jinja2 │ │ └── meta.yaml │ └── evidence_list/ │ ├── v1.0.jinja2 │ └── meta.yaml ├── non_litigation/ │ ├── contract_review/ │ │ ├── v1.0.jinja2 │ │ └── meta.yaml │ └── lawyer_letter/ │ ├── v1.0.jinja2 │ └── meta.yaml └── internal/ ├── legal_opinion/ │ ├── v1.0.jinja2 │ └── meta.yaml └── risk_memo/ ├── v1.0.jinja2 └── meta.yaml这种结构的优势是场景和文书类型一目了然版本管理清晰新增模板不会影响已有模板。meta.yaml里记录模板的元信息比如name: 合同审查意见 scene: non_litigation required_variables: - contract_type - party_a - party_b - key_clauses output_format: markdown last_modified: 2025-01-15 version: v1.0元数据的作用是让调用方知道这个模板需要哪些变量、输出是什么格式避免传参遗漏。同时元数据也可以用来做模板检索——比如根据scene字段筛选出所有非诉类模板。4.2 模板检索与动态加载当模板数量到100时调用方不可能记住每个模板的文件路径。常见做法是写一个模板加载器根据场景和文书类型自动定位模板文件并返回渲染后的提示词。import os import yaml from jinja2 import Template class TemplateLoader: def __init__(self, base_dir: str): self.base_dir base_dir self.index self._build_index() def _build_index(self) - dict: 扫描目录建立 scene/doc_type - 最新版本路径 的索引 index {} for root, dirs, files in os.walk(self.base_dir): for f in files: if f.endswith(.jinja2): rel_path os.path.relpath(os.path.join(root, f), self.base_dir) parts rel_path.split(os.sep) if len(parts) 3: scene, doc_type, version_file parts[0], parts[1], parts[2] version version_file.replace(.jinja2, ) key f{scene}/{doc_type} if key not in index or version index[key][version]: index[key] { path: os.path.join(root, f), version: version } return index def render(self, scene: str, doc_type: str, variables: dict) - str: key f{scene}/{doc_type} if key not in self.index: raise ValueError(f模板不存在: {key}) with open(self.index[key][path], r, encodingutf-8) as f: template Template(f.read()) return template.render(**variables)这段代码的逻辑是初始化时扫描模板目录建立scene/doc_type到最新版本模板路径的索引调用时根据场景和文书类型查找模板渲染后返回提示词。参数说明方面base_dir是模板根目录variables是模板变量字典键名必须和模板中的占位符一致版本比较用的是字符串比较所以版本号命名要保证字典序和实际版本顺序一致比如v1.0、v1.1、v2.0。4.3 模板版本迭代与A/B测试模板不是写完就固定不变的。实际使用中会发现某些模板输出质量不稳定或者某些场景需要调整措辞风格。这时候需要做版本迭代同时保留旧版本以便回滚。A/B测试的做法是同一批输入分别用两个版本的模板生成输出由法务人员盲评打分选择得分更高的版本作为主版本。def ab_test_template(scene: str, doc_type: str, variables_list: list, version_a: str, version_b: str) - dict: 对同一批输入用两个版本模板生成返回对比结果 loader TemplateLoader(templates) results {a: [], b: []} for variables in variables_list: # 临时切换版本实际实现中需要更精细的版本控制 prompt_a loader.render(scene, doc_type, variables) prompt_b loader.render(scene, doc_type, variables) results[a].append(generate_legal_doc(prompt_a)) results[b].append(generate_legal_doc(prompt_b)) return results这段代码是一个简化示例实际做A/B测试时需要更精细的版本控制机制比如在模板路径中显式指定版本号而不是自动选择最新版本。参数说明方面variables_list是测试用例列表建议覆盖典型场景和边界场景version_a和version_b指定要对比的两个版本。测试结果需要人工评分评分维度包括结构完整性、措辞准确性、法条引用规范性、格式合规性。提示模板版本迭代建议保留变更日志记录每次修改的原因和影响范围。法律文书模板的修改可能影响大量输出没有变更日志的话出问题很难追溯。5. 避坑与排查法律文书自动化最容易翻车的五个地方5.1 模型输出格式不稳定Markdown表格时有时无现象同一个模板有时候输出Markdown表格有时候输出纯文本列表有时候表格列数不对。原因提示词中对输出格式的描述不够具体模型在不同温度参数下对格式的理解有波动。另外如果模板中变量内容本身包含Markdown符号也可能干扰模型对格式的判断。解决在提示词中把输出格式要求写死比如“必须用Markdown表格输出表格必须包含以下四列条款位置、风险描述、风险等级、修改建议”。同时把temperature降到0.1减少随机性。如果变量内容包含Markdown符号在传入前做转义处理。5.2 法条引用张冠李戴引用了不存在的条款现象模型输出的法条引用看起来格式正确但条款号或法律名称有误比如把《民法典》第577条写成第578条或者引用了已经废止的法律。原因模型的知识截止日期之后的法律修订它不知道而且模型可能会“编造”看起来合理的法条引用。这是法律文书自动化中最危险的坑。解决在提示词中明确要求“只引用你确定存在的法条如果不确定写‘需人工确认法条引用’”。同时在后处理阶段用法条库做校验把模型引用的法条和权威法条库比对不匹配的标记出来人工复核。我一般会把法条引用单独提取成列表让法务人员逐条核对这一步不能省。5.3 长文书生成到一半被截断现象起诉状或尽职调查报告生成到一半突然中断末尾缺少结论段落或签名栏。原因max_tokens设置不够或者模型在生成长文本时提前终止。DeepSeek API的max_tokens上限取决于模型版本如果文书预计超过3000字需要留足余量。解决把max_tokens设到8000以上如果还是截断把长文书拆成多个段落分别生成。比如起诉状可以拆成“当事人信息”“诉讼请求”“事实与理由”“证据清单”四段每段单独调用API生成最后拼接。拆分生成的好处是每段的质量更可控缺点是段落之间的衔接需要人工检查。5.4 模板变量传参遗漏输出中出现未替换的占位符现象生成的文书中出现{{party_a}}或{{amount}}这样的占位符说明调用方传参时遗漏了某些变量。原因模板变量和调用方传参的键名不一致或者调用方没有检查模板的required_variables元数据。解决在模板加载器中加一道校验渲染前检查required_variables是否都在传入的变量字典中。如果缺失直接抛出异常并列出缺失的变量名而不是让模型生成带占位符的输出。后处理阶段的validate_output函数也会检查未替换的占位符双重保险。5.5 不同场景的提示词互相污染现象生成律师函时出现了合同审查意见的段落结构或者生成合规备忘录时语气偏向诉讼代理词。原因多个场景的提示词模板共享了部分组件但组件之间的边界不清晰导致模型混淆了不同场景的要求。另外如果system message设置得太泛化也可能导致模型在不同场景之间“串味”。解决每个场景的提示词模板保持独立不共享段落结构相关的组件。共享的只应该是法条引用格式、日期格式这类纯格式规范。system message建议按场景定制比如律师函场景的system message强调“正式、克制”合同审查场景的system message强调“中立、客观”。如果发现串味检查模板之间是否有不该共享的内容。6. 把460页模板变成可迭代资产的关键技巧这套方案真正有价值的地方不是一次性生成多少份文书而是把460页静态模板变成可迭代、可度量、可积累的资产。我自己的习惯是每生成一批文书就把人工修改的地方记录下来分析哪些是模型反复出错的地方然后针对性调整提示词。比如发现模型总是在“诉讼请求”部分把金额写错就在提示词里加一条“金额必须与输入变量中的amount字段完全一致不得自行修改”。这种迭代看起来慢但积累下来模板的命中率会越来越高。另一个技巧是建立“场景-模板-输出”的三级评估体系。每个场景下的每个模板定期用一批标准测试用例跑一遍记录输出质量评分。评分维度包括结构完整性是否包含所有必填段落、措辞准确性是否有语法错误或不当表述、法条引用规范性引用格式是否正确、是否有编造、格式合规性是否符合输出格式要求。评分低于阈值的模板触发人工复核和版本迭代。def evaluate_template_output(output: str, expected_sections: list, law_ref_pattern: str) - dict: 评估单次输出的质量 score 0 max_score 4 # 结构完整性 sections_found sum(1 for s in expected_sections if s in output) if sections_found len(expected_sections): score 1 # 措辞准确性简单检查是否有明显语法错误标记 if 。。 not in output and not in output: score 1 # 法条引用规范性 law_refs re.findall(law_ref_pattern, output) if len(law_refs) 0: score 1 # 格式合规性检查是否有Markdown表格 if | in output and --- in output: score 1 return { score: score, max_score: max_score, sections_found: sections_found, law_ref_count: len(law_refs) }这段代码做的是自动化质量评估expected_sections是该文书类型的必填段落列表law_ref_pattern是法条引用的正则表达式。评分结果可以用来做模板版本的横向对比也可以用来监控模板质量的变化趋势。参数说明方面expected_sections需要根据文书类型动态传入law_ref_pattern建议用比较宽松的正则先匹配到候选引用再人工复核准确性。最后一个技巧是关于提示词工程的“后悔药”每次修改模板前先把当前版本备份修改后用同一批测试用例跑对比。如果新版本评分下降立即回滚。法律文书自动化的容错空间很小一个措辞不当可能导致法律风险所以宁可保守迭代不要激进修改。我一般会在模板目录下建一个changelog.md记录每次修改的日期、修改内容、修改原因、测试评分变化。这个习惯帮我避免了好几次“改完发现还不如不改”的翻车。希望帮到你。本文还有配套的精品资源点击获取