从 0 到 1 搭建:基于 Weaviate 和 GPT-4 的法律咨询 Agent 实战

引言

在当今数字化时代,法律服务仍然是一个相对传统且门槛较高的领域。对于普通大众而言,获得专业的法律咨询往往意味着高昂的费用、漫长的等待时间,以及复杂的法律术语理解障碍。而对于法律从业者来说,处理大量重复性的基础咨询也消耗了他们宝贵的时间,使他们无法专注于更复杂的法律问题。

痛点引入

让我们先来看几个常见的场景:

  1. 小张是一位创业者,他想了解关于公司注册的基本流程和需要注意的法律风险。他在网上搜索了大量信息,但这些信息要么过时,要么来源不可靠,要么过于复杂难以理解。他想咨询律师,但初步咨询费用就要数千元,这让他有些犹豫。

  2. 李女士遇到了租房纠纷,房东以各种理由不退押金。她想知道自己的权益是否受到侵害,以及可以通过哪些途径维权。她去了法律援助中心,但需要排队等待很长时间,而且接待的律师时间有限,无法详细解答她的所有问题。

  3. 王律师是一位资深的民商事律师,他每天都会接到很多电话和邮件咨询,其中很多都是关于合同法、劳动法等基础法律问题。虽然这些问题相对简单,但数量众多,占用了他大量的时间,使他无法专注于更复杂的案件。

这些场景反映了当前法律服务领域的几个主要痛点:

  • 获取成本高:专业法律咨询费用昂贵,普通人难以承担。
  • 时间效率低:需要预约、等待,无法即时获得解答。
  • 信息不对称:法律知识复杂,普通人难以准确理解和应用。
  • 资源分配不均:基础咨询占用了大量专业法律资源。

解决方案概述

那么,有没有一种方法可以解决这些问题呢?答案是肯定的——利用人工智能技术,特别是大语言模型(LLM)和向量数据库,我们可以构建一个智能法律咨询 Agent,为用户提供即时、准确、低成本的法律咨询服务。

在本文中,我们将从 0 到 1 搭建一个基于 Weaviate 和 GPT-4 的法律咨询 Agent。这个 Agent 将具备以下能力:

  1. 法律知识问答:回答用户关于各种法律问题的咨询。
  2. 法律条文检索:快速找到相关的法律条文和司法解释。
  3. 案例参考:提供类似的案例供用户参考。
  4. 法律文书草拟:帮助用户草拟简单的法律文书,如合同、遗嘱等。
  5. 风险评估:对用户的情况进行初步的法律风险评估。

我们将使用 Weaviate 作为向量数据库,用于存储和检索法律知识;使用 GPT-4 作为大语言模型,用于理解用户问题、生成回答和进行推理;还将使用 LangChain 作为框架,来协调各个组件,构建完整的 Agent 系统。

最终效果展示

在开始之前,让我们先来看一下最终实现的效果。当用户向我们的法律咨询 Agent 提问时,例如:

“我租了一套房子,租期是一年,现在我只住了半年,因为工作调动需要提前退房。合同上写了提前退房需要支付两个月租金作为违约金,这合法吗?我可以少付或者不付违约金吗?”

我们的 Agent 会先在 Weaviate 中检索相关的法律条文、司法解释和案例,然后结合 GPT-4 的推理能力,给出一个全面、准确且易于理解的回答,例如:

"您好,根据您提供的情况,我为您做以下法律分析:

  1. 关于违约金的合法性:根据《民法典》第五百八十五条的规定,当事人可以约定一方违约时应当根据违约情况向对方支付一定数额的违约金,也可以约定因违约产生的损失赔偿额的计算方法。因此,合同中关于提前退房需要支付违约金的条款是合法的。

  2. 关于违约金的数额:虽然合同约定了两个月租金作为违约金,但根据《民法典》第五百八十五条第二款的规定,约定的违约金过分高于造成的损失的,人民法院或者仲裁机构可以根据当事人的请求予以适当减少。一般来说,违约金超过实际损失的 30% 可以被认为是"过分高于"。

  3. 您可以采取的措施

    • 首先,建议您与房东协商,说明您的情况,争取减少违约金或找到其他解决方案(如帮助房东找到新的租客)。
    • 如果协商不成,您可以要求房东提供其实际损失的证据。如果违约金确实过高,您可以向法院起诉或申请仲裁,请求减少违约金。
    • 此外,根据《民法典》第五百九十条的规定,如果因不可抗力不能履行合同,根据不可抗力的影响,部分或者全部免除责任。但工作调动通常不被认为是不可抗力,因此您可能无法以此为由免责。
  4. 类似案例参考:在[2023]京0105民初12345号案件中,法院认为,虽然合同约定了两个月租金作为违约金,但考虑到原告(租客)提前退房的原因是工作调动,且被告(房东)在原告退房后一个月内就找到了新的租客,实际损失有限,因此将违约金调整为一个月租金。

以上分析仅供参考,具体情况建议您咨询专业律师或向当地法律援助中心寻求帮助。"

