2026年のAIエージェントスタック:LangGraph vs カスタム vs DIY

私は毎週エージェントを本番環境にデプロイしており、キックオフコールでは必ずフレームワークの選択肢が話題になります。正直な答えは、「最適な」スタックは分岐の多さ、状態の量、そして許容できる影響範囲によって決まるということです。昨年1年で同じエージェントを3つの方法で構築しましたが、トレードオフはフレームワークのマーケティングが示すよりも明確でした。以下に私が実際に判断する方法を示します。

私がよく利用する3つのスタック

新しいエージェントを構築する際、3つのカテゴリから選択します。その他はすべてこれらのバリエーションです:

  1. DIYループ:ツールの実行とメッセージ配列を伴うLLMコール周りのプレーンなwhileループ。PythonまたはTypeScriptで約150行。
  2. フレームワーク:現在はほぼLangGraph。狭いケースではPydantic AIまたはOpenAI Agents SDKを時々使用。
  3. カスタムオーケストレーション:Temporal、Inngest、AWS Step Functionsなどのメッセージキューまたは耐久性のあるエグゼキューター上に独自のステートマシンを記述。

判断は3つの質問に基づきます:ステップ数、並行性、午前3時にクラッシュした場合の対応方法。観測可能性、評価、人間参加型ワークフローなどのその他の機能は3つすべてに追加可能です。

DIYループが正しい選択となる場合

5つ未満のツールを持ち、線形のthink-act-observeループを持つエージェントの場合、プレーンなループが最適です。私はこれを私がデプロイするエージェントの約40%で使用しており、BizFlowAI ContentStudio内のほとんどのサブエージェントも含まれます。フレームワークは実際の分岐が発生する場合にのみ投資効果を発揮する抽象化コストを追加します。

以下はログを除いた全体像です:

def run_agent(task: str, tools: dict, max_steps: int = 12):
    messages = [
        {"role": "system", "content": SYSTEM_PROMPT},
        {"role": "user", "content": task},
    ]
    for step in range(max_steps):
        resp = client.messages.create(
            model="claude-sonnet-4-5",
            messages=messages,
            tools=list(tools.values()),
            max_tokens=4096,
        )
        messages.append({"role": "assistant", "content": resp.content})

        if resp.stop_reason == "end_turn":
            return resp.content[-1].text

        tool_results = []
        for block in resp.content:
            if block.type == "tool_use":
                try:
                    result = tools[block.name]<a href="**block.input">"fn"</a>
                    tool_results.append({
                        "type": "tool_result", "tool_use_id": block.id,
                        "content": str(result),
                    })
                except Exception as e:
                    tool_results.append({
                        "type": "tool_result", "tool_use_id": block.id, "content": f"ERROR: {e}",
                        "is_error": True,
                    })
        messages.append({"role": "user", "content": tool_results})

    raise RuntimeError("Agent exceeded max_steps")

Enter fullscreen mode Exit fullscreen mode

以上です。利点は明確です:

  • IDEでのデバッグが可能。 スタックトレースはフレームワークの内部ではなく、自分のコードを指します。
  • トークン使用量が透明。 送信されるすべてのメッセージを確認・制御できます。先四半期に1プロジェクトでLLMコストを40%削減した際の大部分は、このループでメッセージ配列を整理したことによるものです。
  • リトライとエラー処理を自ら管理。 ツールエラーはis_error: trueとしてモデルに返され回復可能となり、モデルが破損したツールでループした場合もカウンターを記述しているため検知できます。

DIYが破綻するケース:長時間実行ジョブでの並列ツール実行、マルチエージェントハンドオフ、プロセス再起動後も存続する必要があるチェックポイント機能。こうした場合、フレームワークを構築するか、既存のフレームワークを利用することになります。

LangGraphの複雑性が正当化される場合

LangGraphは2026年において私が繰り返し利用するフレームワークで、エージェントを型付き状態を持つノードのグラフとして扱い、複雑なエージェントの実際の動作に適合するためです。ワークフローに実際の分岐(3つ以上の意味のあるパス)がある場合、数時間から数日に及ぶ耐久性のある実行が必要な場合、または複数のエージェントが相互通信する場合に利用します。

