一、文档的加载和分割

     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个数据库

(1) 将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]

(2)从Redis中提取数据进行大模型使用

    >>>使用LLM接口封装

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

    )
    return response.choices[0].message.content

  >>>构建Prompt

#8 Prompt模板
# user_query="玩手机"
user_query="时间管理"

#1.检索
search_results=search_instrutions(user_query,3)
search_results='\n'.join(search_results)

#2.构建Prompt
prompt=f"""
你是一个问答机器人。
你的任务是根据下述给定的己知信息回答用户问题。
确保你的回复完全依据下述已知信息。不要编造答案。
如果下述己知信息不足以回答用户的问题,请直接回复“我无法回答您的问题

已知信息:
{search_results}

用户问:
{user_query}

请用中文回答用户问题。
"""
print("=======Prompt=======")
print(prompt)
print("=======Prompt=======")

#3.调用模型 LLM
response=get_completion(prompt)
print("=======回复=======")
print(response)

  >>>整合(1)中,运行效果如下:

更多推荐