这样的回答既专业又易懂,能够为用户提供有价值的参考,同时也为用户指明了下一步的行动方向。

准备工作

在开始搭建我们的法律咨询 Agent 之前,我们需要做好一些准备工作,包括准备开发环境、安装必要的工具和库,以及了解一些基础知识。

环境/工具

以下是我们需要准备的环境和工具:

  1. Python 3.8+:我们将使用 Python 作为主要的编程语言。
  2. Weaviate:向量数据库,用于存储和检索法律知识。
  3. OpenAI API Key:用于调用 GPT-4 模型。
  4. LangChain:用于构建 LLM 应用的框架。
  5. 其他 Python 库:如 requests、pandas、numpy、PyPDF2 等。
安装 Python

如果您还没有安装 Python,请从 Python 官方网站 下载并安装最新版本的 Python。安装完成后,您可以在终端中运行以下命令来验证 Python 是否安装成功:

python --version

python3 --version
安装 Weaviate

Weaviate 是一个开源的向量数据库,我们可以通过 Docker 来安装和运行它。首先,您需要安装 Docker,您可以从 Docker 官方网站 下载并安装。

安装 Docker 后,您可以创建一个 docker-compose.yml 文件,内容如下:

version: '3.4'
services:
  weaviate:
    command:
    - --host
    - 0.0.0.0
    - --port
    - '8080'
    - --scheme
    - http
    image: cr.weaviate.io/semitechnologies/weaviate:1.21.0
    ports:
    - 8080:8080
    - 50051:50051
    volumes:
    - weaviate_data:/var/lib/weaviate
    restart: on-failure:0
    environment:
      QUERY_DEFAULTS_LIMIT: 25
      AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'true'
      PERSISTENCE_DATA_PATH: '/var/lib/weaviate'
      DEFAULT_VECTORIZER_MODULE: 'text2vec-openai'
      ENABLE_MODULES: 'text2vec-openai,generative-openai'
      OPENAI_APIKEY: 'your-openai-api-key'
      CLUSTER_HOSTNAME: 'node1'
volumes:
  weaviate_data:

请将 your-openai-api-key 替换为您自己的 OpenAI API Key。然后,在终端中运行以下命令来启动 Weaviate:

docker-compose up -d

Weaviate 启动后,您可以通过访问 http://localhost:8080 来验证它是否正常运行。

获取 OpenAI API Key

如果您还没有 OpenAI API Key,请访问 OpenAI 官网 注册账户并获取 API Key。

安装 Python 库

我们需要安装一些 Python 库来帮助我们构建法律咨询 Agent。您可以使用以下命令来安装这些库:

pip install weaviate-client langchain openai python-dotenv PyPDF2 pandas numpy requests fastapi uvicorn streamlit

基础知识

在开始搭建之前,让我们先了解一些基础知识,以便更好地理解我们将要构建的系统。

向量数据库

向量数据库是一种专门用于存储和查询高维向量的数据库。在我们的项目中,我们将法律文本(如法律条文、司法解释、案例等)转换为向量(也称为嵌入),然后存储在 Weaviate 中。当用户提问时,我们将用户的问题也转换为向量,然后在向量数据库中查找与问题向量最相似的文本向量,从而找到相关的法律知识。

为什么我们需要向量数据库呢?因为传统的关键词搜索无法很好地理解语义,而向量搜索可以基于语义相似度进行搜索,从而找到更相关的结果。例如,当用户问"我可以要求房东退押金吗?"时,向量搜索可以找到与"押金退还"相关的法律条文,即使这些条文中可能没有出现"要求"这个词。

大语言模型(LLM)

大语言模型是一种基于深度学习的自然语言处理模型,它通过在大量文本数据上进行预训练,学习了丰富的语言知识和模式。在我们的项目中,我们将使用 GPT-4 作为我们的大语言模型,它将帮助我们:

  1. 理解用户问题:分析用户的问题,提取关键信息。
  2. 生成回答:根据检索到的法律知识,生成专业、易懂的回答。
  3. 推理和分析:对用户的情况进行推理和分析,提供法律建议。
RAG(检索增强生成)

RAG(Retrieval-Augmented Generation,检索增强生成)是一种结合了信息检索和文本生成的技术。它的基本思想是:在生成回答之前,先从一个知识库中检索相关的信息,然后将这些信息作为上下文,一起输入给大语言模型,让大语言模型基于这些信息生成回答。

在我们的项目中,我们将使用 RAG 技术来确保我们的法律咨询 Agent 能够提供准确、最新的法律信息,同时减少大语言模型"幻觉"(即生成虚假信息)的问题。

LangChain

LangChain 是一个用于构建大语言模型应用的框架,它提供了一系列工具和组件,帮助我们更容易地构建复杂的 LLM 应用,如聊天机器人、问答系统、Agent 等。在我们的项目中,我们将使用 LangChain 来:

  1. 连接各个组件:将向量数据库、大语言模型、用户界面等组件连接起来。
  2. 构建 Agent:使用 LangChain 的 Agent 框架来构建我们的法律咨询 Agent。
  3. 处理文档:使用 LangChain 的文档加载器和分割器来处理法律文档。

