爆火!基于检索构建RAG应用大模型实战

前言

程序员,如果你存在职业瓶颈,该提升个人能力呢?还是转行进入当下蓝海技术领域大模型,近几个月,我发现大模型的风吹到了各行各业,悄悄在改变着各行业。但是也存在一种现象,懂得非常懂,不懂得是举步维艰,我建议不管你是不是一个技术工作者,其实都可借助大模型去做一些事情,不管你是为了提效还是改变自己的现有职业路径,应该从中都可找到你想要的答案。

我在这篇文中将通过浅显易懂的方式,分享一个我应用的实例-基于检索构建RAG,你也可以尝试,不管从技术应用角度出发,还是说对大模型应用长远计划,都希望能帮助你,欢迎讨论。
在这里插入图片描述

一.RAG介绍

随着大模型被使用的频率越来越多,人们对于它的强大问题回答能力感到震惊,但是在这一过程中,人们也发现大语言模型并不是十全十美的,本身有局限性,主要表现在两个方面。首先,它的知识不是实时的,因为它的训练数据源来自于互联网,而某些知识在模型训练时可能在互联网上没有曝光。其次,大模型可能无法涵盖私有领域和企业内部的资料。

为了解决这个问题,可以想到能否动态地将知识补充给大模型,使其能够回答更多问题呢?这就要提到检索增强的生成模型(RAG),顾名思义就是通过检索的方式来增强生成式模型的能力。

为了实现它的功能,我们首先要构造一个知识库,将想要补充的动态内容放入知识库当中,当用户提问时,通过计算相关性找到最相关的知识片段,然后将这些片段整合,最终传递给大模型处理,这样就可以增加大模型回答问题的能力。

认识了RAG之后,接下来我们就来看一下RAG构建流程。

二.RAG构建流程

目前一种可使用的方式是将我们所要补充的知识文件进行处理,再利用检索技术,得到文件中所需要的知识,再将它结合prompt传递给大模型,这样就可以变相的增强大模型的知识储备,具体可以分为以下5个步骤。

1. 文档的加载与切割

这里要用到pdfminer里的三个工具:

pdfminer.six:是一个用于处理PDF文档的库。它可以帮助我们从PDF中提取文本、布局信息等,使得我们可以以程序化的方式处理PDF文档。

pdfminer.high_level:是PDFMiner的高级接口,提供了更简单的方法来处理PDF文档,特别是用于提取文本。主要用于高级PDF文档处理,例如提取文本、页面等。

pdfminer.layout:是PDFMiner的一部分,用于处理PDF文档的布局信息,例如文本在页面上的位置、字体信息等。主要用于获取PDF文档的布局信息,这在某些情况下是很有用的,例如需要按照页面布局进行特殊处理。

在控制台输入

#调用包管理工具即可下载:
pip install pdfminer.six
把对应的工具导入代码文件中,接下来就可以写主体的代码了:

from pdfminer.high_level import extract_pages
from pdfminer.layout import LTTextContainer

def extract_text_from_pdf(filename, page_numbers=None, min_line_length=1):
    '''从 PDF 文件中(按指定页码)提取文字'''
    paragraphs = []
    buffer = ''
    full_text = ''
    # 提取全部文本
    for i, page_layout in enumerate(extract_pages(filename)):
        # 如果指定了页码范围,跳过范围外的页
        if page_numbers is not None and i not in page_numbers:
            continue
        for element in page_layout:
            if isinstance(element, LTTextContainer):
                full_text += element.get_text() + '\n'
    # 按空行分隔,将文本重新组织成段落
lines = full_text.split('\n')

PDF文档的加载与文本提取:

使用pdfminer库中的extract_pages函数从指定的PDF文件中提取页面布局信息。

遍历每个页面的布局信息,仅保留文本容器LTTextContainer类型的元素,并将其文本内容拼接成一个完整的文本字符串

full_text。

for text in lines:
        if len(text) >= min_line_length:
            buffer += (' '+text) if not text.endswith('-') else text.strip('-')
        elif buffer:
            paragraphs.append(buffer)
            buffer = ''
    if buffer:
        paragraphs.append(buffer)
    return paragraphs

paragraphs = extract_text_from_pdf("llama2.pdf", min_line_length=10)

for para in paragraphs[:3]:
print(para+"\n")

文本的重新组织与切割:将完整的文本字符串按照空行进行分隔,重新组织成段落。通过指定的min_line_length参数过滤掉长度小于该值的行。处理以连字符结尾的情况,将连字符连接的两行文本合并在一起。

这一部分实现了对PDF文档的加载与切割以及文本的重新组织与切割。通过使用pdfminer库中的extract_pages函数,从指定的PDF文件中提取页面布局信息,遍历每个页面的文本容器元素,将其文本内容拼接成一个完整的文本字符串。随后,对该文本字符串按照空行进行分隔,重新组织成段落,并通过设定的min_line_length参数过滤掉长度小于该值的行。同时,处理以连字符结尾的情况,将连字符连接的两行文本合并在一起。最终,返回包含重新组织后的文本段落的列表。

