LangGraph × Pydantic × SubGraph の落とし穴と解決策 🚀

LLM

~PythonでのLangGraph活用時にハマるポイントを徹底解説~

LangGraphは、LangChainのワークフロー管理を強化するためのフレームワークです。特に SubGraph(ネストされたグラフ構造)を活用すると、複雑な処理の分割や管理がしやすくなります。しかし、 Pydantic を組み合わせた場合、意外な落とし穴にハマることがあります。

本記事では、実際に遭遇したエラーを事例として紹介し、その原因と解決策を詳しく解説します。


🔹 この記事で解説すること

✅ SubGraph の基本概念と Pydantic との組み合わせ方
✅ SubGraph の State に Pydantic を使った際の問題点
✅ 実際のエラー事例とその解決策
✅ LangGraph の最新バージョンでの修正点

これを読めば、 LangGraph で Pydantic を適用する際の注意点がクリアになります!


1️⃣ LangGraphのSubGraphとは?

まずは SubGraph について簡単に整理しておきましょう。

▶ SubGraph の基本概念

LangGraph は、ノード(Node)とエッジ(Edge)を定義することで、処理のフローを構築するフレームワークです。通常のグラフ構造に加えて、あるグラフの中に別のグラフを組み込む「ネスト構造」を作成できます。これを SubGraph と呼びます。

例えば、以下のような構造を考えてみましょう。

from typing import TypedDict

class GraphState(TypedDict):
    key: str
    count: int

しかし、 TypedDict には以下のような制約があります。

🔴 型チェックが緩い(値のバリデーションがない)
🔴 デフォルト値を定義しにくい
🔴 データの変換がしづらい

そこで、 Pydantic を使うと、型チェックやデフォルト値の管理がしやすくなります。

from pydantic import BaseModel, Field

class GraphState(BaseModel):
    key: str
    count: int = Field(default=0)  # デフォルト値を指定

これにより、State のデータ構造をより厳密に管理できるようになります。

しかし、 Pydantic を使った場合に特有の問題が発生します。次のセクションで具体的な事例を見ていきましょう。


3️⃣ エラー事例①:SubGraphのStateのデフォルト値が適用されない

▶ 発生したエラー

Pydantic の BaseModel を SubGraph の State に使ったとき、本来ならデフォルト値が適用されるはずの value に None が入ってしまい、 ValidationError が発生しました。

from pydantic import BaseModel, Field

class ChildState(BaseModel):
    path: list[str]
    value: str = Field(default="default value")

# グラフを実行
graph.invoke({"path": []})

# エラー発生
# ValidationError: none is not an allowed value (type=type_error.none.not_allowed)

▶ 原因

LangGraph の State は、内部的に Pydantic の通常の初期化とは異なる方法でインスタンスを生成しているため、 Field(default=...) が適用されません。

▶ 解決策

デフォルト値を明示的に __init__ で設定することで回避できます。

class ChildState(BaseModel):
    def __init__(self, **input):
        input["value"] = input.get("value") or "default value"
        super().__init__(**input)

    path: list[str]
    value: str

この方法なら、 invoke 実行時に value のデフォルト値が正しく設定されるようになります。


4️⃣ エラー事例②:親のStateが子のStateのフィールドを持っていないとエラーが発生する

▶ 発生したエラー

親の State に SubGraph の State のフィールドを含めていないと、以下のような InvalidUpdateError が発生します。

graph.invoke({'path': []}, debug=True)

# エラー発生
# InvalidUpdateError: Expected dict, got 

▶ 原因

LangGraph の state.py では dict を前提にキーの存在確認を行っています。しかし、 Pydantic の BaseModel は辞書型ではないため、期待される処理の分岐に入らずエラーが発生します。

▶ 解決策

親の State に SubGraph の State のフィールドをすべて含めることで回避できます。

class ParentState(BaseModel):
    path: list[str]
    value: str  # 子のStateのフィールドを追加

5️⃣ 最新バージョン(0.1.15 以降)での改善点

LangGraph の 0.1.15 以降では、この State の取り扱いが改善されました。

✅ BaseModel を State に使っても InvalidUpdateError が発生しないよう修正
✅ SubGraph の State のデフォルト値が正しく適用されるよう修正


6️⃣ まとめ|LangGraph × Pydantic の正しい使い方

問題点 原因 解決策
SubGraph の State のデフォルト値が適用されない LangGraph の State の初期化処理が Pydantic と異なる __init__ でデフォルト値を明示的に設定する
親の State に子の State のフィールドがないとエラー BaseModel が辞書型ではないため、LangGraph の State チェックでエラーが発生 親の State に子の State のフィールドを含める
0.1.14 以前のバージョンでは BaseModel の State でエラーが発生 LangGraph の State 管理が TypedDict を前提に設計されていた 0.1.15 以降にアップデートする

💡 LangGraph を Pydantic と組み合わせる場合は、常に最新バージョンを確認しましょう! 🚀

最新情報をチェックしよう!