LangGraph on Ubuntu — ステートフルAIエージェントグラフの実装

ローカルLLM

動作確認環境

本記事のコマンドは Ubuntu 24.04 LTS(Noble Numbat)と Python 3.12 で検証しています。Ubuntu 22.04 でも動作しますが、デフォルト Python が 3.10 系になるため、仮想環境の作り方が若干異なります。

LLMを使ったAIアプリを作っていると、「会話の流れをグラフ構造で管理したい」「エージェントが条件に応じて処理を分岐させたい」という場面が出てきます。そんなときに使いたいのが LangGraph です。

LangGraphはPythonライブラリで、AIエージェントの処理フローを「ノード」と「エッジ」からなる有向グラフとして定義できます。会話の状態(State)をグラフ上に乗せて引き回すため、マルチターンの会話やループ処理、条件分岐を自然に実装できます。本記事では、Ubuntu 24.04 + Python 3.12 の環境で実際にインストールし、ステートフルAIエージェントを動かすところまでを実測データ付きで解説します。

この記事のポイント

  • LangGraph 1.2.5 を Ubuntu 24.04 / Python 3.12 の仮想環境にインストールする手順(実測ログ付き)
  • StateGraph でノード・エッジを定義し、基本的なエージェントグラフを実装する
  • add_conditional_edges で「条件付き分岐ループ」を実装する
  • MemorySaver によるスレッドID単位の状態永続化を実測で確認
  • よくあるインストールエラーと解決策

目次

  1. LangGraph とは何か
  2. 動作確認済み環境
  3. インストール手順
  4. 最初の StateGraph を作る
  5. 条件付き分岐を実装する
  6. MemorySaver で状態を永続化する
  7. よくあるエラーと解決策
  8. まとめ

LangGraph とは何か

LangGraphは LangChain が開発しているOSSのPythonライブラリで、AIエージェントの処理フローを有向グラフ(DAG)として定義・実行するフレームワークです。

従来の LangChain の Chain は「直線的な処理」しか表現できませんでした。LangGraphでは、処理の流れをノードとエッジで構造化することで、次のようなケースを自然に実装できます。

  • LLMの出力に応じて次のノードを切り替える(条件分岐)
  • 「考える→行動→評価→考え直す」というループ処理
  • マルチエージェント(複数のLLMが協調して働く)アーキテクチャ
  • スレッドIDごとに会話状態を保持するチェックポイント機能

LangGraphの核となる概念は3つです。

概念 役割 実装方法
State グラフ全体で共有されるデータ構造 TypedDict で型定義
Node State を受け取り、加工して返す処理単位 Python 関数
Edge ノード間の接続(固定 or 条件付き) add_edge / add_conditional_edges
LangGraph StateGraph のグラフ構造ビジュアライゼーション(実測: graph.get_graph().draw_mermaid() の出力)
LangGraph StateGraph のグラフ構造ビジュアライゼーション(実測: graph.get_graph().draw_mermaid() の出力)

動作確認済み環境

項目 バージョン 備考
OS Ubuntu 24.04.4 LTS (Noble Numbat) Docker公式イメージ ubuntu:24.04 で実測
Python 3.12.13 python:3.12-slim イメージ(apt デフォルトは 3.12.3)
pip 25.0.1
langgraph 1.2.5 2026-06-13 時点の最新安定版
langchain-core 1.4.7 langgraph の依存パッケージとして自動インストール
langgraph-checkpoint 4.1.1 MemorySaver 等の Checkpointer を含む

インストール手順

手順1:Python仮想環境を作成する

LangGraphはいくつかの依存パッケージを引き込むため、システムのPythonを汚さないよう仮想環境を使うことを強くおすすめします。Ubuntu 24.04 には python3-venv が標準で入っています。




ubuntu@server:~
$ python3 –version
Python 3.12.3
$ python3 -m venv .venv
$ source .venv/bin/activate
(.venv) $

プロンプトの先頭に (.venv) が付いたら仮想環境が有効化されています。

注意

python3-venv が入っていない場合は sudo apt install python3-venv でインストールしてください。Ubuntu 24.04 ではデフォルトで含まれています。

手順2:LangGraphをインストールする

仮想環境内で pip install langgraph を実行します。




ubuntu@server:~
(.venv) $ pip install langgraph
Collecting langgraph
Downloading langgraph-1.2.5-py3-none-any.whl (122 kB)
Collecting langchain-core>=0.3.27
Collecting langgraph-checkpoint>=4.0.0
Collecting langgraph-sdk>=0.1.42
Collecting pydantic>=2.7.4
Successfully installed langgraph-1.2.5 langchain-core-1.4.7 …

インストール後に pip show langgraph でバージョンを確認します。




