AutoGen vs LangGraph vs CrewAI: 2026年に実務で使えるのはどれか

先月、社内のデータレポート生成フローを自動化するタスクを引き受けた。毎週月曜日に複数のデータソースを集約して、SlackにKPIサマリーを投稿するやつだ。手動でやると毎週1〜2時間かかっていて、チーム全員が嫌がっていた。

この手の仕事はAIエージェントにうってつけに見える。でも実装に入る前に「どのフレームワークを使うか」で詰まった。AutoGen(Microsoft)、LangGraph(LangChain)、CrewAI——この3つをそれぞれ実際のプロジェクトに当てはめながら約2週間テストした。その結果をまとめる。

結論から言う。LangGraphを選んだ。ただし、それには理由があるし、ユースケースによってはCrewAIの方がはるかに合理的な選択になる。AutoGenは——正直言って——使うシーンをかなり選ぶ。

AutoGen v0.4: APIが激変して最初の半日を溶かした

GitHubのスター数が多くドキュメントも充実していたので、最初はAutoGenから触り始めた。ただ、すぐに壁にぶつかった。

v0.4(2025年初頭リリース)でAPIが根本から書き直されている。v0.2以前のコードはほぼ動かない。Stack OverflowやQiitaの記事の多くがまだ古いAPIで書かれていて、最初の半日を「なぜimportが通らないのか」のデバッグに費やした。autogen-agentchatautogen-coreを両方インストールしないといけないとか、公式ドキュメントのどこに書いてあるの、という話だ(GitHub Issue #4782あたりで同じ悩みを持つ人たちが大量にいる)。

v0.4の設計思想はマルチエージェントの「会話」を中心に置いている。AssistantAgent同士がメッセージをやり取りして、RoundRobinGroupChatSelectorGroupChatでターンを管理する。

import asyncio
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_ext.models.openai import OpenAIChatCompletionClient

async def main():
    model_client = OpenAIChatCompletionClient(model="gpt-4o")

    # データ収集担当エージェント
    collector = AssistantAgent(
        name="DataCollector",
        model_client=model_client,
        system_message=(
            "あなたはデータ収集の専門家です。"
            "与えられたデータソースから必要な情報を抽出してください。"
        ),
    )

    # レポート作成担当エージェント
    reporter = AssistantAgent(
        name="Reporter",
        model_client=model_client,
        system_message=(
            "あなたはビジネスレポートの専門家です。"
            "DataCollectorから受け取った情報を元に簡潔なKPIサマリーを作成してください。"
        ),
    )

    team = RoundRobinGroupChat(
        [collector, reporter],
        max_turns=6,  # 必ず設定すること——ないと普通に無限ループする
    )
    result = await team.run(
        task="先週の売上データを分析してSlack投稿用のサマリーを作成してください"
    )
    print(result.messages[-1].content)

asyncio.run(main())

このパターン自体は直感的で、複数のエージェントが「議論」しながら答えに近づくのは面白い。研究用途や複雑な推論が必要なタスクには向いている。

本番で使うとき致命的になり得るのが、実行フローの制御が難しい点だ。エージェントが自律的に会話するのはいいが、「このステップが終わったら必ずここに来る」という保証がない。デバッグ用のログも大量すぎて構造化されておらず、何が起きているか追うのが辛い。自分のユースケース(決まったパイプラインを確実に実行する)には合わなかった。

一方で、AutoGenが明らかに輝くのは探索的なタスクだ。「このデータセットから面白いパターンを見つけてほしい」みたいな、正解が事前に定義できないケース。エージェント間の自律的な対話でアイデアが広がる感覚は、他の2つには出せない。

LangGraph: 最初は「過剰設計じゃないか」と思った

正直、LangGraphに最初に触れたとき、「なんでこんな複雑なの」と思った。グラフを定義して、ノードを追加して、エッジを張って——シンプルなタスクに対してボイラープレートが多すぎる印象だった。

でも2〜3日使い込んだら、この設計の意味がわかった。

LangGraphの本質は明示的な状態管理だ。エージェントの実行状態をすべてState(TypedDictで定義)に持ち、ノード間のデータの流れが全部見える。条件分岐もadd_conditional_edgesで明示的に定義する。

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

class PipelineState(TypedDict):
    raw_data: str
    analysis: str
    report: str
    retry_count: int
    messages: Annotated[list, operator.add]

def collect_data(state: PipelineState) -> dict:
    # 実際にはAPIを叩いてデータを取得する
    return {"raw_data": "Q4売上: ¥120M, 前年比+15%..."}

def analyze(state: PipelineState) -> dict:
    result = llm.invoke(f"以下を分析してください: {state['raw_data']}")
    return {"analysis": result.content}

def generate_report(state: PipelineState) -> dict:
    report = llm.invoke(f"分析結果からレポートを作成: {state['analysis']}")
    return {
        "report": report.content,
        "retry_count": state.get("retry_count", 0),
    }

def quality_check(state: PipelineState) -> str:
    # レポートが短すぎたら最大2回リトライ
    if len(state["report"]) < 200 and state.get("retry_count", 0) < 2:
        return "retry"
    return "publish"

builder = StateGraph(PipelineState)
builder.add_node("collect", collect_data)
builder.add_node("analyze", analyze)
builder.add_node("report", generate_report)

builder.set_entry_point("collect")
builder.add_edge("collect", "analyze")
builder.add_edge("analyze", "report")
builder.add_conditional_edges(
    "report",
    quality_check,
    {"retry": "analyze", "publish": END},
)

graph = builder.compile()
result = graph.invoke({"raw_data": "", "retry_count": 0})

このコードを見れば、実行フローが一目でわかる。collect → analyze → report、品質が低ければanalyzeに戻る。デバッグのときに「いまどのノードにいるのか」が常に明確なのが助かる。

一つ気になったのが、LangSmithとの連携だ。LangChainの有料サービスだけど、デバッグには本当に助かった。エージェントの各ステップで何が起きているかがブラウザ上のUIで追えるので、ローカルのログを必死に読む必要がない。無料プランでも月2,000トレースまで使えるので個人プロジェクトなら十分だと思う。

本番運用で特に評価が高かったのが、ヒューマン・イン・ザ・ループの設定のしやすさだ。interrupt_beforeinterrupt_afterを使えば、特定のノードの前後でグラフを一時停止して人間のレビューを挟める。「完全自律エージェント」ではなく人間の承認フローが必要な業務アプリでは、このコントロールが効く。

CrewAI: プロトタイプを一番速く作れたが、本番は要注意

CrewAIは3つの中で一番「書いていて楽しい」フレームワークだった。役割(Role)を持ったエージェントをチームとして編成し、タスクを自然言語で定義するだけで動く。

from crewai import Agent, Task, Crew

analyst = Agent(
    role="データアナリスト",
    goal="売上データを分析して重要なインサイトを抽出する",
    backstory="5年以上のデータ分析経験を持つエキスパート",
    verbose=True,
)

writer = Agent(
    role="ビジネスライター",
    goal="分析結果を分かりやすいレポートにまとめる",
    backstory="経営陣向けレポート作成が得意なコミュニケーター",
    verbose=True,
)

analysis_task = Task(
    description="Q4売上データを分析し、前四半期比・前年比・主要KPIの変化を特定してください",
    expected_output="箇条書きで5〜7個のインサイト",
    agent=analyst,
)

report_task = Task(
    description="分析インサイトを元に、Slack投稿用の200字以内のサマリーを作成してください",
    expected_output="Slack投稿用テキスト",
    agent=writer,
    context=[analysis_task],  # 前のタスクの出力を参照——これを忘れると詰む
)

crew = Crew(agents=[analyst, writer], tasks=[analysis_task, report_task])
result = crew.kickoff()

コード量が少なく、役割が自然言語で定義されているので、非エンジニアにも見せやすい。チームのプロダクトマネージャーに見せたとき「これならエージェントの動きがイメージできる」と言っていた。

で——ここが肝心なのだけど——CrewAIには実行フローのコントロールが根本的に弱いという問題がある。エージェントが「そのタスクを完了した」と判断するのが内部ロジックに依存していて、外からハンドリングしにくい。タスクが複雑になると、エージェントが予期しない行動をとることがある。本番で「なぜこの出力になったのか」を追うのが辛い。

CrewAI 0.80以降(2025年末リリース)でFlowsという機能が追加されて状態管理が多少改善されたが、LangGraphの明示性には追いついていない印象だ。100%確信があるわけではないが、CrewAI Flowsは根本的な設計思想を変えるものではなく、既存のアーキテクチャに後付けした感が否めない。

やらかし話と、実際のベンチマーク結果

やらかした話をひとつ。CrewAIで最初に作ったとき、contextパラメーターを渡し忘れていて、writerエージェントがanalystの出力を参照できずに動いていた。出力はそれっぽく見えたのに、実は前のタスクの結果を全く使っていなかった。LangGraphなら状態の型定義でコンパイル時に気づけるケースだった。それに気づくまで30分くらいかかった。

2週間の実装テストで見えた比較を率直に書く。

デバッグしやすさ: LangGraph > AutoGen > CrewAI。LangGraphは状態が全部見えるしLangSmithがある。AutoGenはログが多いが構造化されていない。CrewAIは何が起きているか一番追いにくかった。

初期開発速度: CrewAI > AutoGen > LangGraph。CrewAIで最初の動くプロトタイプができたのは2時間足らず。LangGraphは状態の設計とグラフの接続で丸一日かかった。

本番での予測可能性: 1週間稼働させた感触では、LangGraphが一番安定している。CrewAIは稀に予期しない出力を返した——特にデータが空の場合の処理が弱かった。AutoGenはエラー回復が意外と自然で、エージェント間で問題を「相談」して解決しようとする挙動がある(これが良いかどうかはユースケース次第だが)。

結局どれを選ぶか

ポジションを明確にする。

本番運用するエージェントパイプラインを作るなら、LangGraphを使う。初期のセットアップコストは高いが、状態管理の明示性とデバッグのしやすさは他の2つにない強みだ。条件分岐が複雑なワークフロー、監査ログが必要な業務アプリ、ヒューマン・イン・ザ・ループが必要なシステム——こういった場面では迷わずLangGraph。

素早くプロトタイプを作って検証したいなら、CrewAIから始めるのが合理的だ。コンセプト検証、ステークホルダーへのデモ、PoC——CrewAIなら数時間で動くものができる。本番移行を見据えているなら、その時点でLangGraphへの書き直しを検討すればいい。

AutoGenは、複数のLLMが協調してより良い答えを導き出す探索的なユースケース向け。コードレビューを複数の視点で評価させる、複雑なリサーチクエスチョンをエージェントが協調して解く——こういった場面なら、AutoGenのアーキテクチャが一番しっくりくる。

自分のデータパイプラインはLangGraphで本番に上げた。今は毎週月曜朝8時にエージェントが自動でレポートを生成してSlackに投稿している。最初の1週間は状態の型定義でハマりまくったが、今は安定して動いている。チームの月曜朝の作業が1〜2時間削減されたので、結果的には正解だったと思っている。

この3つのフレームワークは今後も動き続ける。AutoGenはv0.5の開発が進んでいるし、LangGraphもLangChain本体との統合が深まっている。半年後にはまた状況が変わっているかもしれない。ただ、設計思想の軸——「自律的な会話」「明示的なグラフ」「役割ベースのチーム」——は当面変わらないはずなので、フレームワークを選ぶ基準として使えると思う。

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top