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应用开发的前沿。

相关推荐
蛇皮划水怪1 天前
深入浅出LangChain4J
java·langchain·llm
、BeYourself1 天前
LangChain4j 流式响应
langchain
、BeYourself1 天前
LangChain4j之Chat and Language
langchain
qfljg1 天前
langchain usage
langchain
kjkdd1 天前
6.1 核心组件(Agent)
python·ai·语言模型·langchain·ai编程
渣渣苏2 天前
Langchain实战快速入门
人工智能·python·langchain
小天呐2 天前
01—langchain 架构
langchain
香芋Yu2 天前
【LangChain1.0】第九篇 Agent 架构设计
langchain·agent·架构设计
kjkdd2 天前
5. LangChain设计理念和发展历程
python·语言模型·langchain·ai编程
ASKED_20192 天前
Langchain学习笔记一 -基础模块以及架构概览
笔记·学习·langchain