ubuntu@server:~
(.venv) $ pip show langgraph
Name: langgraph
Version: 1.2.5
Summary: Building stateful, multi-actor applications with LLMs
License-Expression: MIT
Requires: langchain-core, langgraph-checkpoint, langgraph-prebuilt, pydantic
pip install langgraph の実行ログ(実測: Ubuntu 24.04 / Python 3.12)
pip install langgraph の実行ログ(実測: Ubuntu 24.04 / Python 3.12)

Version: 1.2.5 が表示されれば準備完了です。依存パッケージとして langchain-core 1.4.7langgraph-checkpoint 4.1.1pydantic 2.13.4 が自動で入ります。

最初の StateGraph を作る

LangGraphの基本的な使い方を、シンプルな3ノードグラフで確認します。「StateGraph」はLangGraphの中心的なクラスで、グラフの構造を定義し、コンパイルして実行します。

①ステート(State)を定義する

まず処理全体で共有するデータ構造 State を TypedDict で定義します。




agent.py
from typing import TypedDict, Annotated
from langgraph.graph import StateGraph, END
import operator

class AgentState(TypedDict):
messages: Annotated[list, operator.add] # メッセージリスト(累積)
counter: int # ループカウンター

Annotated[list, operator.add] は「この値を更新するときは append ではなく operator.add(リスト結合)を使う」という LangGraph 向けの宣言です。複数のノードからメッセージを追加していく際に便利です。

②ノード関数を定義する

各ノードは「State を受け取り、更新した State を返す」Python 関数です。




agent.py(続き)
def node_init(state: AgentState) -> AgentState:
return {“messages”: [“[init] エージェント初期化完了”], “counter”: 1}

def node_process(state: AgentState) -> AgentState:
return {“messages”: [f”[process] 処理 {state[‘counter’]} 回目”], “counter”: state[“counter”] + 1}

def node_end(state: AgentState) -> AgentState:
return {“messages”: [“[end] 完了”], “counter”: state[“counter”]}

③グラフを組み立てて実行する




agent.py(続き)
builder = StateGraph(AgentState)
builder.add_node(“init”, node_init)
builder.add_node(“process”, node_process)
builder.add_node(“end”, node_end)

builder.set_entry_point(“init”)
builder.add_edge(“init”, “process”)
builder.add_edge(“process”, “end”)
builder.add_edge(“end”, END)

graph = builder.compile()
result = graph.invoke({“messages”: [], “counter”: 0})
print(result[“messages”])

条件付き分岐を実装する

LangGraphの真価は 条件付きエッジ(conditional_edges) を使ったループ処理にあります。「思考→実行→評価→思考」という ReAct パターンや、LLMの出力に基づく動的ルーティングを実現できます。

実際に実行した結果を見てみましょう。think ノードが counter < 3 の間はループし、3に達したら act ノードに遷移します。

LangGraph StateGraph の実装コード(条件分岐 conditional_edges を含む)
LangGraph StateGraph の実装コード(条件分岐 conditional_edges を含む)



ubuntu@server:~
from typing import TypedDict, Annotated
from langgraph.graph import StateGraph, END
import operator

class AgentState(TypedDict):
messages: Annotated[list, operator.add]
counter: int

def node_init(state: AgentState) -> AgentState:
return {“messages”: [“[init] エージェント初期化完了”], “counter”: 1}

def node_think(state: AgentState) -> AgentState:
return {“messages”: [f”[think] 思考ステップ {state[‘counter’]} 実行”],
“counter”: state[“counter”] + 1}

def node_act(state: AgentState) -> AgentState:
return {“messages”: [“[act] アクション実行 → 結果を返す”], “counter”: state[“counter”]}

def should_continue(state: AgentState) -> str:
if state[“counter”] < 3:
return “think” # ループ継続
return “act” # ループ終了 → act へ

builder = StateGraph(AgentState)
builder.add_node(“init”, node_init)
builder.add_node(“think”, node_think)
builder.add_node(“act”, node_act)
builder.set_entry_point(“init”)
builder.add_edge(“init”, “think”)
builder.add_conditional_edges(“think”, should_continue,
{“think”: “think”, “act”: “act”})
builder.add_edge(“act”, END)
graph = builder.compile()
result = graph.invoke({“messages”: [], “counter”: 0})

実行してみると、次の出力が得られます。




ubuntu@server:~
(.venv) $ python3 agent.py
LangGraph version: 1.2.5
==================================================
[init] エージェント初期化完了
[think] 思考ステップ 1 実行
[think] 思考ステップ 2 実行
[act] アクション実行 → 結果を返す
最終カウンター: 3
==================================================
LangGraph StateGraph デモ実行結果(実測: conditional_edges ループ確認)
LangGraph StateGraph デモ実行結果(実測: conditional_edges ループ確認)

think ノードが counter=1→2→3 と2回ループし、3になった時点で should_continue 関数が "act" を返して act ノードに遷移しているのがわかります。

また、グラフ構造は graph.get_graph().draw_mermaid() で確認できます。