核心步骤

现在,我们已经做好了准备工作,让我们开始从 0 到 1 搭建我们的法律咨询 Agent。我们将这个过程分为以下几个步骤:

步骤 1:理解需求和设计系统架构

在开始编码之前,我们需要先理解我们的需求,并设计系统的架构。

需求分析

我们的法律咨询 Agent 需要满足以下需求:

  1. 用户可以通过自然语言提问:用户可以用日常语言描述他们的法律问题,不需要使用专业的法律术语。
  2. 系统能理解用户的问题:系统能分析用户的问题,提取关键信息,理解用户的意图。
  3. 系统能检索相关的法律知识:系统能从法律知识库中检索出与用户问题相关的法律条文、司法解释、案例等。
  4. 系统能生成专业、易懂的回答:系统能基于检索到的法律知识,生成既专业又易懂的回答,为用户提供有价值的法律建议。
  5. 系统能处理多轮对话:系统能记住之前的对话内容,与用户进行多轮对话,深入了解用户的情况。
  6. 系统能提供参考资料:系统能在回答中引用相关的法律条文、案例等参考资料,并提供来源信息。
系统架构设计

基于以上需求,我们设计了以下系统架构:

用户提问

问题

查询向量

查询

相关文档

上下文

问题分析

对话历史

调用

生成回答

回答

显示回答

向量化

存储

原始数据

用户界面

对话管理

问题理解与分析

向量检索

Weaviate 向量数据库

回答生成

GPT-4

数据预处理

数据存储

法律数据源

我们的系统主要由以下几个部分组成:

  1. 用户界面:用户与系统交互的界面,我们将使用 Streamlit 来构建一个简单的 Web 界面。
  2. 对话管理:管理对话流程,保存对话历史,处理多轮对话。
  3. 问题理解与分析:分析用户的问题,提取关键信息,生成查询向量。
  4. 向量检索:在 Weaviate 中检索与用户问题相关的法律文档。
  5. Weaviate 向量数据库:存储法律知识的向量表示。
  6. 回答生成:结合检索到的法律文档、对话历史和问题分析,调用 GPT-4 生成回答。
  7. 数据预处理:处理原始法律数据,将其分割成小块,向量化。
  8. 数据存储:将向量化后的法律数据存储到 Weaviate 中。

步骤 2:设置 Weaviate 向量数据库

在这一步中,我们将设置 Weaviate 向量数据库,创建一个 schema 来定义我们的数据结构。

首先,我们需要创建一个 Python 脚本,连接到 Weaviate 并定义 schema。让我们创建一个名为 setup_weaviate.py 的文件:

import weaviate
import os
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()

# 连接到 Weaviate
client = weaviate.Client(
    url="http://localhost:8080",
    additional_headers={
        "X-OpenAI-Api-Key": os.getenv("OPENAI_API_KEY")
    }
)

# 检查是否连接成功
if client.is_ready():
    print("Weaviate is ready!")
else:
    print("Weaviate is not ready!")
    exit(1)

# 定义 schema
schema = {
    "classes": [
        {
            "class": "LegalDocument",
            "description": "A legal document, such as a law, regulation, or case",
            "vectorizer": "text2vec-openai",
            "moduleConfig": {
                "text2vec-openai": {
                    "model": "text-embedding-ada-002",
                    "type": "text"
                }
            },
            "properties": [
                {
                    "name": "title",
                    "dataType": ["string"],
                    "description": "The title of the document"
                },
                {
                    "name": "content",
                    "dataType": ["text"],
                    "description": "The content of the document"
                },
                {
                    "name": "type",
                    "dataType": ["string"],
                    "description": "The type of the document, e.g., law, regulation, case"
                },
                {
                    "name": "category",
                    "dataType": ["string"],
                    "description": "The category of the document, e.g., civil law, criminal law, labor law"
                },
                {
                    "name": "source",
                    "dataType": ["string"],
                    "description": "The source of the document, e.g., NPC, Supreme Court"
                },
                {
                    "name": "date",
                    "dataType": ["date"],
                    "description": "The date of the document"
                },
                {
                    "name": "url",
                    "dataType": ["string"],
                    "description": "The URL of the document, if available"
                }
            ]
        }
    ]
}

# 删除已有的 schema(如果存在)
if client.schema.exists("LegalDocument"):
    client.schema.delete_class("LegalDocument")
    print("Deleted existing LegalDocument class")

# 创建新的 schema
client.schema.create(schema)
print("Created new schema")

# 验证 schema 是否创建成功
created_schema = client.schema.get()
print("Created schema:")
print(created_schema)

在这个脚本中,我们首先连接到 Weaviate,然后定义了一个名为 LegalDocument 的类,它有以下属性:

  • title:文档的标题
  • content:文档的内容
  • type:文档的类型(法律、法规、案例等)
  • category:文档的类别(民法、刑法、劳动法等)
  • source:文档的来源(全国人大、最高人民法院等)
  • date:文档的日期
  • url:文档的 URL(如果有)

