Claude Agent SDKとLangGraphの違い — ループを任せるか、遷移を描くか
Claude Agent SDKはClaude Codeのエージェントループごと組み込み、LangGraphはノードとエッジで状態遷移を自分で描きます。制御・永続化・中断の持ち方を並べ、選び方を示します。
違いは「ループを誰が持つか」にある
Claude Agent SDKとLangGraphは、どちらもエージェントをコードから動かす道具です。ただ、最初に手渡されるものが違います。
Claude Agent SDKは、Claude Codeが使っているエージェントループ・ビルトインツール・コンテキスト管理を、PythonとTypeScriptから呼べるようにしたライブラリです。ループはすでに動いていて、開発者は何を許可し、どこで止めるかを決めます。
LangGraphは、長時間動く状態付きエージェントのための低レベルなオーケストレーション基盤です。ノードとエッジで処理の流れを自分で描き、LLMに任せる箇所と決め打ちのコードで進める箇所を使い分けます。
| 比べる軸 | Claude Agent SDK | LangGraph |
|---|---|---|
| 位置づけ | Claude Agent SDKClaude Codeのエージェントを組み込むライブラリ | LangGraphオーケストレーション基盤(ランタイム) |
| 次の一手を決める主体 | Claude Agent SDKClaudeがループの中で決める | LangGraphグラフのエッジと自分で書いた分岐 |
| 最初から持つもの | Claude Agent SDKファイル操作・コマンド実行・フック・サブエージェント・MCP・権限・セッション | LangGraph状態・ノード・エッジ・永続化・中断 |
| 状態の保存 | Claude Agent SDKセッション(再開・フォーク) | LangGraphチェックポインターとストア |
| 人の承認 | Claude Agent SDK権限評価の流れとコールバック | LangGraphinterrupt()で止めて再開 |
「どちらが高機能か」ではなく、「ループを任せたいのか、遷移を自分で設計したいのか」で選びます。以降は、この軸に沿って制御・状態・中断・分業を順に見ます。
Claude Agent SDKは、完成したループを渡してくる
SDKの概要ページは、これを「自分のプロセスで運用する、Claude Codeのエージェントの組み込み」と位置づけています。中身はClaude Codeのバイナリを動かすライブラリで、Claude Codeの機能がそのまま使えます。
ループの進み方は単純です。Claudeがツール呼び出しを要求し、SDKが実行し、結果をClaudeへ返す。この1往復が1ターンで、ツール呼び出しを含まない応答が出たところでループが終わります。途中でコードに制御が戻ることはありません。
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def main():
options = ClaudeAgentOptions(
allowed_tools=["Read", "Edit", "Bash", "Glob", "Grep"],
max_turns=30, # 暴走防止の上限
)
async for message in query(
prompt="auth モジュールのテスト失敗の原因を直して",
options=options,
):
if isinstance(message, ResultMessage):
print(message.result)
asyncio.run(main())ここには「最初にテストを走らせる、次に読む、次に直す」という手順がありません。順序はClaudeがその場で決めます。開発者が書いたのは、使ってよいツールと、ターン数の上限だけです。
上限はmax_turns(TypeScriptではmaxTurns)とmax_budget_usd(同maxBudgetUsd)の2種類があります。max_turnsが数えるのはツール呼び出しを含むターンだけです。上限を置かないと、「コードベースを改善して」のような曖昧な依頼ではループが長く続きます。
ループ内部の挙動(メッセージの型、自動圧縮、並列ツール実行)はAgent SDKのエージェントループで詳しく扱っています。
LangGraphは、遷移を自分で描く
LangGraphには「エージェントのループ」が最初からあるわけではありません。状態の型を決め、ノード(処理)を足し、エッジ(次にどこへ進むか)でつなぎます。
from langgraph.graph import StateGraph, MessagesState, START, END
def mock_llm(state: MessagesState):
return {"messages": [{"role": "ai", "content": "hello world"}]}
graph = StateGraph(MessagesState)
graph.add_node(mock_llm)
graph.add_edge(START, "mock_llm")
graph.add_edge("mock_llm", END)
graph = graph.compile()
graph.invoke({"messages": [{"role": "user", "content": "hi!"}]})これは概要ページにあるhello worldです。LLMを呼ぶ処理は1ノードにすぎず、その前後に何をつなぐかは開発者が決めます。
分岐はエッジで表します。add_conditional_edgesにノード名と判定関数を渡すと、判定関数の戻り値で次のノードが変わります。状態更新と遷移先を1つの関数でまとめたいときはCommandを返します。
def route(state: MessagesState):
last = state["messages"][-1]
return "tools" if getattr(last, "tool_calls", None) else END
graph.add_conditional_edges("agent", route)「LLMがツールを呼びたがったらツールノードへ、そうでなければ終了」というエッジを描けば、エージェントループが成立します。つまり、Claude Agent SDKが内蔵しているループを、LangGraphでは構成要素から組み立てる形です。
LangGraphのドキュメントは、ワークフローとエージェントを分けて説明しています。ワークフローは決まった順序のコードパスで進み、エージェントは自分で手順とツールの使い方を決めます。LangGraphの強みは、この2つを1つのグラフに混ぜられる点です。決定論的な箇所は予測可能で監査しやすく、モデルに任せる箇所だけが柔軟に動きます。
なお、LangGraphはプロンプトやアーキテクチャを抽象化しません。ツール呼び出しループのような定型の構成がほしいときは、LangChainのエージェント(LangGraphの上に作られた抽象化)を使う案内が概要ページにあります。LangGraph自体を使うのにLangChainは必須ではありません。
状態はどう持つか — セッションとチェックポイント
どちらも「中断しても続きから再開できる」点は共通です。ただ、再開の単位が違います。
| 観点 | Claude Agent SDK | LangGraph |
|---|---|---|
| 保存の単位 | Claude Agent SDK会話(セッション) | LangGraphグラフ状態のスナップショット(チェックポイント) |
| 再開の鍵 | Claude Agent SDKセッションID(または直近のセッション) | LangGraphthread_id |
| 過去に戻って試す | Claude Agent SDKセッションをフォーク(元は変わらない) | LangGraphタイムトラベル(チェックポインターの用途の1つ) |
| 長期の記憶 | Claude Agent SDKCLAUDE.mdやメモリなどClaude Codeの仕組み | LangGraphストア(スレッドをまたぐ値) |
| 別ホストで続ける | Claude Agent SDKセッションストアを渡すか、ファイルを移す | LangGraph永続化に対応したチェックポインターを選ぶ |
Claude Agent SDKの再開は、「前回の会話」を復元する動きです。読んだファイル、行った分析、実行した操作を含む全文脈が戻ります。フォークは元の履歴をコピーした新しいセッションを作り、元のセッションは変わりません。
セッションファイルは作成したマシンのローカルに置かれます。CIワーカーやサーバーレスのように別ホストで再開するなら、session_store(TypeScriptではsessionStore)のアダプターを渡してトランスクリプトを自前のバックエンドに複製します。再開に頼らず、必要な結果をアプリの状態として持ち、新しいセッションのプロンプトに渡す選択肢もあります。
LangGraphでは、グラフをcompile(checkpointer=...)でコンパイルし、実行のたびにthread_idを渡します。同じthread_idを使えば同じチェックポイントから続き、新しい値なら空の状態から始まります。チェックポインターは短期の(スレッドに閉じた)記憶、ストアは長期の(スレッドをまたぐ)記憶という役割分担です。
本番では永続化に対応したチェックポインターを使います。InMemorySaverとMemorySaverはRAMに保存するため、プロセスを再起動すると消えます。チェックポイントは会話が長くなるほど溜まるので、古いものを消す運用も要ります。
人の承認を挟むとき — 権限評価とinterrupt
自動で動くエージェントに「ここは人が確認する」を入れる方法は、両者で発想が逆です。
Claude Agent SDKでは、ツール呼び出しが権限評価の流れを通ります。順序はフック、拒否ルール、確認ルール、権限モード、許可ルール、canUseToolコールバックです。どこにも当たらなかった呼び出しが、最後にコールバックへ届きます。
注意点がひとつあります。許可ルールやacceptEdits・bypassPermissionsで自動承認された呼び出しは、canUseToolに届きません。コールバックに書いた確認が黙って素通りされることがあります。すべての呼び出しで必ず走らせたい検査は、PreToolUseフックに置きます。フックは他のどの段階より先に動き、フックの拒否はbypassPermissionsでも効きます。
LangGraphでは、ノードの中でinterrupt()を呼びます。グラフの状態が保存され、再開されるまで実行が止まります。
from langgraph.types import interrupt
def approval_node(state: State):
approved = interrupt("この操作を実行してよいですか?")
return {"approved": approved}再開はCommand(resume=...)でグラフを呼び直します。渡した値が、ノード内のinterrupt()の戻り値になります。使うには、チェックポインターとthread_idが必須です。
ここにも設計上の落とし穴があります。LangGraphのドキュメントは、interruptをtry/exceptで包まないこと、ノード内でinterruptの呼び出し順を変えないこと、interruptの前に走る副作用は冪等にすることを挙げています。再開時にはノードが先頭から再実行されるためです。
まとめると、Claude Agent SDKは「ツール単位のゲート」、LangGraphは「処理の途中に置く任意の停止点」です。承認を挟む場所が「このツールを呼ぶ直前」なら前者が素直で、「3ステップ目の結果を人が編集してから4ステップ目へ」のように業務の区切りで止めたいなら後者が合います。
分業の考え方 — サブエージェントとグラフの分岐
複数の役割で仕事を分けたいときも、扱いが違います。
Claude Agent SDKのサブエージェントは、メインのエージェントが生成する別のエージェントインスタンスです。それぞれが自分の会話を持ち、途中のツール呼び出しや結果はサブエージェントの中に閉じ、親に返るのは最終メッセージだけです。コンテキストの隔離、並列実行、専門的な指示、ツールの制限が主な利点です。サブエージェントがさらにサブエージェントを生成することもでき、深さは環境変数で制限します。
LangGraphでは、分業はグラフの形そのものです。並列化、ルーティング、オーケストレーター・ワーカー、評価と改善の繰り返しといったパターンが、ノードとエッジの組み合わせで描かれます。誰に何を渡すかは、モデルの判断ではなく設計図に書かれます。
「誰に任せるかをモデルが決めてよい」ならサブエージェント、「この入力ならこのノード」を固定したいならグラフ、という整理になります。同じSDK系のOpenAI Agents SDKやGoogle ADKとの違いは、OpenAI Agents SDKとの比較とGoogle ADKとの比較にまとめています。
どちらを選ぶか — 状況から決める
| こういう状況 | 寄せる先 | 理由 |
|---|---|---|
| コードを読んで直す、調べてまとめるなど、手順を決めにくい作業 | 寄せる先Claude Agent SDK | 理由ファイル操作・コマンド実行を含むループが最初からある |
| 手順が決まっていて、一部だけLLMに任せたい | 寄せる先LangGraph | 理由決定論的なノードと、LLMのノードを1つのグラフに混ぜられる |
| 業務の区切りごとに人が確認・編集する | 寄せる先LangGraph | 理由interrupt()で任意の位置に止められる |
| ツール単位で許可・拒否を細かく管理したい | 寄せる先Claude Agent SDK | 理由拒否・確認ルール、権限モード、フックで制御する |
| 実行を永続化し、失敗後に続きから回したい | 寄せる先LangGraph | 理由チェックポインターが状態を保存する |
| 自社のアプリに、コーディングエージェントの能力をそのまま載せたい | 寄せる先Claude Agent SDK | 理由Claude Codeの機能をそのまま呼べる |
両者を排他と考える必要はありません。LangGraphのノードの中から、Claudeにコードを書かせる処理を呼ぶ構成も考えられます。概要ページにこの組み合わせの推奨は書かれていないため、設計は自分で検証する前提になります。LangGraph側の実装手順はClaude CodeでLangGraphエージェントを実装する手順にあります。
ホスト型のエージェントが選択肢に入るなら、状態遷移とイベントの扱いをManaged Agentsのworkflow runで確認できます。
導入前に確認する条件
Claude Agent SDKには、認証まわりの条件があります。承認を得ていない限り、サードパーティの開発者が自社製品でclaude.aiのログインやレート制限を提供することは認められません。クイックスタートに書かれているAPIキー認証を使います。
利用はAnthropicの商用利用規約に従います。自社のユーザーに提供する製品やサービスを動かす場合も同じです。
Claude Agent SDKの言語はPythonとTypeScriptです。ほかの言語から同じループを動かすなら、-pフラグと--output-format jsonを付けたCLIをサブプロセスとして起動する方法が案内されています。製品の中でClaudeを名乗るときのブランド表記にも制約があり、「Claude Code」や「Claude Code Agent」の名称は使えません。
LangGraph側で押さえる条件は、チェックポインターの選択です。開発中はメモリ上で足りても、本番ではPostgresのような永続化できる実装が必要になります。PostgresSaverを使うときは、thread_idが255文字を超えないようにします。
まとめ
Claude Agent SDKは「判断をモデルに任せ、周りに柵を立てる」道具、LangGraphは「判断の置き場所を自分で決める」道具です。判断の置き場所を選べることがLangGraphの自由度であり、同時に設計の手間でもあります。
迷ったときは、手順を事前に書けるかで切り分けます。書けないなら、ループごと渡してツールと権限で囲う。書けるなら、グラフに起こして、LLMの出番だけを限定する。後者でも、重い実行部分だけをClaude Agent SDKに任せる構成は成立します。