通义千问2.5-7B法律场景案例:合同审查系统搭建教程

你是不是也遇到过这样的烦恼?收到一份几十页的合同,密密麻麻的法律条文看得人头晕眼花,想找出里面的风险点,又怕自己不够专业漏掉关键信息。或者作为法务,每天要处理大量格式合同,重复性的审阅工作占据了大部分时间,效率低下还容易疲劳出错。

今天,我就带你用通义千问2.5-7B-Instruct模型,从零开始搭建一个智能合同审查系统。这个系统能帮你自动识别合同中的关键条款、潜在风险,甚至给出修改建议,把法务从繁琐的重复劳动中解放出来,把精力集中在更复杂的策略性工作上。

我们用的模型是阿里在2024年9月发布的通义千问2.5-7B-Instruct。它只有70亿参数,但能力可不小,在多项基准测试里都是7B级别里的第一梯队。最关键的是,它支持128K的超长上下文,意味着它能一口气“吃下”整本长篇合同进行分析,而且开源协议允许商用,我们可以放心地把它用在业务场景里。

接下来,我会手把手带你完成环境搭建、系统设计、代码实现和效果测试。即使你之前没怎么接触过大模型,跟着步骤走也能搞定。

1. 环境准备与快速部署

首先,我们需要一个能运行模型的环境。通义千问2.5-7B-Instruct对硬件要求比较友好,量化后模型大小只有4GB左右,一张消费级的RTX 3060显卡就能流畅运行。

1.1 基础环境安装

我推荐使用 conda 来管理Python环境,这样可以避免包版本冲突。如果你还没有安装conda,可以去官网下载Miniconda。

打开你的终端(Linux/Mac)或命令提示符/PowerShell(Windows),依次执行以下命令:

# 1. 创建一个新的Python环境,命名为qwen-law
conda create -n qwen-law python=3.10 -y

# 2. 激活这个环境
conda activate qwen-law

# 3. 安装PyTorch(根据你的CUDA版本选择,以CUDA 11.8为例)
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

# 4. 安装模型运行和Web框架的核心库
pip install transformers accelerate sentencepiece einops scipy gradio

transformers 是Hugging Face的模型库,accelerate 用于优化推理速度,gradio 则能让我们快速搭建一个可视化的Web界面。

1.2 获取与加载模型

模型文件比较大,我们可以直接从Hugging Face模型库拉取。通义千问的官方模型仓库是 Qwen/Qwen2.5-7B-Instruct

创建一个新的Python脚本,比如叫 load_model.py,写入以下代码来测试模型是否能正常加载:

from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

# 指定模型名称
model_name = "Qwen/Qwen2.5-7B-Instruct"

print(f"正在加载分词器...")
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)

print(f"正在加载模型...这可能要几分钟,取决于你的网速和磁盘。")
# 使用 bfloat16 精度节省显存,并自动将模型分配到GPU
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype=torch.bfloat16,
    device_map="auto",
    trust_remote_code=True
)

print("模型加载成功!")

第一次运行时会下载模型文件(约14GB FP16格式),请确保网络通畅和磁盘空间充足。下载完成后,后续加载就很快了。

如果你显存比较紧张(比如只有8GB),可以使用量化版本,能显著降低资源占用。将上面的加载代码稍作修改:

from transformers import BitsAndBytesConfig

# 配置4位量化
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_use_double_quant=True,
    bnb_4bit_quant_type="nf4"
)

model = AutoModelForCausalLM.from_pretrained(
    model_name,
    quantization_config=bnb_config, # 加入量化配置
    device_map="auto",
    trust_remote_code=True
)

2. 合同审查系统核心功能设计