我们还指定了使用 text2vec-openai 模块和 text-embedding-ada-002 模型来向量化我们的文档。

现在,我们可以运行这个脚本来设置 Weaviate:

python setup_weaviate.py

如果一切顺利,您应该会看到输出表明 Weaviate 已准备就绪,并且 schema 已成功创建。

步骤 3:准备和向量化法律数据

在这一步中,我们将准备法律数据,将其处理成适合向量化和存储的格式,然后将其向量化并存储到 Weaviate 中。

数据来源

我们可以从以下来源获取法律数据:

  1. 法律法规数据库:如中国人大网、中国政府网的法律法规数据库。
  2. 裁判文书网:如中国裁判文书网,获取案例数据。
  3. 法律书籍和教材:公开出版的法律书籍和教材。
  4. 法律机构网站:如最高人民法院、最高人民检察院的网站。

在本文中,为了演示方便,我们将使用一些公开的法律文本作为示例数据。

数据预处理

我们需要对法律数据进行预处理,将其分割成小块,因为大语言模型有上下文长度限制,而且将长文档分割成小块也有助于提高检索的准确性。

让我们创建一个名为 preprocess_data.py 的文件:

import os
import re
from typing import List
from PyPDF2 import PdfReader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()

# 定义文档处理类
class DocumentProcessor:
    def __init__(self, chunk_size=1000, chunk_overlap=200):
        """
        初始化文档处理器
        :param chunk_size: 每个块的大小(字符数)
        :param chunk_overlap: 块之间的重叠大小(字符数)
        """
        self.text_splitter = RecursiveCharacterTextSplitter(
            chunk_size=chunk_size,
            chunk_overlap=chunk_overlap,
            length_function=len,
        )
    
    def read_pdf(self, file_path: str) -> str:
        """
        读取 PDF 文件
        :param file_path: PDF 文件路径
        :return: PDF 文件的文本内容
        """
        reader = PdfReader(file_path)
        text = ""
        for page in reader.pages:
            text += page.extract_text()
        return text
    
    def read_txt(self, file_path: str) -> str:
        """
        读取文本文件
        :param file_path: 文本文件路径
        :return: 文本文件的内容
        """
        with open(file_path, "r", encoding="utf-8") as f:
            return f.read()
    
    def clean_text(self, text: str) -> str:
        """
        清理文本,去除多余的空格、换行等
        :param text: 原始文本
        :return: 清理后的文本
        """
        # 去除多余的空格
        text = re.sub(r'\s+', ' ', text)
        # 去除多余的换行
        text = re.sub(r'\n+', '\n', text)
        return text.strip()
    
    def split_document(self, text: str) -> List[str]:
        """
        将文档分割成小块
        :param text: 文档文本
        :return: 分割后的文本块列表
        """
        chunks = self.text_splitter.split_text(text)
        return chunks
    
    def process_file(self, file_path: str) -> List[str]:
        """
        处理文件,读取、清理、分割
        :param file_path: 文件路径
        :return: 分割后的文本块列表
        """
        # 根据文件扩展名选择读取方法
        if file_path.endswith(".pdf"):
            text = self.read_pdf(file_path)
        elif file_path.endswith(".txt"):
            text = self.read_txt(file_path)
        else:
            raise ValueError(f"Unsupported file type: {file_path}")
        
        # 清理文本
        text = self.clean_text(text)
        
        # 分割文本
        chunks = self.split_document(text)
        
        return chunks

# 示例使用
if __name__ == "__main__":
    # 初始化文档处理器
    processor = DocumentProcessor(chunk_size=1000, chunk_overlap=200)
    
    # 处理一个示例文件
    file_path = "data/sample_law.txt"  # 请确保这个文件存在
    if os.path.exists(file_path):
        chunks = processor.process_file(file_path)
        print(f"Processed {file_path}, got {len(chunks)} chunks")
        for i, chunk in enumerate(chunks[:3]):  # 只打印前3个块
            print(f"\nChunk {i+1}:")
            print(chunk)
    else:
        print(f"File {file_path} does not exist")

在这个脚本中,我们定义了一个 DocumentProcessor 类,它可以:

  1. 读取 PDF 和文本文件
  2. 清理文本,去除多余的空格和换行
  3. 将文本分割成小块

我们使用了 LangChain 的 RecursiveCharacterTextSplitter 来分割文本,它会尝试在段落、句子、单词等边界处分割文本,以确保每个块的语义完整性。

向量化和存储数据

现在,我们已经有了预处理好的数据,让我们将其向量化并存储到 Weaviate 中。创建一个名为 store_data.py 的文件:

import weaviate
import os
import uuid
from datetime import datetime
from dotenv import load_dotenv
from preprocess_data import DocumentProcessor

# 加载环境变量
load_dotenv()

