LangGraph の構築:第一原理から設計するエージェントランタイム
LangChain チームが、生産環境でのスケーラビリティと制御性を最優先し、従来の抽象化を排した低レベルなエージェントランタイム「LangGraph」のアルファ版を発表しました。
キーポイント
設計思想の転換:抽象化から制御へ
既存の LangChain が学習しやすくカスタマイズしにくいというフィードバックを踏まえ、LangGraph では「最小限の抽象化」を採用し、開発者がエージェントの挙動を完全に制御・管理できることを最優先しました。
生産環境向けの実装
スタートアップや大企業(LinkedIn, Uber, Klarna 等)が実際に使用している実績に基づき、耐久性(durability)とスケーラビリティを重視した設計で、本番環境での運用を前提としています。
LangGraph アルファ版の公開
2 年以上の設計プロセスを経て、LangChain のエージェント機能のリブートとして位置づけられた LangGraph 1.0 のアルファバージョンが正式にリリースされ、開発者が試せるようになりました。
エージェント構築の課題解決
従来のソフトウェアとは異なる AI エージェント特有の課題(非決定性、状態管理など)を克服するため、グラフベースの構造を用いて複雑なワークフローを確実かつ再現可能に実行する仕組みを提供します。
影響分析・編集コメントを表示
影響分析
この記事は、生成 AI エージェント開発のトレンドが「手軽に動かすこと」から「堅牢に運用すること」へとシフトしていることを示す重要な転換点です。LangChain の公式チームが自社のフレームワークの限界を認め、あえて抽象化を削って制御性を高めるという逆説的なアプローチを採用したことは、業界全体が本番環境での AI 導入の壁に直面している証左であり、今後のエージェント開発のパラダイムを変える可能性があります。
編集コメント
「使いやすさ」を犠牲にしてでも「制御性」と「耐久性」を選ぶという、本番環境向け AI ツール開発における非常に勇気ある判断が示されています。開発者にとっては学習コストは上がるかもしれませんが、大規模なエージェントシステムを安定して運用する上で不可欠な指針となるでしょう。

