当前位置: 首页 > article >正文

【RAG】RAG 系统的基本搭建流程(ES关键词检索示例)

RAG 系统的基本搭建流程

搭建过程:

  1. 文档加载,并按一定条件切割成片段
  2. 将切割的文本片段灌入检索引擎
  3. 封装检索接口
  4. 构建调用流程:Query -> 检索 -> Prompt -> LLM -> 回复

1. 文档的加载与切割

# !pip install --upgrade openai
# 安装 pdf 解析库
# !pip install pdfminer.six
from pdfminer.high_level import extract_pages
from pdfminer.layout import LTTextContainerdef extract_text_from_pdf(filename, page_numbers=None, min_line_length=1):'''从 PDF 文件中(按指定页码)提取文字'''paragraphs = []buffer = ''full_text = ''# 提取全部文本for i, page_layout in enumerate(extract_pages(filename)):# 如果指定了页码范围,跳过范围外的页if page_numbers is not None and i not in page_numbers:continuefor element in page_layout:if isinstance(element, LTTextContainer):full_text += element.get_text() + '\n'# 按空行分隔,将文本重新组织成段落lines = full_text.split('\n')for text in lines:if len(text) >= min_line_length:buffer += (' '+text) if not text.endswith('-') else text.strip('-')elif buffer:paragraphs.append(buffer)buffer = ''if buffer:paragraphs.append(buffer)return paragraphsparagraphs = extract_text_from_pdf("llama2.pdf", min_line_length=10)for para in paragraphs[:4]:print(para+"\n")
######
##输出:
Llama 2: Open Foundation and Fine-Tuned Chat ModelsHugo Touvron∗ Louis Martin† Kevin Stone† Peter Albert Amjad Almahairi Yasmine Babaei Nikolay Bashlykov Soumya Batra Prajjwal Bhargava Shruti Bhosale Dan Bikel Lukas Blecher Cristian Canton Ferrer Moya Chen Guillem Cucurull David Esiobu Jude Fernandes Jeremy Fu Wenyin Fu Brian Fuller Cynthia Gao Vedanuj Goswami Naman Goyal Anthony Hartshorn Saghar Hosseini Rui Hou Hakan Inan Marcin Kardas Viktor Kerkez Madian Khabsa Isabel Kloumann Artem Korenev Punit Singh Koura Marie-Anne Lachaux Thibaut Lavril Jenya Lee Diana Liskovich Yinghai Lu Yuning Mao Xavier Martinet Todor Mihaylov Pushkar Mishra Igor Molybog Yixin Nie Andrew Poulton Jeremy Reizenstein Rashi Rungta Kalyan Saladi Alan Schelten Ruan Silva Eric Michael Smith Ranjan Subramanian Xiaoqing Ellen Tan Binh Tang Ross Taylor Adina Williams Jian Xiang Kuan Puxin Xu Zheng Yan Iliyan Zarov Yuchen Zhang Angela Fan Melanie Kambadur Sharan Narang Aurelien Rodriguez Robert Stojnic Sergey Edunov Thomas Scialom∗GenAI, Meta

这段代码实现了从PDF文档中提取文本并按段落进行切割的功能,是构建RAG(检索增强生成)系统中文档处理的关键步骤。下面详细解析其工作原理和实现逻辑:


1. 环境准备

# !pip install --upgrade openai
# !pip install pdfminer.six
from pdfminer.high_level import extract_pages
from pdfminer.layout import LTTextContainer
  • pdfminer.six:PDF解析库,用于提取PDF中的文本和布局信息。
  • extract_pages:逐页解析PDF文档。
  • LTTextContainer:识别PDF中的文本块(段落或文字区域)。

2. 核心函数 extract_text_from_pdf

输入参数
  • filename:PDF文件路径。
  • page_numbers:指定提取的页码范围(可选)。
  • min_line_length:最小行长度阈值,用于过滤无意义的短行(如页码或页眉)。

