LangGraphとは?AIを「賢いチャット」から「止まっても再開できる業務システム」へ変える仕組み

AI・機械学習

結論から言えば、LangGraphは「賢いAIを作る道具」というより、AIに長い仕事を安全に任せるための実行基盤です。

生成AIのデモは、質問を送れば数秒後に答えが返ってきます。しかし実際の業務では、調査、判断、ツール操作、承認待ち、やり直しなどが発生します。途中でAPIが失敗することもあれば、担当者の確認が翌日になることもあります。

LangGraphは、こうした「一度では終わらない仕事」を、状態を持つグラフとして管理します。AIを単なるチャット相手から、止まっても続きから再開できる業務システムへ変えるための仕組みだと考えると分かりやすいでしょう。

2026年7月23日時点で、Python版LangGraphのPyPI上の最新安定版は1.2.2です。LangGraphはLangChain社が開発していますが、LangChainを必須とせず、単独でも利用できます。

LangGraphを一言で説明すると

AIが次に何をするかを、状態・処理・分岐の組み合わせで管理するフレームワーク。

LangGraphでは、AIの処理を主に3つの要素で表します。

要素 役割 業務にたとえると
State(状態) 現在までに得た情報や処理結果を保持する 案件ファイル、申請書、作業メモ
Node(ノード) 調査、判断、生成、API実行などの処理を行う 担当者や作業工程
Edge(エッジ) 次に実行するノードを決める 承認後は実行、否認なら差し戻し

一般的なプログラムにも変数、関数、条件分岐はあります。LangGraphの価値は、それらをAI向けのグラフとして表現することだけではありません。途中状態の保存、失敗後の再開、人による確認、実行状況のストリーミングなどを、同じ実行モデルの中で扱える点にあります。

なぜ普通のLLMアプリだけでは足りないのか

1回の質問に1回答えるだけなら、LangGraphは不要です。問題は、AIに複数の工程を任せ始めたときに表面化します。

  • 検索結果を読んでから、追加調査の必要性を判断する
  • 複数のツールを使い、結果に応じて手順を変更する
  • 重要な操作の前に、人の承認を待つ
  • 長時間の処理が失敗したとき、最初からやり直さず再開する
  • 過去の会話や利用者の設定を引き継ぐ
  • どの判断で失敗したのかを後から確認する

この段階になると、本当の課題は「AIの回答精度」だけではありません。状態管理、再実行、権限、監査、重複処理の防止といった、従来の業務システムと同じ問題が発生します。

LangGraphは、LLMを特別扱いしすぎず、失敗する可能性のある処理の一つとしてワークフローへ組み込みます。この現実的な設計思想が、単純なエージェント用ライブラリとの大きな違いです。

LangGraphの重要機能は「記憶」より「再開」にある

LangGraphの紹介では、メモリ機能が注目されがちです。しかし実務でより重要なのは、チェックポイントによる中断と再開です。

チェックポイントは、グラフの各段階における状態の保存地点です。処理が途中で失敗しても、保存済みの状態から再開できます。公式ドキュメントでは、この永続化が次の機能の土台として説明されています。

  • 人が途中で確認・修正するHuman-in-the-loop
  • 会話やタスクの状態を引き継ぐ短期メモリ
  • 過去の状態へ戻して再実行するタイムトラベル
  • 障害後に最後の成功地点から再開する耐障害性

ここで重要なのは、チェックポイントが「ログ」ではないことです。ログは何が起きたかを記録しますが、チェックポイントは処理を続けるための状態そのものを保存します。

Human-in-the-loopは確認画面ではなく「待てる設計」

AIエージェントにメール送信、契約変更、返金、データ削除などを任せる場合、最後まで完全自動化するのは危険です。LangGraphのinterruptを使うと、処理を途中で止め、人からの入力が届くまで待機できます。

たとえば、AIが返金理由と金額を調べた後、担当者に「この返金を承認しますか」と確認し、承認された場合だけ決済APIを実行できます。確認が数時間後でも数日後でも、永続化された状態から再開できます。

ただし、interruptから再開すると、ノードは中断した行の次からではなく、ノードの先頭から再実行されます。そのため、中断前に行う副作用のある処理は、何度実行されても結果が壊れないように設計する必要があります。

承認前に「送信」「課金」「削除」を実行しない。実行する場合は必ず重複防止キーを持たせる。

LangGraphが向いているケース・向いていないケース

ケース 適性 理由
単発の文章生成や要約 低い 通常のLLM呼び出しで十分
決まった3工程だけの小さな処理 低〜中 通常の関数やジョブキューの方が簡単な場合が多い
調査結果に応じて手順が変わる 高い 条件分岐やループをグラフで管理できる
人の承認を挟む業務 高い 状態を保存したまま長時間待機できる
複数のAI・ツールが協調する 高い 各処理の役割と遷移を明示できる
失敗後に途中から再開したい 高い チェックポイントを利用できる
すべてをAIに自由判断させたい 注意 自由度が高すぎるとコスト・時間・事故率が読めない

判断基準は、「AIを使うか」ではなく「状態を持つ長い処理か」です。処理が短く、分岐もなく、失敗したら最初からやり直せばよいなら、LangGraphを導入すると複雑さだけが増えます。

WorkflowとAgentを混同しない

LangGraphの公式ガイドでは、WorkflowとAgentを区別しています。Workflowは進む道筋があらかじめ決まっており、Agentは状況に応じて自分で手順やツールを選びます。

実務では、すべてをAgentにする必要はありません。むしろ、次のようなハイブリッド構成が安定します。

  1. 入力検証、権限確認、保存は決定的なコードで行う
  2. 分類、要約、候補生成など曖昧さがある部分だけLLMへ任せる
  3. 高リスク操作の前で人の承認を挟む
  4. 実行結果を再び決定的なコードで検証・記録する