在写代码之前,我们先想清楚这个系统要干什么。一个实用的合同审查系统,至少应该具备以下几个核心功能:

  1. 关键信息提取:自动找出合同中的甲方乙方、金额、日期、违约责任等关键条款。
  2. 风险点识别:提示合同中可能存在的法律风险,比如权利义务不对等、付款条件苛刻、争议解决条款不利等。
  3. 条款合规性检查:根据预设的合规模板或规则,检查条款是否符合公司内部规定或通用法律规范。
  4. 修改建议生成:针对有风险的条款,给出具体的修改建议或替代文案。
  5. 摘要与总结:对长篇幅合同生成简洁明了的摘要,便于快速把握核心内容。

通义千问2.5-7B-Instruct支持函数调用(Function Calling)JSON格式强制输出,这对我们构建结构化输出的系统非常有利。我们可以设计一个“审查要点清单”,让模型严格按照这个清单的格式输出结果。

3. 分步实现智能审查逻辑

让我们把上面的功能拆解,一步步用代码实现。

3.1 构建系统提示词(Prompt)

模型的表现很大程度上取决于我们如何“提问”。我们需要设计一个清晰、具体的指令,告诉模型它现在是一个“资深法律专家”,并且要按照固定的格式输出。

创建一个新的文件 contract_reviewer.py,我们先来定义这个核心的提示词模板:

SYSTEM_PROMPT_TEMPLATE = """你是一名经验丰富的资深法律专家,专注于合同审查与风险防控。请对用户提供的合同文本进行专业、严谨的审查。

请严格按照以下JSON格式输出审查结果,不要输出任何其他解释性文字:
{
  “basic_info”: {
    “parties”: “提取出的合同双方名称”,
    “contract_value”: “合同金额/价款”,
    “sign_date”: “签署日期”,
    “effective_date”: “生效日期”,
    “term”: “合同期限”
  },
  “risk_analysis”: [
    {
      “clause_location”: “风险条款在合同中的大致位置(如‘付款条款第3款’)”,
      “risk_description”: “对该风险的具体描述”,
      “risk_level”: “风险等级(高/中/低)”,
      “suggestion”: “具体的修改建议或谈判策略”
    }
    // ... 可以有多条风险分析
  ],
  “compliance_check”: [
    {
      “item”: “检查项(如‘争议解决方式’)”,
      “status”: “状态(符合/不符合/待明确)”,
      “detail”: “具体情况说明”
    }
    // ... 可以有多条合规检查
  ],
  “executive_summary”: “用一段话简要总结本合同的核心内容、主要风险及行动建议”
}

合同文本如下:
"""

这个提示词做了几件事:设定了模型角色,明确了输出格式(JSON),并定义了详细的结构(基础信息、风险分析、合规检查、摘要)。模型会努力按照这个格式来组织它的“思考结果”。

3.2 实现合同审查函数

接下来,我们写一个函数,它接收合同文本,调用模型,并返回解析好的审查结果。

import json
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

class ContractReviewer:
    def __init__(self, model_name="Qwen/Qwen2.5-7B-Instruct"):
        print("初始化合同审查器...")
        self.tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
        # 使用量化配置以节省资源
        bnb_config = BitsAndBytesConfig(
            load_in_4bit=True,
            bnb_4bit_compute_dtype=torch.bfloat16,
            bnb_4bit_use_double_quant=True,
            bnb_4bit_quant_type="nf4"
        )
        self.model = AutoModelForCausalLM.from_pretrained(
            model_name,
            quantization_config=bnb_config,
            device_map="auto",
            trust_remote_code=True
        )
        self.system_prompt = SYSTEM_PROMPT_TEMPLATE

    def review_contract(self, contract_text):
        """审查合同的主函数"""
        # 1. 构建完整的用户输入
        full_prompt = self.system_prompt + contract_text

        # 2. 将文本转换为模型可接受的输入格式
        messages = [
            {"role": "user", "content": full_prompt}
        ]
        text = self.tokenizer.apply_chat_template(
            messages,
            tokenize=False,
            add_generation_prompt=True
        )
        model_inputs = self.tokenizer([text], return_tensors="pt").to(self.model.device)

        # 3. 生成结果
        print("模型正在分析合同...")
        generated_ids = self.model.generate(
            **model_inputs,
            max_new_tokens=2048,  # 根据合同长度调整
            do_sample=True,
            temperature=0.2,      # 较低的温度使输出更确定、更专业
            top_p=0.9
        )
        generated_ids = [
            output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
        ]
        response = self.tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]

        # 4. 尝试从输出中提取JSON
        try:
            # 查找JSON结构的开始和结束
            start_idx = response.find('{')
            end_idx = response.rfind('}') + 1
            if start_idx != -1 and end_idx != 0:
                json_str = response[start_idx:end_idx]
                result = json.loads(json_str)
                return result
            else:
                return {"error": "未在模型输出中找到有效的JSON结构", "raw_output": response}
        except json.JSONDecodeError as e:
            return {"error": f"解析JSON失败: {e}", "raw_output": response}