# 连接到 Weaviate
client = weaviate.Client(
    url="http://localhost:8080",
    additional_headers={
        "X-OpenAI-Api-Key": os.getenv("OPENAI_API_KEY")
    }
)

class DataStore:
    def __init__(self, client):
        """
        初始化数据存储类
        :param client: Weaviate 客户端
        """
        self.client = client
    
    def create_document_object(self, chunk, metadata):
        """
        创建一个文档对象
        :param chunk: 文本块
        :param metadata: 元数据
        :return: 文档对象
        """
        return {
            "title": metadata.get("title", ""),
            "content": chunk,
            "type": metadata.get("type", ""),
            "category": metadata.get("category", ""),
            "source": metadata.get("source", ""),
            "date": metadata.get("date", datetime.now().isoformat()[:10]),
            "url": metadata.get("url", "")
        }
    
    def store_document_chunks(self, chunks, metadata):
        """
        存储文档块到 Weaviate
        :param chunks: 文本块列表
        :param metadata: 元数据
        """
        with self.client.batch as batch:
            batch.batch_size = 100
            for chunk in chunks:
                document_object = self.create_document_object(chunk, metadata)
                # 添加 UUID
                document_uuid = str(uuid.uuid4())
                # 添加到批次
                batch.add_data_object(
                    data_object=document_object,
                    class_name="LegalDocument",
                    uuid=document_uuid
                )
        print(f"Stored {len(chunks)} chunks to Weaviate")
    
    def process_and_store_file(self, file_path, metadata):
        """
        处理文件并存储到 Weaviate
        :param file_path: 文件路径
        :param metadata: 元数据
        """
        # 处理文件
        processor = DocumentProcessor()
        chunks = processor.process_file(file_path)
        
        # 存储到 Weaviate
        self.store_document_chunks(chunks, metadata)

# 示例使用
if __name__ == "__main__":
    # 初始化数据存储类
    data_store = DataStore(client)
    
    # 定义示例文件和元数据
    files_to_process = [
        {
            "file_path": "data/sample_law.txt",
            "metadata": {
                "title": "中华人民共和国民法典(节选)",
                "type": "法律",
                "category": "民法",
                "source": "全国人民代表大会",
                "date": "2020-05-28",
                "url": "http://www.npc.gov.cn/"
            }
        },
        # 您可以添加更多文件
    ]
    
    # 处理并存储文件
    for file_info in files_to_process:
        if os.path.exists(file_info["file_path"]):
            print(f"Processing {file_info['file_path']}...")
            data_store.process_and_store_file(file_info["file_path"], file_info["metadata"])
        else:
            print(f"File {file_info['file_path']} does not exist")

在这个脚本中,我们定义了一个 DataStore 类,它可以:

  1. 创建文档对象
  2. 将文档块批量存储到 Weaviate 中
  3. 处理文件并存储到 Weaviate 中

现在,我们可以准备一些示例法律文本文件,放在 data 目录下,然后运行这个脚本,将数据存储到 Weaviate 中:

python store_data.py

为了让我们的演示更完整,让我们创建一个示例法律文本文件 data/sample_law.txt,内容可以是《民法典》的一些节选:

中华人民共和国民法典

(2020年5月28日第十三届全国人民代表大会第三次会议通过)

目录

第一编 总则
第一章 基本规定
第二章 自然人
第一节 民事权利能力和民事行为能力
第二节 监护
第三节 宣告失踪和宣告死亡
第四节 个体工商户和农村承包经营户
第三章 法人
第一节 一般规定
第二节 营利法人
第三节 非营利法人
第四节 特别法人
第四章 非法人组织
第五章 民事权利
第六章 民事法律行为
第一节 一般规定
第二节 意思表示
第三节 民事法律行为的效力
第四节 民事法律行为的附条件和附期限
第七章 代理
第一节 一般规定
第二节 委托代理
第三节 代理终止
第八章 民事责任
第九章 诉讼时效
第十章 期间计算

第二编 物权
第一分编 通则
第一章 一般规定
第二章 物权的设立、变更、转让和消灭
第一节 不动产登记
第二节 动产交付
第三节 其他规定
第三章 物权的保护
第二分编 所有权
第四章 一般规定
第五章 国家所有权和集体所有权、私人所有权
第六章 业主的建筑物区分所有权
第七章 相邻关系
第八章 共有
第九章 所有权取得的特别规定
第三分编 用益物权
第十章 一般规定
第十一章 土地承包经营权
第十二章 建设用地使用权
第十三章 宅基地使用权
第十四章 居住权
第十五章 地役权
第四分编 担保物权
第十六章 一般规定
第十七章 抵押权
第一节 一般抵押权
第二节 最高额抵押权
第十八章 质权
第一节 动产质权
第二节 权利质权
第十九章 留置权
第五分编 占有
第二十章 占有

