Skip to content

Langchainで文字列からDocumentオブジェクトを作成

Langchainの進化について

2024年にLangchainはモジュール構造が変更され、langchain-corelangchain-communitylangchain-text-splittersの3つの主要パッケージに分割されました。本記事では最新のlangchain-coreを使用した方法を中心に解説します。

核心的なエラーと解決策

最初に発生するAttributeError: 'tuple' object has no attribute 'page_content'エラーの主な原因は2つです:

  1. Documentオブジェクトをリストでラップしていない
    Langchainの多くの関数は単一のDocumentオブジェクトではなくDocumentのリストを期待しています

  2. 古いインポートパスの使用
    最新バージョンではインポートパスがlangchain_core.documentsに変更されています

基本的なソリューション

文字列から単一Documentを作成

python
from langchain_core.documents import Document

# 文字列からDocumentを作成
text = "分析対象のテキスト内容"
doc = Document(
    page_content=text,
    metadata={"source": "カスタムソース", "created_at": "2023-12-01"}
)

複数Documentを処理する場合

python
# 複数の文字列からDocumentリストを作成
texts = ["テキスト1", "テキスト2", "テキスト3"]
documents = [
    Document(page_content=text, metadata={"index": i}) 
    for i, text in enumerate(texts)
]

重要な注意点

load_qa_chaininput_documentsパラメータはDocumentオブジェクトのリストを要求します。単一のDocumentでも必ずリストでラップしてください。

load_qa_chainの正しい呼び出し方

python
# 正しい呼び出し方 (docをリストでラップ)
chain({
    "input_documents": [doc],  # 単一のDocumentでもリスト内に配置
    "human_input": query
})

メタデータ活用のベストプラクティス

Documentオブジェクトにはソース情報やカスタム属性を追加できます:

python
# メタデータの効果的な活用例
metadata = {
    "source": "APIデータ",
    "timestamp": "2023-12-01T14:30:00Z",
    "document_type": "財務レポート",
    "version": 1.2
}

doc = Document(
    page_content="2023年第四四半期の決算報告...",
    metadata=metadata
)

高度なユースケース

テキストスプリッターとの統合

python
from langchain_text_splitters import CharacterTextSplitter

text_splitter = CharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=200
)

# 長文を分割して複数のDocumentを作成
long_text = "非常に長い財務分析レポートの内容..."
split_docs = text_splitter.create_documents(
    texts=[long_text],
    metadatas=[{"source": "社内レポート"}]
)

複数ソースからのドキュメント作成

python
# 様々なソースからDocumentを作成する例
def create_document_from_source(content, source_type):
    metadata = {
        "source": source_type,
        "processing_date": datetime.now().isoformat()
    }
    return Document(page_content=content, metadata=metadata)

# 異なるソースのデータを統合
database_doc = create_document_from_source("DBからのデータ", "database")
api_doc = create_document_from_source("APIからのレスポンス", "api")
user_input_doc = create_document_from_source("ユーザー入力テキスト", "user_input")

all_docs = [database_doc, api_doc, user_input_doc]

トラブルシューティング

ImportErrorが発生する場合

古いバージョン(0.0.x系)を使用している場合は互換性のあるインポート方法:

::code-group

python
# 古いバージョンの場合
from langchain.docstore.document import Document
python
# 推奨: 最新バージョン (v0.1.x以降)
from langchain_core.documents import Document

:::

「page_content」属性エラーの解決策

python
# AttributeErrorに対処するために必ずチェック
if isinstance(doc, Document):
    # 適切な処理
    print(doc.page_content)
else:
    # 型を確認し変換
    print(f"期待されるDocument型ではありません: {type(doc)}")
    # リストに変換
    if not isinstance(doc, list):
        doc = [doc]

ファイル経由の代替方法

どうしてもDocument作成で問題が解決しない場合の代替手段:

python
from langchain_community.document_loaders import TextLoader
import tempfile

def str_to_doc(text):
    """文字列を一時ファイル経由でDocumentに変換"""
    with tempfile.NamedTemporaryFile(delete=False, suffix=".txt") as tmp:
        tmp.write(text.encode('utf-8'))
        tmp_path = tmp.name
    
    loader = TextLoader(tmp_path)
    docs = loader.load()
    return docs

結論

Langchainで文字列からDocumentオブジェクトを作成する基本原則は次の通りです:

  1. 最新のインポートパスを使用する
    from langchain_core.documents import Document

  2. 単一のDocumentであってもリストでラップする
    input_documents=[doc]形式で渡す

  3. メタデータを活用して文書の出典を管理する
    検索拡張生成(RAG)のパフォーマンス向上に貢献

  4. 長文は適切に分割する
    テキストスプリッターを使用して処理しやすいサイズに分割