LangChain と LangGraph を用いた AI エージェントのアーキテクチャ解説

AI エージェント(Agent)という言葉が、近年急速に広まりました。しかし、その実態はしばしば曖昧で、「大規模言語モデル(LLM)を少しラップしただけ」と思われがちです。実際には、エージェントの知能性は、単なるモデルの能力ではなく、制御構造状態管理によって支えられています。本稿では、LangChain と LangGraph の二つの主要フレームワークを軸に、エージェントの設計思想と実装パターンを技術的に整理します。

LangChain:線形パイプラインとしての LLM

LangChain は、初期の LLM アプリケーション開発において標準となったフレームワークです。その核となるのは Chain —— すなわち、一連の処理ステップを順次つなげた線形フローです。

このアプローチでは、LLM はあくまで「処理ノードの一つ」であり、全体の制御権は開発者が書いたコードにあります。たとえば、ユーザー入力の前処理 → LLM 推論 → 出力整形 の3段階フローは、以下のように表現できます:

from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser

# プロンプトテンプレート定義
template = ChatPromptTemplate.from_messages([("user", "{query}")])

# LLM クライアント(例:Qwen-Plus via Alibaba Cloud)
llm = ChatOpenAI(
    model="qwen-plus",
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    api_key="your_api_key_here"
)

# 出力パーサー
parser = StrOutputParser()

# チェイン構築:template → llm → parser
pipeline = template | llm | parser

# 実行
result = pipeline.invoke({"query": "日本の四季について簡潔に説明してください"})
print(result)  # 出力例: "春は桜、夏は祭り、秋は紅葉、冬は雪…"

このチェインは堅牢ですが、柔軟性に欠けます。途中で LLM の出力が不適切だった場合、例外処理や再試行ロジックを手動で組み込む必要があります。つまり、LLM は判断せず、ただ与えられたタスクを遂行する「作業員」に過ぎません。

LangGraph:状態駆動型の反復的制御

複雑なタスクに対応するためには、静的なチェインを超えた動的な制御が必要です。LangGraph は、これを 状態(State)グラフベースの遷移(Graph-based Transitions) で実現します。

ここでは、LLM が「指揮者」として振る舞い、現在の状態に基づいて次のアクションを選択・実行します。以下は、作家推薦とその文体でのジョーク生成という2ステップタスクの実装例です:

from typing import TypedDict, Annotated, Optional
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import InMemorySaver
from langchain_community.chat_models import ChatTongyi

class WorkflowState(TypedDict):
    writer: Optional[str]
    humor: Optional[str]

def recommend_writer(state: WorkflowState) -> dict:
    response = ChatTongyi(model="qwen-plus", api_key="...").invoke(
        "人気のある現代作家を一人、名前のみで答えてください。"
    )
    return {"writer": response.content.strip()}

def generate_humor(state: WorkflowState) -> dict:
    prompt = f"作家『{state['writer']}』の文体を真似て、100文字以内のユーモアを書いてください。"
    response = ChatTongyi(model="qwen-plus", api_key="...").invoke(prompt)
    return {"humor": response.content.strip()}

# グラフ構築
builder = StateGraph(WorkflowState)
builder.add_node("writer_step", recommend_writer)
builder.add_node("humor_step", generate_humor)
builder.add_edge(START, "writer_step")
builder.add_edge("writer_step", "humor_step")
builder.add_edge("humor_step", END)

# チェックポイント保存機能を有効化
memory = InMemorySaver()
graph = builder.compile(checkpointer=memory)

実行後、結果を確認すると:

config = {"configurable": {"thread_id": "demo-001"}}
final_state = graph.invoke({}, config)
print("作家:", final_state["writer"])      # → 村上春樹
print("ジョーク:", final_state["humor"])  # → 「猫が村上春樹の登場人物だと告白…」

さらに重要なのは、状態の編集と再実行が可能である点です。たとえば、作家を「村上春樹」から「郭德纲」に差し替えて再実行すれば、そのスタイルに合わせた新しいジョークが即座に生成されます。

# 特定ステップの状態を更新
history = list(graph.get_state_history(config))
target_state = history[1]  # writer_step の直後の状態
updated_config = graph.update_state(
    target_state.config,
    {"writer": "郭德纲"}
)

# 再実行(humor_step から再開)
revised = graph.invoke(None, updated_config)
print(revised["humor"])  # → 郭德纲風のコメディ出力

このように、LangGraph は「LLM + 状態保持 + 条件付きループ + ノード間遷移」という四要素を統合し、真の意味での自律的エージェントを構築する基盤を提供します。

エージェント設計の三つの基本パターン

実用的なエージェントは、以下の三つの再利用可能な構造パターンを組み合わせて構築されます。

  • リフレクション(Reflection)
    出力を自己評価し、不十分であれば再生成を繰り返すループ。コード生成や論理検証に有効。
  • ツールルーティング(Tool Routing)
    LLM がクエリ内容を分析し、適切な外部ツール(検索API、計算エンジン、DB接続など)を動的に選択・呼び出す。
  • スーパーバイザーアーキテクチャ(Supervisor Pattern)
    上位のLLMがタスクをサブエージェント(専門ノード)に分割・割り当て、進捗を監視・調整する。マルチステップ・マルチエキスパートなワークフローに最適。

これらのパターンは、ネストや並列実行により複雑化できます。たとえば、「コード生成エージェント」内部にリフレクションループを持たせ、「ドキュメント調査エージェント」にツールルーティングを組み込むことで、高信頼性の開発支援システムが構築可能です。

まとめ:エージェントとは「制御の抽象化」である

LangChain は LLM を「関数として扱う」手法を示しました。一方、LangGraph は LLM を「状態を持つプログラムの中心制御ユニット」として位置づけ、実行時における意思決定と修正を可能にします。

したがって、エージェントの本質は、LLM の推論能力を、状態管理と制御フローというソフトウェア工学の原則で包摂することにあります。これは、単なるプロンプトエンジニアリングではなく、AI ベースのアプリケーション設計という新たな分野の誕生を意味します。

タグ: LangChain langgraph ai-agent large-language-model graph-ai

7月2日 18:24 投稿