*By Nuno Campos*
要約: 私たちは約 2 年前に、低レベルのエージェントフレームワークである LangGraph をリリースしました。すでに LinkedIn、Uber、Klarna といった企業が、本番環境で動作するエージェントを構築するためにこれを利用しています。LangGraph は、非常に人気のある LangChain フレームワークからのフィードバックに基づいて構築され、生産環境向けにエージェントフレームワークがどのように機能すべきかを再考したものです。私たちは AI エージェントにとって最適な抽象化レベルを探求し、最終的にはほとんど、あるいは全く抽象化しないという結論に至りました。その代わり、私たちは「制御」と「耐久性」に焦点を当てました。この投稿では、信頼性の高いエージェントを構築する過程で得た知見に基づき、LangGraph の設計原則とアプローチについて共有します。
LangGraph ALPHA
ついに LangGraph 1.0 のアルファ版をリリースしました!
—
私たちは、2 年以上前に LangChain の非常に人気のあるチェーンやエージェントの再構築として LangGraph を開始しました。オリジナルの langchain オープンソースライブラリ(無数の GitHub イシュー、ディスカッション、Discord、Slack、Twitter の投稿)がリリースされて以来受け取ったすべてのフィードバックに対応するために、ゼロから始めることが最も柔軟性があると考えたのです。私たちが最も頻繁に耳にしたのは、「langchain は始めやすいが、カスタマイズやスケーリングは難しい」という点でした。今回は、LangGraph を本番環境でエージェントを実行するために使用するものにするという目標を最優先しました。トレードオフを迫られた際にも、人々が始めやすさよりも、本番環境での使用準備ができていることを優先しました。
この投稿では、LangGraph のスコープ設定と設計プロセスについて共有します。
- まず、従来のソフトウェア開発と比較してエージェント構築がどのように異なるかを解説します。
- 次に、これらの違いを必須機能に変換した方法について議論します。
- 最後に、これらの要件に対してフレームワークをどのように設計しテストしたかを示します。
その結果、エージェントの規模とスループットの両方にスケールする、低レベルで本番環境対応のエージェントフレームワークが生まれました。
エージェントに必要なものは何か?
私たちが最初に問うた2つの質問は、「実際に LangGraph を構築する必要があるのか?」そして「既存のフレームワークを使ってエージェントを生産環境に導入できないのか?」でした。これらの問いに答えるためには、エージェントが過去のソフトウェアとどのように異なる(あるいは類似している)かを定義する必要がありました。私たちは多数のエージェントを自ら構築し、Uber、LinkedIn、Klarna、Elastic などのチーム 2024年の生産環境におけるトップ5の LangGraph エージェント と協力する中で、これらを3つの重要な違いに絞り込みました。
- より高いレイテンシ(遅延)は、ユーザーのエンゲージメントを維持することを困難にする
- 失敗した長時間実行タスクのリトライは、コストが高く時間がかかる
- AI の非決定論的な性質には、チェックポイント、承認、テストが必要である
レイテンシ(遅延)の管理
LLM ベースのエージェントにおける最初の定義的特質かつ課題はレイテンシです。以前はバックエンドエンドポイントのレイテンシをミリ秒単位で測定していましたが、今ではエージェントの実行時間を秒、分、あるいは間もなく時間単位で測定する必要があります。
その理由は、LLM 自体が遅く、テスト時の計算リソース(test-time compute)が増えるにつれてさらに遅くなっているからです。また、望ましい結果を達成するために複数の LLM 呼び出しが必要となる場合が多く、ループするエージェントや、以前の出力を修正するための連鎖的な LLM プロンプトを使用することもあります。通常、LLM の呼び出しの前と後に非 LMM ステップを追加する必要があります。例えば、データベースの行をコンテキストに読み込んだり、LLM の呼び出しの正確性を確認するためのガードレールや検証器を作成したりする必要があるかもしれません。
これらの遅延は新しいものを構築することを可能にしますが、エンドユーザーを最後まで関与させ続ける必要があります。そこで、エージェントを構築する際に役立つと判断した 2 つの機能を見出しました。
- パラライゼーション(並列化)。エージェントに複数のステップがある場合、次のステップが前のステップの出力を必要としないときは、それらを並列で実行できます。ただし、本番環境でこれを確実に実行するには、並列ステップ間のデータ競合(data races)を避ける必要があります。
- ストリーミング。エージェントの実際の遅延をこれ以上短縮すると結果が悪化する場合、知覚される遅延(perceived latency)に頼ります。ここで鍵となるのは、エージェントが動作している間にユーザーに有用な情報を表示することです。これは進捗バーやエージェントが行った主要なアクションから、エンドユーザーに対して LLM のメッセージをトークン単位でリアルタイムにストリーミングするまで、あらゆる形態を取り得ます。
信頼性の管理
LLM エージェントの遅延には、他の影響も伴います。ご存知の通り、ソフトウェアの不具合は避けられません。長時間実行されるエージェントほど失敗しやすく、実行時間が長いほど何かが間違える機会が増えるからです。
従来のソフトウェアで不具合が発生した場合、通常は再試行を行います。しかし AI エージェントの場合、それが最善のアプローチとは限りません。もしエージェントが 10 分間のうち 9 分目に失敗した場合、最初からやり直すのは非常に時間がかかり、かつ高コストになります。
そこで、リストにさらに 2 つの機能を追加する必要があると判断しました。
- タスクキュー。キューは、エージェントの実行をトリガーしたリクエストから切り離すことで、一般的な失敗原因の 1 つを排除します。必要に応じて、エージェントを信頼性が高くかつ公平に再試行するための基盤を提供します。
- チェックポイント機能。これは計算状態のスナップショットを中間段階で保存し、実際に失敗した場合の再試行コストを大幅に削減します。
非決定性の LLM の管理
次に、LLM が持つ非決定性という性質が、さらに 2 つの課題を生み出します。従来のソフトウェアを書く場合、少なくともコードが何をするべきか、期待通りに構築した際にどのような結果が得られるかは把握できます。しかし、生成 AI はこれを明らかに変えてしまいます。
LLM では、入力も出力もどちらも開かれたものになります。ChatGPT を使用した経験がある方なら想像できるでしょう。前日に使ったのと同じプロンプトでさえ、異なる結果を生むことがありますし、同じ質問をさまざまな方法で問い合わせて類似の結果が得られることの容易さも実感できるはずです。
これが、LLM エージェントが以前の他のソフトウェアと比較して非常に強力である理由の大きな部分を占めていますが、一方で本番環境へ移行する際には課題も生じます。
開発中に実施するテストでは、ユーザーがエージェントをどのように利用するかという驚くべき多くのパターンを見逃す可能性が極めて高いです。ユーザーがエージェントとどう相互作用するか、あるいは LLM がどのように応答するかについて、すべてを事前に計画することは真に不可能です。したがって、本番環境へ移行する際には、さらに 2 つの機能が非常に有用となります:
- Human-in-the-loop。AI エージェントの作業を中断して再開するツールを持つことで、それまでに完了した作業をやり直すことなく、あらゆる時点で介入・再開が可能になります。これにより、AI エージェントにとって不可欠な UX パターンが多数実現します。例えば、アクションの承認または拒否、次のアクションの編集、明確化のための質問、あるいは過去のステップからやり直すための「タイムトラベル」などが挙げられます。
- Tracing(追跡)。スケーラビリティに対応するためには、開発者はエージェントループの詳細内で何が起きているかを明確に把握できる必要があります。エージェントの入力、軌跡、出力を確認できなければ、ユーザーが何を求めているか、エージェントがそれをどう処理しているか、そしてユーザーが結果に満足しているかどうかを知ることはできません。
エージェント構築に必要な開発者の要件
これが、エージェントを実環境(プロダクション)へ移行する際に、開発者が最も必要とする 6 つの機能を絞り込んだ方法です。
- Parallelization(並列化)– 実際のレイテンシを削減するため
- Streaming(ストリーミング)– 知覚されるレイテンシを削減するため
- Task queue(タスクキュー)– リトライ回数を減らすため
- Checkpointing(チェックポイント)– 各リトライのコストを削減するため
- Human-in-the-loop – ユーザーと協働するため
- Tracing – ユーザーがどのように利用しているかを学ぶため
あなたが構築しようとしているエージェントにこれらの機能の大半が必要ない場合(例えば、ツールを持たず単一のプロンプトで動作する非常に短いエージェントである場合)、LangGraph や他のフレームワークは不要かもしれません。
これらの機能それぞれを構築することを検討する中で、私たちは開発者が、エンドユーザーにとって LLM アプリケーションの動作が明らかに遅くなるという代償を払ってまで、すべての機能を備えたフレームワークを採用することはないと気づきました。特にチャットボットとして展開されるエージェントにおいてはそうです。これが低レイテンシを最終的な包括的な要件とする理由となりました。
次に、これらの機能を LangGraph にどのように組み込んだかについて解説します。
2. なぜ LangGraph を構築するのか?
存在意義に関する問いに戻りましょう。新しいものを構築すべきか、それとも LLM の登場以前に作られた既存のオープンソースフレームワークを採用すべきか。機能のリストを手にした今、その決断を下すのは非常に容易でした。
新しいフレームワークが必要だった理由
既存のフレームワークは主に 2 つのカテゴリーに分かれていました:
DAG フレームワーク(Apache Airflow などによって普及)
これらは名前のみで除外せざるを得ませんでした。LLM エージェントはループ処理から大きな恩恵を受けるためです。つまり、LLM エージェントの計算グラフは循環的であり、DAG アルゴリズムでは扱えないからです。
永続実行エンジン(Temporal などによって普及)
これらの選択肢はより近いものでしたが、最終的には LLM エージェントの設計以前に作られたものだったため、ストリーミングといった特定の機能が不足していました。さらに、これらのエンジンではステップ間に遅延が生じ、チャットボット開発者にとって顕著な問題となっていたのです。最後に、その設計上の理由から、履歴内のステップ数が増えるほどパフォーマンスが低下するという点があり、LLM エージェントがより長く複雑になるにつれて、これは良い賭けではないように思われました。
そこで結論として、LLM は十分に異なるため、新しい時代に対応させるには既存の生産インフラに新たなアイデアを注入する必要があると考えました。そこで私たちは LangGraph の構築に取り掛かりました。
3. 私たちの設計哲学
LangGraph を設計するにあたり、2 つの主要な原則を掲げました。
- 私たちは AI の未来がどうなるか知りません。未来について仮定するほど少ないほど良いのです。1 年、2 年、3 年後に LLM(大規模言語モデル)を使って構築するとどのような姿になるのか、誰も本当に知りません。したがって、フレームワークの設計に組み込む仮定を少なくすればするほど、将来においてもその重要性は保たれます。私たちが組み込みたかった唯一の仮定とは、前述した認識、つまり LLM は遅く、不安定で、かつ開かれたものであるという事実です。
- それはコードを書くような感覚であるべきです。このフレームワークのパブリック API(アプリケーションプログラミングインターフェース)は、フレームワークを使用しない通常のコードを書くことと可能な限り近接している必要があります。開発者のコードに課すすべての要件は、非常に価値の高い機能を可能にするために正当化されなければなりません。そうでなければ、フレームワークを完全にスキップする誘惑の方が強すぎてしまいます。あらゆるコードフレームワークにとって最大の競合相手は、常に「フレームワークなし」です。
- これらの原則は、私たちが今に至るまで守り続けているいくつかの重要な設計決定に影響を与えました。
- まず、ライブラリのランタイムは開発者向け SDK とは独立しています。SDK は、開発者がエージェントを構築する際に使用する公開インターフェース(クラス、関数、メソッド、定数など)です。現在、私たちは 2 つの SDK を提供しています。1 つは StateGraph、もう 1 つは命令型/関数型 API です。ランタイム(私たちが PregelLoop と呼んでいます)は前述した各機能を実装し、各エージェント呼び出しに対して計算グラフを計画して実行します。この設計により、開発者向け API とランタイムを独立して進化させることが可能になります。例えば、SDK 側では命令型 SDK の導入や、共有状態を持たない最初の Graph インターフェースという当初の SDK の非推奨化が可能になりました。一方、ランタイム側では、過去 2 年間にわたって公開 API に影響を与えることなく多くのパフォーマンス向上を実装でき、より大胆なランタイムの変更の実験も可能になりました。これについては後ほど分散実行について触れる際に詳しく説明します。
- 次に、6 つの機能それぞれをビルディングブロックとして提供し、開発者がいつでも自らのエージェントで使用するものを選択できるようにしたかったのです。例えば、人間が関与するシナリオにおける中断/再開機能は、実際に必要とするまで邪魔になることはありません(これは、ノードのいずれかで interrupt() 関数を呼び出すように追加するだけで、非常に簡単です)。その結果、LangGraph は、最新のハイレベル抽象化にすべてを賭けるよう開発者を説得しようとする他のフレームワーク群の中で、ユニークな低レベルフレームワークとして位置づけられました。私たちはこれらの流行が来たり去ったりするのを何度も見てきましたが、LangGraph が依然として関連性を保ち続けているため、これまでの私たちのアプローチには満足しています。
4. LangGraph ランタイム
これらの点を踏まえ、LangGraph が私たちが望んだ 6 つの機能(並列化、ストリーミング、チェックポイント、人間をループに組み込む機能、トレーシング、タスクキュー)それぞれを実装する方法を見ていきましょう。
離散的なステップを持つ構造化エージェント
私たちが下した他のすべてのアーキテクチャ上の決定に影響を与えている一つの考えがあります。それは「構造化エージェント」というアイデアです。コンピュータプログラムにより多くの構造を追加し、ある程度の柔軟性を引き換えに数々の新機能を獲得するという長い伝統があります。かつては、基本的な構築要素である if 文や while ループ が新しい存在として登場しました。エージェントもまた、単一の大きな while ループを持つ一つの関数として直接記述することができます。しかし、そうすると、チェックポイント機能や人間をループに組み込む機能を実装する能力を失ってしまいます。(注:一部のサブルーチン(ジェネレーターなど)の実行を技術的に中断することは可能かもしれませんが、その実行状態は、異なるマシンで異なる時刻から再開できるポータブルな形式で保存することはできません。)
実行アルゴリズム
エージェントを複数の離散ステップに構造化することを選んだら、その実行を組織化するための何らかのアルゴリズムを選ぶ必要があります。たとえ「アルゴリズムなし」と感じるほど単純なものであっても、それが LangGraph がローンチ前にスタートした地点でした。「アルゴリズムなし」を使う問題点は、一見シンプルに見えるものの、その場で適当に作り上げていくことになり、予期せぬ結果を招くことです(例えば、LangGraph の前身となる初期バージョンでは、並列ノード間で非決定論的な動作が生じるという課題がありました)。ループが必要であるため、通常の DAG アルゴリズム(トポロジカルソートとその関連手法)は適用できません。私たちは最終的に、BSP / Pregel アルゴリズムの上に構築することを選びました。これは、ループ(サイクル)を完全にサポートしつつ、決定論的な並列処理を実現するからです。
私たちの実行アルゴリズムは以下の通り動作します:
- チャンネルはデータ(任意の Python/JS データ型)を含み、名前と現在のバージョン(単調増加する文字列)を持ちます
- ノードは実行される関数であり、1 つ以上のチャンネルに購読しており、それらが変更されると実行されます
- 1 つ以上のチャンネルが入力にマッピングされており、つまりエージェントへの開始入力がこれらのチャンネルに書き込まれるため、これらに購読されているすべてのノードがトリガーされます
- 1 つ以上のチャンネルが出力にマッピングされており、つまりエージェントの戻り値は、実行が停止した時点でのこれらのチャンネルの値です
実行はループとして進行し、各反復では
- 現在のチャンネルバージョンと各購読者が最後に確認したバージョンを比較することで、実行する 1 つ以上のノードを選択します
- それらのノードを並列で実行します。この際、チャンネル値(つまり状態)の独立したコピーを使用するため、実行中に互いに影響し合いませ ん
- ノードは実行中に状態のローカルコピーを変更します
- すべてのノードが完了すると、各状態コピーからの更新がそれぞれのチャンネルに適用されます。これは決定論的な順序で行われ(これがデータ競合を防止する仕組みです)、その後チャンネルバージョンがインクリメントされます
実行ループは、実行すべきノードが残っていない場合(つまり、チャンネルと購読関係を比較した結果、すべてのノードが購読しているチャンネルの最新バージョンを確認済みである場合)か、開発者が設定できる定数値である反復ステップ数が尽きた場合に停止します。
フレームワーク機能の検証
これが、実装したかった 6 つの機能にどのように対応するかを見てみましょう。
- Parallelization. このアルゴリズムはデータ競走のない安全な並列化のために設計されており、ノード間の依存関係が許す限り自動的に並列実行を選択します。また、並列実行されるノードには隔離された状態のコピーを使用し、更新をどのノードが先に開始または完了したか(これは実行ごとに変わる可能性があります)に依存しない順序で適用します。これにより、各ノードの実行順序やレイテンシがエージェントの最終出力に影響を与えることがなくなります。LLM は非決定論的であるため、出力の変動が決してエージェントフレームワークのせいではないことを保証することは重要な特性だと考えました。これにより、問題のデバッグが格段に容易になります。
- Streaming. 構造化された実行モデル(つまり、計算が離散的なステップやノードに分割されるモデル)は、実行中を通じて中間出力や更新をエミットする機会を大幅に増やします。当社の実行エンジンでは、カスタム開発コードを必要とせずに、ノードの実行中およびステップ境界においてストリーミング出力を収集しています。これにより、LangGraph では 6 つの異なるストリームモード(values, updates, messages, tasks, checkpoints, custom)を提供できるようになりました。チャットボットであればメッセージストリームモードを使用し、長時間実行されるエージェントであれば更新モードを使用するといった具合です。
- Checkpointing. これもまた、構造化された実行が可能にするものです。私たちは、保存から任意の時間経過後にどのマシンでも再開可能なチェックポイント、つまり特定のマシンでプロセスを継続して稼働させることや、メモリ上に生データを保持することに依存しないチェックポイントを保存したいと考えています。これを実現するために、シリアライズされたチャネル値(デフォルトでは MsgPack にシリアライズされ、オプションで暗号化可能)と、そのバージョン文字列、および各ノードが最も最近に参照したチャネルバージョンの記録を保存します。
- Human-in-the-loop. 耐障害性を可能にする同じチェックポイント機能は、エージェントに対する「予期された中断」を実現するためにも使用できます。つまり、継続する前にユーザーや開発者からの入力を求めるために、エージェント自身が自ら中断できる能力を与えることです。通常この機能は、入力到着を待っている間もエージェントを実行し続けることで実装されますが、残念ながらこれは時間とボリュームの両面でスケーラビリティに欠けます。多数のエージェントが同時に中断されている場合や、返信までに数日(あるいは数ヶ月!)待ちたい場合は、実際の中断(チェックポイント機能によって同じ地点から再開可能にする仕組み)こそが唯一の解決策です。
- Tracing. 構造化された実行を使用するもう一つの優れた特性は、エージェントの実行中および事後に、その進捗を調査するための非常に明確なステップが得られることです。私たちは以前に最初の LLM オブザーバビリティプラットフォームとして LangSmith を構築していたため、LangGraph は当然ながらネイティブでそれと統合されています。今日ではまた LangGraph Studio も利用可能で、実行中のエージェントをデバッグできますし、より広い互換性のために OTEL トレースもエミット可能です。
- Task queue. これは LangGraph のような Python ライブラリの範囲外であったため、このニーズに応えるために LangGraph Platform を作成することになりました。
全体として、このアーキテクチャはエージェントに必要な 6 つの主要機能をすべて提供します。同時に、構造化されたアプローチとそれを探索するためのツールのおかげで、エージェントの作成とデバッグがより迅速になります。最後に、これは優れたパフォーマンスプロファイルで実現されており、エージェントの規模や本番環境での必要スループットに応じてスケールします—これについては次のセクションで詳しく説明します。
5. パフォーマンス特性
前述した通り、開発者は信頼性を求めますが、レイテンシ(応答遅延)を犠牲にしてまで求めるわけではありません。そのため、私たちのアプローチがこれらのトレードオフに対してどのように機能しているかを検討する必要があります。LangGraph は、それを用いて構築するエージェントのあらゆる規模測定において非常に滑らかにスケーリングします。これは、エージェントがより長く、ステップ数が増え、中断が多くなり、状態サイズが大きくなるなど、ますます複雑化していく未来において、極めて有利な立場にあります。
LangGraph エージェントの実行は、その規模を制御する主要な変数によってどのように影響を受けるのでしょうか?
まず、最も一般的な LangGraph 開発者 SDK である StateGraph における主要なサイズ変数を列挙しましょう:
- ノードの数(個々のステップ、通常は関数)
- エッジの数(ノード間の接続。固定または条件付きのいずれか)
- チャンネルの数(状態オブジェクト内のキー)
- アクティブなノードの数(特定のステップで並列実行されるもの)
- 呼び出し履歴の長さ(現在の呼び出しにおける過去のステップ)
- スレッドの数(異なる入力とコンテキストに対する独立した呼び出し)
次に、LangGraph エージェントの呼び出しにおける主要な瞬間を列挙し、それぞれの変数に対してどのようにスケーリングするかを見ていきましょう:
- スレッドの最新のチェックポイントからストレージへ転送し、それをシリアライズ解除して開始または再開する呼び出し
- 次の実行ステップを計画する段階で、次にどのノードを実行するかを決定し、その入力を用意する
- 現在のアクティブなノードを実行するステップで、各ノードのコードを実行し、チャネルやエッジへの書き込みを行う
- 呼び出しステップを終了する段階で、各チャネルへの更新を適用(チャネルリデューサーの実行とチャネルバージョンのインクリメント)し、最新のチェックポイントを保存(シリアライズしてストレージへ転送)する
なお、計画アクションが次に実行すべきノードを返さない場合、実行は単に停止するため、「呼び出し終了」というアクションは存在しない。
要約すると、各アクションの拡張性はエージェントサイズに対して以下のようになる:
メトリック / アクション
呼び出し開始
ステップ計画
ステップ実行
ステップ終了
ノード数
O(n)
O(1)
O(1)
O(n)
エッジ数
O(1)
O(1)
O(n)
O(1)
チャネル数
O(n)
O(n)
O(n)
O(n)
アクティブなノード数
O(1)
O(n)
O(n)
O(n)
履歴の長さ
O(1)
O(1)
O(1)
O(1)
スレッド数
O(1)
O(1)
O(1)
O(1)
では、これらの中からいくつかをより詳細に確認しよう。まず、呼び出しを開始するプロセスから始める:
- ノード数に対して線形にスケーリングします。各ノードには、その入力エッジの現在の状態を保持する 1 つの隠された制御チャネルが存在するためです。
- エッジ数に対して一定です。各宛先ノードにおけるすべてのエッジの状態が、単一の制御チャネルに集約されるためです。
- チャネル数に対して線形にスケーリングします。各チャネルには、その現在の値のシリアライズ表現が存在するためです。
- アクティブなノード数に対して一定です。この変数との関係はありません。
- ヒストリの長さに対して一定です。最新のスナップショットのみを取得し、それ以前のステップを再生する必要がないためです。
- スレッド数に対して一定です。スレッドは完全に独立しており、各呼び出しでは単一のスレッドのみが影響を受けるためです。
次に、次のステップの計画について:
- ノード数は一定であり、前ステップ完了時に更新されたチャンネルのリストを保存することで、次のノードを計画する際に全ノードを反復処理する必要がなくなります
- エッジ数も一定です。各ノードに対してすべてのエッジが単一のトリガーチャンネルに集約されるためです
- チャンネル数は線形にスケーリングします。各ノードの入力を組み立てる際、現在設定されているチャンネルを確認するためにチャンネルを反復処理するためです
- アクティブなノード数も線形にスケーリングします。このステップで実行する各ノードについて、その呼び出しに使用する入力と構成を組み立てるためです
- 履歴の長さは一定です。すべての以前の書き込みを集約した最新のチェックポイントのみを扱うためです
- スレッド数は一定です。スレッドは完全に独立しており、各呼び出しが単一のスレッドのみを対象とするためです
第三に、ステップの実行:
- ノード数は一定であり、ステップ内でアクティブなノードのみがそのステップの実行に影響します
- このステップでアクティブなノードのエッジ数に対して線形にスケーリングし、各アクティブなノードは自身の出力エッジすべてへ公開を行います
- チャンネル数に対して線形にスケーリングし、各アクティブなノードについて、そのノードが値への更新を返したかどうかを確認します(辞書形式の戻り値を使用する場合は、これをチャンネル数に対して一定となるように最適化し、戻り値のキーのみを反復処理します)
- アクティブなノード数に対して線形にスケーリングし、各アクティブなノードは並列で実行されます
- 履歴の長さに対して一定であり、現時点では履歴を扱いません
- スレッド数に対して一定であり、スレッドは完全に独立しており、各呼び出しは単一のスレッドのみを対象とするためです
最後に、ステップの完了について:
- ノード数に対して線形にスケーリングします。各ノードには、その入力エッジの現在の状態を保持する 1 つの隠された制御チャネルが存在するためです。
- エッジ数に対して一定です。各宛先ノードにおけるすべてのエッジの状態が、単一の制御チャネルに集約されるためです。
- チャネル数に対して線形にスケーリングします。各チャネルはアクティブなノードからの書き込みで更新され、そのバージョン番号が増分されます。
- アクティブなノード数に対して線形にスケーリングします。各アクティブノードからの書き込みを収集するためです。
- 履歴の長さに対して一定です。すべての以前の書き込みを集約した最新のチェックポイントのみを扱うためです。
- スレッド数に対して一定です。スレッドは完全に独立しており、各呼び出しが単一のスレッドにのみ影響を与えるためです。
これらのパフォーマンス特性は、ライブラリの設計選択の結果であると同時に、過去 2 年間にわたって実施してきた多数のパフォーマンス最適化の成果でもあります。
はじめに
要約すると、LLM を使用して構築することの違いや、エージェントを本番環境で実行するために必要なものは何かについて、深く考察しました。これらの考えが LangGraph の構築と反復開発へとつながりました。LangGraph は制御と耐久性に焦点を当てており、これにより、あなたのエージェントが意図した通りに動作する可能性が最も高まります。
LangGraph についてさらに詳しく学び、ご自身のプロジェクトで試してみたい場合は、ドキュメントへお進みください。
関連コンテンツ