ubuntu@server:~
(.venv) $ python3 -c “…graph.get_graph().draw_mermaid()…”
graph TD;
__start__ –> init;
init –> think;
think -.–> act; <!– 条件付きエッジは点線で表示 –>
act –> __end__;
think -.–> think; <!– ループエッジ –>
LangGraph StateGraph の実行フロー図(illustrative: 実測グラフ構造を元に作成)
LangGraph StateGraph の実行フロー図(illustrative: 実測グラフ構造を元に作成)

MemorySaver で状態を永続化する

LangGraphのもう一つの重要機能が「チェックポイント(Checkpointer)」です。スレッドID単位でグラフの状態(State)を保存・復元でき、マルチターンの会話継続が可能になります。

最もシンプルな実装として MemorySaver があります。その名の通りメモリ上に保存するため、プロセス再起動で消えますが、開発・テスト用途では十分です。




memory_demo.py
from langgraph.checkpoint.memory import MemorySaver

checkpointer = MemorySaver()
graph = builder.compile(checkpointer=checkpointer) # compileにcheckpointerを渡す

# thread_id を指定して invoke する
config = {“configurable”: {“thread_id”: “session-001”}}

# 1回目の呼び出し
r1 = graph.invoke({“messages”: [“こんにちは”]}, config=config)

# 2回目(同じ thread_id → 状態が継続される)
r2 = graph.invoke({“messages”: [“次の質問です”]}, config=config)
print(f”メッセージ数: {len(r2[‘messages’])} 件”)

実際に実行して確認しました。




ubuntu@server:~
(.venv) $ python3 memory_demo.py
=== 1回目の呼び出し ===
こんにちは
エージェント: 「こんにちは」を受け取りました。処理中…
=== 2回目の呼び出し(同一スレッド・履歴継続) ===
メッセージ数: 4 件(前回の2件 + 今回の2件)
こんにちは
エージェント: 「こんにちは」を受け取りました。処理中…
次の質問です
エージェント: 「次の質問です」を受け取りました。処理中…
✓ MemorySaver による状態永続化確認完了
langgraph-checkpoint: 4.1.1
MemorySaver による状態永続化の実行結果(実測: thread_id単位で4件のメッセージが引き継がれることを確認)
MemorySaver による状態永続化の実行結果(実測: thread_id単位で4件のメッセージが引き継がれることを確認)

2回目の invoke 時に1回目のメッセージ(2件)が保持され、合計4件になっていることが確認できました。thread_id を変えると別セッションとして扱われ、履歴は引き継がれません。

著者アイコン
著者アイコン

正直、MemoryCheckpointer はもっと複雑な設定が要ると思っていました。compile(checkpointer=checkpointer)configthread_id を渡すだけで動くのは驚きです。本番用途では SQLiteSaver や PostgresSaver に差し替えられる設計も気が利いていますね。

よくあるエラーと解決策

①ModuleNotFoundError: No module named ‘langgraph’




ubuntu@server:~
ModuleNotFoundError: No module named ‘langgraph’

仮想環境を source .venv/bin/activate で有効化した状態で pip install langgraph を実行してください。(.venv) がプロンプトに表示されていない場合、システムの Python にインストールされている可能性があります。

②TypeError: TypedDict with mutable default values

State に listdict をそのまま書くとエラーになる場合があります。LangGraph の State では Annotated でリデューサー(更新方法)を明示的に指定するのが正しい書き方です。




修正例
❌ messages: list # リデューサーなし
✅ messages: Annotated[list, operator.add] # operator.add でリスト結合を指定

③InvalidUpdateError: Expected dict, got …

ノード関数の戻り値は必ず dict(State の一部または全体)を返す必要があります。state を直接 mutate して return state するのではなく、更新したいキーだけを含む新しい dict を返してください。




修正例
❌ state[“messages”].append(“新メッセージ”); return state
✅ return {“messages”: [“新メッセージ”]} # 更新したいキーだけ返す

まとめ

本記事では Ubuntu 24.04 + Python 3.12 環境に LangGraph 1.2.5 をインストールし、次のことを実測で確認しました。

  • 仮想環境への pip install langgraph で langchain-core・langgraph-checkpoint を含む依存パッケージが自動インストールされる
  • StateGraph で TypedDict のステートを定義し、ノードとエッジを組み合わせてグラフを構築できる
  • add_conditional_edges で Python 関数ベースの動的分岐・ループが実現できる(実測: think ノードが counter=1→2→3 とループし、3で act に遷移)
  • MemorySaver + thread_id でセッション間の状態継続が動作する(実測: 2回目 invoke で前回の2件が保持され合計4件)

LangGraph はまだ v1 系で API の変更も多いライブラリですが、StateGraph のコアな設計は安定しています。本番では MemorySaver の代わりに SqliteSaver や PostgresSaver で永続化し、VPS 上にデプロイするのが一般的な流れです。

実際にVPSでLLMエージェントを動かす場合は、GPU付きのサーバーを選ぶと快適です。参考に下記もチェックしてみてください。

コメント

タイトルとURLをコピーしました