基于Llama3为本地文件创建生成式AI搜索引擎

基于Llama3构建本地文件生成式AI搜索引擎

大家好,下面将介绍一个开源项目,即一款创新的生成式搜索引擎,能够实现用户与本地文件的智能互动。此项目在微软Copilot等现有工具的基础上,推出了一种开放源代码的替代方案,旨在推动技术共享与创新。

1.系统设计

为构建本地生成式搜索引擎或助手,需要几个组件:

  • 内容索引系统:负责存储本地文件内容,并配备信息检索引擎,以便高效地搜索与用户查询或问题最相关的文档。

  • 语言模型:用于分析选定的本地文档内容,并据此生成精炼的总结性答案。

  • 用户界面:为用户提供直观的操作界面,以便轻松地进行查询和获取信息。

组件之间的交互方式如下所示:

图片

系统设计和架构。使用Qdrant作为向量存储,Streamlit用于用户界面。Llama 3可以通过Nvidia NIM API(700B版本)使用,也可以通过HuggingFace下载(80B版本)。文档分块使用Langchain完成。

构建本地生成式搜索引擎的第一步是创建索引,用以存储和检索本地文件内容。当用户提出问题,系统会通过这个索引快速定位到最相关的文档。随后,选定的文档内容被送入高级语言模型,该模型不仅生成答案,还提供对引用文档的明确标注。最终,用户界面将这些信息以清晰、易于理解的方式展示给用户。

2.语义索引

语义索引旨在通过分析文件内容与查询之间的相似度,提供最相关的文档匹配。索引的构建采用了Qdrant作为其向量存储解决方案。Qdrant客户端库的便利之处在于,它不需要完整的服务器端安装,便能在工作内存中直接进行文档相似性比较,极大地简化了部署流程,仅需通过pip命令安装Qdrant客户端即可。

Qdrant初始化时,需要预先设定所使用的向量化方法和度量标准(注意,hf参数稍后定义)。向量化和度量的具体配置应在客户端初始化阶段完成。以下是Qdrant初始化的一个示例:

from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams
client = QdrantClient(path="qdrant/")
collection_name = "MyCollection"
if client.collection_exists(collection_name):
    client.delete_collection(collection_name)

client.create_collection(collection_name,vectors_config=VectorParams(size=768, distance=Distance.DOT))
qdrant = Qdrant(client, collection_name, hf)

为构建向量索引,必须对硬盘中的文档进行嵌入处理。需要选择合适的嵌入方法和向量比较度量标准,不同的段落、句子或词嵌入技术将产生不同的结果。在文档向量搜索中,主要挑战之一是非对称搜索问题,这在信息检索领域极为常见,尤其是在处理短查询与长文档匹配时。传统的单词或句子嵌入技术通常针对相似长度的文档进行优化,如果文档长度与查询长度差异过大,就可能导致信息检索效果不佳。

然而,有一种嵌入方法能够有效应对非对称搜索问题。以MSMARCO数据集为例,该数据集基于Bing的搜索查询和文档,由Microsoft发布,并针对此类问题进行了优化。MSMARCO数据集的模型经过微调,能够提供出色的搜索效果,非常适合解决当前面临的问题。

在本次实现中,选用了针对MSMARCO数据集进行过微调的模型,名为:

sentence-transformers/msmarco-bert-base-dot-v5

这个模型基于BERT架构,并针对点积相似性度量进行了特别优化。在初始化Qdrant客户端时,已明确采用点积作为衡量相似性的方法(注意此模型的维度为768):

client.create_collection(collection_name,vectors_config=VectorParams(size=768, distance=Distance.DOT))

在选择相似性度量标准时,虽然余弦相似性是一个可行选择,但鉴于模型已针对点积优化,采用点积能够实现更优的性能表现。点积的优势在于它不仅关注向量间的角度差异,还包括了向量的大小因素,这在评估向量整体相似度时尤为重要。通过归一化处理,可以在特定条件下使两种度量标准达到相同效果。然而,当向量的大小成为一个关键考量时,点积显然是更为合适的度量手段。

模型初始化建议利用GPU以提升计算效率,具体代码实现如下:

model_name = "sentence-transformers/msmarco-bert-base-dot-v5"
model_kwargs = {'device': 'cpu'}
encode_kwargs = {'normalize_embeddings': True}
hf = HuggingFaceEmbeddings(
    model_name=model_name,
    model_kwargs=model_kwargs,
    encode_kwargs=encode_kwargs
)

BERT类模型受限于其内存消耗的二次方增长特性,只能处理有限长度的上下文,通常不超过512个token。面对这一局限,有两种应对策略:一是仅利用文档前512个token生成答案,舍弃之后的内容;二是将文档切分为多个小块,每块作为一个独立单元存储于索引之中。为了保留完整的信息,我们选择了后者。文档的分块工作,计划利用LangChain的内置分块工具来完成:

from langchain_text_splitters import TokenTextSplitter
text_splitter = TokenTextSplitter(chunk_size=500, chunk_overlap=50)
texts = text_splitter.split_text(file_content)
metadata = []
for i in range(0,len(texts)):
    metadata.append({"path":file})
qdrant.add_texts(texts,metadatas=metadata)

在编写的代码中,把文本切割成500个token的段落,并设置了50个token的重叠区域,这样做是为了在段落的首尾保持上下文的连贯性。接着,为每个段落创建了包含文档存储路径的元数据,并将其与文本段落一并索引。

在将文件内容索引之前,必须先读取这些文件。而在读取之前,需要先确定哪些文件需要被索引。本项目简化了这一流程,允许用户指定他们希望索引的文件夹。索引器将递归地搜索该文件夹及其子文件夹中的所有文件,并索引那些支持的文件类型,如PDF、Word、PPT和TXT格式。

以下是检索给定文件夹及其子文件夹内所有文件的递归方法:

def get_files(dir):
    file_list = []
    for f in listdir(dir):
        if isfile(join(dir,f)):
            file_list.append(join(dir,f))
        elif isdir(join(dir,f)):
            file_list= file_list + get_files(join(dir,f))
    return file_list

完成文件检索后,接下来便是读取这些文件中的文本内容。目前,工具支持的文件格式包括MS Word文档(.docx)、PD

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

python慕遥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值