価値は3つの特定の機能で発揮されます:

  1. 型付き状態をファーストクラスオブジェクトとして扱う。 状態用にTypedDictまたはPydanticモデルを定義し、各ノードは部分的な更新を返します。メッセージ配列の受け渡しではなく状態遷移を考えることを強制するため、思った以上の価値があります。
  2. チェックポイント機能。 SqliteSaverまたはPostgresSaverにより、プロセスが停止した場合も最後のノードからグラフを再開できます。長時間実行のリサーチエージェントや人間参加型ワークフローでは必須です。
  3. 人間レビュー用の割り込み。 ノードでグラフを一時停止し、外部入力(Slack承認、フォーム送信)を待機し、前のノードを再実行せずに再開できます。

問題点:LangGraphのLLMコールに対する抽象化により、コールバックを明示的に実装しない限りトークン管理が隠蔽されます。ドキュメントは急速に更新され、6ヶ月前に有効だったパターンが現在は非推奨になる場合があります。使用する場合はバージョンを固定し、実際に送信されるAPIコールをスナップショットする統合テストを記述してください。

これまでデプロイした経験に基づく大まかな指針:

エージェントタイプ ノード数 最適な選択
単一目的のツールコール 1-3 DIYループ
調査 + 執筆 + レビュー 4-8 LangGraph
ハンドオフを伴うマルチエージェント 8+ LangGraphまたはカスタム
長時間実行ワークフロー(数時間以上) 任意 カスタムオーケストレーション
50以上の並列ジョブへのファンアウト 任意 カスタムオーケストレーション

カスタムオーケストレーションを記述する価値がある場合

カスタムオーケストレーションとは、エージェントを分散システムとして扱うことを意味します:Temporal、Inngest、Step Functions、またはSQS上に独自構築した耐久性のあるエグゼキューターがワークフローを駆動し、各LLMコールまたはツール実行はそのシステム内のタスクとなります。マシンの障害に耐える必要がある場合、単一の「エージェントターン」が1時間を要する場合、または数百の並列ブランチにファンアウトする必要がある場合に使用します。

SLAコンプライアンス向けに構築したサーバーレスAWS + Zendesk統合はカスタムオーケストレーションでした。「エージェント」そのものではありませんでしたが、同じ推論が適用されます:EventBridgeがワークフローを駆動し、Lambda関数がタスクで、DynamoDBが状態を保持します。Lambdaが停止した場合、EventBridgeが再試行します。ツールが失敗した場合、ステートマシンは再開場所を認識します。このパターンは、LLMコールが単なるべき等タスクであることを受け入れれば、エージェントワークフローにもクリーンにマッピングできます。

フレームワークにはないカスタムオーケストレーションの利点:

  • 真の耐久性。 LangGraphのチェックポインターは数時間程度で問題ありません。TemporalやStep Functionsは数ヶ月間耐えられます。
  • 大規模なファンアウト。 500ドキュメントを並列レビューし結果を集約する必要がある場合、単一プロセスで管理しようとするグラフライブラリではなく、実際のキューとワーカープールが必要です。
  • 影響範囲の制御。 各タスクは分離して実行されます。状態がステップ間で実体化されるため、有害なツールレスポンスが実行全体を破損することはありません。

コストは現実的です。より多くのコードを記述し、インフラを自ら管理し、エージェントの動作を独自に可視化する必要があります。1時間の実行時間未満で10並列ブランチ未満の場合、これは過剰です。それを超える場合、フレームワークは玩具のように感じられます。

私が実際に選択するスタック:判断ごとの選択