随着大语言模型发展日新月异,关于大模型的介绍也是五花八门,但是大多数内容都不够全面。为了更系统的学习和入门大模型,我看了知乎的大模型课程。起初只是抱着试试看的态度,但是听了两节课就觉得内容超出了预期,讲课的都是圈内大牛,经验丰富,专业性强,还是热门开源项目的作者,理论和实践都很强,课程入口就是下面这个卡片。

2.接口引擎

这一部分也要用到两个工具,分别是elasticsearch7和nltk,下边我们先了解一下这两个工具。

elasticsearch7:是Elasticsearch 的官方 Python 客户端库,用于与 Elasticsearch 服务器进行交互。主要用于在 Python 中与 Elasticsearch 集群进行通信,执行搜索、索引创建和更新等操作。Elasticsearch是一个分布式搜索引擎,广泛用于全文搜索和日志分析等场景。

NLTK (Natural Language Toolkit):自然语言处理(NLP)领域的库,提供了丰富的工具和资源,用于处理和分析人类语言数据。主要用于文本处理、分词、词性标注、语法分析等自然语言处理任务。nltk包含了大量语料库和算法,使得在NLP任务中更容易使用Python进行开发。

有了这两个工具,就可以使得我们方便的检索知识库中的内容,并且更好地提取出我们所需要的信息。同样我们使用包管理工具进行加载。

pip install elasticsearch
pip install nltk

接下来的代码主要涉及与Elasticsearch的交互,包括建立索引、将文本数据灌入索引以及执行搜索操作。以下是具体的步骤:

 #文本处理与关键词提取
from elasticsearch7 import Elasticsearch, helpers
from nltk.stem import PorterStemmer
from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords
import nltk
import re
nltk.download('stopwords')
import warnings
warnings.simplefilter("ignore")  # 屏蔽 ES 的一些Warnings
nltk.download('punkt')  # 英文切词、词根、切句等方法
nltk.download('stopwords')  # 英文停用词库
def to_keywords(input_string):
    '''(英文)文本只保留关键字'''
    # 使用正则表达式替换所有非字母数字的字符为空格
    no_symbols = re.sub(r'[^a-zA-Z0-9\s]', ' ', input_string)
    word_tokens = word_tokenize(no_symbols)
    # 加载停用词表
    stop_words = set(stopwords.words('english'))
    ps = PorterStemmer()
    # 去停用词,取词根
    filtered_sentence = [ps.stem(w)
    for w in word_tokens if not w.lower() in stop_words]
         return ' '.join(filtered_sentence)

我们使用NLTK库进行文本处理,包括词干提取(PorterStemmer)、分词(word_tokenize)和去除停用词(stopwords)等操作。代码中的re库用于处理正则表达式,这样就可以将处理后的文本转换为关键词。

建立Elasticsearch连接时使用Elasticsearch类建立到Elasticsearch服务的连接,指定服务地址、端口以及用户名和密码。使用es.indices.create方法创建新的Elasticsearch索引,以存储文本数据。

创建索引

es.indices.create(index=index_name)

灌库指令

actions = [
    {
        "_index": index_name,
        "_source": {
            "keywords": to_keywords(para),
            "text": para
        }
    }
    for para in paragraphs
]

#文本灌库
helpers.bulk(es, actions)
在上面的代码中,我们使用列表推导式构建actions列表,其中每个元素是一个字典,包含了索引名称、关键词和原始文本。每个段落的关键词是通过前面定义的to_keywords函数处理得到的。最后使用helpers.bulk函数将文本数据批量灌入Elasticsearch索引。

接下来我们需要定义一个search函数,用于执行基于关键词的搜索操作。使用search函数执行搜索,指定查询字符串和返回结果的数量。将搜索结果中的文本内容提取出来,并打印输出。接下来我们看一下如何实现定义搜索函数:

def search(query_string, top_n=3):
    # ES 的查询语言
    search_query = {
        "match": {
            "keywords": to_keywords(query_string)
        }
    }
    res = es.search(index=index_name, query=search_query, size=top_n)
    return [hit["_source"]["text"] for hit in res["hits"]["hits"]]

results = search("how many parameters does llama 2 have?", 2)
for r in results:
print(r+"\n")

完成接口引擎开发之后,接下来我们就要对接口封装。

3. 接口封装

这一部分涉及到与OpenAI GPT-3.5-turbo模型的交互,以及封装与OpenAI的通信过程:

from openai import OpenAI
import os

加载环境变量

from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())  # 读取本地 .env 文件,里面定义了 OPENAI_API_KEY

client = OpenAI()