第三编 合同
第一分编 通则
第一章 一般规定
第二章 合同的订立
第三章 合同的效力
第四章 合同的履行
第五章 合同的保全
第六章 合同的变更和转让
第七章 合同的权利义务终止
第八章 违约责任
第二分编 典型合同
第九章 买卖合同
第十章 供用电、水、气、热力合同
第十一章 赠与合同
第十二章 借款合同
第十三章 保证合同
第一节 一般规定
第二节 保证责任
第十四章 租赁合同
第十五章 融资租赁合同
第十六章 保理合同
第十七章 承揽合同
第十八章 建设工程合同
第十九章 运输合同
第一节 一般规定
第二节 客运合同
第三节 货运合同
第四节 多式联运合同
第二十章 技术合同
第一节 一般规定
第二节 技术开发合同
第三节 技术转让合同和技术许可合同
第四节 技术咨询合同和技术服务合同
第二十一章 保管合同
第二十二章 仓储合同
第二十三章 委托合同
第二十四章 物业服务合同
第二十五章 行纪合同
第二十六章 中介合同
第二十七章 合伙合同
第三分编 准合同
第二十八章 无因管理
第二十九章 不当得利

第四编 人格权
第一章 一般规定
第二章 生命权、身体权和健康权
第三章 姓名权和名称权
第四章 肖像权
第五章 名誉权和荣誉权
第六章 隐私权和个人信息保护

第五编 婚姻家庭
第一章 一般规定
第二章 结婚
第三章 家庭关系
第一节 夫妻关系
第二节 父母子女关系和其他近亲属关系
第四章 离婚
第五章 收养
第一节 收养关系的成立
第二节 收养的效力
第三节 收养关系的解除

第六编 继承
第一章 一般规定
第二章 法定继承
第三章 遗嘱继承和遗赠
第四章 遗产的处理

第七编 侵权责任
第一章 一般规定
第二章 损害赔偿
第三章 责任主体的特殊规定
第四章 产品责任
第五章 机动车交通事故责任
第六章 医疗损害责任
第七章 环境污染和生态破坏责任
第八章 高度危险责任
第九章 饲养动物损害责任
第十章 建筑物和物件损害责任

附则

第一编 总则

第一章 基本规定

第一条 为了保护民事主体的合法权益,调整民事关系,维护社会和经济秩序,适应中国特色社会主义发展要求,弘扬社会主义核心价值观,根据宪法,制定本法。

第二条 民法调整平等主体的自然人、法人和非法人组织之间的人身关系和财产关系。

第三条 民事主体的人身权利、财产权利以及其他合法权益受法律保护,任何组织或者个人不得侵犯。

第四条 民事主体在民事活动中的法律地位一律平等。

第五条 民事主体从事民事活动,应当遵循自愿原则,按照自己的意思设立、变更、终止民事法律关系。

第六条 民事主体从事民事活动,应当遵循公平原则,合理确定各方的权利和义务。

第七条 民事主体从事民事活动,应当遵循诚信原则,秉持诚实,恪守承诺。

第八条 民事主体从事民事活动,不得违反法律,不得违背公序良俗。

第九条 民事主体从事民事活动,应当有利于节约资源、保护生态环境。

第十条 处理民事纠纷,应当依照法律;法律没有规定的,可以适用习惯,但是不得违背公序良俗。

第十一条 其他法律对民事关系有特别规定的,依照其规定。

第十二条 中华人民共和国领域内的民事活动,适用中华人民共和国法律。法律另有规定的,依照其规定。

...

第三编 合同

第一分编 通则

第一章 一般规定

第四百六十三条 本编调整因合同产生的民事关系。

第四百六十四条 合同是民事主体之间设立、变更、终止民事法律关系的协议。

婚姻、收养、监护等有关身份关系的协议,适用有关该身份关系的法律规定;没有规定的,可以根据其性质参照适用本编规定。

第四百六十五条 依法成立的合同,受法律保护。

依法成立的合同,仅对当事人具有法律约束力,但是法律另有规定的除外。

第四百六十六条 当事人对合同条款的理解有争议的,应当依据本法第一百四十二条第一款的规定,确定争议条款的含义。

合同文本采用两种以上文字订立并约定具有同等效力的,对各文本使用的词句推定具有相同含义。各文本使用的词句不一致的,应当根据合同的相关条款、性质、目的以及诚信原则等予以解释。

第四百六十七条 本法或者其他法律没有明文规定的合同,适用本编通则的规定,并可以参照适用本编或者其他法律最相类似合同的规定。

在中华人民共和国境内履行的中外合资经营企业合同、中外合作经营企业合同、中外合作勘探开发自然资源合同,适用中华人民共和国法律。

第四百六十八条 非因合同产生的债权债务关系,适用有关该债权债务关系的法律规定;没有规定的,适用本编通则的有关规定,但是根据其性质不能适用的除外。

...

第十四章 租赁合同

第七百零三条 租赁合同是出租人将租赁物交付承租人使用、收益,承租人支付租金的合同。

第七百零四条 租赁合同的内容一般包括租赁物的名称、数量、用途、租赁期限、租金及其支付期限和方式、租赁物维修等条款。

第七百零五条 租赁期限不得超过二十年。超过二十年的,超过部分无效。

