20_LangChain多数据源生成

LangChain多数据源生成

引言

随着大语言模型(LLM)应用场景的不断扩展,从多种数据源获取和处理信息的能力变得越来越重要。LangChain框架提供了丰富的数据加载器,可以从各种来源加载数据,包括CSV、HTML、Markdown、PDF等多种格式。本教程将详细介绍如何使用LangChain加载和处理不同类型的数据源,以便在下游任务中使用。

1. LangChain数据源概述

LangChain与各种数据源有数百个集成,可以从中加载数据:Slack、Notion、Google Drive等。每个文档加载器都有自己特定的参数,但它们可以通过相同的方式使用.load()方法调用。这种统一的接口使得从不同来源加载数据变得简单而一致。

2. 环境准备

首先,我们需要安装必要的依赖库:

bash 复制代码
# 安装主要依赖
pip install langchain langchain-community langchain-openai unstructured beautifulsoup4 pypdf markdown rapidocr-onnxruntime python-dotenv

# 对于特定数据源,可能需要额外的依赖
pip install pandas html2text

3. 加载CSV文件

3.1 CSV文件简介

逗号分隔值(CSV)文件是一种使用逗号分隔值的定界文本文件。文件的每一行是一个数据记录。每个记录由一个或多个字段组成,字段之间用逗号分隔。

3.2 基本用法

LangChain实现了一个CSVLoader,可以将CSV文件加载为一系列Document对象。CSV文件的每一行都会被翻译为一个文档。

python 复制代码
from langchain_community.document_loaders import CSVLoader

# 创建一个CSV加载器
loader = CSVLoader(file_path="./data/sample_data.csv")

# 加载数据
documents = loader.load()

# 查看加载的文档
print(f"加载了 {len(documents)} 个文档")
print(f"第一个文档的内容: {documents[0].page_content}")
print(f"第一个文档的元数据: {documents[0].metadata}")

3.3 自定义CSV解析和加载

CSVLoader接受一个csv_args关键字参数,用于自定义传递给Python的csv.DictReader的参数。有关支持的csv参数的更多信息,请参阅csv模块文档。

python 复制代码
from langchain_community.document_loaders import CSVLoader

# 创建一个带有自定义参数的CSV加载器
loader = CSVLoader(
    file_path="./data/sample_data.csv",
    csv_args={
        'delimiter': ';',  # 使用分号作为分隔符
        'quotechar': '"',  # 使用双引号作为引用字符
        'fieldnames': ['名称', '年龄', '城市']  # 自定义字段名
    }
)

# 加载数据
documents = loader.load()

# 查看加载的文档
print(f"加载了 {len(documents)} 个文档")
print(f"第一个文档的内容: {documents[0].page_content}")

4. 加载HTML文件

4.1 HTML简介

超文本标记语言(HTML)是用于在Web浏览器中显示的文档的标准标记语言。

4.2 使用Unstructured加载HTML

Unstructured是一个强大的库,可以解析各种文档格式,包括HTML。

python 复制代码
from langchain_community.document_loaders import UnstructuredHTMLLoader

# 创建一个HTML加载器
loader = UnstructuredHTMLLoader("./data/example.html")

# 加载数据
data = loader.load()

# 查看加载的文档
print(f"加载了 {len(data)} 个文档")
print(f"文档内容: {data[0].page_content[:100]}...")

4.3 使用BeautifulSoup4加载HTML

我们还可以使用BeautifulSoup4通过BSHTMLLoader加载HTML文档。这将把HTML中的文本提取到page_content中,并将页面标题提取到metadata的title中。

python 复制代码
from langchain_community.document_loaders import BSHTMLLoader

# 创建一个BeautifulSoup HTML加载器
loader = BSHTMLLoader("./data/example.html")

# 加载数据
data = loader.load()

# 查看加载的文档
print(f"加载了 {len(data)} 个文档")
print(f"文档内容: {data[0].page_content[:100]}...")
print(f"文档标题: {data[0].metadata.get('title', 'No title')}")

5. 加载Markdown文件

5.1 Markdown简介

