多文档处理与ChromaDB持久化技巧
来到golang学习网的大家,相信都是编程学习爱好者,希望在这里学习文章相关编程知识。下面本篇文章就来带大家聊聊《LangChain多文档处理与ChromaDB持久化技巧》,介绍一下,希望对大家的知识积累有所帮助,助力实战开发!

本教程旨在解决LangChain中`TextLoader`和`CharacterTextSplitter`在处理多个文本文件及大型文本块时遇到的常见问题,如仅处理首个文档、分割失效及Chunk大小异常。我们将详细介绍如何利用`RecursiveCharacterTextSplitter`实现智能文本分割,并构建一个支持批量加载多类型文档的解决方案,最终将处理后的文本高效、可靠地持久化至ChromaDB向量数据库,确保LLM能准确检索所需信息。
在构建基于大型语言模型(LLM)的检索增强生成(RAG)系统时,准确高效地加载、分割和存储文档是至关重要的一步。然而,开发者在使用LangChain的TextLoader和CharacterTextSplitter时,常会遇到一些挑战,例如系统仅处理目录中的第一个文档、文本块(chunk)大小远超预期、以及后续文档未能被正确分割和存储,导致LLM无法检索到这些信息。
遇到的问题:LangChain文本加载与分割的常见挑战
在使用LangChain处理本地文档时,如果代码逻辑未能正确迭代处理所有文件,TextLoader默认可能只加载指定路径的单个文件。例如,以下代码片段在处理多个文件时,通常只会加载./folder/file.txt这一个文件,而忽略同目录下的其他文件。
loader = TextLoader("./folder/file.txt") # 明确指向单个文件
documents = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=300, chunk_overlap=0)
# texts = text_splitter.split_documents(documents) # 假设这里有split操作
chromaDirectory = "./folder/chroma_db"
# Chroma.from_documents(texts, embeddings, persist_directory=chromaDirectory)此外,CharacterTextSplitter在面对非常大的文本块时,可能会出现分割异常,例如即便设置了chunk_size=300,也可能生成远超此限制的文本块,甚至在处理后续文本时完全失效,不再进行分割。这通常是由于其基于简单字符分割的机制,对于结构复杂的文档或超长无分隔符的文本段落表现不佳。当这些未正确分割的文本被存储到向量数据库(如ChromaDB)中时,LLM在检索时自然无法找到相关信息,因为其上下文窗口和检索机制依赖于合理大小的文本块。
解决方案概述:多文档处理与智能文本分割
为了克服上述挑战,我们需要一套更健壮的文档加载和文本分割策略。核心解决方案包括:
- 批量加载多类型文档: 实现一个函数,能够遍历指定目录,识别并加载所有支持的文档类型(如.txt),而不仅仅是单个文件。
- 采用RecursiveCharacterTextSplitter: 替代CharacterTextSplitter,RecursiveCharacterTextSplitter能够根据一系列分隔符递归地分割文本,从而更好地处理结构复杂或长度不一的文本,确保文本块大小符合预期。
- 正确持久化ChromaDB: 确保ChromaDB的配置正确,特别是persist_directory和client_settings,以保证数据在程序运行结束后能够被保存。
逐步实现:构建健壮的文档处理流程
我们将通过以下步骤,构建一个能够高效处理多文档、智能分割文本并持久化到ChromaDB的完整流程。
1. 灵活的文档加载器
首先,定义一个映射表,用于支持不同文件类型的加载器。这使得我们的系统更具扩展性,可以轻松添加对.pdf、.docx等其他文件类型的支持。
import os
import glob
from typing import List
from langchain.docstore.document import Document
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.document_loaders import TextLoader
from langchain_community.vectorstores import Chroma # 使用 langchain_community 替代旧的 Chroma 导入
from langchain_openai import OpenAIEmbeddings # 假设使用OpenAI的嵌入模型
from chromadb.config import Settings
# 定义支持的文档加载器映射
DOC_LOADERS_MAPPING = {
".txt": (TextLoader, {"encoding": "utf8"}),
# 可以根据需要添加更多文档加载器,例如:
# ".pdf": (PyPDFLoader, {}),
# ".docx": (Docx2txtLoader, {}),
}
def load_document(path: str) -> Document:
"""
加载单个文档。
"""
try:
ext = "." + path.rsplit(".", 1)[-1]
if ext in DOC_LOADERS_MAPPING:
loader_class, loader_args = DOC_LOADERS_MAPPING[ext]
loader = loader_class(path, **loader_args)
# load() 方法返回一个 Document 列表,我们通常只取第一个
return loader.load()[0]
raise ValueError(f"不支持的文件扩展名: {ext}")
except Exception as exception:
raise ValueError(f"加载文档时发生错误 '{path}': {exception}")2. 批量加载目录文档
接着,实现一个函数来遍历指定目录及其子目录,查找所有支持的文件类型,并使用load_document函数批量加载它们。
def load_documents_from_dir(path: str) -> List[Document]:
"""
从指定目录加载所有支持的文档。
"""
try:
all_files = []
for ext in DOC_LOADERS_MAPPING:
# 递归查找目录中所有匹配扩展名的文件
all_files.extend(
glob.glob(os.path.join(path, f"**/*{ext}"), recursive=True)
)
# 批量加载文件
return [load_document(file_path) for file_path in all_files]
except Exception as exception:
raise RuntimeError(f"加载文件时发生错误: {exception}")3. 智能文本分割
现在,我们使用RecursiveCharacterTextSplitter来对加载的文档进行智能分割。它会尝试不同的分隔符(如\n\n, \n, `,.等),直到文本块大小符合预期,这比CharacterTextSplitter`更灵活和鲁棒。
# 加载所有文档
documents = load_documents_from_dir("./folder/")
# 初始化RecursiveCharacterTextSplitter
# chunk_size: 每个文本块的最大长度
# chunk_overlap: 相邻文本块之间的重叠字符数,有助于保持上下文连贯性
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=300,
chunk_overlap=50
)
# 分割文档
texts = text_splitter.split_documents(documents)4. 持久化到ChromaDB
最后一步是将分割后的文本块及其对应的嵌入(embeddings)存储到ChromaDB中。确保ChromaDB的persist_directory设置正确,并且通过client_settings明确指定持久化选项,以保证数据在程序关闭后不会丢失。
# 初始化嵌入模型,例如OpenAIEmbeddings
# 请确保已设置OPENAI_API_KEY环境变量
embeddings = OpenAIEmbeddings()
chroma_db_path = "./folder/chroma_db"
# 初始化ChromaDB并持久化
chroma_db = Chroma.from_documents(
texts,
embeddings,
persist_directory=chroma_db_path,
client_settings= Settings(
persist_directory=chroma_db_path,
chroma_db_impl="duckdb+parquet", # 指定ChromaDB的实现方式,确保持久化
anonymized_telemetry=False, # 关闭匿名遥测
),
)
# 显式调用persist()方法确保数据写入磁盘
chroma_db.persist()
# 清除内存中的ChromaDB实例(可选,但有助于释放资源)
chroma_db = None完整代码示例
将上述所有组件整合,形成一个完整的文档处理和ChromaDB持久化流程。
import os
import glob
from typing import List
from langchain.docstore.document import Document
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.document_loaders import TextLoader
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings # 假设使用OpenAI的嵌入模型
from chromadb.config import Settings
# --- 1. 定义支持的文档加载器映射 ---
DOC_LOADERS_MAPPING = {
".txt": (TextLoader, {"encoding": "utf8"}),
# 可以根据需要添加更多文档加载器
# ".pdf": (PyPDFLoader, {}),
# ".docx": (Docx2txtLoader, {}),
}
# --- 2. 加载单个文档函数 ---
def load_document(path: str) -> Document:
"""
加载单个文档。
"""
try:
ext = "." + path.rsplit(".", 1)[-1]
if ext in DOC_LOADERS_MAPPING:
loader_class, loader_args = DOC_LOADERS_MAPPING[ext]
loader = loader_class(path, **loader_args)
return loader.load()[0]
raise ValueError(f"不支持的文件扩展名: {ext}")
except Exception as exception:
raise ValueError(f"加载文档时发生错误 '{path}': {exception}")
# --- 3. 批量加载目录文档函数 ---
def load_documents_from_dir(path: str) -> List[Document]:
"""
从指定目录加载所有支持的文档。
"""
try:
all_files = []
for ext in DOC_LOADERS_MAPPING:
all_files.extend(
glob.glob(os.path.join(path, f"**/*{ext}"), recursive=True)
)
return [load_document(file_path) for file_path in all_files]
except Exception as exception:
raise RuntimeError(f"加载文件时发生错误: {exception}")
# --- 主执行流程 ---
if __name__ == "__main__":
# 确保存在一个名为 'folder' 的目录,并在其中放置一些 .txt 文件进行测试
# 例如:
# ./folder/doc1.txt
# ./folder/doc2.txt
# ...
# 1. 设置文档目录和ChromaDB持久化目录
source_directory = "./folder/"
chroma_db_path = "./folder/chroma_db"
# 确保ChromaDB目录存在
os.makedirs(chroma_db_path, exist_ok=True)
# 2. 批量加载文档
print(f"正在从目录 '{source_directory}' 加载文档...")
documents = load_documents_from_dir(source_directory)
print(f"共加载了 {len(documents)} 个文档。")
if not documents:
print("未找到任何文档,请检查目录和文件。")
else:
# 3. 初始化文本分割器
print("正在初始化文本分割器...")
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=300,
chunk_overlap=50
)
# 4. 分割文档
print("正在分割文档...")
texts = text_splitter.split_documents(documents)
print(f"文档被分割成 {len(texts)} 个文本块。")
# 5. 初始化嵌入模型
# 请确保已设置OPENAI_API_KEY环境变量
# 或者使用其他本地嵌入模型,例如 SentenceTransformers
print("正在初始化嵌入模型...")
try:
embeddings = OpenAIEmbeddings()
except Exception as e:
print(f"初始化OpenAIEmbeddings失败,请检查OPENAI_API_KEY:{e}")
print("尝试使用其他嵌入模型或退出。")
exit() # 或者选择使用其他嵌入模型
# 6. 持久化到ChromaDB
print(f"正在将文本块及嵌入持久化到ChromaDB,路径:'{chroma_db_path}'...")
chroma_db = Chroma.from_documents(
texts,
embeddings,
persist_directory=chroma_db_path,
client_settings= Settings(
persist_directory=chroma_db_path,
chroma_db_impl="duckdb+parquet",
anonymized_telemetry=False,
),
)
chroma_db.persist()
print("ChromaDB数据已成功持久化。")
# 7. 验证(可选):加载并查询ChromaDB
print("正在加载ChromaDB并进行简单查询验证...")
loaded_db = Chroma(
persist_directory=chroma_db_path,
embedding_function=embeddings,
client_settings= Settings(
persist_directory=chroma_db_path,
chroma_db_impl="duckdb+parquet",
anonymized_telemetry=False,
),
)
# 尝试查询一个与文档内容相关的短语
query = "关于文档内容的关键信息" # 根据你的文档内容修改查询
results = loaded_db.similarity_search(query, k=2)
print(f"查询 '{query}' 的结果:")
for i, doc in enumerate(results):
print(f"--- 结果 {i+1} ---")
print(f"内容: {doc.page_content[:100]}...") # 打印前100字符
print(f"元数据: {doc.metadata}")
print("-" * 20)
print("文档处理和ChromaDB持久化流程完成。")关键注意事项与最佳实践
- RecursiveCharacterTextSplitter的优势: 它是处理复杂文档的最佳选择,因为它会尝试多种分隔符策略,例如先按段落分割,再按句子,最后按单词,确保分割的语义完整性。
- chunk_size与chunk_overlap:
- chunk_size:应根据LLM的上下文窗口大小和你的应用需求来设置。过大可能导致LLM处理效率下降或无法完全理解上下文;过小可能导致信息碎片化。
- chunk_overlap:适当的重叠可以确保在文本块边界处的信息不会丢失,有助于LLM在检索时获得更完整的上下文。
- 多文件类型支持: DOC_LOADERS_MAPPING提供了一个灵活的框架来扩展对不同文档类型的支持。只需导入相应的LangChain加载器并添加到映射中即可。
- ChromaDB持久化: 务必设置persist_directory并在Chroma.from_documents或Chroma初始化时通过client_settings指定chroma_db_impl="duckdb+parquet",并显式调用chroma_db.persist()。这确保了数据在应用程序关闭后仍然存在。
- 错误处理: 在加载文档的函数中加入try-except块,可以提高程序的健壮性,及时捕获文件不存在、编码错误等问题。
- 嵌入模型选择: 示例中使用OpenAIEmbeddings,但在实际生产环境中,你可能需要考虑成本、性能和数据隐私,选择其他本地或云端的嵌入模型(如HuggingFace SentenceTransformers)。
总结
通过本教程,我们解决了LangChain在处理多文档和文本分割时遇到的常见问题。通过采用RecursiveCharacterTextSplitter进行智能文本分割,并构建一个支持批量加载多类型文档的健壮流程,我们能够确保所有文档都被正确处理,并高效、可靠地持久化到ChromaDB。这一优化方案将显著提升基于LLM的RAG系统的检索准确性和整体性能,使得LLM能够从你提供的所有信息中有效地学习和回答问题。
以上就是《多文档处理与ChromaDB持久化技巧》的详细内容,更多关于的资料请关注golang学习网公众号!
PHP如何用GET传递数组参数
- 上一篇
- PHP如何用GET传递数组参数
- 下一篇
- Golang自定义异常处理技巧分享
-
- 文章 · python教程 | 14分钟前 |
- Python文件写入方法全解析
- 423浏览 收藏
-
- 文章 · python教程 | 14分钟前 |
- 单通道转RGB与Matplotlib显示技巧
- 497浏览 收藏
-
- 文章 · python教程 | 29分钟前 |
- Streamlit生成PDF下载教程详解
- 494浏览 收藏
-
- 文章 · python教程 | 38分钟前 |
- MinIOlist_objects_v2优化技巧与实战应用
- 163浏览 收藏
-
- 文章 · python教程 | 48分钟前 |
- Dash多值输入:字符串转列表实战教学
- 398浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- PythonGPU加速技巧与使用方法
- 172浏览 收藏
-
- 文章 · python教程 | 1小时前 | Python Excel
- Python合并Excel单元格技巧分享
- 453浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- PyCharm无解释器错误解决方法
- 318浏览 收藏
-
- 文章 · python教程 | 2小时前 | Python Python官网
- Python官网邮件归档查询怎么查
- 111浏览 收藏
-
- 文章 · python教程 | 2小时前 |
- 二叉树转双向链表详细教程
- 165浏览 收藏
-
- 文章 · python教程 | 3小时前 |
- SQLAlchemy2.0与Pydantic类型转换教程
- 254浏览 收藏
-
- 文章 · python教程 | 4小时前 |
- Python项目Docker构建教程详解
- 304浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ChatExcel酷表
- ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
- 3251次使用
-
- Any绘本
- 探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
- 3462次使用
-
- 可赞AI
- 可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
- 3494次使用
-
- 星月写作
- 星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
- 4605次使用
-
- MagicLight
- MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
- 3868次使用
-
- Flask框架安装技巧:让你的开发更高效
- 2024-01-03 501浏览
-
- Django框架中的并发处理技巧
- 2024-01-22 501浏览
-
- 提升Python包下载速度的方法——正确配置pip的国内源
- 2024-01-17 501浏览
-
- Python与C++:哪个编程语言更适合初学者?
- 2024-03-25 501浏览
-
- 品牌建设技巧
- 2024-04-06 501浏览