租赁期限届满,当事人可以续订租赁合同;但是,约定的租赁期限自续订之日起不得超过二十年。

第七百零六条 当事人未依照法律、行政法规规定办理租赁合同登记备案手续的,不影响合同的效力。

第七百零七条 租赁期限六个月以上的,应当采用书面形式。当事人未采用书面形式,无法确定租赁期限的,视为不定期租赁。

第七百零八条 出租人应当按照约定将租赁物交付承租人,并在租赁期限内保持租赁物符合约定的用途。

第七百零九条 承租人应当按照约定的方法使用租赁物。对租赁物的使用方法没有约定或者约定不明确,依据本法第五百一十条的规定仍不能确定的,应当根据租赁物的性质使用。

第七百一十条 承租人按照约定的方法或者根据租赁物的性质使用租赁物,致使租赁物受到损耗的,不承担赔偿责任。

第七百一十一条 承租人未按照约定的方法或者未根据租赁物的性质使用租赁物,致使租赁物受到损失的,出租人可以解除合同并请求赔偿损失。

第七百一十二条 出租人应当履行租赁物的维修义务,但是当事人另有约定的除外。

第七百一十三条 承租人在租赁物需要维修时可以请求出租人在合理期限内维修。出租人未履行维修义务的,承租人可以自行维修,维修费用由出租人负担。因维修租赁物影响承租人使用的,应当相应减少租金或者延长租期。

因承租人的过错致使租赁物需要维修的,出租人不承担前款规定的维修义务。

第七百一十四条 承租人应当妥善保管租赁物,因保管不善造成租赁物毁损、灭失的,应当承担赔偿责任。

第七百一十五条 承租人经出租人同意,可以对租赁物进行改善或者增设他物。

承租人未经出租人同意,对租赁物进行改善或者增设他物的,出租人可以请求承租人恢复原状或者赔偿损失。

第七百一十六条 承租人经出租人同意,可以将租赁物转租给第三人。承租人转租的,承租人与出租人之间的租赁合同继续有效;第三人造成租赁物损失的,承租人应当赔偿损失。

承租人未经出租人同意转租的,出租人可以解除合同。

第七百一十七条 承租人经出租人同意将租赁物转租给第三人,转租期限超过承租人剩余租赁期限的,超过部分的约定对出租人不具有法律约束力,但是出租人与承租人另有约定的除外。

第七百一十八条 出租人知道或者应当知道承租人转租,但是在六个月内未提出异议的,视为出租人同意转租。

第七百一十九条 承租人拖欠租金的,次承租人可以代承租人支付其欠付的租金和违约金,但是转租合同对出租人不具有法律约束力的除外。

次承租人代为支付的租金和违约金,可以充抵次承租人应当向承租人支付的租金;超出其应付的租金数额的,可以向承租人追偿。

第七百二十条 在租赁期限内因占有、使用租赁物获得的收益,归承租人所有,但是当事人另有约定的除外。

第七百二十一条 承租人应当按照约定的期限支付租金。对支付租金的期限没有约定或者约定不明确,依据本法第五百一十条的规定仍不能确定,租赁期限不满一年的,应当在租赁期限届满时支付;租赁期限一年以上的,应当在每届满一年时支付,剩余期限不满一年的,应当在租赁期限届满时支付。

第七百二十二条 承租人无正当理由未支付或者迟延支付租金的,出租人可以请求承租人在合理期限内支付;承租人逾期不支付的,出租人可以解除合同。

第七百二十三条 因第三人主张权利,致使承租人不能对租赁物使用、收益的,承租人可以请求减少租金或者不支付租金。

第三人主张权利的,承租人应当及时通知出租人。

第七百二十四条 有下列情形之一,非因承租人原因致使租赁物无法使用的,承租人可以解除合同:

(一)租赁物被司法机关或者行政机关依法查封、扣押;

(二)租赁物权属有争议;

(三)租赁物具有违反法律、行政法规关于使用条件的强制性规定情形。

第七百二十五条 租赁物在承租人按照租赁合同占有期限内发生所有权变动的,不影响租赁合同的效力。

第七百二十六条 出租人出卖租赁房屋的,应当在出卖之前的合理期限内通知承租人,承租人享有以同等条件优先购买的权利;但是,房屋按份共有人行使优先购买权或者出租人将房屋出卖给近亲属的除外。

出租人履行通知义务后,承租人在十五日内未明确表示购买的,视为承租人放弃优先购买权。

第七百二十七条 出租人委托拍卖人拍卖租赁房屋的,应当在拍卖五日前通知承租人。承租人未参加拍卖的,视为放弃优先购买权。

第七百二十八条 出租人未通知承租人或者有其他妨害承租人行使优先购买权情形的,承租人可以请求出租人承担赔偿责任。但是,出租人与第三人订立的房屋买卖合同的效力不受影响。

第七百二十九条 因不可归责于承租人的事由,致使租赁物部分或者全部毁损、灭失的,承租人可以请求减少租金或者不支付租金;因租赁物部分或者全部毁损、灭失,致使不能实现合同目的的,承租人可以解除合同。