def get_completion(prompt, model="gpt-3.5-turbo"):
    '''封装 openai 接口'''
    messages = [{"role": "user", "content": prompt}]
    response = client.chat.completions.create(
        model=model,
        messages=messages,
        temperature=0,  # 模型输出的随机性,0 表示随机性最小
    )

return response.choices[0].message.content
以上代码,使用python-dotenv库加载环境变量,其中包含了OpenAI API的密钥。使用openai库中的OpenAI类创建一个OpenAI API的客户端。定义get_completion函数,该函数接收一个提示(prompt)并调用OpenAI API的聊天补全接口,获取模型生成的回复。最后使用get_completion函数调用OpenAI GPT-3.5-turbo模型,传入之前构建的中文提示(这里要自己构建一个Prompt模板)。设置temperature参数可以自己设置,建议设为0,以最小化模型生成输出的随机性。

接下来是大模型的必知必会应用Prompt,Prompt用好你会发现让你在开发上和工作期间让你提效翻倍,在RAG应用过程中Prompt应用也是必不可少的,接下来我们看看Prompt模版应用。

4.Prompt模板

这一部分实现一个用于构建中文对话系统的 Prompt 模板。这个模板的目的是为了生成一个符合中文对话语境的问题,并提供对应的已知信息。

def build_prompt(prompt_template, **kwargs):
    '''将 Prompt 模板赋值'''
    prompt = prompt_template
    for k, v in kwargs.items():
        if isinstance(v, str):
            val = v
        elif isinstance(v, list) and all(isinstance(elem, str) for elem in v):
            val = '\n'.join(v)
        else:
            val = str(v)
        prompt = prompt.replace(f"__{k.upper()}__", val)
    return prompt

prompt_template = """

具体来说, 定义一个名为 build_prompt 的函数,该函数接收一个 Prompt 模板和一组关键字参数。使用关键字参数填充模板中的占位符,占位符以 __ 开头,后跟大写字母标识符。这些占位符包括 INFOQUERY。他们的名称无所谓,主要是方便我们之后填充内容即可。

  1. RAG 正式运行
    在下面的代码中,我们定义了一个用户查询的字符串, 使用之前定义的搜索函数 search 对用户查询进行基于关键词的搜索,返回搜索结果。使用build_prompt 函数,将搜索结果和用户查询组装成一个用于 OpenAI 模型的输入 Prompt。
user_query = "how many parameters does llama 2 have?"

1. 检索

search_results = search(user_query, 2)

2. 构建 Prompt

prompt = build_prompt(prompt_template, info=search_results, query=user_query)
print("===Prompt===")
print(prompt)

3. 调用 LLM

response = get_completion(prompt)

print("===回复===")
print(response)

到这里,我们就完成了整个流程的开发,接下来我们就对每个环节进行一个简短的提炼总结,一起来梳理一下整个实现过程。

三、总结

第一步、我们先进行了文档的加载与切割,对文档进行预处理,将原来的文档转化为所需要的形式,方便我们后期的应用和处理。

第二步、我们完成接口引擎,使用搜索工具,将文本数据建立索引,提供一个基础的搜索引擎。这个搜索引擎能够根据输入的查询字符串,在已建立的索引中查找相应的文本信息。

第三步、我们进行接口封装,这部分的主要作用是封装OpenAI的接口调用,使得后续可以方便地调用OpenAI GPT-3.5-turbo模型生成对用户查询的回复。

第四步、应用Prompt模板构建一个符合中文对话语境的输入提示(Prompt),在后续的调用 OpenAI 模型时,将这个 Prompt 传递给模型,以获取更加符合用户查询场景的回复

第五步、让RAG 正式运行,通过调用 OpenAI 模型,传递构建好的 Prompt 给 OpenAI GPT-3.5-turbo 模型,获取模型生成的回复。

通过以上的5个步骤,我们就可以做一个就简单的AI知识库了,在实践中可以结合自己的业务,构建不同的AI知识库,使自己的AI更加强大,实现你技术提升的同时,也拓展了新的技术领域,也可与你实际的业务相结合,进行迭代和升级。

那么,我们该如何学习大模型?

作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

一、大模型全套的学习路线

学习大型人工智能模型,如GPT-3、BERT或任何其他先进的神经网络模型,需要系统的方法和持续的努力。既然要系统的学习大模型,那么学习路线是必不可少的,下面的这份路线能帮助你快速梳理知识,形成自己的体系。

L1级别:AI大模型时代的华丽登场

L2级别:AI大模型API应用开发工程

L3级别:大模型应用架构进阶实践

L4级别:大模型微调与私有化部署

一般掌握到第四个级别,市场上大多数岗位都是可以胜任,但要还不是天花板,天花板级别要求更加严格,对于算法和实战是非常苛刻的。建议普通人掌握到L4级别即可。

以上的AI大模型学习路线,不知道为什么发出来就有点糊,高清版可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

在这里插入图片描述

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

img

三、大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

img

四、AI大模型商业化落地方案

img

作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值