Markdown是一种轻量级标记语言,可用于使用纯文本编辑器创建格式化文本。

5.2 基本用法

LangChain实现了一个UnstructuredMarkdownLoader对象,它需要使用Unstructured包。

python 复制代码
from langchain_community.document_loaders import UnstructuredMarkdownLoader

# 创建一个Markdown加载器
loader = UnstructuredMarkdownLoader("./data/example.md")

# 加载数据
data = loader.load()

# 查看加载的文档
print(f"加载了 {len(data)} 个文档")
print(f"文档内容: {data[0].page_content[:100]}...")

5.3 保留元素

在幕后,Unstructured为不同的文本块创建了不同的"元素"。默认情况下,我们将它们组合在一起,但是您可以通过指定mode="elements"轻松保留这种分离。

python 复制代码
from langchain_community.document_loaders import UnstructuredMarkdownLoader

# 创建一个保留元素的Markdown加载器
loader = UnstructuredMarkdownLoader(
    "./data/example.md",
    mode="elements"
)

# 加载数据
data = loader.load()

# 查看加载的文档
print(f"加载了 {len(data)} 个文档")

# 查看不同元素类型
element_types = set()
for doc in data:
    element_type = doc.metadata.get("category")
    element_types.add(element_type)

print(f"文档包含的元素类型: {element_types}")

6. 加载PDF文件

6.1 PDF文件简介

便携式文档格式(PDF)是由Adobe于1992年开发的一种文件格式,标准化为ISO 32000。它以一种与应用软件、硬件和操作系统无关的方式呈现文档,包括文本格式和图像。

6.2 使用PyPDF

这里我们使用pypdf将PDF加载为文档数组,其中每个文档包含页面内容和带有page编号的元数据。

python 复制代码
from langchain_community.document_loaders import PyPDFLoader

# 创建一个PDF加载器
loader = PyPDFLoader("./data/example.pdf")

# 加载数据
pages = loader.load()

# 查看加载的文档
print(f"加载了 {len(pages)} 页")
print(f"第一页内容: {pages[0].page_content[:100]}...")
print(f"第一页元数据: {pages[0].metadata}")

6.3 对PDF进行向量搜索

一旦我们将PDF加载到LangChain的Document对象中,我们可以像通常一样对它们进行索引(例如,RAG应用程序)。

python 复制代码
from langchain_community.document_loaders import PyPDFLoader
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter

# 加载PDF
loader = PyPDFLoader("./data/example.pdf")
pages = loader.load()

# 分割文本
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=200
)
chunks = text_splitter.split_documents(pages)

# 创建向量存储
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(chunks, embeddings)

# 执行相似性搜索
query = "这个PDF的主要内容是什么?"
docs = vectorstore.similarity_search(query, k=3)

# 查看搜索结果
for i, doc in enumerate(docs):
    print(f"结果 {i+1}:")
    print(f"内容: {doc.page_content[:100]}...")
    print(f"元数据: {doc.metadata}")
    print("-" * 50)

6.4 从图像中提取文本

一些PDF包含文本图像,例如扫描文档或图表。使用rapidocr-onnxruntime软件包,我们也可以将图像提取为文本:

python 复制代码
from langchain_community.document_loaders import PyPDFLoader
import os

# 确保已安装rapidocr-onnxruntime
os.environ["PYPDF_USE_RAPIDOCR"] = "True"

# 创建一个PDF加载器
loader = PyPDFLoader("./data/scanned_document.pdf")

# 加载数据
pages = loader.load()

# 查看加载的文档
print(f"加载了 {len(pages)} 页")
print(f"第一页内容: {pages[0].page_content[:100]}...")

6.5 使用Unstructured

Unstructured支持一个通用接口,用于处理非结构化或半结构化文件格式,例如Markdown或PDF。LangChain的UnstructuredPDFLoader与Unstructured集成,将PDF文档解析为LangChain Document对象。

python 复制代码
from langchain_community.document_loaders import UnstructuredPDFLoader

# 创建一个Unstructured PDF加载器
loader = UnstructuredPDFLoader("./data/example.pdf")

# 加载数据
data = loader.load()

