LLM:检索增强生成(RAG)

news2025/1/19 14:30:18

1 Embedding技术

  简单地说,嵌入(Embedding)思想可以视为一种尝试通过用向量来表示所有东西的“本质”的方法,其特性是“相近的事物”由相近的数表示。

1.1 文本向量(Text Embedding)

  在GPT中,文本嵌入(Text Embedding)是通过将输入文本中的每个词汇或词语转换为高维向量表示的方法。这些向量捕捉了词汇的语义信息,使得模型能够理解文本的含义并生成相关的输出。通过预训练的方式,GPT模型能够学习得到通用的文本表示,从而在各种自然语言处理任务中表现出色,包括文本生成、文本分类、问答等。

1.2 使用GPT进行Embedding

  目前OpenAI官方提供的3个文本向量模型为:

模型最大向量维度可否缩减维度
text-embedding-3-small1536
text-embedding-3-large3072
text-embedding-ada-0021536

text-embedding-3-smalltext-embedding-3-large可以通过embeddings.create中的dimensions参数调整输出的文本向量的维度。一般而言,文本向量维度越小搜索越快,而维度越大搜索越准。embeddings.create接口中的参数主要包括以下几个:

  • input: string或array。当为array时,其元素可以是字符串、整数或整数组成的array。整数会被视为一个token标记,整数组成的array会被视为一个完整的字符串。一个字符串输出一个embedding向量。
  • model: OpenAI提供的embedding模型。
  • dimension: embedding向量的维度;
  • encode-format: embedding向量的编码方式,float(默认值)或base64

具体代码举例如下(关于文本向量的相似度,GPT官方建议使用余弦相似度):

from openai import OpenAI
import os
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())  
client = OpenAI()
import numpy as np
from numpy.linalg import norm
def cos_sim(a, b):
    '''余弦距离 -- 值越接近1越相似'''
    return np.dot(a, b)/(norm(a)*norm(b))
def get_embeddings(texts, model="text-embedding-ada-002", dimensions=None):
    '''封装 OpenAI 的 Embedding 模型接口'''
    if model == "text-embedding-ada-002":
        dimensions = None
    if dimensions:
        data = client.embeddings.create(
            input=texts, model=model, dimensions=dimensions).data
    else:
        data = client.embeddings.create(input=texts, model=model).data
    return [x.embedding for x in data]

if __name__=="__main__":
    vec1=np.reshape(get_embeddings(texts="你好啊")[0],(-1,1536))
    vec2=np.reshape(get_embeddings(texts="hello")[0],(1536,-1))
    print(cos_sim(vec1,vec2))

代码运行结果如下:

[[0.84943191]]

2 向量数据库

  向量数据库是一种特殊类型的数据库,专门用于存储和检索向量数据,是为了有效处理高维数据而设计的。这里要注意一点:向量数据库本身不生成向量,向量是由 Embedding 模型产生的。目前主流的向量数据库有多种:chroma、milvus等。这里以chroma为例简单介绍。

2.1 chroma安装

chroma的安装非常简单,在Python中直接使用pip install命令安装即可。具体如下:

pip install chromadb

2.2 chroma基本操作

chroma向量数据库中的集合(collection)保存一组相关文件,可以看作一个容器,用于存储和组织特定类别或主题的数据。与collection相关的操作包括以下内容:

  • 创建集合:create_collection
  • 删除集合:delete_collection
  • 获取集合:get_collection
  • 获取并创建集合:get_or_create_collection(最常用)

在collection中可以添加add、删除delect、修改modify、插入insert、更新update向量。

2.3 chroma添加向量及查找相似向量

def get_embeddings(texts, model="text-embedding-ada-002", dimensions=None):
    if model == "text-embedding-ada-002":
        dimensions = None
    if dimensions:
        data = client.embeddings.create(
            input=texts, model=model, dimensions=dimensions).data
    else:
        data = client.embeddings.create(input=texts, model=model).data
    return [x.embedding for x in data]

chroma_client=chromadb.Client(Settings(allow_reset=True))
chroma_client.reset()
collection=chroma_client.get_or_create_collection(name="my_collection")

documents=['hello','你吃早饭了吗?',"今天考了多少分?","侬好吗?"]
#向collection中添加向量
collection.add(embeddings=get_embeddings(documents),
            documents=documents,
            ids=["id1", "id2",'id3','id4'])
#查找与“你好”最相近的向量
results=collection.query(
    query_embeddings=get_embeddings(["你好"]),
    n_results=2)
print(results['documents'][0])

其输出内容为:

[‘侬好吗?’, ‘hello’]

注意:chroma等其他向量数据库能快速定位相似变量,是因为这类数据库通常执行的是近似查找,而非精确查找。

3 检索增强生成

  检索增强生成(Retrieval-Augmented Generation, RAG)是一种结合了信息检索和自然语言生成的技术。其基本思想是利用信息检索的技术,从大规模语料库(存储在向量数据库)中检索出与当前任务相关的文本片段,并将这些文本片段作为输入提供给生成模型,以引导生成模型产生更准确、更相关的文本输出。其基本框架为:在这里插入图片描述

