【大模型专栏—实战篇】基于RAG从0到1搭建AI科研知识库

news2024/12/24 3:24:00

在这里插入图片描述

大模型专栏介绍

😊你好,我是小航,一个正在变秃、变强的文艺倾年。

🔔本文为大模型专栏子篇,大模型专栏将持续更新,主要讲解大模型从入门到实战打怪升级。如有兴趣,欢迎您的阅读。

💡适合人群:本科生、研究生、大模型爱好者,期待与你一同探索、学习、进步,一起卷起来叭!

🔗篇章一:本篇主要讲解Python基础、数据分析三件套、机器学习、深度学习、CUDA等基础知识、学习使用AutoDL炼丹
🔗篇章二:本篇主要讲解基本的科研知识、认识数据和显卡、语言模型如RNN、LSTM、Attention、Transformer、Bert、T5、GPT、BLOOM、LLama、Baichuan、ChatGLM等系列、强化学习教程、大模型基础知识及微调等
🔗篇章三:本篇主要讲解智能对话、大模型基础实战如Ollama、Agent、QLoar、Deepspeed、RAG、Mobile Agent等、大模型领域前沿论文总结及创新点汇总


目录

      • 介绍
      • 分类
      • 实战 - 搭建 RAG Demo
        • 预备
        • 索引
        • 检索
        • 生成
        • 打包
        • 部署
      • 实战 - AI科研助手
        • 项目结构
        • 运行效果


介绍

  • 背景:大型语言模型(LLM)存在一些固有的局限性,如“模型幻觉问题”、“时效性问题”和“数据安全问题”。
  • 介绍:RAG 是检索增强生成(Retrieval Augmented Generation )的简称,它为大语言模型 (LLMs) 提供了从数据源检索信息的能力,并以此为基础生成回答。
    在这里插入图片描述
    • 步骤1:问题理解,准确把握用户的意图。
    • 步骤2:知识检索,从知识库中相关的知识检索。【难点,用户提问可能以多种方式表达,而知识库的信息来源可能是多样的,包括PDF、PPT、Neo4j等格式。
    • 步骤3:答案生成,将检索结果与问题。
  • 优点:
    • 提高准确性和相关性。
    • 改善时效性,使模型适应当前事件和知识。
    • 降低生成错误风险,依赖检索系统提供的准确信息。

以下是RAG输出到大型语言模型的典型模板:

你是一个{task}方面的专家,请结合给定的资料,并回答最终的问题。请如实回答,如果问题在资料中找不到答案,请回答不知道。

问题:{question}

资料:
- {information1}
- {information2}
- {information3}

其中,{task}代表任务的领域或主题,{question}是最终要回答的问题,而{information1}、{information2}等则是提供给模型的外部知识库中的具体信息。

分类

参考论文:Retrieval-Augmented Generation for Large Language Models: A Survey

RAG可以根据技术复杂度,分为三种:

  • Naive RAG:Naive RAG是RAG技术的最基本形式,也被称为经典RAG。包括索引、检索、生成三个基本步骤。索引阶段将文档库分割成短的Chunk,并构建向量索引。检索阶段根据问题和Chunks的相似度检索相关文档片段。生成阶段以检索到的上下文为条件,生成问题的回答。
  • Advanced RAG:Advanced RAG在Naive RAG的基础上进行优化和增强。包含额外处理步骤,分别在数据索引、检索前和检索后进行。包括更精细的数据清洗、设计文档结构和添加元数据,以提升文本一致性、准确性和检索效率。在检索前使用问题的重写、路由和扩充等方式对齐问题和文档块之间的语义差异在检索后通过重排序避免“Lost in the Middle”现象,或通过上下文筛选与压缩缩短窗口长度在这里插入图片描述
  • Modular RAG:Modular RAG引入更多具体功能模块,例如查询搜索引擎、融合多个回答等。技术上融合了检索与微调、强化学习等。流程上对RAG模块进行设计和编排,出现多种不同RAG模式。提供更大灵活性,系统可以根据应用需求选择合适的功能模块组合。模块化RAG的引入使得系统更自由、灵活,适应不同场景和需求。

RAG和SFT对比:

特性RAG技术SFT模型微调
知识更新实时更新检索库,适合动态数据,无需频繁重训存储静态信息,更新知识需要重新训练
外部知识高效利用外部资源,适合各类数据库可对齐外部知识,但对动态数据源不够灵活
数据处理数据处理需求低需构建高质量数据集,数据限制可能影响性能
模型定制化专注于信息检索和整合,定制化程度低可定制行为,风格及领域知识
可解释性答案可追溯,解释性高解释性相对低
计算资源需要支持检索的计算资源,维护外部数据源需要训练数据集和微调资源
延迟要求数据检索可能增加延迟微调后的模型反应更快
减少幻觉基于实际数据,幻觉减少通过特定域训练可减少幻觉,但仍然有限
道德和隐私处理外部文本数据时需要考虑隐私和道德问题训练数据的敏感内容可能引发隐私问题

