从零开始搭建RAG系统系列(三):数据准备与预处理

步骤一:数据准备与预处理

  • 目标:将我们的原始知识文档(例如,一组关于某个开源项目的介绍文档,可能是TXT或PDF格式)加载进来,并将其分割成适合RAG系统处理的、带有元数据的文本块(chunks)。

具体操作:

1. 数据加载(Data Loading)

我们需要从文件系统中加载文档。Lang Chain提供了多种DocumentLoader`来处理不同类型的文件。

首先,假设我们有一个名为knowledge_base`的文件夹,里面存放了我们的知识文档。例如,可以创建两个简单的.txt文件:

knowledge_base/project_intro.txt:
RAGFlow是一个基于Python的开源检索增强生成框架。

它致力于简化RAG应用的开发、评估和部署流程。

RAGFlow的核心特性包括模块化设计、多种检索策略支持以及易于扩展的接口。

该项目由ABCLab于2024年发起。
knowledge_base/features.txt:
RAGFlow的主要功能包括:

  1. 数据接⼊:⽀持PDF, TXT, Markdown等多种⽂档格式。
  2. 智能分块:提供多种⽂本分割策略,如递归分割、语义分割。
  3. 向量化与索引:集成主流Embedding模型和向量数据库。
  4. 灵活检索:⽀持向量检索、关键词检索及混合检索。
  5. LLM集成:⽅便对接OpenAI、HuggingFace等多种⼤语⾔模型。
  6. 评估套件:内置常⽤RAG评估指标和⼯具。

现在,我们使⽤LangChain的 DirectoryLoaderTextLoader 来加载这些⽂档

ini 复制代码
from langchain_community.document_loaders import DirectoryLoader, TextLoader
from langchain_core.documents import Document # Document type
from typing import List
# 定义知识库⽬录
knowledge_base_path = "./knowledge_base"
# 注意:请确保在Python脚本的同级⽬录下创建 knowledge_base ⽂件夹,并将上述txt⽂件放⼊其
# 使⽤DirectoryLoader加载⽬录下所有.txt⽂件,指定使⽤TextLoader
loader = DirectoryLoader(
knowledge_base_path,
glob="**/*.txt", # 匹配所有txt⽂件
loader_cls=TextLoader, # 使⽤TextLoader加载
loader_kwargs={'encoding': 'utf-8'}, # TextLoader的参数,确保UTF-8编码
use_multithreading=True, # 可以加速加载多个⽂件
show_progress=True # 显⽰加载进度
)
documents: List[Document] = loader.load()
if documents:print(f"成功加载 {len(documents)} 个⽂档.")
for i, doc in enumerate(documents):
print(f"\n--- ⽂档 {i+1}: {doc.metadata.get('source', '未知来源')} ---
print(f"内容预览 (前100字符): {doc.page_content[:100]}")
else:
print(f"未能从 '{knowledge_base_path}' 加载到任何⽂档。请检查路径和⽂件。")
# 对于PDF⽂件加载,可以使⽤PyPDFLoader (需要 pip install pypdf)
# from langchain_community.document_loaders import PyPDFLoader
# pdf_loader = PyPDFLoader("path/to/your/document.pdf")
# pdf_documents = pdf_loader.load()

说明:DirectoryLoader可以方便地加载整个目录的文件。每个加载的Document对象通常包含两部分:page_content(文档的文本内容)和metadata(一个字典,通常包含如 source等元信息,即文件名)。

2.文本分割(Text Splitting)

长文档需要被切分成更小的语义单元(chunks), 以便Embedding模型处理并提高检索的精确性。LangChain的 RecursiveCharacterTextSplitter是一个常用的选择,它会尝试按预设的一系列分隔符(如换行符、句号等)递归地分割文本,以求在满足大小限制的同时尽量保持语义的完整性。

上图展⽰了⽂本分割的过程。⻓⽂档被切分成较⼩的⽂本块 (chunks)。相邻⽂本块之间通常设置重叠(overlap)部分(⽰例中红⾊字体为上⼀块的重叠内容,绿⾊字体为与下⼀块的重叠内容),以确保语义的连续性,避免关键信息在分割点被割裂。

ini 复制代码
from langchain.text_splitter import RecursiveCharacterTextSplitter

# 初始化⽂本分割器

text_splitter = RecursiveCharacterTextSplitter(

chunk_size=200, # 每个块的最⼤字符数。应根据Embedding模型和LLM的上下⽂窗⼝进⾏调

# 对于中⽂,⼀个汉字通常算1个token,但具体取决于模型的分词器。

# BGE等模型通常有512 tokens的输⼊限制。

chunk_overlap=20, # 相邻块之间的重叠字符数,帮助保留上下⽂连贯性。

separators=["\n\n", "\n", "。", "!", "?", ",", "、", " ", ""], # 中⽂场景

length_function=len, # 使⽤字符⻓度计算chunk_size

add_start_index=True # 在metadata中添加块在原⽂中的起始位置,可选

)

if documents: # 确保前⾯加载成功

document_chunks: List[Document] = text_splitter.split_documents(document

print(f"\n⽂档被分割成 {len(document_chunks)} 个⽂本块.")

if document_chunks:

print(f"第⼀个⽂本块预览: {document_chunks[0].page_content}")

print(f"第⼀个⽂本块元数据: {document_chunks[0].metadata}")

else:

print("没有⽂档可供分割。")

document_chunks = [] # 初始化为空列表以防后续代码出错

说明::chunk_size 和 chunk_overlap 的选择对RAG性能有显著影响,需要根据具体数据、Embedding模型的能力以及LLM的上下文窗口大小进行实验调整。对于中文文本,合理设置separators尤为重要,以尽可能在自然的语义边界(如段落、句子)进行切分。

相关推荐
一水鉴天14 小时前
整体设计 定稿 之6 完整设计文档讨论及定稿 之4 整体设计数据库设计规范(含两个版本)
开发语言·人工智能·架构
第六五14 小时前
语音信号的时域、频域与时频域特征
人工智能·语音识别
正经教主14 小时前
【Trae+AI】和Trae学习搭建App_2.1:第3章·手搓后端基础框架Express
人工智能·后端·学习·express
梁辰兴14 小时前
OpenAI更新ChatGPT Images:生成速度最高提升4倍,原生多模态模型
人工智能·科技·ai·chatgpt·大模型·openai·图像生成
古城小栈14 小时前
边缘大模型本地部署与推理实战:以GPT-OSS-20B为例
人工智能·gpt·语言模型·边缘计算
感谢地心引力14 小时前
【AI】免费的代价?Google AI Studio 使用指南与 Cherry Studio + MCP 实战教程
人工智能·ai·google·chatgpt·gemini·mcp·cherry studio
Tezign_space14 小时前
SEO优化与AI内容运营的技术融合:架构、算法与实施路径
人工智能·架构·内容运营·私域运营·ai内容生成·seo流量增长·内容运营效率
小苑同学14 小时前
PaperReding:《LLaMA: Open and Efficient Foundation Language Models》
人工智能·语言模型·llama
geneculture14 小时前
融智学体系图谱(精确对应版)
大数据·人工智能·学习·融智学的重要应用·信智序位
业精于勤的牙14 小时前
浅谈:算法中的斐波那契数(六)
人工智能·算法