# 实例化审查器
reviewer = ContractReviewer()

3.3 创建可视化Web界面

光有后台逻辑还不够,我们需要一个界面来交互。Gradio库能让我们用很少的代码就做出一个Web应用。

在同一个文件中,继续添加以下代码:

import gradio as gr

def review_contract_interface(contract_text):
    """供Gradio界面调用的函数"""
    if not contract_text.strip():
        return "请输入合同文本。"
    result = reviewer.review_contract(contract_text)

    if "error" in result:
        return f"处理出错:{result['error']}\n原始输出:{result.get('raw_output', '')}"

    # 格式化输出结果,使其更易读
    output_lines = []
    output_lines.append("## 📄 合同审查报告")
    output_lines.append("---")

    # 1. 基础信息
    output_lines.append("### 1. 基础信息提取")
    basic = result.get("basic_info", {})
    for key, value in basic.items():
        output_lines.append(f"- **{key}**: {value if value else '未明确提及'}")

    # 2. 风险分析
    output_lines.append("\n### 2. 风险点分析")
    risks = result.get("risk_analysis", [])
    if risks:
        for i, risk in enumerate(risks, 1):
            output_lines.append(f"**风险点 {i}**")
            output_lines.append(f"   - 位置:{risk.get('clause_location', 'N/A')}")
            output_lines.append(f"   - 描述:{risk.get('risk_description', 'N/A')}")
            output_lines.append(f"   - 等级:{risk.get('risk_level', 'N/A')}")
            output_lines.append(f"   - 建议:{risk.get('suggestion', 'N/A')}")
            output_lines.append("")
    else:
        output_lines.append("- 未识别到显著高风险条款。")

    # 3. 合规检查
    output_lines.append("### 3. 合规性检查")
    checks = result.get("compliance_check", [])
    if checks:
        for check in checks:
            status_icon = "✅" if check.get('status') == '符合' else "⚠️" if check.get('status') == '待明确' else "❌"
            output_lines.append(f"{status_icon} **{check.get('item', 'N/A')}**: {check.get('detail', 'N/A')}")
    else:
        output_lines.append("- 未执行特定合规检查。")

    # 4. 执行摘要
    output_lines.append("\n### 4. 综合摘要与建议")
    output_lines.append(result.get("executive_summary", "未生成摘要。"))

    return "\n".join(output_lines)

# 创建Gradio界面
demo = gr.Interface(
    fn=review_contract_interface,
    inputs=gr.Textbox(label="请输入合同全文", lines=20, placeholder="将您的合同文本粘贴在此处..."),
    outputs=gr.Markdown(label="审查结果"),
    title="智能合同审查系统 (基于通义千问2.5-7B)",
    description="上传或粘贴合同文本,系统将自动提取关键信息、识别风险并给出建议。",
    allow_flagging="never"
)

# 启动应用
if __name__ == "__main__":
    # 先加载模型
    reviewer = ContractReviewer()
    print("模型加载完毕,启动Web服务...")
    demo.launch(share=False, server_name="0.0.0.0", server_port=7860) # 在本地7860端口启动