步骤解析
步骤1:逐页提取文本
for i, page_layout in enumerate(extract_pages(filename)):if page_numbers is not None and i not in page_numbers:continuefor element in page_layout:if isinstance(element, LTTextContainer):full_text += element.get_text() + '\n'
  • 遍历PDF每一页,通过LTTextContainer识别文本块。
  • 将文本块内容拼接为full_text,并用换行符分隔不同文本块。
步骤2:处理换行与断词
lines = full_text.split('\n')
for text in lines:if len(text) >= min_line_length:buffer += (' '+text) if not text.endswith('-') else text.strip('-')elif buffer:paragraphs.append(buffer)buffer = ''
  • 断词处理:若行以连字符-结尾,表示单词跨行,需拼接(如"inter- esting"合并为"interesting")。
  • 空格拼接:普通行首添加空格,避免直接拼接导致单词粘连。
步骤3:段落切割
  • 当遇到短行(如空行或页眉),将buffer中的内容作为一个段落存入paragraphs
  • 遍历结束后,检查buffer是否剩余内容并存入。

3. 代码调用示例

paragraphs = extract_text_from_pdf("llama2.pdf", min_line_length=10)
for para in paragraphs[:4]:print(para+"\n")
  • 提取llama2.pdf中所有页的文本,过滤长度小于10的短行。
  • 打印前4个段落,验证输出效果。

4. 设计优缺点

设计优点
  • 跨页处理:自动合并跨页的段落。
  • 断词修复:处理因换行导致的单词拆分。
  • 灵活过滤:通过min_line_length过滤无意义短行。
局限性
  • 依赖PDF结构:若PDF使用非标准布局(如分栏、图片内文字),提取可能不准确。
  • 段落切割逻辑:依赖空行或短行分割段落,对无空行的长文本可能不够鲁棒。

5. 拓展建议

  • 布局分析:结合LTFigureLTImage处理图片中的文本。
  • 高级分段:使用NLP工具(如spacy)基于语义分割段落。
  • 并行处理:对大文档采用多线程加速解析。

通过这段代码,可以实现基础的PDF文本提取与段落切割,为后续的向量化存储和检索增强生成(RAG)奠定基础。实际应用中需结合具体文档结构调整参数和逻辑。

2. 检索引擎

先看一个最基础的ES实现

pip install elasticsearch7# 安装 NLTK(文本处理方法库)pip install nltk
from elasticsearch7 import Elasticsearch, helpers
from nltk.stem import PorterStemmer
from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords
import nltk
import reimport warnings
warnings.simplefilter("ignore")  # 屏蔽 ES 的一些Warningsnltk.download('punkt')  # 英文切词、词根、切句等方法
nltk.download('stopwords')  # 英文停用词库
nltk.download('punkt_tab')def to_keywords(input_string):'''(英文)文本只保留关键字'''# 使用正则表达式替换所有非字母数字的字符为空格no_symbols = re.sub(r'[^a-zA-Z0-9\s]', ' ', input_string)word_tokens = word_tokenize(no_symbols)# 加载停用词表stop_words = set(stopwords.words('english'))ps = PorterStemmer()# 去停用词,取词根filtered_sentence = [ps.stem(w)for w in word_tokens if not w.lower() in stop_words]return ' '.join(filtered_sentence)
# 此处 to_keywords 为针对英文的实现,针对中文的实现请参考 chinese_utils.py

将文本灌入检索引擎

import os, time# 引入配置文件
ELASTICSEARCH_BASE_URL = os.getenv('ELASTICSEARCH_BASE_URL')
ELASTICSEARCH_PASSWORD = os.getenv('ELASTICSEARCH_PASSWORD')
ELASTICSEARCH_NAME= os.getenv('ELASTICSEARCH_NAME')# 1. 创建Elasticsearch连接
es = Elasticsearch(hosts=[ELASTICSEARCH_BASE_URL],  # 服务地址与端口http_auth=(ELASTICSEARCH_NAME, ELASTICSEARCH_PASSWORD),  # 用户名,密码
)# 2. 定义索引名称
index_name = "teacher_demo_index111"# 3. 如果索引已存在,删除它(仅供演示,实际应用时不需要这步)
if es.indices.exists(index=index_name):es.indices.delete(index=index_name)# 4. 创建索引
es.indices.create(index=index_name)# 5. 灌库指令
actions = [{"_index": index_name,"_source": {"keywords": to_keywords(para),"text": para}}for para in paragraphs
]# 6. 文本灌库
helpers.bulk(es, actions)# 灌库是异步的
time.sleep(2)