实战 - 搭建 RAG Demo

预备

1.开通免费试用阿里云PAI—DSW

链接:https://free.aliyun.com/?searchKey=PAI

开通PAI-DSW 试用 ,可获得 5000算力时!有效期3个月!

在这里插入图片描述
2.在魔搭社区进行授权

链接:https://www.modelscope.cn/my/mynotebook/authorization

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
创建实例:在这里插入图片描述
这里一定要选择支持资源包抵扣的服务器
在这里插入图片描述
创建实例后打开,能看到这个界面就成功啦!

在这里插入图片描述

索引

新建bge-small-zh-v1.5-download.py,用于向量模型下载

# 向量模型下载
from modelscope import snapshot_download
model_dir = snapshot_download("AI-ModelScope/bge-small-zh-v1.5", cache_dir='.')
/usr/local/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm
Downloading: 100%|██████████| 190/190 [00:00<00:00, 328B/s]
Downloading: 100%|██████████| 776/776 [00:00<00:00, 1.48kB/s]
Downloading: 100%|██████████| 124/124 [00:00<00:00, 266B/s]
Downloading: 100%|██████████| 47.0/47.0 [00:00<00:00, 92.2B/s]
Downloading: 100%|██████████| 91.4M/91.4M [00:00<00:00, 120MB/s] 
Downloading: 100%|██████████| 349/349 [00:00<00:00, 715B/s]
Downloading: 100%|██████████| 91.4M/91.4M [00:00<00:00, 123MB/s] 
Downloading: 100%|██████████| 27.5k/27.5k [00:00<00:00, 54.9kB/s]
Downloading: 100%|██████████| 52.0/52.0 [00:00<00:00, 65.0B/s]
Downloading: 100%|██████████| 125/125 [00:00<00:00, 253B/s]
Downloading: 100%|██████████| 429k/429k [00:00<00:00, 703kB/s]
Downloading: 100%|██████████| 367/367 [00:00<00:00, 759B/s]
Downloading: 100%|██████████| 107k/107k [00:00<00:00, 220kB/s]

封装向量模型类 EmbeddingModel:

from typing import List
from transformers import AutoTokenizer, AutoModel
import torch

# 定义向量模型类
class EmbeddingModel:
    """
    用于加载预训练的模型并计算文本的嵌入向量的类。
    """

    def __init__(self, path: str) -> None:
        """
        初始化方法,加载预训练的分词器和模型。

        :param path: 预训练模型的路径。
        """
        # 加载预训练的分词器
        self.tokenizer = AutoTokenizer.from_pretrained(path)

        # 加载预训练的模型,并将其移动到GPU上
        self.model = AutoModel.from_pretrained(path).cuda()
        print(f'Loading EmbeddingModel from {path}.')

	# 为了充分发挥GPU矩阵计算的优势,输入和输出都是一个 List,即多条文本和他们的向量表示。
    def get_embeddings(self, texts: List[str]) -> List[List[float]]:
        """
        计算文本列表的嵌入向量。

        :param texts: 要计算嵌入向量的文本列表。
        :return: 嵌入向量的列表。
        """
        # 使用分词器对文本进行编码
        encoded_input = self.tokenizer(texts, padding=True, truncation=True, return_tensors='pt')
        
        # 将编码后的输入数据移动到GPU上
        encoded_input = {k: v.cuda() for k, v in encoded_input.items()}

        # 不计算梯度,以提高计算效率
        with torch.no_grad():
            # 将编码后的输入传递给模型,获取模型输出
            model_output = self.model(**encoded_input)
            
            # 获取句子的嵌入向量,这里假设模型输出的第一个元素包含嵌入信息
            sentence_embeddings = model_output[0][:, 0]

        # 归一化嵌入向量
        sentence_embeddings = torch.nn.functional.normalize(sentence_embeddings, p=2, dim=1)
        
        # 将嵌入向量转换为列表格式并返回
        return sentence_embeddings.tolist()

测试:

print("> Create embedding model...")
embed_model_path = './AI-ModelScope/bge-small-zh-v1___5'
embed_model = EmbeddingModel(embed_model_path)

"""
> Create embedding model...
Loading EmbeddingModel from ./AI-ModelScope/bge-small-zh-v1___5.
"""
检索

编写一个知识库文档knowledge.txt