下面给出一个具体的代码案例:

from pdfminer.high_level import extract_pages
from pdfminer.layout import LTTextContainer
import re
import chromadb
from chromadb.config import Settings
from openai import OpenAI
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) 
client=OpenAI()
#从pdf中提取文档
def extract_text_from_pdf(filename,page_numbers=None,min_line_length=5):
    paragaphs=[]
    full_text=''
    for i,page_layout in enumerate(extract_pages(filename)):
        if page_numbers and i not in page_numbers:
            continue
        for element in page_layout:
            if isinstance(element,LTTextContainer):
                full_text+=element.get_text()+'\n'
    buffer=''
    for text in full_text.split('\n'):
        if len(text)>1 and bool(re.search(r'\b[A-Za-z]+\b',text)):
            buffer+=(' '+text) if not text.endswith('-') else text.strip('-')
        elif buffer:
            paragaphs.append(buffer.lstrip(' '))
            buffer=''
    if buffer:
        paragaphs.appen(buffer)
    return paragaphs
#定义embedding函数
def get_embeddings(texts, model="text-embedding-ada-002", dimensions=None):
    if model == "text-embedding-ada-002":
        dimensions = None
    if dimensions:
        data = client.embeddings.create(
            input=texts, model=model, dimensions=dimensions).data
    else:
        data = client.embeddings.create(input=texts, model=model).data
    return [x.embedding for x in data]
#修改prompt模版
def bulid_prompt(prompt_template, **kwargs):
    prompt=prompt_template
    for k,v in kwargs.items():
        if isinstance(v,str):
            val=v
        elif isinstance(v,list) and all(isinstance(x,str) for x in v):
            val='\n'.join(v)
        else:
            val=str(v)
        prompt=prompt.replace(f"__{k.upper()}__",val)
    return prompt
#调用大模型
def get_completions(prompt,model='gpt-3.5-turbo'):
    response=client.chat.completions.create(
        model=model,
        messages=[{"role":"user","content":prompt}],
        temperature=0.5,
    )
    return response.choices[0].message.content
    
prompt_template = """
你是一个问答机器人。
你的任务是根据下述给定的已知信息回答用户问题。
确保你的回复完全依据下述已知信息。不要编造答案。
如果下述已知信息不足以回答用户的问题,请直接回复"我无法回答您的问题"。

已知信息:
__INFO__

用户问:
__QUERY__

请用中文回答用户问题。
"""
class RAG_BOT():
    def __init__(self):
        chroma_client=chromadb.Client(Settings(allow_reset=True))
        self.collection=chroma_client.get_or_create_collection(name="my_collection")
    def add_documents(self,documents):
        self.collection.add(documents=documents,
                            embeddings=get_embeddings(documents),
                            ids=["id"+str(i) for i in range(len(documents))])
    def query(self,user_query,top_n=2):
        results=self.collection.query(query_embeddings=get_embeddings([user_query]),n_results=top_n)
        prompt=bulid_prompt(prompt_template,query=user_query,info=results['documents'])
        return get_completions(prompt)

documents=extract_text_from_pdf('/Users/sherry/Downloads/llama2.pdf')

rag_bot=RAG_BOT()
rag_bot.add_documents(documents)
print(rag_bot.query("llama2有多少参数?"))

其输出结果为:

根据已知信息,Llama 2 模型有三个变种,参数量分别为 7B、13B 和 70B。

参考资料

  1. https://zhuanlan.zhihu.com/p/647646322
  2. https://guangzhengli.com/blog/zh/vector-database/
  3. https://blog.csdn.net/shebao3333/article/details/130593519

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

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

相关文章

哲♂学家带你用顺序表实现通讯录

实现通讯录能使我们进一步加深对顺序表的理解,接下来就由本哲♂学家带你手把手实现通信录。 其中需要用到顺序表的知识可以点击下面链接了解:http://t.csdnimg.cn/9SjGd话不多说,我们♂开始吧。 一、通讯录头文件声明 由于我们前面已经写过…

随机生成Long全范围数

随机生成Long全范围数 前言实现思路主要代码分区随机生成过程案例:随机生成100个数 朴素的比较总结 前言 使用自带的Random.nextLong()函数生成Long型的长整数,范围比较小,如下图。100个随机数没看见10以内的数字。所以考虑实现随机化生成大…

基于注意力整合的超声图像分割信息在乳腺肿瘤分类中的应用

基于注意力整合的超声图像分割信息在乳腺肿瘤分类中的应用 摘要引言方法 Segmentation information with attention integration for classification of breast tumor in ultrasound image 摘要 乳腺癌是世界范围内女性最常见的癌症之一。基于超声成像的计算机辅助诊断&#x…

scp和rsync

引言 我们平时总会有在不同的设备之间传输文件的需要,好友同事间可以用微信、QQ、网盘等,还是比较方便安全的。而在linux的操作系统中,我们经常需要两台机器之间拷贝文件,或者由于业务需要备份文件,那就不得不用到scp和…

【React】基于JS 3D引擎库实现关系图(图graph)

