powered by TechFeed
表示モード
ハウツー

LangGraphでAIエージェントに「記憶」を持たせる — ノード/エッジ設計が切り拓くステートフルなワークフロー構築

7月3日、Collabnixが「Building Stateful AI Agent Workflows with LangGraph」と題した記事を公開した。有限オートマトンの設計思想をAIワークフローに持ち込み、ノード(処理単位)とエッジ(遷移条件)でエージェントの「状態」を管理するという、LangGraphのアーキテクチャ上の核心を丁寧に解説した内容だ。

7月3日、Collabnixが「Building Stateful AI Agent Workflows with LangGraph」と題した記事を公開した。有限オートマトンの設計思想をAIワークフローに持ち込み、ノード(処理単位)とエッジ(遷移条件)でエージェントの「状態」を管理するという、LangGraphのアーキテクチャ上の核心を丁寧に解説した内容だ。


LangGraphとは何か、LangChainとの関係

LangGraphは、AIエージェントのワークフローをグラフ構造で表現・実行するフレームワークである。LangGraph公式ドキュメントによれば、当初はLangChainエコシステムの拡張として開発されたが、現在はLangChainとは独立した関連プロジェクトとして位置付けられており、LangChainなしでも単体で利用できる。LangChainが「LLMの呼び出しやプロンプト管理」に特化したのに対し、LangGraphは「エージェントの状態管理と実行フロー制御」に特化したレイヤーを担う。


設計思想の核心:有限オートマトンとしてのワークフロー

LangGraphの最も特徴的な点は、ワークフロー全体を有限オートマトン(ステートマシン)として表現することにある。従来のAIチャットボットの多くはステートレス設計、すなわち各リクエストが独立しており前の会話を保持しない。これが「同じことを何度も説明しなければならない」体験の根本原因だ。

LangGraphはこの問題に対し、ノードとエッジという2つのプリミティブで答える。各ノード間を流れる状態オブジェクトがいわばワーキングメモリとして機能し、ユーザーの過去の発言や処理結果を引き継ぐ。この設計は従来のステート管理手法と比較したとき、明確な差別化点がある。

手法 課題
LangChain Memory セッション内の短期記憶に限定されやすく、複雑な分岐制御は別途実装が必要
独自セッション管理 実装コストが高く、ノード間の依存関係が複雑になりやすい
LangGraph グラフ構造でフロー制御と状態管理を一元化。分岐・ループ・並列処理を宣言的に記述できる

※編集部の考察:上記の比較は元記事の趣旨をもとにした整理であり、元記事に明示的な比較表はない。各手法の適合ユースケースは要件次第であり、一概にLangGraphが優れているとは言い切れない点に留意されたい。


コアとなる実装:ノードとエッジの定義

記事の核心は、このノード/エッジの実装パターンにある。なお、以下のコードサンプルは元記事の記述に基づくものだが、現行のLangGraphの正式APIはStateGraphクラスと関数ベースのノード定義を組み合わせるスタイルが標準となっており、クラス継承スタイルとは異なる場合がある。最新の実装パターンはLangGraph公式ドキュメントおよび公式チュートリアルを参照されたい。

ノードの定義例(元記事より):

from langgraph import Node

class QueryNode(Node):
    def process(self, context):
        user_query = context['query']
        # クエリを処理する
        return {'response': f'Processing {user_query}'}

Nodeを継承し、processメソッドに処理を書く。引数のcontextは辞書型で、ノードをまたいで読み書きできる可変な状態オブジェクトだ。あるノードが書き込んだ値を、次のノードが読み取る、という連鎖でワークフローが進む。

エッジ(遷移条件)の定義例(元記事より):

from langgraph import Edge

class QueryToResponseEdge(Edge):
    def evaluate(self, context):
        return 'response' in context

エッジは「どの条件が満たされたら次のノードへ進むか」を定義する。この例ではcontextresponseキーが存在する場合に遷移する。エラーハンドリングや再試行、分岐といったロジックもエッジに集約できる。


コンテキストの永続化

セッションをまたいで状態を保持したい場合、記事ではMongoDBFirestoreとの統合が推奨されている。インメモリの辞書では再起動で消えてしまうため、本番ユースケースでは外部DBへの保存が前提になる。

セッション内の短期的なコンテキスト管理の例:

context_state = {
    "user_name": None,
    "last_interaction": None,
    "previous_queries": []
}

def update_context(query, response):
    context_state["last_interaction"] = {
        "query": query,
        "response": response
    }
    context_state["previous_queries"].append(query)

update_context("What is the weather today?", "It is sunny and warm.")

Dockerによるデプロイ

記事はDockerを使ったコンテナ化も解説している。Dockerfileの構成はシンプルで、python:3.9-slimをベースに依存パッケージをインストールし、ポート5000でFlaskアプリを起動する構成だ。

FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["python", "app.py"]

ビルドと起動:

docker build -t langgraph-workflow .
docker run -p 5000:5000 langgraph-workflow

テスト・本番運用のポイント

記事後半では、実運用で踏みやすい落とし穴も整理されている。

  • Context Bleeding(コンテキスト汚染):あるユーザーの状態が別セッションに漏れる問題。セッション単位でコンテキストを厳密に分離する必要がある。
  • APIレート制限:外部LLM APIへの呼び出しが集中するとスロットリングが発生する。指数バックオフによるリトライ実装が推奨されている。
  • キャッシュ:同一クエリへの繰り返し応答はキャッシュで計算コストを削減できる。
  • ロードバランシング:複数のワーカーインスタンスで負荷分散し、スケーラビリティを確保する。

ユニットテストにはPython標準のunittestを使い、各ノードを独立してテストする方針が示されている。


実用ユースケース

記事が挙げる適用例はカスタマーサービスの自動化パーソナライズドマーケティングボットの2つ。いずれも「過去のやり取りを踏まえた応答」が価値の源泉であり、ステートフルな設計が直接効いてくる領域だ。

LangGraphは、ノードやエッジを追加するだけで既存ワークフローを壊さずに機能拡張できる設計になっており、AIモデル側の能力向上に合わせてワークフロー側も段階的に育てていける点が特徴である。実装の出発点としては、LangGraph公式チュートリアルも参照されたい。


詳細はBuilding Stateful AI Agent Workflows with LangGraphを参照していただきたい。