AIを中心にシステムを作るのではなく、制御可能なワークフローの一部としてAIを配置することが重要です。

最小コードで見るLangGraphの動き

次の例は、高リスクな依頼だけ人の承認を待ち、承認後に処理を続ける最小構成です。

from typing import Literal
from typing_extensions import TypedDict

from langgraph.checkpoint.memory import InMemorySaver
from langgraph.graph import END, START, StateGraph
from langgraph.types import Command, interrupt


class RequestState(TypedDict):
    request: str
    risk: Literal["", "low", "high"]
    approved: bool | None
    result: str


def assess_risk(state: RequestState) -> dict:
    high_risk_words = ("返金", "削除", "送金")
    risk = "high" if any(word in state["request"] for word in high_risk_words) else "low"
    return {"risk": risk}


def route_after_assessment(state: RequestState) -> Literal["review", "execute"]:
    return "review" if state["risk"] == "high" else "execute"


def review(state: RequestState) -> dict:
    approved = interrupt(
        {
            "question": "この操作を承認しますか?",
            "request": state["request"],
        }
    )
    return {"approved": bool(approved)}


def route_after_review(state: RequestState) -> Literal["execute", "reject"]:
    return "execute" if state["approved"] else "reject"


def execute(state: RequestState) -> dict:
    return {"result": f"実行しました: {state['request']}"}


def reject(state: RequestState) -> dict:
    return {"result": "承認されなかったため実行しませんでした"}


builder = StateGraph(RequestState)
builder.add_node("assess_risk", assess_risk)
builder.add_node("review", review)
builder.add_node("execute", execute)
builder.add_node("reject", reject)

builder.add_edge(START, "assess_risk")
builder.add_conditional_edges(
    "assess_risk",
    route_after_assessment,
    {"review": "review", "execute": "execute"},
)
builder.add_conditional_edges(
    "review",
    route_after_review,
    {"execute": "execute", "reject": "reject"},
)
builder.add_edge("execute", END)
builder.add_edge("reject", END)

graph = builder.compile(checkpointer=InMemorySaver())

config = {"configurable": {"thread_id": "request-1001"}}
initial_state: RequestState = {
    "request": "顧客へ返金する",
    "risk": "",
    "approved": None,
    "result": "",
}

paused = graph.invoke(initial_state, config=config, version="v2")
print(paused.interrupts)

completed = graph.invoke(
    Command(resume=True),
    config=config,
    version="v2",
)
print(completed.value["result"])

この例ではInMemorySaverを使っていますが、これは学習・検証用です。本番環境では、プロセスが落ちても状態が失われないデータベース対応のチェックポインターを利用する必要があります。

実務で事故を減らす6つの設計ルール

1. Stateを何でも入る箱にしない

会話全文、検索結果、巨大な文書、ツールの生レスポンスをすべてStateへ入れると、保存容量とデバッグコストが増えます。Stateには「次の判断に必要な情報」を持たせ、巨大なデータは外部ストレージへ置き、参照IDだけを保存する方が安全です。

2. Nodeは小さくし、役割を一つにする

調査、判断、メール作成、送信を一つのNodeにまとめると、どこで失敗したか分かりません。「情報取得」「判定」「文章生成」「外部操作」のように分けると、再実行とテストが容易になります。

3. 副作用のある処理は冪等にする

再開やリトライによって、同じNodeが複数回動く可能性があります。送金、注文、メール送信などには一意な実行IDを付け、同じIDの処理を二重実行しない仕組みを用意します。

4. thread_idを適当に決めない

thread_idは保存された状態を読み込むための重要なキーです。ランダム文字列を毎回生成すると会話や作業を再開できません。一方で、複数利用者が同じIDを共有すると状態が混ざります。利用者ID、案件ID、処理種別などを基に、衝突しない設計が必要です。

5. AIの判断回数に上限を設ける

Agentが自分でループできる構成では、調査を繰り返してコストと時間が膨らむことがあります。最大ステップ数、最大ツール回数、予算、タイムアウトを明示し、終了条件をStateに持たせます。

6. 最終回答だけでなく途中状態を評価する

最終出力が正しくても、不要なAPIを大量に呼んでいたり、危険な判断を偶然回避していたりする場合があります。ノードごとの入力、出力、分岐、ツール実行、所要時間、コストを確認し、経路そのものを評価することが重要です。

Graph APIとFunctional APIはどう選ぶか

LangGraphには、State・Node・Edgeを明示するGraph APIだけでなく、通常の関数、if文、for文に近い書き方で永続化や中断機能を追加できるFunctional APIもあります。

選択肢 向いている状況
Graph API 処理経路を可視化したい、複雑な分岐や並列処理がある、チームで設計を共有したい
Functional API 既存コードを大きく組み替えず、永続化・再開・Human-in-the-loopを追加したい

新規の複雑なエージェントシステムにはGraph APIが理解しやすく、既存のPython処理へ段階的に導入するならFunctional APIが現実的です。

LangGraphは「AIの自由」を増やす道具ではない

LangGraphを導入すると、AIが何でも自律的にできるようになるわけではありません。むしろ本質は、AIの自由を必要な範囲に制限し、状態、分岐、承認、再試行を明示することです。

生成AIシステムで最も危険なのは、モデルが間違えることだけではありません。間違った判断が、どの経路で外部操作へつながったのか分からないことです。LangGraphは、その経路をコードと状態として残し、止め、確認し、再開できるようにします。

単純なチャットには不要です。しかし、AIに数分以上の仕事、外部ツールの操作、人の承認、失敗からの復旧を任せるなら、LangGraphは有力な選択肢です。

参考資料