LangChain ドキュメントの読み込みと分割
以前の記事では手動でテキストを入力しましたが、実際のプロジェクトでは、ドキュメントは PDF、Web ページ、Markdown ファイルなどから取得される場合があります。
このセクションでは、Document Loader を使ってさまざまなドキュメントを読み込む方法と、Text Splitter を使ってドキュメントを検索に適した小さなチャンクに分割する方法を紹介します。
Document Loader——ドキュメントの読み込み
LangChain は数十種類のドキュメントローダーを提供しており、一般的なファイル形式をカバーしています:
| Loader | ソース | インストールパッケージ |
|---|---|---|
| TextLoader | .txt ファイル | langchain(組み込み) |
| PyPDFLoader | PDF ファイル | langchain-community + pypdf |
| WebBaseLoader | ウェブページ URL | langchain-community + beautifulsoup4 |
| CSVLoader | CSV ファイル | langchain-community |
| UnstructuredMarkdownLoader | Markdown ファイル | langchain-community + unstructured |
例
# テキストファイルを読み込む(組み込み、追加インストール不要)
from langchain_community.document_loaders import TextLoader
loader = TextLoader("knowledge.txt", encoding="utf-8")
docs = loader.load()
print(f"{len(docs)} 個のドキュメントを読み込みました")
print(f"内容プレビュー: {docs)
# ウェブページを読み込む
# pip install langchain-community beautifulsoup4
from langchain_community.document_loaders import WebBaseLoader
loader = WebBaseLoader("https://www.example.com/python/python-tutorial.html")
docs = loader.load()
print(f"\nウェブページの内容: {docs)
from langchain_community.document_loaders import TextLoader
loader = TextLoader("knowledge.txt", encoding="utf-8")
docs = loader.load()
print(f"{len(docs)} 個のドキュメントを読み込みました")
print(f"内容プレビュー: {docs)
# ウェブページを読み込む
# pip install langchain-community beautifulsoup4
from langchain_community.document_loaders import WebBaseLoader
loader = WebBaseLoader("https://www.example.com/python/python-tutorial.html")
docs = loader.load()
print(f"\nウェブページの内容: {docs)
Text Splitter——ドキュメントの分割
ドキュメントは通常長すぎるため、効果的に検索するには小さなチャンク(chunk)に分割する必要があります。分割戦略は RAG の効果に直接影響します:
例
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 分割器を作成
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 各チャンクは最大500文字
chunk_overlap=50, # チャンク間は50文字重複
separators=["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""],
# 段落、次に文、最後に文字の順で分割
)
# サンプルドキュメント
long_text = """サンプルは無料のプログラミング学習プラットフォームです。
このプラットフォームは、以下のような豊富なプログラミング言語チュートリアルを提供しています:
- Python チュートリアル:基本構文からデータ分析まで
- Java チュートリアル:オブジェクト指向プログラミングから Spring フレームワークまで
- フロントエンドチュートリアル:HTML、CSS、JavaScript とそのフレームワーク
すべてのチュートリアルには、詳細なコード例とオンライン実行環境が付属しています。
学習者は、学びながら練習することで、プログラミングスキルを素早く習得できます。"""
# ドキュメントを分割
chunks = text_splitter.split_text(long_text)
print(f"原文の長さ: {len(long_text)} 文字")
print(f"分割後: {len(chunks)} チャンク\n")
for i, chunk in enumerate(chunks):
print(f"--- チャンク {i+1} ({len(chunk)} 文字) ---")
print(chunk)
print()
# 分割器を作成
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 各チャンクは最大500文字
chunk_overlap=50, # チャンク間は50文字重複
separators=["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""],
# 段落、次に文、最後に文字の順で分割
)
# サンプルドキュメント
long_text = """サンプルは無料のプログラミング学習プラットフォームです。
このプラットフォームは、以下のような豊富なプログラミング言語チュートリアルを提供しています:
- Python チュートリアル:基本構文からデータ分析まで
- Java チュートリアル:オブジェクト指向プログラミングから Spring フレームワークまで
- フロントエンドチュートリアル:HTML、CSS、JavaScript とそのフレームワーク
すべてのチュートリアルには、詳細なコード例とオンライン実行環境が付属しています。
学習者は、学びながら練習することで、プログラミングスキルを素早く習得できます。"""
# ドキュメントを分割
chunks = text_splitter.split_text(long_text)
print(f"原文の長さ: {len(long_text)} 文字")
print(f"分割後: {len(chunks)} チャンク\n")
for i, chunk in enumerate(chunks):
print(f"--- チャンク {i+1} ({len(chunk)} 文字) ---")
print(chunk)
print()
実行結果:
元の長さ: 153 字 分割後のチャンク: 3 块 --- 块 1 (54 字) --- サンプルは無料のプログラミング学習プラットフォームです。 平台提供了丰富的编程语言教程,包括但不限于: --- 块 2 (49 字) --- - Python 教程:从基础语法到数据分析 - Java 教程:面向对象编程到 Spring 框架 --- 块 3 (50 字) --- - 前端教程:HTML、CSS、JavaScript 及其框架 所有教程都配有详细的代码示例和在线运行环境。
chunk_overlap は非常に重要です。チャンク間に重複がないと、完全な文が半分に切られ、検索時に重要な情報を見逃す可能性があります。50〜100文字の重複が一般的な設定です。
分割パラメータ設定ガイド
| シナリオ | chunk_size | chunk_overlap | 理由 |
|---|---|---|---|
| FAQ 質疑応答 | 200~500 | 20~50 | 質疑応答ペアは短いため、小さなチャンクで十分 |
| 技術ドキュメント | 500~1000 | 50~100 | 技術的な内容にはより多くのコンテキストが必要 |
| 長文/論文 | 1000~2000 | 100~200 | 段落の完全性を保つ必要がある |
| コードベース | 500~1500 | 0~50 | 関数/クラスを自然な境界とする |
完全なフロー:読み込み → 分割 → ベクトル化
例
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma
# from langchain_community.document_loaders import TextLoader
# フロー 1:読み込み
# loader = TextLoader("サンプル_knowledge.txt", encoding="utf-8")
# docs = loader.load()
# デモのため、サンプルテキストを直接使用
docs = [
"サンプルは無料のプログラミング学習ウェブサイトです。",
"このウェブサイトでは、Python、Java、HTML など、さまざまなプログラミング言語のチュートリアルを提供しています。",
"Python3 基礎チュートリアルは全30章で、初心者の入門学習に適しています。",
"HTML 基礎チュートリアルは全25章で、フォーム、マルチメディアなどの内容を含みます。",
"サンプルのすべての基礎チュートリアルは無料です。",
]
# フロー 2:分割
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=100,
chunk_overlap=20,
)
chunks = text_splitter.create_documents(docs)
# フロー 3:ベクトル化と保存
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vector_store = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./サンプル_db",
)
print(f"インデックスを作成しました:{len(chunks)} 個のドキュメントチャンク")
# フロー 4:検索
results = vector_store.similarity_search("Python チュートリアルは全部で何章ですか?", k=2)
for doc in results:
print(f"検索結果: {doc.page_content}")
from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma
# from langchain_community.document_loaders import TextLoader
# フロー 1:読み込み
# loader = TextLoader("サンプル_knowledge.txt", encoding="utf-8")
# docs = loader.load()
# デモのため、サンプルテキストを直接使用
docs = [
"サンプルは無料のプログラミング学習ウェブサイトです。",
"このウェブサイトでは、Python、Java、HTML など、さまざまなプログラミング言語のチュートリアルを提供しています。",
"Python3 基礎チュートリアルは全30章で、初心者の入門学習に適しています。",
"HTML 基礎チュートリアルは全25章で、フォーム、マルチメディアなどの内容を含みます。",
"サンプルのすべての基礎チュートリアルは無料です。",
]
# フロー 2:分割
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=100,
chunk_overlap=20,
)
chunks = text_splitter.create_documents(docs)
# フロー 3:ベクトル化と保存
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vector_store = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./サンプル_db",
)
print(f"インデックスを作成しました:{len(chunks)} 個のドキュメントチャンク")
# フロー 4:検索
results = vector_store.similarity_search("Python チュートリアルは全部で何章ですか?", k=2)
for doc in results:
print(f"検索結果: {doc.page_content}")
実行結果:
インデックス作成済み:5 个文档块 検索結果: Python3 基础教程共 30 章,适合零基础入门学习。 検索結果: サンプルは無料のプログラミング学習ウェブサイトです。その他の拡張