# 查看加载的文档
print(f"加载了 {len(data)} 个文档")
print(f"文档内容: {data[0].page_content[:100]}...")

6.6 保留元素

在幕后,Unstructured为不同的文本块创建不同的"元素"。默认情况下,我们将它们合并在一起,但您可以通过指定mode="elements"轻松保持分离。

python 复制代码
from langchain_community.document_loaders import UnstructuredPDFLoader

# 创建一个保留元素的PDF加载器
loader = UnstructuredPDFLoader(
    "./data/example.pdf",
    mode="elements"
)

# 加载数据
data = loader.load()

# 查看加载的文档
print(f"加载了 {len(data)} 个元素")

# 查看不同元素类型
element_types = set()
for doc in data:
    element_type = doc.metadata.get("category")
    element_types.add(element_type)

print(f"文档包含的元素类型: {element_types}")

6.7 使用Unstructured加载远程PDF

这涵盖了如何将在线PDF加载到我们可以在下游使用的文档格式中。这可用于各种在线PDF站点,如open.umn.edu/opentextboo...arxiv.org/archive/

python 复制代码
from langchain_community.document_loaders import OnlinePDFLoader

# 创建一个在线PDF加载器
loader = OnlinePDFLoader("https://arxiv.org/pdf/2307.09288.pdf")

# 加载数据
data = loader.load()

# 查看加载的文档
print(f"加载了 {len(data)} 个文档")
print(f"文档内容: {data[0].page_content[:100]}...")

7. 综合应用:多源数据加载与处理

在实际应用中,我们可能需要从多个不同的数据源加载数据,并将它们组合在一起进行处理。以下是一个综合示例,展示如何加载不同类型的数据源并将它们组合起来:

python 复制代码
import os
from langchain_community.document_loaders import (
    CSVLoader,
    BSHTMLLoader,
    UnstructuredMarkdownLoader,
    PyPDFLoader
)
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain.chains import RetrievalQA
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()

def load_multiple_sources():
    """从多个数据源加载文档"""
    documents = []
    
    # 加载CSV数据
    if os.path.exists("./data/sample_data.csv"):
        csv_loader = CSVLoader("./data/sample_data.csv")
        documents.extend(csv_loader.load())
        print(f"加载了CSV文档 {len(csv_loader.load())} 个")
    
    # 加载HTML数据
    if os.path.exists("./data/example.html"):
        html_loader = BSHTMLLoader("./data/example.html")
        documents.extend(html_loader.load())
        print(f"加载了HTML文档 {len(html_loader.load())} 个")
    
    # 加载Markdown数据
    if os.path.exists("./data/example.md"):
        md_loader = UnstructuredMarkdownLoader("./data/example.md")
        documents.extend(md_loader.load())
        print(f"加载了Markdown文档 {len(md_loader.load())} 个")
    
    # 加载PDF数据
    if os.path.exists("./data/example.pdf"):
        pdf_loader = PyPDFLoader("./data/example.pdf")
        documents.extend(pdf_loader.load())
        print(f"加载了PDF文档 {len(pdf_loader.load())} 页")
    
    return documents

def create_qa_system(documents):
    """创建问答系统"""
    # 分割文档
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=1000,
        chunk_overlap=200
    )
    chunks = text_splitter.split_documents(documents)
    
    # 创建向量存储
    embeddings = OpenAIEmbeddings()
    vectorstore = FAISS.from_documents(chunks, embeddings)
    
    # 创建检索器
    retriever = vectorstore.as_retriever(
        search_type="similarity",
        search_kwargs={"k": 3}
    )
    
    # 创建问答链
    llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0)
    qa_chain = RetrievalQA.from_chain_type(
        llm=llm,
        chain_type="stuff",
        retriever=retriever,
        return_source_documents=True
    )
    
    return qa_chain