广州大学(Guangzhou University),简称广大(GU),是由广东省广州市人民政府举办的全日制普通高等学校,实行省市共建、以市为主的办学体制,是国家“111计划”建设高校、广东省和广州市高水平大学重点建设高校。广州大学的办学历史可以追溯到1927年创办的私立广州大学;1951年并入华南联合大学;1983年筹备复办,1984年定名为广州大学;2000年7月,经教育部批准,与广州教育学院(1953年创办)、广州师范学院(1958年创办)、华南建设学院西院(1984年创办)、广州高等师范专科学校(1985年创办)合并组建成立新的广州大学。
郑州机械研究所有限公司(以下简称郑机所)的前身机械科学研究院1956年始建于北京,是原机械工业部直属一类综合研究院所,现隶属于国资委中国机械科学研究总院集团有限公司。郑机所伴随着共和国的成长一路走来,应运而生于首都,碧玉年华献中原。多次搬迁,驻地从北京经漯河再到郑州;数易其名,由机械科学研究院到漯河机械研究所再到郑州机械研究所,现为郑州机械研究所有限公司。1956~1958年应运而生:依据全国人大一届二次会议的提议和第一机械工业部的决策,1956年3月6日,第一机械工业部发文《(56)机技研究第66号》,通知“机械科学实验研究院”(后改名为“机械科学研究院”)在北京成立。1959~1968年首次创业:承担国家重大科研项目与开发任务,以及行业发展规划以及标准制定等工作,如“九大设备”的若干关键技术等。1969~1972年搬迁河南:1969年按照“战备疏散”的要求,机械科学研究院主体迁建河南漯河,成立“漯河机械研究所”;1972年因发展需要,改迁河南郑州,成立郑州机械研究所。1973~1998年二次创业:先后隶属于国家机械工业委员会、机械电子工业部、机械工业部;1981年4月罗干由铸造室主任升任副所长,同年经国务院批准具备硕士学位授予权;1985年“葛洲坝二、三江工程及其水电机组项目”荣获国家科技进步特等奖。1999~2016年发展壮大:1999年转企改制,隶属于国资委中国机械科学研究总院;2008年被河南省首批认定为“高新技术企业”;2011年获批组建新型钎焊材料与技术国家重点实验室;2014年被工信部认定为“国家技术创新示范企业”;历经十多年开发出填补国内外空白的大型齿轮齿条试验装备,完成了对三峡升船机齿条42.2万次应力循环次数的疲劳寿命试验测试;营业收入从几千万发展到近6亿;2017年至今协同发展:2017年经公司制改制,更名为郑州机械研究所有限公司,一以贯之地坚持党对国有企业的领导,充分发挥党委把方向、管大局、保落实的领导作用;一以贯之地建立现代企业制度,持续推进改革改制,努力实现以高质量党建引领郑机所高质量发展。 
非洲野犬,属于食肉目犬科非洲野犬属哺乳动物。 又称四趾猎狗或非洲猎犬; 其腿长身短、体形细长;身上有鲜艳的黑棕色、黄色和白色斑块;吻通常黑色,头部中间有一黑带,颈背有一块浅黄色斑;尾基呈浅黄色,中段呈黑色,末端为白色,因此又有“杂色狼”之称。 非洲野犬分布于非洲东部、中部、南部和西南部一带。 栖息于开阔的热带疏林草原或稠密的森林附近,有时也到高山地区活动。其结群生活,没有固定的地盘,一般在一个较大的范围内逗留时间较长。非洲野犬性情凶猛,以各种羚羊、斑马、啮齿类等为食。奔跑速度仅次于猎; 雌犬妊娠期为69-73天,一窝十只仔,哺乳期持续6-12个星期。 其寿命11年。 非洲野犬正处在灭绝边缘,自然界中仅存两三千只。 非洲野犬被列入《世界自然保护联盟濒危物种红色名录》中,为濒危(EN)保护等级。 ",非洲野犬共有42颗牙齿(具体分布为:i=3/3;c=1/1;p=4/4;m=2/3x2),前臼齿比相对比其他犬科动物要大,因此可以磨碎大量的骨头,这一点很像鬣狗。 主要生活在非洲的干燥草原和半荒漠地带,活跃于草原、稀树草原和开阔的干燥灌木丛,甚至包括撒哈拉沙漠南部一些多山的地带。非洲野犬从来不到密林中活动。 

定义一个向量库索引类 VectorStoreIndex