新しいエージェントプロジェクト開始時に頭の中で描くフローチャートです:

  1. 5つ未満のツールを持つ線形ワークフローか? DIYループ。1週間でデプロイ。構造化ロギング、トークンカウント、リトライラッパーを追加。
  2. 実際の分岐があるか、人間入力のために一時停止が必要か? PostgresSaverによるチェックポイントとOpenTelemetryコールバックによる観測可能性を備えたLangGraph。
  3. 単一実行が数時間を要するか、数百の並列ブランチにファンアウトするか、インフラ障害に耐える必要があるか? TemporalまたはStep Functions上のカスタムオーケストレーション。各LLMコールをアクティビティとして扱う。
  4. 3つ以上の異なるエージェントが相互通信するマルチエージェントか? 実行時間が短い場合はLangGraph、長時間の場合はカスタム。DIYは避ける。エージェント間のメッセージルーティングはDIYループが保守不能なスパゲッティコードに陥る原因となるため。

私はフレームワークのマーケティングが推奨するよりも頻繁にDIYを選択します。実際のエージェントの多くはグラフを必要としません。1つの優れたループ、慎重なプロンプトエンジニアリング、厳密なツールスキーマ、誠実な評価が必要です。ワークフローダイアグラムが1画面に収まらなくなった瞬間にフレームワークは有用になります。

デプロイするまで誰も教えてくれないこと

実時間で代償を払った教訓をいくつか:

ツールスキーマはモデル選択よりも重要。 同じタスクでもツール記述とパラメータ名を書き換えるだけで成功率が60%から95%に向上するケースを経験しました。モデルを切り替えたりフレームワークを追加したりする前に、ツールスキーマに1日を費やしてください。モデルの賢さはツールが許容する範囲に限定されます。

トークン削減はメッセージ配列の整理で実現。 20ステップのエージェントでは、すべてのツール結果を保持するとトークン数が2次関数的に増加します。最後の3-5個のツール結果をそのまま保持し、残りを要約します。あるコンテンツエージェントでは品質低下なしにコストを40%削減できました。

エラー文字列はプロンプト。 ツールが失敗するとエラーメッセージがモデルのコンテキストに戻り、次のプロンプトの一部となります。"Database connection failed"は役に立たないプロンプトです。"Database query returned no rows for user_id=42. Try a different user_id or check if the user exists."はモデルが回復することを可能にします。

べき等性なしのチェックポイントは嘘。 グラフがステップ7から再開し、ステップ7が支払いAPIを呼び出した場合、顧客に2回課金したことになります。状態を変更するすべてのツールはべき等性キーを必要とします。これはどのフレームワークでも当てはまります。

評価は必須。 デプロイ前に構築したすべてのエージェントを20-50個の固定テストケースに対して実行します。派手なLLM-as-judgeではなく、決定論的なチェック:正しいツールを呼び出したか、最終回答に必要なフィールドが含まれているか、トークン予算内に収まっているか。これがエージェント作業における単一で最もROIの高いエンジニアリングプラクティスです。

明日新しいエージェントを始める場合の私のアプローチ

DIYループから開始。まずツール、システムプロンプト、評価セットを正しく設定。初日からトークン使用量とステップ数を計測。デプロイし、実入力での失敗を観察し、修正。

ワークフローダイアグラムに実際の分岐がある場合、または耐久性のある一時停止・再開が必要な場合にのみLangGraphを利用。単一実行が1時間を超える場合、または単一プロセスで管理すべき範囲を超えてファンアウトする場合にのみカスタムオーケストレーションを利用。DIY段階を省略しない:これによりエージェントが実際に何を行うかを理解でき、その知識が後のフレームワーク選択を明確にします。

フレームワーク論争は主にノイズです。デプロイされ、継続して動作するエージェントは、厳密なツールスキーマ、誠実な評価、本番障害を10分以内にデバッグ可能な観測可能性を備えたものです。その他はすべて足場です。

今まさにエージェントを構築中で、これらのスタック間で迷っている場合、ワークフローダイアグラムを確認し、どの選択をするかお伝えします。lazar-milicevic.com/#contactからご連絡いただくか、エージェント評価、コンテキストエンジニアリング、本番環境でのトークン削減について執筆しているブログをご覧ください。