主角:3D Force-Directed Graph 简介:一个使用ThreeJS/WebGL进行3D渲染的Graph图库 GitHub: https://github.com/vasturiano/3d-force-graph Ps: 较为复杂或节点巨大时,对GPU>CPU消耗较大,同量级节点对比下优于AntV G6和Echarts…

C语言之分支语句和循环语句

前言 一、什么是语句? 二、分支语句(选择结构) 2.1 if语句 2.2 switch语句 三、循环语句 3.1 while循环 3.2 break与continue语句 3.3 getchar()与putchar() 3.3.1 缓冲区 3.4 for循环 3.4.1 一些for循环的变种 3.5 do...while循…

java运行时内存

从jdk1.7以及以后,静态变量和常量池存在堆空间。

【TSP旅行商问题】改进的大邻域搜索算法LNS

课题名称:基于改进的大规模邻域搜索算法LNS求解TSP问题 版本时间:2024-04-01 程序运行:直接运行LNS_TSP.m 文件即可 代码获取方式: QQ:491052175 VX:Matlab_Lover 模型介绍: 第一步&…

[AutoSar]BSW_Memory_Stack_004 创建一个简单NV block并调试

目录 关键词平台说明背景一、需求二、配置2.1 NvMBlockDescriptors2.2 NvMFeeRef2.3 FeeBlockConfigurations 三、code3.1 声明和定义3.2 调试 关键词 嵌入式、C语言、autosar、OS、BSW 平台说明 项目ValueOSautosar OSautosar厂商vector , EB芯片厂商TI 英飞凌编…

SpringBoot -- 外部化配置

我们如果要对普通程序的jar包更改配置,那么我们需要对jar包解压,并在其中的配置文件中更改配置参数,然后再打包并重新运行。可以看到过程比较繁琐,SpringBoot也注意到了这个问题,其可以通过外部配置文件更新配置。 我…

钉钉事件订阅前缀树算法gin框架解析

当钉钉监测到发生一些事件,如下图 此处举例三个事件user_add_org、user_change_org、user_leave_org,传统的做法是,我们写三个if条件,类似下图 这样字符串匹配效率比较低,于是联想到gin框架中的路由匹配算法&#xff0…

利用Spark将Kafka数据流写入HDFS

利用Spark将Kafka数据流写入HDFS 在当今的大数据时代,实时数据处理和分析变得越来越重要。Apache Kafka作为一个分布式流处理平台,已经成为处理实时数据的事实标准。而Apache Spark则是一个强大的大数据处理框架,它提供了对数据进行复杂处理…

Linux操作系统之nfs网络文件系统

目录 一、NFS简介 1.2 安装配置NFS 一、NFS简介 nfs类似于windows文件共享 将linux的一个目录共享到网络中,网络中的其他所有主机都可以使用这个共享目录中的文件 samba 文件共享 可以在linux中通过samba共享一个目录,然后在linux中可以访问这个共享 …

55 npm run serve 和 npm run build 的分包策略

前言 这里我们来看一下 vue 这边 打包的时候的一些 拆分包的一些策略 我们经常会使用到 npm run build 进行服务的打包 然后 打包出来的情况, 可能如下, 可以看到 chunk-vendors 是进行了包的拆分, 我们这里就是 来看一下 这里 npm run build 的时候的, 一个分包的策略 测试…

【HTML】简单制作一个唱片动画效果

目录 前言 开始 HTML部分 CSS部分 效果图 总结 前言 无需多言,本文将详细介绍一段代码,具体内容如下: 开始 首先新建文件夹,创建两个文本文档,其中HTML的文件名改为[index.html],CSS的…

Matlab|储能辅助电力系统调峰的容量需求研究

目录 1 主要内容 目标函数 约束条件 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序参考文献《储能辅助电力系统调峰的容量需求研究》,主要是对火电、风电和储能等电力设备主体进行优化调度,在调峰能力达不到时采用弃负荷,程序以…

第十四届省赛大学B组(C/C++)子串简写

原题链接:子串简写 程序猿圈子里正在流行一种很新的简写方法: 对于一个字符串,只保留首尾字符,将首尾字符之间的所有字符用这部分的长度代替。 例如 internationalization 简写成 i18n,Kubernetes 简写成 K8s&#…

【贪玩巴斯】Mac的M芯片(M1/2...)下载homebrew方法(24年最新且已验证可行)

1. 按照目前广为流传的方法(M1会出现一些问题): 终端输入: /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 使用国内镜像下载。 2. 输入后按照要求步骤执行即可&#xff…

docker-compose运行springinitializr用来创建springboot2

前言 spring initializr官方的地址是: https://start.spring.io/ ,这是一个用来创建springboot脚手架的一个工具,但是目前这个工具已经更新到springboot3,而我还没学springboot3,目前还想继续创建springboot2,我就想能…

如何预防自己网站被流量劫持?HTTPS加密是否可行?

如何预防自己网站被流量劫持?HTTPS加密是否可行? 文章背景: 所谓的流量劫持,就是利用各种恶意软件修改浏览器、锁定主页或不停弹出新窗口,强制用户访问某些网站,从而造成用户流量损失的情形。 流量劫持是一…