# 定义向量库索引类
class VectorStoreIndex:
    """
    用于创建向量库索引,计算文本之间的相似度并进行查询的类。
    """

    def __init__(self, document_path: str, embed_model: EmbeddingModel) -> None:
        """
        初始化方法,从文件中加载文档并计算它们的嵌入向量。

        :param document_path: 包含文档的文件路径。
        :param embed_model: 用于生成文档嵌入向量的模型实例。
        """
        self.documents = []  # 存储文档文本的列表
        # 从文件中读取文档并添加到文档列表中
        for line in open(document_path, 'r', encoding='utf-8'):
            line = line.strip()
            self.documents.append(line)

        # 存储嵌入模型的引用
        self.embed_model = embed_model

        # 为所有文档计算嵌入向量
        self.vectors = self.embed_model.get_embeddings(self.documents)

        # 打印加载文档的数量和文件路径
        print(f'Loading {len(self.documents)} documents for {document_path}.')

    def get_similarity(self, vector1: List[float], vector2: List[float]) -> float:
        """
        计算两个向量之间的余弦相似度。

        :param vector1: 第一个向量。
        :param vector2: 第二个向量。
        :return: 两个向量之间的余弦相似度。
        """
        # 计算两个向量的点积
        dot_product = np.dot(vector1, vector2)
        # 计算两个向量的模
        magnitude = np.linalg.norm(vector1) * np.linalg.norm(vector2)
        # 如果模为0,返回0以避免除以0的错误
        if not magnitude:
            return 0
        # 返回归一化的点积作为余弦相似度
        return dot_product / magnitude

    def query(self, question: str, k: int = 1) -> List[str]:
        """
        根据问题查询最相似的文档。

        :param question: 查询的问题文本。
        :param k: 返回最相似文档的数量,默认为1。
        :return: 最相似的文档列表。
        """
        # 为问题文本计算嵌入向量
        question_vector = self.embed_model.get_embeddings([question])[0]
        # 计算问题向量与所有文档向量的相似度
        result = np.array([self.get_similarity(question_vector, vector) for vector in self.vectors])
        # 获取最相似的k个文档的索引
        return np.array(self.documents)[result.argsort()[-k:][::-1]].tolist()

测试:

print("> Create index...")​
doecment_path = './knowledge.txt'​
index = VectorStoreIndex(doecment_path, embed_model)

question = '介绍一下广州大学'print('> Question:', question)
context = index.query(question)print('> Context:', context)

如果知识库很大,需要将知识库切分成多个batch,然后分批次送入向量模型。这里,因为我们的知识库比较小,所以就直接传到了get_embeddings() 函数。

返回结果:

在这里插入图片描述
我们传入用户问题 介绍一下广州大学,可以看到,准确地返回了知识库中的第一条知识。

生成

编写Yuan2-2B-Mars-hf-download.py,下载大模型Yuan2-2B-Mars-hf:

# 源大模型下载​
from modelscope import snapshot_download​
model_dir = snapshot_download('IEITYuan/Yuan2-2B-Mars-hf', cache_dir='.')

定义一个大语言模型类 LLM:

# 导入必要的库
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch

# 定义大语言模型类
class LLM:
    """
    用于加载和使用Yuan2.0大型语言模型的类。
    """

    def __init__(self, model_path: str) -> None:
        """
        初始化方法,加载预训练的分词器和模型。

        :param model_path: 预训练模型的路径。
        """
        print("Creat tokenizer...")  # 打印创建分词器的信息
        # 加载预训练的分词器,设置不自动添加结束和开始标记
        self.tokenizer = AutoTokenizer.from_pretrained(model_path, add_eos_token=False, add_bos_token=False, eos_token='<eod>')

        # 向分词器添加特殊标记
        self.tokenizer.add_tokens([
            '<sep>', '<pad>', '<mask>', '<predict>', '<FIM_SUFFIX>', '<FIM_PREFIX>', '<FIM_MIDDLE>',
            '<commit_before>', '<commit_msg>', '<commit_after>', '<jupyter_start>', '<jupyter_text>',
            '<jupyter_code>', '<jupyter_output>', '<empty_output>'
        ], special_tokens=True)

        print("Creat model...")  # 打印创建模型的信息
        # 加载预训练的因果语言模型,并将其设置为半精度浮点数以提高计算效率
        self.model = AutoModelForCausalLM.from_pretrained(model_path, torch_dtype=torch.bfloat16, trust_remote_code=True).cuda()

        # 打印加载模型的信息
        print(f'Loading Yuan2.0 model from {model_path}.')

    def generate(self, question: str, context: List[str]):
        """
        根据问题和上下文生成回答。

        :param question:  用户提问,是一个str。
        :param context: 检索到的上下文信息,是一个List,默认是[],代表没有使用RAG。
        """
        # 如果提供了上下文,构建提示信息
        if context:
            prompt = f'背景:{" ".join(context)}\n问题:{question}\n请基于背景,回答问题。'
        else:
            prompt = question

        # 在提示信息后添加分隔符
        prompt += "<sep>"
        # 使用分词器将提示信息转换为模型输入的格式
        inputs = self.tokenizer(prompt, return_tensors="pt")["input_ids"].cuda()
        # 使用模型生成文本
        outputs = self.model.generate(inputs, do_sample=False, max_length=1024)
        # 解码生成的文本
        output = self.tokenizer.decode(outputs[0])

        # 打印生成的文本,只显示分隔符之后的部分
        print(output.split("<sep>")[-1])

测试:

print("> Create Yuan2.0 LLM...")​
model_path = './IEITYuan/Yuan2-2B-Mars-hf'​
llm = LLM(model_path)

print('> Without RAG:')​
llm.generate(question, [])print('> With RAG:')​
llm.generate(question, context)

在这里插入图片描述

打包

编写requirements.txt

transformers
torch
numpy

编写安装脚本:pip_install.sh

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt

新建main.py

from common import constants
from generation.llm import LLM
from indexing.embedding import EmbeddingModel
from retrieval.vector import VectorStoreIndex


def main():
    print("> Create embedding model...")
    embed_model_path = constants.EMBED_MODEL_PATH
    embed_model = EmbeddingModel(embed_model_path)

    print("> Create index...")
    document_path = constants.DOCUMENT_PATH
    index = VectorStoreIndex(document_path, embed_model)

    question = '介绍一下广州大学'
    print('> Question:', question)
    context = index.query(question)
    print('> Context:', context)

    print("> Create Yuan2.0 LLM...")
    model_path = constants.MODEL_PATH
    llm = LLM(model_path)
    print('> Without RAG:')
    llm.generate(question, [])
    print('> With RAG:')
    llm.generate(question, context)


if __name__ == '__main__':
    main()

在这里插入图片描述

部署

将代码部署到Github:https://github.com/itxaiohanglover/rag_demo

然后进入终端,导入写好的代码:

在这里插入图片描述
在这里插入图片描述

下载模型:

python setup.py

启动代码:

python main.py

在这里插入图片描述

实战 - AI科研助手

在这里插入图片描述

项目主要包含一个Streamlit开发的客户端,以及一个部署好的浪潮源大模型的服务端。​

  • 客户端接收到用户上传的PDF后,发送到服务端。服务端首先完成PDF内容解析,然后拼接摘要Prompt并输入源大模型,得到模型输出结果后,返回给客户端并展示给用户。​
  • 如果用户接下来进行提问,客户端将用户请求发送到服务端,服务端进行Embedding和Faiss检索,然后将检索到的chunks与用户请求拼接成Prompt并输入到源大模型,得到模型输出结果后,返回给客户端进行结构化,然后展示给用户。
项目结构

在这里插入图片描述
主模块:main.py

# 导入必要的库和模块
from langchain_community.document_loaders import PyPDFLoader  # 用于加载PDF文件的加载器
from common import constants  # 导入常量配置
import streamlit as st  # 导入Streamlit库,用于构建Web界面

from llm.yuan2_llm import Yuan2_LLM  # 导入自定义的大型语言模型类
from langchain_huggingface import HuggingFaceEmbeddings  # 导入HuggingFace嵌入模型
# 导入提示模板类
from prompts.chatbot_template import ChatBot
from prompts.summarizer_template import Summarizer

# 定义模型路径
model_path = constants.MODEL_PATH  # 从常量配置中获取模型路径

# 定义向量模型路径
embedding_model_path = constants.EMBED_MODEL_PATH  # 从常量配置中获取向量模型路径


# 定义一个函数,用于获取llm和embeddings
@st.cache_resource  # 使用Streamlit的缓存装饰器来缓存函数的结果
def get_models():
    llm = Yuan2_LLM(model_path)  # 创建Yuan2_LLM实例

    # 定义模型和编码的参数
    model_kwargs = {'device': 'cuda'}
    encode_kwargs = {'normalize_embeddings': True}  # 设置为True以计算余弦相似度
    embeddings = HuggingFaceEmbeddings(
        model_name=embedding_model_path,  # 向量模型的名称或路径
        model_kwargs=model_kwargs,  # 模型参数
        encode_kwargs=encode_kwargs,  # 编码参数
    )
    return llm, embeddings  # 返回创建的LLM和嵌入模型实例


def main():
    # 创建一个标题
    st.title('💬 Yuan2.0 AI科研助手')  # 设置Streamlit应用的标题

    # 获取llm和embeddings
    llm, embeddings = get_models()  # 调用get_models函数获取模型实例

    # 初始化summarizer
    summarizer = Summarizer(llm)  # 创建Summarizer实例用于生成文本摘要

    # 初始化ChatBot
    chatbot = ChatBot(llm, embeddings)  # 创建ChatBot实例用于回答问题

    # 上传pdf
    uploaded_file = st.file_uploader("Upload your PDF", type='pdf')  # 创建文件上传器,允许用户上传PDF文件

    if uploaded_file:
        # 加载上传PDF的内容
        file_content = uploaded_file.read()  # 读取上传的文件内容

        # 写入临时文件
        temp_file_path = "temp.pdf"  # 定义临时文件路径
        with open(temp_file_path, "wb") as temp_file:
            temp_file.write(file_content)  # 将文件内容写入临时文件

        # 加载临时文件中的内容
        loader = PyPDFLoader(temp_file_path)  # 创建PDF加载器实例
        docs = loader.load()  # 使用加载器加载文档内容

        st.chat_message("assistant").write(f"正在生成论文概括,请稍候...")  # 在Streamlit界面上显示消息

        # 生成概括
        summary = summarizer.summarize(docs)  # 调用summarizer的summarize方法生成摘要

        # 在聊天界面上显示模型的输出
        st.chat_message("assistant").write(summary)  # 显示生成的摘要

        # 接收用户问题
        if query := st.text_input("Ask questions about your PDF file"):  # 创建文本输入框,允许用户输入问题
            # 检索 + 生成回复
            chunks, response = chatbot.run(docs, query)  # 调用chatbot的run方法进行检索和生成回答

            # 在聊天界面上显示模型的输出
            st.chat_message("assistant").write(f"正在检索相关信息,请稍候...")  # 显示检索信息的消息
            st.chat_message("assistant").write(chunks)  # 显示检索到的文档片段

            st.chat_message("assistant").write(f"正在生成回复,请稍候...")  # 显示生成回答的消息
            st.chat_message("assistant").write(response)  # 显示生成的回答