def main():
    """主函数"""
    # 加载多源数据
    documents = load_multiple_sources()
    
    if not documents:
        print("未找到任何文档,请确保数据文件存在。")
        return
    
    print(f"总共加载了 {len(documents)} 个文档")
    
    # 创建问答系统
    qa_chain = create_qa_system(documents)
    
    # 进行问答
    while True:
        query = input("\n请输入您的问题(输入'退出'结束): ")
        if query.lower() in ["退出", "exit", "quit"]:
            break
        
        result = qa_chain({"query": query})
        
        print("\n回答:")
        print(result["result"])
        
        print("\n来源文档:")
        for i, doc in enumerate(result["source_documents"]):
            print(f"文档 {i+1}:")
            print(f"内容: {doc.page_content[:100]}...")
            print(f"元数据: {doc.metadata}")
            print("-" * 50)

if __name__ == "__main__":
    main()

8. 实际应用场景

8.1 知识库构建

通过从多个数据源加载数据,可以构建一个综合的知识库,用于回答问题、生成内容或进行数据分析。

python 复制代码
from langchain_community.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings

# 从目录中加载所有支持的文档
loader = DirectoryLoader(
    "./data",
    glob="**/*.*",  # 加载所有文件
    loader_cls=None,  # 自动选择合适的加载器
    show_progress=True
)

# 加载文档
documents = loader.load()
print(f"加载了 {len(documents)} 个文档")

# 分割文档
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=200
)
chunks = text_splitter.split_documents(documents)

# 创建持久化向量存储
embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(
    documents=chunks,
    embedding=embeddings,
    persist_directory="./chroma_db"
)
vectorstore.persist()

print(f"成功创建知识库,包含 {len(chunks)} 个文本块")

8.2 数据分析与报告生成

结合多源数据和LLM,可以进行数据分析并自动生成报告。

python 复制代码
import pandas as pd
from langchain_community.document_loaders import CSVLoader
from langchain_openai import ChatOpenAI
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate

# 加载CSV数据
loader = CSVLoader("./data/sales_data.csv")
documents = loader.load()

# 将文档转换为DataFrame
data = []
for doc in documents:
    data.append(eval(doc.page_content))
df = pd.DataFrame(data)

# 进行简单的数据分析
total_sales = df["sales"].sum()
avg_sales = df["sales"].mean()
top_product = df.loc[df["sales"].idxmax()]

# 使用LLM生成分析报告
llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0.2)

template = """
基于以下销售数据分析,生成一份简洁的业务报告:

总销售额: {total_sales}
平均销售额: {avg_sales}
销售最好的产品: {top_product}

报告应包括:
1. 销售概况
2. 关键发现
3. 建议的下一步行动

报告:
"""

prompt = PromptTemplate(
    input_variables=["total_sales", "avg_sales", "top_product"],
    template=template
)

chain = LLMChain(llm=llm, prompt=prompt)

report = chain.run(
    total_sales=total_sales,
    avg_sales=avg_sales,
    top_product=str(top_product)
)

print(report)

8.3 多模态内容处理

结合文本和图像数据,可以进行多模态内容处理。

python 复制代码
from langchain_community.document_loaders import PyPDFLoader, ImageCaptionLoader
from langchain.schema import Document
from langchain_openai import ChatOpenAI
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate

# 加载PDF文本
pdf_loader = PyPDFLoader("./data/report.pdf")
pdf_docs = pdf_loader.load()

# 加载图像描述
image_loader = ImageCaptionLoader(
    path_images=["./data/chart1.png", "./data/chart2.png"]
)
image_docs = image_loader.load()

# 合并文档
all_docs = pdf_docs + image_docs

# 提取文本内容
text_content = "\n\n".join([doc.page_content for doc in pdf_docs])
image_descriptions = "\n\n".join([doc.page_content for doc in image_docs])

# 使用LLM生成综合分析
llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0.2)

template = """
基于以下报告文本和图表描述,提供一个综合分析:

报告文本:
{text_content}

图表描述:
{image_descriptions}

请提供:
1. 报告的主要发现
2. 图表展示的关键趋势
3. 文本和图表数据的关联分析

分析:
"""

prompt = PromptTemplate(
    input_variables=["text_content", "image_descriptions"],
    template=template
)

chain = LLMChain(llm=llm, prompt=prompt)

analysis = chain.run(
    text_content=text_content,
    image_descriptions=image_descriptions
)

