第2章 LangChain基礎

更新日:2025年12月16日

本章では、LangChainのアーキテクチャと主要コンポーネントについて解説する。Model I/O(Chat Models、Prompt Templates、Output Parsers)、Memory(会話履歴管理)、Toolsの基本概念と実装方法を学ぶ。

1. LangChainの概要

LangChainは、LLMを活用したアプリケーションを構築するためのオープンソースフレームワークである。2022年10月にHarrison Chaseによって公開され、急速に普及した。LangChainは、LLMの入出力を抽象化し、複雑なワークフローを簡潔に記述するための統一的なインターフェースを提供する。

1.1 アーキテクチャ

LangChain v0.3(2024年時点)のパッケージ構成は以下の通りである。

Table 1. LangChainのパッケージ構成

パッケージ 説明 用途
langchain-core 基盤となる抽象クラスとLCEL 必須
langchain チェーン、エージェントの実装 アプリ開発
langchain-community サードパーティ統合 各種サービス連携
langchain-openai OpenAI統合 GPTモデル利用
langgraph グラフベースエージェント 高度なエージェント
langsmith 観測・評価プラットフォーム デバッグ・監視

Fig 1. インストール例

pip install langchain langchain-openai langchain-community

環境変数にOpenAI APIキーを設定する。

export OPENAI_API_KEY="sk-..."

1.2 主要コンポーネント

LangChainの主要コンポーネントは以下の6つに分類される。

Table 2. LangChainの主要コンポーネント

コンポーネント 説明
Model I/O LLMへの入出力を管理(プロンプト、モデル呼び出し、出力解析)
Retrieval 外部データの取得(ドキュメントローダー、ベクトルストア、検索)
Memory 会話履歴や状態の管理
Chains 複数の処理を連結したワークフロー
Agents LLMが動的にツールを選択・実行
Callbacks 処理のフックとログ記録

本章ではModel I/O、Memory、Toolsの基礎を解説する。Retrieval(RAG)は第4章、Chains/AgentsはLCEL(第3章)およびLangGraph(第7章)で詳しく扱う。

2. Model I/O

Model I/Oは、LLMへの入出力を抽象化するコンポーネント群である。プロンプトの構築、モデル呼び出し、出力の解析という3つの要素から構成される。

2.1 Chat Models

Chat Modelsは、対話形式のLLMを抽象化したクラスである。OpenAI、Anthropic、Google、ローカルモデルなど、様々なプロバイダーのモデルを統一的なインターフェースで利用できる。

Fig 2. ChatOpenAIの基本的な使用方法

from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage

# モデルの初期化
model = ChatOpenAI(model="gpt-4o", temperature=0)

# メッセージの作成
messages = [
    SystemMessage(content="あなたは親切なアシスタントです。"),
    HumanMessage(content="Pythonの特徴を3つ教えてください。")
]

# 呼び出し
response = model.invoke(messages)
print(response.content)

LangChainのChat Modelsは、invoke()、stream()、batch()といった標準メソッドを提供する。これはRunnable インターフェースに基づいており、LCEL(第3章)でチェーンを構築する際の基盤となる。

Table 3. Chat Modelsの主要メソッド

メソッド 説明 戻り値
invoke() 同期的に1回呼び出し AIMessage
stream() ストリーミング出力 Iterator[AIMessageChunk]
batch() 複数入力を並列処理 List[AIMessage]
ainvoke() 非同期呼び出し AIMessage

2.2 Prompt Templates

Prompt Templatesは、動的なプロンプトを生成するためのテンプレート機能である。変数を埋め込んだテンプレートを定義し、実行時に値を注入してプロンプトを生成する。

Fig 3. ChatPromptTemplateの使用例

from langchain_core.prompts import ChatPromptTemplate

# テンプレートの定義
prompt = ChatPromptTemplate.from_messages([
    ("system", "あなたは{language}の専門家です。"),
    ("human", "{topic}について説明してください。")
])

# 変数を埋め込んでメッセージを生成
messages = prompt.invoke({
    "language": "Python",
    "topic": "リスト内包表記"
})

print(messages)

ChatPromptTemplateは、from_messages()で複数のメッセージを含むテンプレートを作成できる。{変数名}の形式でプレースホルダーを定義し、invoke()時に辞書で値を渡す。

Fig 4. MessagesPlaceholderによる会話履歴の挿入

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt = ChatPromptTemplate.from_messages([
    ("system", "あなたは親切なアシスタントです。"),
    MessagesPlaceholder(variable_name="history"),
    ("human", "{input}")
])

# 会話履歴を含めて呼び出し
messages = prompt.invoke({
    "history": [
        HumanMessage(content="こんにちは"),
        AIMessage(content="こんにちは!何かお手伝いできますか?")
    ],
    "input": "Pythonについて教えて"
})

MessagesPlaceholderを使うと、会話履歴のようなメッセージのリストをテンプレートに挿入できる。これはMemoryと組み合わせて使用することが多い。

2.3 Output Parsers

Output Parsersは、LLMの出力を構造化データに変換するためのコンポーネントである。LLMの出力は文字列であるが、実際のアプリケーションでは辞書やオブジェクトとして扱いたい場合が多い。