if __name__ == '__main__':
    main()  # 如果是主程序,则调用main函数运行应用

提示词模块:

chatbot_template.py

from langchain_core.prompts import PromptTemplate
from langchain_text_splitters import RecursiveCharacterTextSplitter  # 导入文本分割器
from langchain.chains.question_answering import load_qa_chain  # 导入load_qa_chain,用于加载问答链
from langchain_community.vectorstores import FAISS
# 定义聊天机器人模板
chatbot_template = '''
假设你是一个AI科研助手,请基于背景,简要回答问题。

背景:
{context}

问题:
{question}
'''.strip()


# 定义ChatBot类
class ChatBot:
    """
    ChatBot类用于处理用户提问,并基于文档内容生成回答。
    """

    def __init__(self, llm, embeddings):
        self.prompt = PromptTemplate(
            input_variables=["text"],
            template=chatbot_template
        )  # 定义聊天机器人提示模板
        self.chain = load_qa_chain(llm=llm, chain_type="stuff", prompt=self.prompt)  # 加载问答链
        self.embeddings = embeddings  # 嵌入模型,用于文档向量化

        # 加载文本分割器,用于将长文本切分成小块
        self.text_splitter = RecursiveCharacterTextSplitter(
            chunk_size=450,
            chunk_overlap=10,
            length_function=len
        )

    def run(self, docs, query):
        """
        处理用户提问,生成回答。

        :param docs: 文档列表,每个文档包含page_content属性
        :param query: 用户的提问
        :return: 检索到的文档片段和生成的回答
        """
        # 读取所有文档内容
        text = ''.join([doc.page_content for doc in docs])

        # 使用文本分割器切分成chunks
        all_chunks = self.text_splitter.split_text(text=text)

        # 将文本chunks转换为向量并存储
        VectorStore = FAISS.from_texts(all_chunks, embedding=self.embeddings)

        # 检索与提问最相似的chunks
        chunks = VectorStore.similarity_search(query=query, k=1)

        # 使用问答链生成回答
        response = self.chain.run(input_documents=chunks, question=query)

        return chunks, response  # 返回检索到的文档片段和生成的回答

summarizer_template.py

# 导入必要的库和模块
from langchain.chains.llm import LLMChain  # 导入LLMChain,用于构建基于LLM的生成链
from langchain_core.prompts import PromptTemplate  # 导入PromptTemplate,用于构建提示模板


# 定义摘要模板
summarizer_template = """
假设你是一个AI科研助手,请用一段话概括下面文章的主要内容,200字左右。

{text}
"""

# 定义Summarizer类
class Summarizer:
    """
    Summarizer类用于将长文本内容压缩成简短的摘要。
    """

    def __init__(self, llm):
        self.llm = llm  # LLM实例,用于生成文本
        self.prompt = PromptTemplate(
            input_variables=["text"],
            template=summarizer_template
        )  # 定义摘要提示模板
        self.chain = LLMChain(llm=self.llm, prompt=self.prompt)  # 创建LLMChain实例,用于生成摘要

    def summarize(self, docs):
        """
        从文档中生成摘要。

        :param docs: 文档列表,其中每个文档包含page_content属性
        :return: 生成的摘要文本
        """
        # 从第一页中获取摘要内容,假设摘要位于'ABSTRACT'和'KEY WORDS'之间
        content = docs[0].page_content.split('ABSTRACT')[1].split('KEY WORDS')[0]
        summary = self.chain.run(content)  # 使用LLMChain生成摘要
        return summary  # 返回生成的摘要

源大模型模块:
yuan2_llm.py

# 导入必要的库
from typing import List, Optional, Any
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch

# 导入常量配置
from common import constants

# 导入LLM基类
from langchain.llms.base import LLM
from langchain.callbacks.manager import CallbackManagerForLLMRun

# 定义模型路径
model_path = constants.MODEL_PATH

# 定义模型数据类型
torch_dtype = torch.bfloat16