print(analysis)

9. 最佳实践与注意事项

9.1 数据加载优化

  • 批量处理:对于大型文档集合,考虑批量加载和处理
  • 并行处理:使用多线程或异步处理加快加载速度
  • 增量加载:只加载新的或更改的文档,而不是每次都重新加载所有内容
python 复制代码
import concurrent.futures
from langchain_community.document_loaders import PyPDFLoader

def load_pdf(file_path):
    """加载单个PDF文件"""
    loader = PyPDFLoader(file_path)
    return loader.load()

# 并行加载多个PDF
pdf_files = ["./data/doc1.pdf", "./data/doc2.pdf", "./data/doc3.pdf"]

with concurrent.futures.ThreadPoolExecutor() as executor:
    results = list(executor.map(load_pdf, pdf_files))

# 合并结果
all_pages = []
for pages in results:
    all_pages.extend(pages)

print(f"总共加载了 {len(all_pages)} 页")

9.2 错误处理

在处理多种数据源时,错误处理尤为重要:

python 复制代码
from langchain_community.document_loaders import PyPDFLoader
import logging

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

def safe_load_document(loader_func, *args, **kwargs):
    """安全地加载文档,处理可能的错误"""
    try:
        return loader_func(*args, **kwargs)
    except Exception as e:
        logger.error(f"加载文档时出错: {str(e)}")
        return []

# 使用安全加载函数
def load_pdf_safely(file_path):
    return safe_load_document(
        lambda: PyPDFLoader(file_path).load()
    )

# 测试
documents = load_pdf_safely("./data/possibly_corrupted.pdf")
print(f"成功加载了 {len(documents)} 个文档")

9.3 数据预处理

在将数据输入到LLM之前,通常需要进行一些预处理:

python 复制代码
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_transformers import (
    Html2TextTransformer,
    BeautifulSoupTransformer
)

# 加载HTML文档
from langchain_community.document_loaders import BSHTMLLoader
loader = BSHTMLLoader("./data/example.html")
documents = loader.load()

# 使用HTML转换器
html2text = Html2TextTransformer()
cleaned_docs = html2text.transform_documents(documents)

# 或者使用BeautifulSoup转换器
bs_transformer = BeautifulSoupTransformer()
cleaned_docs_alt = bs_transformer.transform_documents(documents)

# 文本分割
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=200
)
chunks = text_splitter.split_documents(cleaned_docs)

print(f"预处理后的文档块数: {len(chunks)}")

10. 总结

LangChain提供了强大而灵活的工具,用于从各种数据源加载和处理数据。通过本教程,我们学习了如何加载CSV、HTML、Markdown和PDF等不同类型的数据,以及如何将它们组合起来用于下游任务。

这些技术可以应用于各种场景,如构建知识库、生成报告、进行数据分析等。通过合理利用这些工具,我们可以充分发挥LLM的潜力,创建更强大、更智能的应用程序。

随着LangChain生态系统的不断发展,我们可以期待更多的数据源集成和更强大的数据处理能力。持续关注LangChain的更新,将帮助我们保持在AI应用开发的前沿。

相关推荐
掘我的金2 小时前
19_LangChain结合SQL实现数据分析问答
langchain
王国强20093 小时前
LangChain 设计原理分析¹⁴ | 模拟实现一个精简版 LangChain
langchain
王国强20094 小时前
LangChain 设计原理分析¹³ | LangChain Serve 快速部署
langchain
前端双越老师11 小时前
【干货】使用 langChian.js 实现掘金“智能总结” 考虑大文档和 token 限制
人工智能·langchain·node.js
Dajiaonew12 小时前
Spring AI RAG 检索增强 应用
java·人工智能·spring·ai·langchain
xuanwuziyou1 天前
LangChain 多任务应用开发
人工智能·langchain
大志说编程1 天前
LangChain框架入门16:智能客服系统RAG应用实战
后端·langchain·aigc
AI大模型1 天前
从零开始,亲手开发你的第一个AI大模型(一)基础知识
程序员·langchain·agent
掘我的金2 天前
15_LangChain自定义Callback组件
langchain