Fig 5. StrOutputParserの使用例

from langchain_core.output_parsers import StrOutputParser

parser = StrOutputParser()

# AIMessageから文字列を抽出
result = parser.invoke(response)
print(result)  # 文字列として出力

Fig 6. JsonOutputParserの使用例

from langchain_core.output_parsers import JsonOutputParser
from langchain_core.pydantic_v1 import BaseModel, Field

# 出力スキーマの定義
class BookInfo(BaseModel):
    title: str = Field(description="本のタイトル")
    author: str = Field(description="著者名")
    year: int = Field(description="出版年")

parser = JsonOutputParser(pydantic_object=BookInfo)

# パーサーのformat_instructionsをプロンプトに含める
prompt = ChatPromptTemplate.from_messages([
    ("system", "あなたは書籍情報を抽出するアシスタントです。"),
    ("human", "以下の書籍情報をJSON形式で出力してください。\n{format_instructions}\n\n書籍: {book}")
])

# パーサーの指示を取得
format_instructions = parser.get_format_instructions()

JsonOutputParserはPydanticモデルと組み合わせることで、型安全な出力を得ることができる。get_format_instructions()は、LLMに対してどのような形式で出力すべきかを説明するテキストを生成する。

3. Memory

Memoryは、会話の履歴や状態を保持するためのコンポーネントである。LLM自体はステートレスであり、過去の会話を記憶していない。Memoryを使用することで、文脈を考慮した対話が可能になる。

3.1 会話履歴管理

最も基本的なMemoryの実装は、会話履歴をリストとして保持するものである。LangChainでは、ChatMessageHistoryクラスを使用する。

Fig 7. ChatMessageHistoryの使用例

from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.messages import HumanMessage, AIMessage

# 履歴の初期化
history = ChatMessageHistory()

# メッセージの追加
history.add_user_message("こんにちは")
history.add_ai_message("こんにちは!何かお手伝いできますか?")
history.add_user_message("今日の天気は?")

# 履歴の取得
print(history.messages)
# [HumanMessage(...), AIMessage(...), HumanMessage(...)]

会話が長くなると、コンテキストウィンドウの制限に達する可能性がある。この問題に対処するため、LangChainは様々なMemory実装を提供している。

3.2 Memory Types

LangChainには複数のMemory実装があり、ユースケースに応じて選択できる。

Table 4. Memory Typesの比較

Memory Type 説明 特徴
ConversationBufferMemory 全履歴を保持 シンプル、長い会話で問題
ConversationBufferWindowMemory 直近N回の会話を保持 固定サイズ、古い履歴を破棄
ConversationSummaryMemory 履歴を要約して保持 トークン節約、詳細を失う
ConversationTokenBufferMemory トークン数で制限 正確なトークン管理

Fig 8. ConversationBufferWindowMemoryの使用例

from langchain.memory import ConversationBufferWindowMemory

# 直近3回の会話を保持
memory = ConversationBufferWindowMemory(k=3, return_messages=True)

memory.save_context(
    {"input": "こんにちは"},
    {"output": "こんにちは!"}
)
memory.save_context(
    {"input": "名前は?"},
    {"output": "私はAIアシスタントです。"}
)

# 履歴の取得
history = memory.load_memory_variables({})
print(history["history"])

実際のアプリケーションでは、セッションごとに履歴を永続化する必要がある。Redis、PostgreSQL、MongoDBなどのバックエンドを使用したMemory実装も提供されている。

4. Tools

Toolsは、LLMが外部の機能やAPIを呼び出すためのインターフェースである。LLMは学習データに基づいて応答を生成するが、リアルタイムの情報取得、計算、データベース操作などは行えない。Toolsを使用することで、LLMの能力を拡張できる。

Fig 9. カスタムToolの定義

from langchain_core.tools import tool

@tool
def get_word_count(text: str) -> int:
    """テキストの単語数をカウントする。
    
    Args:
        text: カウント対象のテキスト
        
    Returns:
        単語数
    """
    return len(text.split())

# ツールの情報
print(get_word_count.name)  # "get_word_count"
print(get_word_count.description)  # docstringから生成
print(get_word_count.args_schema.schema())  # 引数のJSONスキーマ

@toolデコレータを使用すると、通常のPython関数をLangChainのToolとして登録できる。docstringはツールの説明として使用され、LLMがどのツールを使うべきか判断する際の参考になる。

Table 5. LangChainの組み込みTools(例)

Tool 説明 パッケージ
DuckDuckGoSearchRun Web検索 langchain-community
WikipediaQueryRun Wikipedia検索 langchain-community
PythonREPLTool Pythonコード実行 langchain-experimental
ShellTool シェルコマンド実行 langchain-community

Toolsは単体では機能せず、Agent(第6章)やLangGraph(第7章)と組み合わせて使用する。Agentは、ユーザーの入力に基づいてどのToolを呼び出すかをLLMが判断し、実行結果を受け取ってさらに処理を続けるという自律的な動作を実現する。

参考・免責事項
本コンテンツは2025年12月時点の情報に基づいて作成されています。LangChainは活発に開発が進められており、APIや機能が変更される可能性があります。最新情報は公式ドキュメント(https://python.langchain.com/docs/)をご確認ください。