现在,运行 python contract_reviewer.py,等待模型加载完成后,打开浏览器访问 http://localhost:7860,你就能看到一个简洁的合同审查界面了。

4. 实战测试:看看效果如何

光说不练假把式,我们用一个简单的《软件授权协议》片段来测试一下。把下面的文本粘贴到我们刚做好的Web界面里:

本软件授权协议(以下简称“本协议”)由以下双方于2024年10月27日签订:
授权方(甲方):北京创新科技有限公司
被授权方(乙方):上海智用信息技术有限公司

鉴于甲方是【办公协同软件V2.0】的合法著作权人,乙方希望获得该软件的使用许可,双方经友好协商,达成如下协议:

第一条 授权内容
甲方授予乙方在本协议有效期内,于乙方公司内部(仅限总部及两家分公司)非排他性、不可转让的使用权。

第二条 费用与支付
2.1 本协议授权费用总额为人民币伍万元整(¥50,000)。
2.2 乙方应于本协议生效后五个工作日内,一次性向甲方支付全部费用。甲方收到全款后提供软件激活码。
2.3 若乙方延迟付款,每延迟一日,应按未付金额的千分之五向甲方支付滞纳金。

第三条 甲方责任与保证
3.1 甲方保证其有权进行本协议所述之授权。
3.2 甲方应在收到款项后24小时内提供软件及必要的技术支持。

第四条 乙方责任
4.1 乙方不得对软件进行反向工程、反编译或试图获取源代码。
4.2 因乙方使用软件导致的任何第三方索赔,由乙方独立承担全部责任。

第五条 协议期限与终止
5.1 本协议有效期自签订之日起至2025年10月26日止。
5.2 任何一方严重违约,守约方有权单方终止本协议。

第六条 争议解决
因本协议引起的或与本协议有关的任何争议,双方应友好协商解决;协商不成的,任何一方均有权向甲方所在地人民法院提起诉讼。

第七条 其他
7.1 本协议一式两份,双方各执一份,具有同等法律效力。

点击提交,稍等片刻(模型推理需要一点时间),你可能会看到类似下面的审查报告(具体输出因模型生成随机性略有不同):

合同审查报告

1. 基础信息提取

  • parties: 授权方(甲方):北京创新科技有限公司;被授权方(乙方):上海智用信息技术有限公司
  • contract_value: 人民币伍万元整(¥50,000)
  • sign_date: 2024年10月27日
  • effective_date: 签订之日(2024年10月27日)
  • term: 自签订之日起至2025年10月26日止(一年)

2. 风险点分析 风险点 1

  • 位置:费用与支付条款第2.3款
  • 描述:滞纳金标准为每日千分之五,折合年化利率高达182.5%,远超法律支持的范围(通常参照LPR的4倍),可能被认定为过高而无法获得法院全额支持。
  • 等级:高
  • 建议:建议将滞纳金标准修改为“按全国银行间同业拆借中心公布的贷款市场报价利率(LPR)的4倍计算”,或直接约定一个合理的固定比例(如每日万分之五)。

风险点 2

  • 位置:争议解决条款第6条
  • 描述:约定由“甲方所在地人民法院”管辖,对乙方(被授权方)而言,一旦发生纠纷,将需要赴异地诉讼,显著增加维权成本和时间,处于不利地位。
  • 等级:中
  • 建议:争取修改为“乙方所在地人民法院”或“合同履行地(即乙方主要使用地)人民法院”,或约定通过仲裁解决。

风险点 3

  • 位置:乙方责任第4.2款
  • 描述:条款约定“因乙方使用软件导致的任何第三方索赔,由乙方独立承担全部责任”。此条款过于绝对,若因软件本身存在权利瑕疵(如甲方未获充分授权)或固有缺陷导致第三方索赔,此条款可能因免除甲方主要责任、加重乙方责任而被认定为格式条款无效。
  • 等级:中
  • 建议:建议修改为“因乙方违反本协议约定使用软件导致的第三方索赔,由乙方承担责任。因软件本身的权利瑕疵或固有缺陷导致的第三方索赔,由甲方承担责任。”