ケーススタディ
LangGraph
観測可能性と評価
信頼性の高い金融データ検索を解決するために、Kensho が LangGraph を用いて構築したマルチエージェントフレームワーク
LangChain チーム
2026 年 3 月 26 日
4 分

ケーススタディ
LangChain
LangGraph
AI を活用して数千名の顧客をオンボーディングする Remote の LangChain と LangGraph の活用事例
LangChain チーム
2026 年 1 月 19 日
5 分

ケーススタディ
LangGraph
LangSmith
Fastweb と Vodafone: LangGraph と LangSmith を用いた AI エージェントによる顧客体験の変革
LangChain チーム
2025 年 12 月 16 日
7 分
エージェントが実際に何をしているかを確認する
LangSmith は、エージェントエンジニアリングプラットフォームであり、開発者がすべてのエージェントの意思決定をデバッグし、変更の評価を行い、ワンクリックでデプロイできるように支援します。
原文を表示

*By Nuno Campos*
Summary: We launched LangGraph as a low level agent framework nearly two years ago, and have already seen companies like LinkedIn, Uber, and Klarna use it to build production ready agents. LangGraph builds upon feedback from the super popular LangChain framework, and rethinks how agent frameworks should work for production. We aimed to find the right abstraction for AI agents, and decided that was little to no abstraction at all. Instead, we focused on control and durability. This post shares our design principles and approach to designing LangGraph based on what we've learned about building reliable agents.
LangGraph ALPHA
We just launched an alpha version of LangGraph 1.0!
—
We started LangGraph as a reboot of LangChain's super popular chains and agents more than two years ago. We decided that starting fresh would give us the most leeway to address all the feedback we had received since the launch of the original langchain open source library (in countless GitHub issues, discussions, Discord, Slack and Twitter posts). The main thing we heard was that langchain was easy to get started but hard to customize and scale.**This time around, our top goal was to make LangGraph what you'd use to run your agents in production. When we had to make tradeoffs, we prioritized production-readiness over how easy it would be for people to get started.
In this post, we'll share our process for scoping and designing LangGraph.
- First: we cover what's different about building agents compared to traditional software.
- Next: we discuss how we turned these differences into required features.
- Finally: we show how we designed and tested our framework for these requirements.
The result is a low-level, production ready agent framework that scales with both the size and throughput of your agents.
1. What do agents need?
The first two questions we asked were, “Do we actually need to build LangGraph?” And, “Why can’t we use an existing framework to put agents in production?” To answer these questions, we had to define what makes an agent different (or similar) to previous software. By building many agents ourselves and working with teams like Uber, LinkedIn, Klarna, and Elastic, we boiled these down to 3 key differences.
- More latency makes it harder to keep users engaged
- Retrying long-running tasks when they fail is expensive and time-consuming
- The non-deterministic nature of AI requires checkpoints, approvals, and testing
Managing latency
The first defining quality and challenge of LLM-based agents is latency**. We used to measure the latency of our backend endpoints in milliseconds. Now, we need to measure agent run times in seconds, minutes, or soon hours.
This is because LLMs themselves are slow and are becoming slower with test-time compute. It’s also because we often need multiple LLM calls to achieve our desired results, with looping agents, and chaining LLM prompts to fix earlier output. And, we usually need to add non-LLM steps before and after the LLM call. For instance, you might need to get database rows into the context or create guardrails and verifiers to check the LLM call for accuracy.
All this latency enables building new things, but you do still need to keep end users engaged throughout. So, we identified two features that would come in handy when building agents:
- Parallelization. Whenever there were multiple steps to your agent, when the next step doesn’t need the output of the previous one, then you could run them in parallel. But to do this reliably in production you want to avoid data races between your parallel steps.
- Streaming. When you can’t reduce the actual latency of your agent any further without making it produce worse results, then you turn to perceived latency. Here the key unlock comes from showing useful information to the user while the agent is running, which can go all the way from a progress bar, or key actions taken by the agent, all the way to streaming LLM messages token-by-token in real-time to the end-user.
Managing reliability
The slowness of LLM agents had other implications, too. As we all know all too well, inevitably all software bugs out. Long-running agents fail more often because, the longer they run, the more opportunity there is for something to go wrong.
When traditional software bugs out, you usually want to retry. With AI agents? That may not be the best approach. If your agent fails on minute 9 of 10, going back to the beginning is pretty time consuming and also expensive.
So we knew we had to add two more features to the list:
- Task queue. Queues eliminate one common source of failure by disconnecting the running of the agent from the request that triggered it. They provide the primitives to retry the agent reliably and fairly when needed.
- Checkpointing. This saves snapshots of the computation state at intermediate stages and makes it a lot cheaper to retry when it does fail.
Managing non-deterministic LLMs
Next, the non-deterministic nature of LLMs creates two more challenges. When you write traditional software, you at least know what the code is supposed to do and what should result if you built it as you hoped. Generative AI obviously changes this.
With LLMs, both input and their output is open-ended. You can imagine when you’ve used ChatGPT, and the same prompt you used a day before produces a different result, or, how easy it is to ask your question in many different ways and get back similar results.
This is a very big part of what makes LLM agents so powerful compared other previous software, but it also introduces challenges when taking them to production.
The testing you do while developing will almost certainly miss many surprising ways in which your users will use your agent. You truly can’t plan for all the ways users will interact with your agent or how the LLM will respond. And so, two more features then become very useful when going to production:
- Human-in-the-loop. Having the tools to interrupt and resume the agent at any point, without having to redo work done until then, enables many essential UX patterns for AI agents. For example, you can approve or reject actions, edit the next action, ask clarifying questions, or even time travel to re-do things from a previous step.
- Tracing. To build for scale, developers need clear visibility into what’s happening within the details of their agent loops. You need to see inputs, trajectories, and outputs of the agent, otherwise you won’t know what users are asking of it, how the agent is handling it, and if users are happy with the outcome.
What developers need to build agents
This is how we built our shortlist of the six features most developers need when taking agents to production.
- Parallelization – to save actual latency
- Streaming – to save perceived latency
- Task queue – to reduce number of retries
- Checkpointing – to reduce the cost of each retry
- Human-in-the-loop - to collaborate with the user
- Tracing - to learn how users use it
If the agent you’re building doesn’t need most of these features (eg. because it’s a very short agent without tools and a single prompt), then you might not need LangGraph, or any other framework.
As we thought about building for each of these features, we also realized that developers wouldn’t adopt a framework that that provided all those features at the cost of making their LLM app perceivably slower to end users. Especially for agents deployed as chatbots. That made low latency our final overarching requirement.
Next, we’ll cover how we built these capabilities into LangGraph.
2. Why build LangGraph at all?
Back to our existential question, should we build something new, or adopt one of the existing open source frameworks built before LLMs? Armed with our feature shortlist, it became pretty easy to make that decision.
Why was a new framework needed?
Existing frameworks were mostly split between two categories:
DAG frameworks (made popular by Apache Airflow and many others)
These we had to exclude just based on the name, as LLM agents really benefit from looping, ie. the computation graph for an LLM agent is cyclical, and thus cannot be handled by DAG algorithms.
Durable execution engines (made popular by Temporal and others)
These options were closer, but in the end, as they were designed before LLM agents, so they were lacking some of those specific features — namely streaming. In addition, these engines introduced latency between steps which would have been noticeable to chatbot developers. Lastly, due to their design, the performance degrades the more steps there are in the history, which sounded like a bad bet to make as LLM agents get longer and more complicated.
So in the end our answer was, yes LLMs are different enough that previous production infrastructure needed some new ideas injected into it to become relevant for the new era. And so we embarked on building LangGraph.
3. Our design philosophy
We designed LangGraph with two leading principles.
- We don’t know what the future holds for AI. The fewer assumptions we make about the future the better. No one really knows what it will look like to build with LLMs one, two, three years from now, so the fewer assumptions we bake into the design of the framework, the more relevant it will be in the future. The only assumptions we wanted to bake into it were the realizations we talked about above, i.e. that LLMs are slow, flaky, and open-ended.
- It should feel like writing code. The public API for the framework should be as close as possible to writing regular framework-less code. Every requirement we place on the developer’s code needs to be justified by enabling a really high-value feature. Otherwise the pull of skipping the framework altogether is just too strong. The biggest competitor to any code framework is always no framework.
These principles impacted a few key design decisions that have stayed with us ever since.
- First, the runtime of the library is independent from the developer SDKs. The SDKs are the public interfaces (classes, functions, methods, constants, etc) that developers use when building their agents. We currently offer two – StateGraph and the imperative/functional API. The runtime (which we call PregelLoop) implements each of the features listed earlier, plans the computation graph for each agent invocation, and executes it. This design enables us to evolve the developer APIs and the runtime independently. For instance, on the SDK side, it has allowed us to introduce the imperative SDK, and deprecate the very first SDK we offered, a Graph interface without shared state. On the runtime side, it has enabled us to implement many performance improvements over the last 2 years without any impact to the public APIs, and enabled experimentation with more radical changes to the runtime – more about this later when we get to distributed execution.
- Second, we wanted to provide each of the 6 features as building blocks, with the developer free to pick which to use in their agent at any point in time. For instance, the ability to interrupt/resume for human-in-the-loop scenarios doesn’t get in your way until you reach for it (which is as easy as adding a call to the interrupt() function in one of your nodes). So LangGraph ended up as a uniquely low-level framework in a sea of other frameworks trying to convince developers to bet everything on the high-level abstraction du jour. We have seen these come and go, and LangGraph remaining relevant, so we’re happy with our approach so far.
4. The LangGraph runtime
With all this in mind, let’s look at how LangGraph implements each of the 6 features we wanted to have (as a reminder, these are parallelization, streaming, checkpointing, human-in-the-loop, tracing and a task queue).
Structured agents with discrete steps
If there is one idea that informs every other architectural decision we’ve made, it is the idea of structured agents. There’s a long tradition of adding more structure to computer programs, trading some amount of flexibility for a host of new features. Once upon a time, basic constructs like if statements and while loops were the new kid on the block. Agents too can be written directly as a single function with one big while loop. But when you do that, you lose the ability to implement features like checkpointing or human-in-the-loop. (Note: While it may technically be possible to interrupt execution of some kinds of subroutines, like generators, that execution state can’t be saved in a portable format that can be resumed from a different machine at a different time.)
Execution algorithm
Once you make the choice to structure agents into multiple discrete steps, you need to choose some algorithm to organize its execution. Even if it’s a naive one that feels like "no algorithm," which is where LangGraph started before launch. The problem with using “no algorithm” is, while it may seem simpler, you’re making it up as you go along, and end up with unexpected results. (For instance, an early version of a precursor to LangGraph suffered from non-deterministic behavior with concurrent nodes). The usual DAG algorithms (topological sort and friends) are out of the picture, given we need loops. We ended up building on top of the BSP/ Pregel algorithm, because it provides deterministic concurrency, with full support for loops (cycles).
Our execution algorithm works like this:
- Channels contain data (any Python/JS data type), and have a name and current version (a monotonically increasing string)
- Nodes are functions to run, which subscribe to one or more channels, and run whenever they change
- One or more channels are mapped to input, ie. the starting input to the agent is written to those channels, and therefore triggers any nodes subscribed to them
- One or more channels are mapped to output, ie. the return value of the agent is the value of those channels when execution halts
The execution proceeds in a loop, where each iteration
- Selects the 1 or more nodes to run, by comparing current channel versions and the last versions seen by each of their subscribers
- Executes those nodes in parallel, with independent copies of the channel values (ie. the state, so they don’t affect each other while running)
- Nodes modify their local copy of the state while running
- Once all nodes finish, the updates from each copy of the state are applied to their respective channels, in a deterministic order (this is what guarantees no data races), and the channel versions are bumped
The execution loop stops when there are no more nodes to run (ie. after comparing channels with their subscriptions we find all nodes have seen the most recent version of their subscribed channels), or when we run out of iteration steps (a constant the developer can set).
Validating framework features
Let’s see how this maps to the 6 features we wanted to implement.
- Parallelization. This algorithm is designed for safe parallelization without data races, it automatically selects parallel execution whenever the dependencies between the nodes allow, it executes parallel nodes with isolated state copies, and it applies updates from nodes in an order which doesn’t depend on which one started or finished first (as that can change between executions). This ensures that the execution order and latency of each node never influences the final output of the agent. Given LLMs are non-deterministic, we felt this was an important property, to ensure that variability in your outputs is never the fault of the agent framework, making it a lot easier to debug issues.
- Streaming. Structured execution models (ie. where the computation is split into discrete steps and/or nodes) offer many more opportunities for emitting intermediate output and updates throughout. Our execution engine collects streaming output from inside nodes while they are running, as well as at the step boundaries, without requiring any custom developer code. This has enabled us to offer 6 distinct stream modes in LangGraph, values, updates, messages, tasks, checkpoints and custom. A streaming chatbot might use messages stream mode, while a longer running agent might use updates mode.
- Checkpointing. Again, structured execution is what makes this feasible. We want to save checkpoints that can be resumed on any machine, an arbitrary amount of time after they were saved – ie. checkpoints that don’t rely on keeping a process running in a specific machine, or keeping any live data in memory. To enable this we record serialised channel values (by default serialised to MsgPack, optionally encrypted), their version strings, and a record of which channel versions each node has most recently seen.
- Human-in-the-loop. The same checkpointing that enables fault tolerance can also be used to power “expected interruptions” of the agent, ie. giving the agent the ability to interrupt itself to ask the user or developer for input before continuing. Usually this capability is implemented by leaving the agent running while it waits for the input to arrive, but sadly that scales neither in time nor in volume. If you have many agents interrupted simultaneously, or if you want to wait several days (or months!) before replying, then actual interruption (powered by checkpointing to resume again from the same point) is the only way to go.
- Tracing. Another nice property of using structured execution is you get very clear steps to inspect the progress of your agent, while it runs and after the fact. We had previously built LangSmith as the first LLM observability platform, so naturally LangGraph integrates natively with it. Today we have also LangGraph Studio, where you can debug your agent while it’s running, and LangGraph can also emit OTEL traces for wider compatibility.
- Task queue. This was out of scope for a Python library such as LangGraph, so we ended up creating LangGraph Platform to answer this need.
All in all, this architecture delivers the 6 key features needed for agents. At the same time, it makes creating and debugging agents faster, thanks to the structured approach, and the tools to explore it. And finally, it does so with an excellent performance profile, which scales with the size of your agent, and the throughput you need in production – more on this in the next section.
5. Performance characteristics
Like we mentioned earlier, developers want reliability, but not at the expense of latency. So we need to look at how our approach is working against these tradeoffs. LangGraph scales very gracefully with all size measures of the agents you build with it. This is a great place to be in for a future where agents are becoming ever longer, with more steps, more interruptions, larger state, etc.
How is the execution of a LangGraph agent affected by the key variables that control its size?
First, let’s list the key size variables in StateGraph, the most common LangGraph developer SDK:
- The number of nodes (individual steps, usually functions)
- The number of edges (or the connections between nodes, which can be fixed or conditional)
- The number of channels (or the keys in your state object)
- The number of active nodes (to be executed in parallel in a given step)
- The length of invocation history (previous steps of the current invocation)
- The number of threads (independent invocations on different inputs and context)
Now, let’s list the key moments in an invocation of a LangGraph agent, and see how each scales with each variable:
- Starting or resuming invocation, which consists of transferring from storage the most recent checkpoint for that thread, and deserializing it
- Planning the next invocation step, where we decide which nodes to execute next, and prepare their inputs
- Running the active nodes for a step, where we execute the code for each node, producing writes to channels and edges
- Finishing an invocation step, which consists of applying updates to each channel (running channel reducers and bumping channel versions) and saving the latest checkpoint (serializing and transferring to storage)
Note there is no 'finishing invocation' action as execution simply stops when the planning action returns no nodes to execute next.
In summary, this is how each action scales with agent size:
Metric / Action
Starting invocation
Planning a step
Running a step
Finishing a step
Number of nodes
O(n)
O(1)
O(1)
O(n)
Number of edges
O(1)
O(1)
O(n)
O(1)
Number of channels
O(n)
O(n)
O(n)
O(n)
Active nodes
O(1)
O(n)
O(n)
O(n)
Length of history
O(1)
O(1)
O(1)
O(1)
Number of threads
O(1)
O(1)
O(1)
O(1)
Now, let’s look more in detail at some of these. First, starting an invocation:
- Scales linearly with number of nodes, for each node there is one hidden control channel holding the current state of its incoming edges
- Constant on the number of edges as the state of all edges for each destination node is collapsed into a single control channel
- Scales linearly with number of channels, for each channel there is a serialized representation of its current value
- Constant on the number of active nodes, there is no relation to this variable
- Constant on the length of history, as we only fetch the latest checkpoint, and don’t need to replay steps before it
- Constant on number of threads, as threads are completely independent, and each invocation only touches a single one
Second, planning the next step:
- Constant on the number of nodes, when finishing the previous step we store the list of updated channels, which lets us avoid iterating over all nodes when planning the next one
- Constant on the number of edges, as all edges are collapsed into a single trigger channel per node
- Scales linearly with the number of channels, when assembling the input for each node we loop over channels to check which are currently set
- Scales linearly with number of active nodes, for each node to execute in this step we assemble the input and configuration to use for its invocation
- Constant on the length of history, as we only deal with the latest checkpoint, which aggregates all previous writes
- Constant on number of threads, as threads are completely independent, and each invocation only touches a single one
Third, running a step:
- Constant on the number of nodes, only nodes active in a step influence the running of that step
- Scales linearly on the number of edges of the nodes active in this step, each active node publishes to each of its outgoing edges
- Scales linearly on the number of channels, for each active node we check if the node returned an update to its value (when using a dictionary return value we optimize this to be constant on the number of channels, and just iterate over the keys of the return value)
- Scales linearly with the number of active nodes, each active node is executed concurrently
- Constant on the length of history, we don’t deal with history at this time
- Constant on number of threads, as threads are completely independent, and each invocation only touches a single one
Lastly, finishing a step:
- Scales linearly with number of nodes, for each node there is one hidden control channel holding the current state of its incoming edges
- Constant on the number of edges as the state of all edges for each destination node is collapsed into a single control channel
- Scales linearly with number of channels, each channel is updated with the writes from the active nodes, and its version is bumped
- Scales linearly with number of active nodes, as we collect writes from each active node
- Constant on the length of history, as we only deal with the latest checkpoint, which aggregates all previous writes
- Constant on number of threads, as threads are completely independent, and each invocation only touches a single one
These performance characteristics have been the result of both our choice of design for the library, as well as numerous performance optimizations we have made over the past two years.
Getting started
In summary, we thought deeply about what is different about building with LLMs and what it takes your agent to run in production. These ideas led us to build and iterate on LangGraph. LangGraph focuses on control and durability, so you have the best chance of your agent doing what you intended.
If you want to learn more about LangGraph and test it out for your own projects, head on over to the docs to get started.
Related content

Case Studies
LangGraph
Observability & Evals
How Kensho built a multi-agent framework with LangGraph to solve trusted financial data retrieval
The LangChain Team
March 26, 2026
4
min

Case Studies
LangChain
LangGraph
How Remote uses LangChain and LangGraph to onboard thousands of customers with AI
The LangChain Team
January 19, 2026
5
min

Case Studies
LangGraph
LangSmith
Fastweb + Vodafone: Transforming Customer Experience with AI Agents using LangGraph and LangSmith
The LangChain Team
December 16, 2025
7
min
See what your agent is really doing
LangSmith, our agent engineering platform, helps developers debug every agent decision, eval changes, and deploy in one click.
関連記事
WebBrain の紹介:Chrome と Firefox で動作するオープンソースのローカルファースト AI ブラウザエージェント
Interfaze が拡散型 ASR モデル「diffusion-gemma-asr-small」を公開、6 か国語の並列ノイズ除去デコーダーで音声認識を実現
アリババのページエージェント:DOM を介して自然言語で Web インターフェースを制御する JavaScript 内蔵 GUI エージェント
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み