# 定义源大模型类
class Yuan2_LLM(LLM):
    """
    YUAN2_LLM类用于加载和使用预训练的大型语言模型。
    它继承自langchain的LLM基类,并实现了自己的_call方法来生成文本。
    """

    # 类变量,用于存储分词器和模型实例
    tokenizer: AutoTokenizer = None
    model: AutoModelForCausalLM = None

    def __init__(self, model_path: str):
        super().__init__()

        # 加载预训练的分词器和模型
        print("Creating tokenizer...")
        self.tokenizer = AutoTokenizer.from_pretrained(model_path, add_eos_token=False, add_bos_token=False,
                                                       eos_token='<eod>')
        # 添加特殊标记
        self.tokenizer.add_tokens(
            ['<sep>', '<pad>', '<mask>', '<predict>', '<FIM_SUFFIX>', '<FIM_PREFIX>', '<FIM_MIDDLE>', '<commit_before>',
             '<commit_msg>', '<commit_after>', '<jupyter_start>', '<jupyter_text>', '<jupyter_code>',
             '<jupyter_output>', '<empty_output>'], special_tokens=True)

        print("Creating model...")
        self.model = AutoModelForCausalLM.from_pretrained(model_path, torch_dtype=torch_dtype,
                                                          trust_remote_code=True).cuda()

    def _call(
            self,
            prompt: str,
            stop: Optional[List[str]] = None,
            run_manager: Optional[CallbackManagerForLLMRun] = None,
            **kwargs: Any,
    ) -> str:
        """
        生成文本的方法,根据输入的prompt生成响应。

        :param prompt: 输入的文本提示
        :param stop: 停止生成的标记列表
        :param run_manager: 运行管理器,用于监控和管理生成过程
        :param kwargs: 其他可选参数
        :return: 生成的文本响应
        """
        prompt = prompt.strip()
        prompt += "<sep>"
        inputs = self.tokenizer(prompt, return_tensors="pt")["input_ids"].cuda()
        outputs = self.model.generate(inputs, do_sample=False, max_length=4096)
        output = self.tokenizer.decode(outputs[0])
        response = output.split("<sep>")[-1].split("<eod>")[0]

        return response

    @property
    def _llm_type(self) -> str:
        """
        返回模型的类型标识。

        :return: 模型类型字符串
        """
        return "Yuan2_LLM"
运行效果
bash run.sh

启动脚本:run.sh

streamlit run main.py --server.address 127.0.0.1 --server.port 6006

论文概括:
在这里插入图片描述

What kind of attention architecture is LFA?

在这里插入图片描述

📌 [ 笔者 ]   文艺倾年
📃 [ 更新 ]   2024.9.15
❌ [ 勘误 ]   /* 暂无 */
📜 [ 声明 ]   由于作者水平有限,本文有错误和不准确之处在所难免,
              本人也很想知道这些错误,恳望读者批评指正!

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2137214.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

nvidia-docker Failed to initialize NVML: Unknown Error

nvidia镜像拉下来了&#xff0c;但是运行不了。 执行以下命令 sudo docker run --rm --runtimenvidia --gpus all ubuntu nvidia-smi报错 Failed to initialize NVML: Unknown Error参考 https://stackoverflow.com/questions/72932940/failed-to-initialize-nvml-unknown-er…

基于springboot 校园闲置物品交换平台设计与实现---附源码74557

摘 要 随着我国互联网技术的飞速发展&#xff0c;网络购物已经成为人们日常生活的重要组成部分。特别是在校园中&#xff0c;由于学生群体的特殊性&#xff0c;闲置物品交易的需求日益增长。然而&#xff0c;目前校园闲置物品物品交易市场仍然存在许多问题&#xff0c;如信息不…

声波的波数,通常用k表示

声波的波数&#xff08;通常用 k 表示&#xff09;是描述声波空间变化的一个参数&#xff0c;它与声波的频率和介质中的传播速度有关。波数 k 是一个具体值&#xff0c;并且在均匀介质中它是固定的&#xff0c;计算公式如下&#xff1a; 均匀介质中的波数是一个具体值&#xff…

react crash course 2024 (1)理论概念

state的作用 react hooks 而无需写一个class jsx 样式用 spa

判断当前环境是否为docker容器下

判断当前环境是否为docker容器下 webshell后或登录到系统后台&#xff0c;判断是否为docker容器可使用如下方法&#xff1a; 方式一&#xff1a;使用ls -alh命令查看是否存在.dockerenv来判断是否在docker容器环境内 ls -alh /.dockerenv如下图无.dockerenv文件&#xff0c;所…

Clickhouse使用笔记

clickhouse官方文档&#xff1a;https://clickhouse.com/docs/zh/sql-reference/data-types/decimal 一&#xff0c;建表 create table acitivity_user_record ( id String DEFAULT generateUUIDv4(), -- 主键自增 activityId String, userId String, userName Nullable(Strin…

【论文解读】图像序列识别:CRNN技术在场景文本识别中的应用与突破(附论文地址)

论文地址&#xff1a;https://arxiv.org/pdf/1507.05717 这篇文章的标题是《An End-to-End Trainable Neural Network for Image-based Sequence Recognition and Its Application to Scene Text Recognition》&#xff0c;作者是Baoguang Shi, Xiang Bai和Cong Yao&#xff0c…