实现关键字检索

def search(query_string, top_n=3):# ES 的查询语言search_query = {"match": {"keywords": to_keywords(query_string)}}res = es.search(index=index_name, query=search_query, size=top_n)return [hit["_source"]["text"] for hit in res["hits"]["hits"]]results = search("how many parameters does llama 2 have?", 2)
for r in results:print(r+"\n")### 输出1. Llama 2, an updated version of Llama 1, trained on a new mix of publicly available data. We also increased the size of the pretraining corpus by 40%, doubled the context length of the model, and adopted grouped-query attention (Ainslie et al., 2023). We are releasing variants of Llama 2 with 7B, 13B, and 70B parameters. We have also trained 34B variants, which we report on in this paper but are not releasing.§

3. LLM接口封装

from openai import OpenAI
import os
# 加载环境变量
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())  # 读取本地 .env 文件,里面定义了 OPENAI_API_KEYclient = OpenAI()
#%%
def get_completion(prompt, model="gpt-3.5-turbo"):'''封装 openai 接口'''messages = [{"role": "user", "content": prompt}]response = client.chat.completions.create(model=model,messages=messages,temperature=0,  # 模型输出的随机性,0 表示随机性最小)return response.choices[0].message.content

4. Prompt模版

def build_prompt(prompt_template, **kwargs):'''将 Prompt 模板赋值'''inputs = {}for k, v in kwargs.items():if isinstance(v, list) and all(isinstance(elem, str) for elem in v):val = '\n\n'.join(v)else:val = vinputs[k] = valreturn prompt_template.format(**inputs)
prompt_template = """
你是一个问答机器人。
你的任务是根据下述给定的已知信息回答用户问题。已知信息:
{context}用户问:
{query}如果已知信息不包含用户问题的答案,或者已知信息不足以回答用户的问题,请直接回复"我无法回答您的问题"。
请不要输出已知信息中不包含的信息或答案。
请用中文回答用户问题。
"""

5. RAG Pipeline

user_query = "how many parameters does llama 2 have?"# 1. 检索
search_results = search(user_query, 2)# 2. 构建 Prompt
prompt = build_prompt(prompt_template, context=search_results, query=user_query)
print("===Prompt===")
print(prompt)# 3. 调用 LLM
response = get_completion(prompt)print("===回复===")
print(response)
===Prompt===你是一个问答机器人。
你的任务是根据下述给定的已知信息回答用户问题。已知信息:1. Llama 2, an updated version of Llama 1, trained on a new mix of publicly available data. We also increased the size of the pretraining corpus by 40%, doubled the context length of the model, and adopted grouped-query attention (Ainslie et al., 2023). We are releasing variants of Llama 2 with 7B, 13B, and 70B parameters. We have also trained 34B variants, which we report on in this paper but are not releasing.§In this work, we develop and release Llama 2, a collection of pretrained and fine-tuned large language models (LLMs) ranging in scale from 7 billion to 70 billion parameters. Our fine-tuned LLMs, called Llama 2-Chat, are optimized for dialogue use cases. Our models outperform open-source chat models on most benchmarks we tested, and based onour human evaluations for helpfulness and safety, may be a suitable substitute for closed source models. We provide a detailed description of our approach to fine-tuning and safety improvements of Llama 2-Chat in order to enable the community to build on our work and contribute to the responsible development of LLMs.用户问:
how many parameters does llama 2 have?如果已知信息不包含用户问题的答案,或者已知信息不足以回答用户的问题,请直接回复"我无法回答您的问题"。
请不要输出已知信息中不包含的信息或答案。
请用中文回答用户问题。===回复===
Llama 2有7B, 13B和70B参数。

扩展:

Elasticsearch(简称ES)是一个广泛应用的开源搜索引擎: https://www.elastic.co/

关于ES的安装、部署等知识,网上可以找到大量资料,例如: https://juejin.cn/post/7104875268166123528

关于经典信息检索技术的更多细节,可以参考: https://nlp.stanford.edu/IR-book/information-retrieval-book.html

6. 关键字检索的局限性

同一个语义,用词不同,可能导致检索不到有效的结果

# user_query="Does llama 2 have a chat version?"
user_query = "Does llama 2 have a conversational variant?"search_results = search(user_query, 2)for res in search_results:print(res+"\n")
1. Llama 2, an updated version of Llama 1, trained on a new mix of publicly available data. We also increased the size of the pretraining corpus by 40%, doubled the context length of the model, and adopted grouped-query attention (Ainslie et al., 2023). We are releasing variants of Llama 2 with 7B, 13B, and 70B parameters. We have also trained 34B variants, which we report on in this paper but are not releasing.§variants of this model with 7B, 13B, and 70B parameters as well.

相关文章:

【RAG】RAG 系统的基本搭建流程(ES关键词检索示例)

RAG 系统的基本搭建流程 搭建过程: 文档加载,并按一定条件切割成片段将切割的文本片段灌入检索引擎封装检索接口构建调用流程:Query -> 检索 -> Prompt -> LLM -> 回复 1. 文档的加载与切割 # !pip install --upgrade openai…...

记录小白使用 Cursor 开发第一个微信小程序(二):创建项目、编译、预览、发布(250308)

文章目录 记录小白使用 Cursor 开发第一个微信小程序(二):创建项目、编译、预览、发布(250308)一、创建项目1.1 生成提示词1.2 生成代码 二、编译预览2.1 导入项目2.2 编译预览 三、发布3.1 在微信开发者工具进行上传3…...

游戏引擎学习第146天

音高变化使得对齐读取变得不可能,我们可以支持循环声音了。 我们今天的目标是完成之前一段时间所做的音频代码。这个项目并不依赖任何引擎或库,而是一个教育项目,目的是展示从头到尾运行一个游戏所需要的全部代码。无论你对什么方面感兴趣&a…...

nodejs关于后端服务开发的探究

前提 在当前的环境中关于web server的主流开发基本上都是java、php之类的,其中java spring系列基本上占了大头,而python之流也在奋起直追,但别忘了nodejs也是可以做这个服务的,只是位置有点尴尬,现在就来探究下nodejs…...

Java 大视界 -- Java 大数据在智能体育赛事运动员表现分析与训练优化中的应用(122)

💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...

线性代数之矩阵特征值与特征向量的数值求解方法

文章目录 前言1. 幂迭代法(Power Iteration)幂法与反幂法求解矩阵特征值幂法求最大特征值编程实现补充说明 2. 逆幂迭代法(Inverse Iteration)移位反幂法 3. QR 算法(QR Algorithm)——稠密矩阵理论推导编程…...

SparkAi系统体验

DeepSeek-R1-671B大模型满血版私有化部署高可用教程-SparkAi系统集成图文教程 一、SparkAI是什么二、功能模块介绍系统快速体验 三、系统功能模块3.1 AI全模型支持/插件系统3.2 AI智能体应用3.3 AI专业绘画3.4 AI视频生成3.5 Dall-E2/E3/E4绘画3.6 智能思维导图生成3.7 AI绘画广…...

软件工程---构件

在软件工程中,构件是一个独立的、可复用的软件单元,它具有明确的功能、接口和行为,并且可以在不同的环境中加以集成和复用。构件的概念是软件架构和组件化开发的核心思想之一,其目的是促进软件系统的模块化、可维护性和可扩展性。…...

视频录像机视频通道是指什么

视频录像机的视频通道是指摄像机在监控矩阵或硬盘录像机设备上的视频输入的物理位置。 与摄像头数量关系:在视频监控系统中,有多少个摄像头就需要多少路视频通道,通道数量决定了视频录像机可接入摄像头的数量,一般硬盘录像机有4路…...

【Unity】 HTFramework框架(六十一)Project窗口文件夹锁定器

更新日期:2025年3月7日。 Github源码:[点我获取源码] Gitee源码:[点我获取源码] 索引 Project窗口文件夹锁定器框架文件夹锁定自定义文件夹锁定限制条件 Project窗口文件夹锁定器 在Project窗口中,文件夹锁定器能够为任何文件夹加…...

INFINI Labs 产品更新 | Easysearch 增加异步搜索等新特性

INFINI Labs 产品更新发布!此次更新,Easysearch 增加了新的功能和数据类型,包括 wildcard 数据类型、Point in time 搜索 API、异步搜索 API、数值和日期字段的 doc-values 搜索支持,Console 新增了日志查询功能。 INFINI Easyse…...

3.6c语言

#define _CRT_SECURE_NO_WARNINGS #include <math.h> #include <stdio.h> int main() {int sum 0,i,j;for (j 1; j < 1000; j){sum 0;for (i 1; i < j; i){if (j % i 0){sum i;} }if (sum j){printf("%d是完数\n", j);}}return 0; }#de…...

基于Kubernetes部署MySQL主从集群

以下是一个基于Kubernetes部署MySQL主从集群的详细YAML示例&#xff0c;包含StatefulSet、Service、ConfigMap和Secret等关键配置。MySQL主从集群需要至少1个主节点和多个从节点&#xff0c;这里使用 StatefulSet 初始化脚本 实现主从自动配置。 1. 创建 Namespace (可选) ap…...

Docker基础篇——Ubuntu下Docker安装

大家好我是木木&#xff0c;在当今快速发展的云计算与云原生时代&#xff0c;容器化技术蓬勃兴起&#xff0c;Docker 作为实现容器化的主流工具之一&#xff0c;为开发者和运维人员带来了极大的便捷 。下面我们一起进行Docker安装。 Docker的官方Ubuntu安装文档&#xff0c;如…...

postman接口请求中的 Raw是什么

前言 在现代的网络开发中&#xff0c;API 的使用已经成为数据交换的核心方式之一。然而&#xff0c;在与 API 打交道时&#xff0c;关于如何发送请求体&#xff08;body&#xff09;内容类型的问题常常困扰着开发者们&#xff0c;尤其是“raw”和“json”这两个术语之间的区别…...

物联网设备接入系统后如何查看硬件实时数据?

要在软件中实时查看硬件设备的信息&#xff0c;通常需要结合前后端技术来实现。以下是设计思路和实现步骤&#xff1a; 1. 系统架构设计 实时查看硬件设备信息的系统通常采用以下架构&#xff1a; 数据采集层: 硬件设备通过传感器采集数据&#xff0c;发送到InfluxDB。数据存…...

最新版本TOMCAT+IntelliJ IDEA+MAVEN项目创建(JAVAWEB)

前期所需&#xff1a; 1.apache-tomcat-10.1.18-windows-x64&#xff08;tomcat 10.1.8版本或者差不多新的版本都可以&#xff09; 2.IntelliJ idea 24年版本 或更高版本 3.已经配置好MAVEN了&#xff08;一定先配置MAVEN再搞TOMCAT会事半功倍很多&#xff09; 如果有没配置…...

《生成对抗网络:当AI学会自我博弈的艺术》

2023年DALLE 2生成的《太空歌剧院》斩获艺术比赛大奖时&#xff0c;我在画作前驻足了整整十分钟——那些光影的渐变、笔触的韵律&#xff0c;竟来自两个神经网络的博弈游戏。这让我想起AlphaGo自我对弈突破人类棋谱局限的往事&#xff0c;生成对抗网络&#xff08;GAN&#xff…...

【Linux学习笔记】Linux基本指令分析和权限的概念

【Linux学习笔记】Linux基本指令分析和权限的概念 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;Linux学习笔记 文章目录 【Linux学习笔记】Linux基本指令分析和权限的概念前言一. 指令的分析1.1 alias 指令1.2 grep 指令1.3 zip/unzip 指…...

PHP之常用函数

在你有别的编程语言的基础下&#xff0c;你想学习PHP&#xff0c;可能要了解的一些关于常用函数的信息。 获取时间 //获取时间 后面跟自定义时间格式 echo date("Y-m-d H:i:s");删除变量 unset($a);判断变量是否存在 var_dump(isset($a));判断变量是否为null va…...

Leetcode 刷题记录 05 —— 普通数组

本系列为笔者的 Leetcode 刷题记录&#xff0c;顺序为 Hot 100 题官方顺序&#xff0c;根据标签命名&#xff0c;记录笔者总结的做题思路&#xff0c;附部分代码解释和疑问解答。 目录 01 最大子数组和 方法一&#xff1a;动态规划&#xff08;卡达尼算法&#xff09; 方法…...

【LLM】kimi 1.5模型架构和训练流程

note 推出两个多模态模型&#xff0c;深度思考模型 long-CoT 对标 o1&#xff0c;通用模型 short-CoT 模型对标 gpt-4o。 文章目录 note一、kimi 1.5模型训练流程预训练SFT训练long-CoT SFTRL训练long2short 小结Reference 一、kimi 1.5模型训练流程 推出两个多模态模型&…...

deepseek在pycharm中的配置和简单应用

对于最常用的调试python脚本开发环境pycharm&#xff0c;如何接入deepseek是我们窥探ai代码编写的第一步&#xff0c;熟悉起来总没坏处。 1、官网安装pycharm社区版&#xff08;免费&#xff09;&#xff0c;如果需要安装专业版&#xff0c;需要另外找破解码。 2、安装Ollama…...

第二十四天 学习分布式数据管理,了解如何在多个设备间共享数据

HarmonyOS分布式数据管理实战&#xff1a;轻松实现多设备数据共享 一、为什么需要分布式数据管理&#xff1f; 在万物互联的时代&#xff0c;我们的智能设备数量正在快速增长。根据IDC最新报告&#xff0c;2023年平均每个用户拥有6.2台智能设备。HarmonyOS的分布式能力正是为…...

Android15 Camera框架中的StatusTracker

StatusTracker介绍 StatusTracker是Android15 Camera框架中用来协调Camera3各组件之间状态转换的类。 StatusTracker线程名&#xff1a;std::string("C3Dev-") mId "-Status" Camera3 StatusTracker工作原理 StatusTracker实现批处理&#xff08;状态…...

MyBatis-Plus 注解大全

精心整理了最新的面试资料和简历模板&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 MyBatis-Plus 注解大全 MyBatis-Plus 是基于 MyBatis 的增强工具&#xff0c;通过注解简化了单表 CRUD 操作和复杂查询的配置。以下是常用注解的分类及详细说…...

【MySQL_03】数据库基本--核心概念

文章目录 一、数据库基础1.1 数据库基础定义1.2 数据库分类与典型产品1.3 数据库模型1.4 数据库层次结构1.5 数据库核心机制1.6 数据表和视图1.61 数据表&#xff08;Table&#xff09;1.62 视图&#xff08;View&#xff09; 1.7 键类型1.8 MySQL数据类型1.9 数据库范式化 二、…...

Ubuntu 下 nginx-1.24.0 源码分析 (1)

main 函数在 src\core\nginx.c int ngx_cdecl main(int argc, char *const *argv) {ngx_buf_t *b;ngx_log_t *log;ngx_uint_t i;ngx_cycle_t *cycle, init_cycle;ngx_conf_dump_t *cd;ngx_core_conf_t *ccf;ngx_debug_init(); 进入 main 函数 最…...

边缘计算盒子:解决交通拥堵的智能方案

在当今的智能交通系统中&#xff0c;边缘计算盒子&#xff08;Edge Computing Box&#xff09;正逐渐成为不可或缺的核心组件。这种设备通过将计算能力下沉到网络边缘&#xff0c;极大地提升了数据处理的速度和效率&#xff0c;特别适用于实时性要求极高的交通监控场景。本文将…...

工程化与框架系列(22)--前端性能优化(中)

前端性能优化&#xff08;运行&#xff09; &#x1f3c3; 引言 运行时性能直接影响用户交互体验和应用流畅度。本文将深入探讨前端运行时性能优化的各种策略和技术&#xff0c;包括渲染优化、内存管理、计算优化等关键主题&#xff0c;帮助开发者构建高性能的Web应用。 运行…...