3. 合规性检查授权范围: 符合。明确了软件名称、使用范围(公司内部)、性质(非排他、不可转让)。 ⚠️ 付款条件: 待明确。“生效后五个工作日内”付款,但协议未明确“生效”是否以盖章为准,建议明确生效条件。 ❌ 责任豁免: 不符合。第4.2款可能构成不合理的责任豁免,需修改。

4. 综合摘要与建议 本合同为一份为期一年的软件授权协议,标的明确,费用固定。核心风险集中于对乙方不利的格式条款:滞纳金过高可能无效;争议解决管辖地增加乙方成本;甲方责任豁免过于宽泛。建议乙方重点就上述三点进行谈判修改。基础商业条款(授权范围、费用、期限)清晰,无重大瑕疵。

看,系统自动提取了双方信息、金额和日期,精准地抓住了“滞纳金过高”、“管辖地对乙方不利”、“责任条款显失公平”这几个关键风险点,并给出了非常具体、可操作的修改建议。这已经达到了初级法务助理的水平,能极大提升初审效率。

5. 进阶优化与使用建议

我们的基础系统已经能用了,但如果你想让它更强大、更贴合实际业务,可以考虑下面几个方向:

  • 知识库增强:将《民法典》合同编、公司内部合规手册等文件,通过RAG(检索增强生成)技术接入系统。当模型审查时,可以实时参考这些权威条文和内部规定,让建议更有依据。
  • 批量处理与API化:将上面的核心函数封装成一个REST API(使用FastAPI或Flask),这样就能集成到公司的OA或合同管理系统里,实现批量上传、自动审查。
  • 审查规则自定义:在提示词或前端界面中,允许用户勾选或输入本次审查的重点。例如,专门关注“数据安全条款”、“知识产权归属”或“跨境传输条款”,让审查更有针对性。
  • 历史学习与迭代:将人工审核后确认的模型错误或不足反馈回来,用于构造更高质量的训练数据,在未来对模型进行微调(Fine-tuning),让它越来越懂你公司的业务和审查偏好。

使用时的几点小建议

  1. 分章节审查:对于超长合同(超过数万字),可以尝试按“鉴于条款”、“权利义务”、“费用”、“违约责任”、“争议解决”等章节分段输入审查,再将结果汇总,准确度可能更高。
  2. 结果需人工复核:务必记住,当前AI是“辅助”工具,其输出必须由专业法务人员进行最终复核和判断,不能直接作为法律意见使用。
  3. 提示词微调:如果你发现模型在某个特定类型合同(如股权投资协议、劳动合同)上表现不佳,可以专门为这类合同设计更精细的提示词,例如提供几个标准的“无风险条款”作为范例。

6. 总结

通过这个教程,我们完成了一个从零到一的智能合同审查系统搭建。我们利用了通义千问2.5-7B-Instruct模型强大的自然语言理解、长文本处理和结构化输出能力,将它应用于专业的法律场景。

这个系统的优势很明显:**7B的“小身材”**让它可以在消费级显卡上部署,成本可控;128K的长上下文让它能处理完整的合同文档;出色的指令跟随和JSON输出能力让我们能构建出结构化、易集成的应用。

它解决的不仅仅是“自动找风险点”的问题,更是将法务人员从海量、重复的格式合同初审工作中解放出来,让他们能聚焦于更复杂的交易结构设计、商业谈判和战略风险管理。对于中小企业或业务量大的团队来说,这样一个工具能立竿见影地提升法务工作的效率和标准化程度。

技术的价值在于落地。希望这个案例能给你带来启发,无论是用于合同审查,还是稍加改造用于文书起草、合规问答、案例检索等其他法律科技场景,通义千问2.5-7B都是一个值得尝试的、高性价比的起点。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