代码随想录训练营 Day58打卡 图论part08 拓扑排序 dijkstra朴素版 + 堆优化版

代码随想录训练营 Day58打卡 图论part08 一、拓扑排序 例题&#xff1a;卡码117. 软件构建 题目描述 某个大型软件项目的构建系统拥有 N 个文件&#xff0c;文件编号从 0 到 N - 1&#xff0c;在这些文件中&#xff0c;某些文件依赖于其他文件的内容&#xff0c;这意味着如果…

不同的二叉搜索树

题目 给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;5示例 2&#xff1a; 输入&#xff1a;n 1 输出&#xff…

JSP经典设计模式流程分析:JSP+JavaBean设计模式+MVC设计模式

JSP两种经典设计模式 Model1设计模式:JSPJavaBean 架构图 什么是JavaBean JavaBean是一种JAVA语言写成的可重用组件&#xff0c;它遵循特定的编程规范&#xff0c;如类必须是公共的、具有无参构造函数&#xff0c;并提供getter/setter方法等。这里的JavaBean不单单指的是实体…

五、回溯算法-算法总结

文章目录 五、回溯算法5.1 背景5.2 模板5.3 集合类5.3.1 子集5.3.2 子集2 5.4 排列类5.4.1 全排列5.4.2 全排列2 5.5 组合类5.5.1 组合总和5.5.2 电话号码的字母组合 五、回溯算法 5.1 背景 回溯法&#xff08;backtrack&#xff09;常用于遍历列表所有子集&#xff0c;是 DF…

OpenAI草莓正式发布,命名o1

一、相关介绍 当地时间 9 月 12 日&#xff0c;OpenAI 推出全新模型 o1&#xff0c;它是该公司计划推出的一系列“推理”模型中的首个&#xff0c;也就是此前业内传闻许久的“Strawberry&#xff08;草莓&#xff09;”项目。 据悉&#xff0c;o1 模型在众多任务中能够比人类更…

LabVIEW机动车动态制动性能校准系统

机动车动态制动性能测试系统通过高精度的硬件设备与LabVIEW软件的紧密配合&#xff0c;实现了对机动车制动性能的精确校准与评估。系统不仅提高了测试的精确性和效率&#xff0c;而且具备良好的用户交互界面&#xff0c;使得操作更加简便、直观。 项目背景 随着机动车辆数量的…

C++:类和对象全解

C&#xff1a;类和对象全解 一、类的定义和初始化&#xff08;一&#xff09;类的定义1、类的成员变量&#xff08;1&#xff09;成员变量&#xff08;2&#xff09;成员函数 2、实例化对象&#xff08;1&#xff09;采用普通构造函数&#xff08;2&#xff09;采用初始化列表 …

MySQL数据的增删改查(二)

目录 约束 非空约束&#xff08;NOT NULL&#xff09; 唯一约束&#xff08;UNIQUE&#xff09; 默认值约束&#xff08;DEFAULT&#xff09; 主键约束&#xff08;PRIMARY KEY&#xff09; 外键约束&#xff08;FOREIGN KEY&#xff09; 检查约束&#xff08;CHECK&…

LabVIEW机械产品几何精度质检系统

随着制造业的发展&#xff0c;对产品质量的要求越来越高&#xff0c;机械产品的几何精度成为衡量其品质的重要指标。为了提高检测效率和精度&#xff0c;开发了一套基于LabVIEW的几何精度质检系统&#xff0c;该系统不仅可以自动化地进行几何尺寸的测量&#xff0c;而且能实时分…

kafka 之 本地部署单机版

安装JDK 查看你选择的版本需要安装哪一个版本的jdk 网址 下载 JDK下载 注&#xff1a;如果网页不允许下载&#xff0c;使用wget命令下载即可&#xff0c;下载之后安装。 建议使用rpm安装&#xff0c;之后使用 update-alternatives --config java 控制当前环境使用Java的版…

SpringBoot 处理 @KafkaListener 消息

消息监听容器 1、KafkaMessageListenerContainer 由spring提供用于监听以及拉取消息&#xff0c;并将这些消息按指定格式转换后交给由KafkaListener注解的方法处理&#xff0c;相当于一个消费者&#xff1b; 看看其整体代码结构&#xff1a; 可以发现其入口方法为doStart(),…

2024-2025年最全的计算机软件毕业设计选题大全

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

通过API接口获取数据:高效、灵活的数据交互之道

在数字化时代&#xff0c;数据已成为企业最宝贵的资产之一。企业和开发者对于数据的获取、处理和分析的需求日益增长。API&#xff08;应用程序编程接口&#xff09;接口作为连接不同系统和应用程序的桥梁&#xff0c;提供了一种高效、灵活的方式来获取和交换数据。本文将探讨为…