RAG(Retrieval-Augmented Generation,检索增强生成)流程
目录
- 一、知识文档的准备
- 二、OCR转换
- 三、分词处理
- 四、创建向量数据库
- 五、初始化语言聊天模型
- 1.prompt
- 2.检索链
- 3.对话
- 完整代码
知识文档的准备:首先需要准备知识文档,这些文档可以是多种格式,如Word、TXT、PDF等。使用文档加载器或多模态模型(如OCR技术)将这些文档转换为可理解的纯文本数据。对于长篇文档,还需进行文档切片,以便更高效地处理和检索信息。
嵌入模型:将文本转换为向量形式,以便通过计算向量之间的差异来识别语义上相似的句子。常见的嵌入模型包括Word2Vec、BERT和GPT系列等。
向量数据库:将嵌入后的向量数据存储在向量数据库中,以便进行高效的相似性搜索。
查询检索:当用户提出查询时,系统会将查询通过嵌入模型转换为向量,然后在向量数据库中进行相似性搜索,找到与查询最相关的文档或信息。
生成回答:将检索到的相关信息与用户的查询结合,生成最终的回答。生成模型会利用检索到的信息作为上下文输入,并结合大语言模型来生成文本内容。
这里的嵌入模型用的是本地部署的ollama,也可以使用openai,但是连接不太稳定,还有阿里云的通义千问。
一、知识文档的准备
知识库中存放pdf等类型的文档,准备后面转换为txt文本
二、OCR转换
OCR转换会将PDF、图片这些信息提取得到TXT文本。数据质量的好坏直接影响着后面模型对话效果。因此PDF解析选用的工具必须精确且合适。
在这个例子中,我是事先将PDF用MinerU解析成markdown形式了
三、分词处理
文本分词处理(Tokenization)是自然语言处理(NLP)中的一个重要步骤,其目的是将连续的文本字符串分割成有意义的单元,这些单元通常被称为“词”或“标记”(tokens)。分词处理是文本分析的基础,因为大多数NLP任务都需要在词级别上进行操作,例如文本分类、情感分析、机器翻译等。
中文分词使用了jieba库
jieba 是一个非常流行的 Python 中文分词库,主要用于将中文文本切分成单个词语。它支持多种分词模式,并提供了丰富的功能来满足不同的自然语言处理需求。
主要功能和特点:
分词模式:
精确模式:将文本精确地切分成单个词语,适合用于文本分析。
全模式:将文本中所有可能的词语都扫描出来,速度非常快,但可能存在冗余数据。
搜索引擎模式:在精确模式的基础上,对长词再次进行切分,提高召回率,适合用于搜索引擎分词。
自定义词典:用户可以通过自定义词典来增加新词,以提高分词的准确性。
关键词提取:jieba 提供了基于 TF-IDF 算法的关键词提取功能,可以从文本中提取出最重要的词。
词性标注:通过 jieba.posseg 模块,可以在分词的同时获取词性信息。
并行分词:支持并行分词,以提高分词速度
。
四、创建向量数据库
def create_vector_store(tokenized_texts: List[List[str]], embeddings_model: OllamaEmbeddings) -> FAISS:"""将分词后的文本创建向量库"""try:# 将分词列表转换回文本processed_texts = [' '.join(tokens) for tokens in tokenized_texts]# 批量处理优化batch_size = 100 # 可以根据实际情况调整vectors = []# # 如果有 GPU# if FAISS.get_num_gpus():# res = FAISS.StandardGpuResources()# index = FAISS.index_cpu_to_gpu(res, 0, index)for i in tqdm(range(0, len(processed_texts), batch_size), desc="创建向量数据库"):batch = processed_texts[i:i + batch_size]# 批量创建向量vector_store = FAISS.from_texts(texts=batch,embedding=embeddings_model,metadatas=[{"index": j} for j in range(i, i + len(batch))] # 添加元数据以追踪文档)vectors.append(vector_store)# 如果有多个批次,合并它们if len(vectors) > 1:final_vector_store = vectors[0]for v in vectors[1:]:final_vector_store.merge_from(v)else:final_vector_store = vectors[0]# 保存向量库到本地final_vector_store.save_local("resume_vectors")return final_vector_storeexcept Exception as e:print(f"创建向量库时发生错误: {str(e)}")raise
五、初始化语言聊天模型
刚刚就是制作了向量数据库,这是大模型的第一步,下面还需要有明确的提示词prompt
1.prompt
2.检索链
检索链(Retrieval Chain)是一种在信息检索和自然语言处理中使用的技术流程,主要用于从大规模数据集中高效地找到与用户查询最相关的信息片段或文档
3.对话
使用一个while循环始终在对话中
完整代码
import os
import jieba
import re
from typing import List
import pdf
# from langchain_community.embeddings import OpenAIEmbeddings
from langchain_community.embeddings import OllamaEmbeddings
from langchain_community.vectorstores import FAISS
from langchain_community.llms import Ollama
from tqdm import tqdm from loguru import logger
from magic_pdf.data.data_reader_writer import FileBasedDataWriter
from magic_pdf.pipe.UNIPipe import UNIPipeimport nltk
# 下载punkt
nltk.download('punkt')# 设置 OpenAI API 密钥
# os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY")
# 创建 OpenAI API 密钥
api_key = "sk-xxx"
os.environ["OPENAI_API_KEY"] = api_key# 定义简历文件夹路径
resume_folder = "./data/demo"# 读取 PDF 文件并提取文本
# def extract_text_from_pdfs(folder_path):
# texts = []
# for filename in os.listdir(folder_path):
# if filename.endswith(".pdf"):
# with open(os.path.join(folder_path, filename), "rb") as file:
# reader = PyPDF2.PdfReader(file)
# text = ""
# for page in reader.pages:
# text += page.extract_text()
# texts.append(text)
# return texts# 读取markdown文件并提取文本
def extract_text_from_markdown(folder_path):texts = []for filename in os.listdir(folder_path):if filename.endswith(".md"):with open(os.path.join(folder_path, filename), "r", encoding="utf-8") as file:text = file.read()texts.append(text)return textsdef clean_text(text: str) -> str:"""清理文本,移除特殊字符和多余的空白"""# 替换多个空白字符为单个空格text = re.sub(r'\s+', ' ', text)# 移除特殊字符,保留中文、英文、数字和基本标点text = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9.,!?;:,。!?;:]', ' ', text)return text.strip()def tokenize_texts(texts: List[str]) -> List[List[str]]:"""对文本进行分词处理""Args:texts: 要处理的文本列表Returns:处理后的分词列表"""tokenized_texts = []for text in texts:# 清理文本cleaned_text = clean_text(text)# 分别处理中文和英文words = []# 使用jieba进行中文分词segments = jieba.cut(cleaned_text)# 过滤空字符串和纯空白字符words = [word for word in segments if word.strip()]# 移除停用词(可选)# words = [word for word in words if word not in stopwords]tokenized_texts.append(words)return tokenized_textsdef create_vector_store(tokenized_texts: List[List[str]], embeddings_model: OllamaEmbeddings) -> FAISS:"""将分词后的文本创建向量库"""try:# 将分词列表转换回文本processed_texts = [' '.join(tokens) for tokens in tokenized_texts]# 批量处理优化batch_size = 100 # 可以根据实际情况调整vectors = []# # 如果有 GPU# if FAISS.get_num_gpus():# res = FAISS.StandardGpuResources()# index = FAISS.index_cpu_to_gpu(res, 0, index)for i in tqdm(range(0, len(processed_texts), batch_size), desc="创建向量数据库"):batch = processed_texts[i:i + batch_size]# 批量创建向量vector_store = FAISS.from_texts(texts=batch,embedding=embeddings_model,metadatas=[{"index": j} for j in range(i, i + len(batch))] # 添加元数据以追踪文档)vectors.append(vector_store)# 如果有多个批次,合并它们if len(vectors) > 1:final_vector_store = vectors[0]for v in vectors[1:]:final_vector_store.merge_from(v)else:final_vector_store = vectors[0]# 保存向量库到本地final_vector_store.save_local("resume_vectors")return final_vector_storeexcept Exception as e:print(f"创建向量库时发生错误: {str(e)}")raise# 提取简历文本
resume_texts = extract_text_from_markdown(resume_folder)
# resume_texts = extract_text_from_pdfs(resume_folder)
print("简历文本提取完成")# 简历文本分词
tokenized_texts = tokenize_texts(resume_texts)
print(f"简历文本分词完成,共处理 {len(tokenized_texts)} 份文档")# 可以打印一些统计信息(可选)
for i, tokens in enumerate(tokenized_texts):print(f"文档 {i+1} 分词数量: {len(tokens)}")# 创建 OpenAI 嵌入
embeddings = OllamaEmbeddings(model="nomic-embed-text:latest",base_url='xxx')
print("ollama 嵌入完成~")# 创建向量库
vector_store = create_vector_store(tokenized_texts, embeddings)
print("向量库创建完成")# Initialize OpenAI model
# from langchain_community.chat_models import ChatOpenAI
# llm = ChatOpenAI(model='gpt-4o', temperature=0.1, api_key=os.environ.get("OPENAI_API_KEY"))from langchain_community.llms import Ollama
llm = Ollama(model="llama3.3:70b", temperature=0.1, num_ctx=60000,base_url='xxx')# Update imports
from langchain.chains import RetrievalQA # Changed from create_retrieval_qa_chain
from langchain.prompts import PromptTemplate # Import the necessary classPROMPT_TEMPLATE = """
已知信息:{context}。
"你是一个核聚变、人工智能、科学计算领域的人才鉴别专家,你具备管理大量简历的能力;请注意我向你提供了很多简历PDF文件,但每个PDF文件对应一个候选人,包括候选人的姓名、年龄、技能、经历、项目、成果等内容,请仔细识别各个信息。 \
现在需要你帮我分析每个候选人的详细信息,包括:年龄、教育程度、专业技能、职业履历、项目背景、研究成果、获得荣誉、发展潜力,然后帮我完成以下两个功能: \
1.当我给出开展项目的描述信息时,你能帮我准确地按照适配项目的优先级推荐相关候选人,每次允许按照优先级顺序推荐多个候选人,并且详细给出推荐原因,使用markdown的表格形式给出,包括以下信息:姓名、年龄、专业技能、推荐原因; \
2.当我需要分析一个候选人时,请你能进行客观、准确的评估,先描述其主要信息,然后按照:专业能力、科研成果、项目成绩、发展潜力、综合能力进行评分,每项总分100,结果以markown形式给出。 \
请务必注意每个简历仅对应一个候选人,切记不要混淆各个人的信息;1个候选人只需引用1次相关文档即可,仔细识别每个文档中候选人的姓名。"请回答以下问题:{question}
"""
# 创建提示模板
prompt_template = PromptTemplate(input_variables=["context", "question"],template=PROMPT_TEMPLATE
)# 创建检索链
chain_type_kwargs = {"prompt": prompt_template,"document_variable_name": "context",
}# 创建检索链
qa = RetrievalQA.from_chain_type(llm=llm,chain_type="stuff",retriever=vector_store.as_retriever(),chain_type_kwargs=chain_type_kwargs,
)def chat_loop():print("\n欢迎使用简历分析助手!")print("输入 'quit' 或 'exit' 结束对话")while True:# Get user inputuser_input = input("\n请输入您的问题: ").strip()# Check if user wants to exitif user_input.lower() in ['quit', 'exit']:print("感谢使用,再见!")breakif user_input:try:# Get the responseresult = qa.run(user_input)print("\n回答:")print(result)except Exception as e:print(f"发生错误: {str(e)}")continueif __name__ == "__main__":chat_loop()
相关文章:

RAG(Retrieval-Augmented Generation,检索增强生成)流程
目录 一、知识文档的准备二、OCR转换三、分词处理四、创建向量数据库五、初始化语言聊天模型1.prompt2.检索链3.对话 完整代码 知识文档的准备:首先需要准备知识文档,这些文档可以是多种格式,如Word、TXT、PDF等。使用文档加载器或多模态模型…...

【Python学习(六)——While、for、循环控制、指数爆炸】
Python学习(六)——While、for、循环控制、指数爆炸 本文介绍了While、for、循环控制、指数爆炸,仅作为本人学习时记录,感兴趣的初学者可以一起看看,欢迎评论区讨论,一起加油鸭~~~ 心中默念:Py…...

解释一下:运放的输入失调电流
输入失调电流 首先看基础部分:这就是同相比例放大器 按照理论计算,输入VIN=0时,输出VOUT应为0,对吧 仿真与理论差距较大,有200多毫伏的偏差,这就是输入偏置电流IBIAS引起的,接着看它的定义 同向和反向输入电流的平均值,也就是Ib1、Ib2求平均,即(Ib1+Ib2)/2 按照下面…...
力扣hot100——二分查找
35. 搜索插入位置 class Solution { public:int searchInsert(vector<int>& a, int x) {if (a[0] > x) return 0;int l 0, r a.size() - 1;while (l < r) {int mid (l r 1) / 2;if (a[mid] < x) l mid;else r mid - 1;}if (a[l] x) return l;else …...
PHP 使用集合 处理复杂数据 提升开发效率
在 PHP 中,集合(Collections)通常是通过数组或专门的集合类来实现的。 集合(Collection)是一种高级的数据结构,可以提供比普通数组更强大的操作和功能,特别是当你需要更复杂的数据处理时。 La…...

Unity 对Sprite或者UI使用模板测试扣洞
新建两个材质球: 选择如下材质 设置如下参数: 扣洞图片或者扣洞UI的材质球 Sprite或者UI的材质球 新建一个单独Hole的canvas,将SortOrder设置为0,并将原UI的canvans的SortOrder设置为1 对2DSprite则需要调整下方的参数 hole的O…...

unity学习3:如何从github下载开源的unity项目
目录 1 网上别人提供的一些github的unity项目 2 如何下载github上的开源项目呢? 2.1.0 下载工具 2.1.1 下载方法1 2.1.2 下载方法2(适合内部项目) 2.1.3 第1个项目 和第4项目 的比较 第1个项目 第2个项目 第3个项目 2.1.4 下载方法…...

PHP后执行php.exe -v命令报错并给出解决方案
文章目录 一、执行php.exe -v命令报错解决方案 一、执行php.exe -v命令报错 -PHP Warning: ‘C:\windows\SYSTEM32\VCRUNTIME140.dll’ 14.38 is not compatible with this PHP build linked with 14.41 in Unknown on line 0 解决方案 当使用PHP8.4.1时遇到VCRUNTIME140.dll…...

CDP集群安全指南-动态数据加密
[〇]关于本文 集群的动态数据加密主要指的是加密通过网络协议传输的数据,防止数据在传输的过程中被窃取。由于大数据涉及的主机及服务众多。你需要更具集群的实际环境来评估需要为哪些环节实施动态加密。 这里介绍一种通过Cloudera Manager 的Auto-TLS功能来为整个…...
【shell编程】报错信息:Undefined Variable(包含6种解决方法)
大家好,我是摇光~ 当Shell脚本报错“Undefined Variable”时,是未定义变量的意思。 以下是对每个可能原因及其对应详细解决方案的详细解释: 原因1:拼写错误 原因: 脚本中变量名的拼写在使用和定义时不一致。例如&…...

Dubbo扩展点加载机制
加载机制中已经存在的一些关键注解,如SPI、©Adaptive> ©Activateo然后介绍整个加载机制中最核心的ExtensionLoader的工作流程及实现原理。最后介绍扩展中使用的类动态编译的实 现原理。 Java SPI Java 5 中的服务提供商https://docs.oracle.com/jav…...

unity学习7:unity的3D项目的基本操作: 坐标系
目录 学习参考 1 unity的坐标系 1.1 左手坐标系 1.2 左手坐标系和右手坐标系的区别 1.3 坐标系的原点(0,0,0) 2 坐标系下的具体xyz坐标 2.1 position这里的具体xyz坐标值 2.2 父坐标 2.3 世界坐标和相对坐标 2.3.1 世界坐标 2.3.2 相对坐标 2.4 父物体,…...

PyTorch框架——基于深度学习EfficientDeRain神经网络AI去雨滴图像增强系统
第一步:EfficientDeRain介绍 EfficientDeRain 是一个针对单张图像去雨的开源项目,该项目由清华大学的研究团队提出,主要用于处理图像中的雨水干扰,恢复图像的真实场景 核心功能 图像去雨:EfficientDeRain 通过学习像素…...
写一个类模板三个模板参数K,V,M,参数是函数(函数参数、lambda传参、函数指针)
cal是类的成员函数。cal的3个入参是func1(K),func2(K,V),func3(K,V,M),请写出cal,并在main函数中调用cal 在您给出的要求中,cal成员函数并不直接…...

国内Ubuntu环境Docker部署Stable Diffusion入坑记录
国内Ubuntu环境Docker部署Stable Diffusion入坑记录 本文旨在记录使用dockerpython进行部署 stable-diffusion-webui 项目时遇到的一些问题,以及解决方案,原项目地址: https://github.com/AUTOMATIC1111/stable-diffusion-webui 问题一览: …...
现代光学基础6
总结自老师的ppt yt6 半导体激光器开卷考试学习资料 目录 半导体激光器边发射半导体激光器垂直腔面发射激光器(VCSEL)激光产生条件(激光原理)半导体激光器的水容器模型有源半导体区域类型和载流子注入发光二极管(L…...

解决HBuilderX报错:未安装内置终端插件,是否下载?或使用外部命令行打开。
版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl 错误描述 在HBuilderX中执行npm run build总是提醒下载插件;图示如下: 但是,下载总是失败。运行项目时候依然弹出上述提醒。 解决方案 …...

基于Java的超级玛丽游戏的设计与实现【源码+文档+部署讲解】
目 录 1、绪论 1.1背景以及现状 1.2 Java语言的特点 1.3 系统运行环境及开发软件: 1.4 可行性的分析 1.4.1 技术可行性 1.4.2 经济可行性 1.4.3 操作可行性 2、 需求分析 2.1 用户需求分析 2.2功能需求分析 2.3界面设计需求分析…...
Spring Boot项目中使用单一动态SQL方法可能带来的问题
1. 查询计划缓存的影响 深入分析 数据库系统通常会对常量SQL语句进行编译并缓存其执行计划以提高性能。对于动态生成的SQL语句,由于每次构建的SQL字符串可能不同,这会导致查询计划无法被有效利用,从而需要重新解析、优化和编译,…...

conan从sourceforge.net下载软件失败
从sourceforge.net下载软件,经常会没有开始下载就返回了。 原因是: 自动选择的镜像站不能打开。 在浏览器中,我们可以手动选择站点尝试,但是conan就不行了。 手动选择一个站点,能够有文件保存窗口弹出,之后…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...

2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...

网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用
文章目录 一、背景知识:什么是 B-Tree 和 BTree? B-Tree(平衡多路查找树) BTree(B-Tree 的变种) 二、结构对比:一张图看懂 三、为什么 MySQL InnoDB 选择 BTree? 1. 范围查询更快 2…...