大模型RAG (三)
一、文档的加载和分割
1、文档LLM回复系统搭建
2、把文本切分成chunks
把文本切分成chunks的方式有很多种:
1.按照句子来切分
2.按照字符数来切分
3.按固定字符数结合overlapping window
4. 递归方法 RecursiveCharacterTextSplitter
案例1: 按照句子来切分
import re txts=("大语言模型是基于深度学习架构、通过海量文本数据训练而成的人工智能系统。它能够理解自然语言、生成连贯文本,并在对话、翻译、摘要、创作等多种任务中表现出接近人类的表达能力。模型的性能通常与其参数量、训练数据规模和优化算法密切相关。随着技术不断迭代,大模型已从单一文本生成,逐步走向多模态理解、逻辑推理与工具调用,成为新一代人工智能应用的重要基础。") #正则表达式匹配中文句子结束的标点符合 sentences = re.split(r'(。| !|?|\...\...])', txts) #重新组合句子和结尾的标点符合 chunks=[sentence +(puncutation if puncutation else '') for sentence, puncutation in zip(sentences[::2], sentences[1::2])] for i ,chunk in enumerate(chunks): print(f"chunk {i+1}:{len(chunk)}:{chunk}")案例2:按照字符数来切分
import re txts=("大语言模型是基于深度学习架构、通过海量文本数据训练而成的人工智能系统。它能够理解自然语言、生成连贯文本,并在对话、翻译、摘要、创作等多种任务中表现出接近人类的表达能力。模型的性能通常与其参数量、训练数据规模和优化算法密切相关。随着技术不断迭代,大模型已从单一文本生成,逐步走向多模态理解、逻辑推理与工具调用,成为新一代人工智能应用的重要基础。") def split_fixed_count(text,count): return [text[i:i+count] for i in range(0,len(text),count)] #如果按照每50个字符来切分文本 chunks=split_fixed_count(txts,50) for i ,chunk in enumerate(chunks): print(f"chunk {i+1}:{len(chunk)}:{chunk}")案例3:按固定字符数结合overlapping window
import re txts=("大语言模型是基于深度学习架构、通过海量文本数据训练而成的人工智能系统。它能够理解自然语言、生成连贯文本,并在对话、翻译、摘要、创作等多种任务中表现出接近人类的表达能力。模型的性能通常与其参数量、训练数据规模和优化算法密切相关。随着技术不断迭代,大模型已从单一文本生成,逐步走向多模态理解、逻辑推理与工具调用,成为新一代人工智能应用的重要基础。") #将文本切分成多个部分 def sliding_chunks(text,chunk_size,step): return [text[i:i+chunk_size] for i in range(0,len(text),step)] #如果按照每100个字符来切分文本,步长为50 chunks=sliding_chunks(txts,100,50) for i ,chunk in enumerate(chunks): print(f"chunk {i+1}:{len(chunk)}:{chunk}")
案例4: 递归方法 RecursiveCharacterTextSplitter
import re from langchain_text_splitters import RecursiveCharacterTextSplitter txts = ( "大语言模型是基于深度学习架构、通过海量文本数据训练而成的人工智能系统。它能够理解自然语言、生成连贯文本,并在对话、翻译、摘要、创作等多种任务中表现出接近人类的表达能力。模型的性能通常与其参数量、训练数据规模和优化算法密切相关。随着技术不断迭代,大模型已从单一文本生成,逐步走向多模态理解、逻辑推理与工具调用,成为新一代人工智能应用的重要基础。") # 初始化分割器 # chunk_size: 每个块的最大长度 # chunk_overlap: 每个块之间的重叠长度 # length_function: 计算文本长度的函数,默认是len # RecursiveCharacterTextSplitter会递归地尝试不同的分隔符(如段落、句子、单词等)来分割文本,确保分割后的文本块尽可能完整且有语义意义 text_splitter = RecursiveCharacterTextSplitter(chunk_size=50, chunk_overlap=10, length_function=len) #一个文本块列表,每个文本块的长度不超过50个字符,且相邻文本块有10个字符的重叠部分。 chunks = text_splitter.split_text(txts) for i, chunk in enumerate(chunks): print(f"chunk {i + 1}:{len(chunk)}:{chunk}")注意:
安装: pip install langchain
安装: pip install langchain-text-splitters
新版(1.2.15):from langchain_text_splitters import ...
LangChain 官方做了模块化拆分,文本分割器独立成包了。
二、向量检索
1、检索的方式
- 关键字搜索:通过用户输入的关键字来查找文本数据。
- 语义搜索:不仅考虑关键词的匹配,还考虑词汇之间的语义关系,以提供更准确的搜索结果。
2、关键字搜索
我们需要把相关的信息存储在Redis中。我们需要先安装一个Redis。先下载再直接解压缩。
然后cmd进入到对应的目录。然后输入redis-server.exe
再安装一个RDM工具来查看导入的数据
连接到Redis服务器,默认有16个数据库
将json中的数据存入到Redis数据库中
python安装 pip install redis
import redis # pip install redis from openai import OpenAI from dotenv import load_dotenv import json # 默认加载项目根目录下的 .env 文件 load_dotenv() # 1. 获取client对象,OpenAI类对象 client=OpenAI() #2. 获取redis对象 #localhost:指定Redis服务器地址为本地主机 #6379:指定Redis服务器端口为6379 #db=0:指定Redis数据库索引为0;(Redis默认有16个数据库(0-15)) #decode_responses=True:指定Redis返回的数据类型为字符串 r = redis.Redis(host='localhost', port=6379, db=0,decode_responses=True) #3.读取数据 with open('train_zh.json', 'r', encoding='utf-8') as f: data = json.load(f) #4.取出问题 instrutions= [item['instruction'] for item in data[0:800]] #5.输出数据 outputs=[item['output'] for item in data[0:800]] #6.将数据存入redis for instrution,output in zip(instrutions,outputs): #存入Redis,值序列化为JSON r.set(instrution,output) #key为问题,value为答案 #7.查询数据:根据关键字搜索instruction中包含该关键字的条目 def search_instrutions(keyword,top=3): # 通过模糊匹配 keys=r.keys(pattern='*'+keyword+'*') data=[] #遍历通过模糊匹配找到的所有键 for key in keys: data.append(r.get(key)) return data[:top]