第七百三十条 当事人对租赁期限没有约定或者约定不明确,依据本法第五百一十条的规定仍不能确定的,视为不定期租赁;当事人可以随时解除合同,但是应当在合理期限之前通知对方。

第七百三十一条 租赁物危及承租人的安全或者健康的,即使承租人订立合同时明知该租赁物质量不合格,承租人仍然可以随时解除合同。

第七百三十二条 承租人在房屋租赁期限内死亡的,与其生前共同居住的人或者共同经营人可以按照原租赁合同租赁该房屋。

第七百三十三条 租赁期限届满,承租人应当返还租赁物。返还的租赁物应当符合按照约定或者根据租赁物的性质使用后的状态。

第七百三十四条 租赁期限届满,承租人继续使用租赁物,出租人没有提出异议的,原租赁合同继续有效,但是租赁期限为不定期。

租赁期限届满,房屋承租人享有以同等条件优先承租的权利。

...

第八章 违约责任

第五百七十七条 当事人一方不履行合同义务或者履行合同义务不符合约定的,应当承担继续履行、采取补救措施或者赔偿损失等违约责任。

第五百七十八条 当事人一方明确表示或者以自己的行为表明不履行合同义务的,对方可以在履行期限届满前请求其承担违约责任。

第五百七十九条 当事人一方未支付价款、报酬、租金、利息,或者不履行其他金钱债务的,对方可以请求其支付。

第五百八十条 当事人一方不履行非金钱债务或者履行非金钱债务不符合约定的,对方可以请求履行,但是有下列情形之一的除外:

(一)法律上或者事实上不能履行;

(二)债务的标的不适于强制履行或者履行费用过高;

(三)债权人在合理期限内未请求履行。

有前款规定的除外情形之一,致使不能实现合同目的的,人民法院或者仲裁机构可以根据当事人的请求终止合同权利义务关系,但是不影响违约责任的承担。

第五百八十一条 当事人一方不履行债务或者履行债务不符合约定,根据债务的性质不得强制履行的,对方可以请求其负担由第三人替代履行的费用。

第五百八十二条 履行不符合约定的,应当按照当事人的约定承担违约责任。对违约责任没有约定或者约定不明确,依据本法第五百一十条的规定仍不能确定的,受损害方根据标的的性质以及损失的大小,可以合理选择请求对方承担修理、重作、更换、退货、减少价款或者报酬等违约责任。

第五百八十三条 当事人一方不履行合同义务或者履行合同义务不符合约定的,在履行义务或者采取补救措施后,对方还有其他损失的,应当赔偿损失。

第五百八十四条 当事人一方不履行合同义务或者履行合同义务不符合约定,造成对方损失的,损失赔偿额应当相当于因违约所造成的损失,包括合同履行后可以获得的利益;但是,不得超过违约一方订立合同时预见到或者应当预见到的因违约可能造成的损失。

第五百八十五条 当事人可以约定一方违约时应当根据违约情况向对方支付一定数额的违约金,也可以约定因违约产生的损失赔偿额的计算方法。

约定的违约金低于造成的损失的,人民法院或者仲裁机构可以根据当事人的请求予以增加;约定的违约金过分高于造成的损失的,人民法院或者仲裁机构可以根据当事人的请求予以适当减少。

当事人就迟延履行约定违约金的,违约方支付违约金后,还应当履行债务。

...

步骤 4:集成 GPT-4 API

在这一步中,我们将集成 GPT-4 API,构建一个简单的问答接口。创建一个名为 gpt_integration.py 的文件:

import os
import openai
from dotenv import load_dotenv
from typing import List, Dict

# 加载环境变量
load_dotenv()

# 设置 OpenAI API 密钥
openai.api_key = os.getenv("OPENAI_API_KEY")

class GPTIntegration:
    def __init__(self, model="gpt-4", temperature=0.7, max_tokens=2000):
        """
        初始化 GPT 集成类
        :param model: 使用的模型
        :param temperature: 温度参数,控制输出的随机性
        :param max_tokens: 最大生成 token 数
        """
        self.model = model
        self.temperature = temperature
        self.max_tokens = max_tokens
    
    def generate_response(self, system_prompt: str, user_prompt: str, conversation_history: List[Dict] = None) -> str:
        """
        生成 GPT 响应
        :param system_prompt: 系统提示词
        :param user_prompt: 用户提示词
        :param conversation_history: 对话历史
        :return: GPT 生成的响应
        """
        # 构建消息列表
        messages = [{"role": "system", "content": system_prompt}]
        
        # 添加对话历史
        if conversation_history:
            messages.extend(conversation_history)
        
        # 添加当前用户输入
        messages.append({"role": "user", "content": user_prompt})
        
        try:
            # 调用 OpenAI API
            response = openai.ChatCompletion.create(
                model=self.model,
                messages=messages,
                temperature=self.temperature,
                max_tokens=self.max_tokens
            )
            
            # 提取生成的响应
            assistant_response = response.choices[0].
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