LangGraph vs CrewAI vs AutoGen:2026年版マルチエージェントAI完全ガイド
2025年は単体のAIエージェントを作っていましたね。2026年は、複数のエージェントを同時に動かす時代になりました。
なんでもかんでも一人でやろうとして破綻する万能エージェントの代わりに、今は役割ごとに専門エージェントを分けてチームのように協力させるのがトレンドです。でも問題が一つ。フレームワークが3つもあるんですよね—LangGraph、CrewAI、AutoGen。それぞれ思想が全然違うので、選び方を間違えると後で作り直すハメになるかもしれません。
この記事では、各フレームワークの違いと使いどころをしっかり整理していきます。コードも一緒に見ていきましょう。
なぜ単体エージェントじゃダメなのか
フレームワークの話の前に、そもそもなぜマルチエージェントが必要なのか確認しておきましょう。
万能エージェントの限界
カスタマーサポート用のAIを作るとして、このエージェントがやるべきことは:
- お客さんが何を求めているか把握
- 関連情報をDBから検索
- 顧客のアカウント情報を確認
- 適切な返答を生成
- 必要に応じて人間にエスカレ
これを一つのエージェントで全部やろうとすると:
# いわゆる「神エージェント」アンチパターン class CustomerServiceAgent: def handle_request(self, message: str) -> str: intent = self.classify_intent(message) context = self.search_knowledge_base(intent) account_info = self.get_account_info() response = self.generate_response(context, account_info) if self.should_escalate(response): return self.escalate_to_human() return response
何が問題かというと:
- トークンすぐ溢れる:あれこれプロンプトに詰め込むとコンテキストウィンドウ即死
- LLMが混乱する:分類したり返答作ったり忙しすぎ
- 遅い:並列でできることも直列で回す羽目に
- デバッグ地獄:エラー出たら2000行のプロンプトを漁ることに
マルチエージェントで解決
役割ごとにエージェントを分けるとこうなります:
┌─────────────────────────────────────────────────────────────┐
│ オーケストレーター │
│ (リクエストを適切なエージェントに振り分け) │
└─────────────────┬──────────────────────────────┬───────────┘
│ │
┌─────────────▼─────────────┐ ┌─────────────▼─────────────┐
│ 分類エージェント │ │ 検索エージェント │
│ (意図把握専門) │ │ (RAG専門) │
└─────────────┬─────────────┘ └─────────────┬─────────────┘
│ │
┌─────────────▼─────────────┐ ┌─────────────▼─────────────┐
│ アカウントエージェント │ │ 返答エージェント │
│ (CRM照会専門) │ │ (文章作成専門) │
└───────────────────────────┘ └───────────────────────────┘
こうするメリット:
- 各エージェントが自分の仕事だけやるからプロンプトがシンプル
- 独立したエージェントは同時に動かせる
- 一つがコケても全体は死なない
- テストもエージェント単位でできる
さて、各フレームワークがこれをどう実現しているか見ていきましょう。
LangGraph:グラフでフローを設計する
LangGraphはLangChainチームが作りました。核となるコンセプトはエージェントシステムをグラフで表現すること。ノードが関数で、エッジがフローです。全部可視化できるので「今何やってるんだっけ?」がすぐわかります。
基本的な考え方
- ノード = 関数(エージェントでもツールでもただのロジックでも)
- エッジ = 次に何するか
- ステート = ノード間でやり取りするデータ
コード見れば一発で理解できると思います:
from typing import Annotated, TypedDict from langgraph.graph import StateGraph, START, END from langgraph.graph.message import add_messages from langchain_openai import ChatOpenAI # エージェント間で共有するステート定義 class AgentState(TypedDict): messages: Annotated[list, add_messages] current_intent: str knowledge_context: str account_info: dict should_escalate: bool # 各エージェントを関数で定義 def classify_intent(state: AgentState) -> AgentState: """意図分類エージェント""" llm = ChatOpenAI(model="gpt-4o") response = llm.invoke([ {"role": "system", "content": "ユーザーの意図をbilling, technical, general, complaintのどれかに分類して"}, {"role": "user", "content": state["messages"][-1].content} ]) return {"current_intent": response.content.strip().lower()} def retrieve_knowledge(state: AgentState) -> AgentState: """ナレッジ検索エージェント""" intent = state["current_intent"] # 本番ではベクトルDBクエリ knowledge_map = { "billing": "請求ポリシー:30日以内なら返金可能...", "technical": "技術問題:まず再起動してみてください...", "general": "会社概要:SaaSプラットフォームです...", "complaint": "クレーム対応:真摯に対応します..." } return {"knowledge_context": knowledge_map.get(intent, "")} def lookup_account(state: AgentState) -> AgentState: """アカウント照会エージェント""" # 本番ではCRM APIコール return { "account_info": { "tier": "premium", "tenure_months": 24, "open_tickets": 2 } } def generate_response(state: AgentState) -> AgentState: """返答生成エージェント""" llm = ChatOpenAI(model="gpt-4o") prompt = f"""以下の情報をもとに丁寧に返答して: 意図:{state['current_intent']} 参考情報:{state['knowledge_context']} 顧客ランク:{state['account_info']} お客様のメッセージ:{state['messages'][-1].content}""" response = llm.invoke([{"role": "user", "content": prompt}]) return {"messages": [response]} def check_escalation(state: AgentState) -> AgentState: """オペレーター接続が必要かチェック""" should_escalate = ( state["current_intent"] == "complaint" and state["account_info"].get("tier") == "premium" ) return {"should_escalate": should_escalate} def route_after_check(state: AgentState) -> str: if state["should_escalate"]: return "escalate" return "respond" def escalate_to_human(state: AgentState) -> AgentState: return { "messages": [ {"role": "assistant", "content": "専門スタッフにおつなぎします。"} ] } # グラフ組み立て def build_graph(): workflow = StateGraph(AgentState) workflow.add_node("classify", classify_intent) workflow.add_node("retrieve", retrieve_knowledge) workflow.add_node("lookup", lookup_account) workflow.add_node("check_escalation", check_escalation) workflow.add_node("respond", generate_response) workflow.add_node("escalate", escalate_to_human) workflow.add_edge(START, "classify") workflow.add_edge("classify", "retrieve") workflow.add_edge("retrieve", "lookup") workflow.add_edge("lookup", "check_escalation") workflow.add_conditional_edges( "check_escalation", route_after_check, {"respond": "respond", "escalate": "escalate"} ) workflow.add_edge("respond", END) workflow.add_edge("escalate", END) return workflow.compile() # 実行 graph = build_graph() result = graph.invoke({ "messages": [{"role": "user", "content": "請求書がおかしいです!"}], "current_intent": "", "knowledge_context": "", "account_info": {}, "should_escalate": False })
LangGraphのいいところ
1. 可視化できる
from IPython.display import Image, display display(Image(graph.get_graph().draw_mermaid_png()))
グラフを図として出力できます。複雑なフローも一目瞭然。
2. 途中で止めて再開できる
from langgraph.checkpoint.memory import MemorySaver memory = MemorySaver() graph = build_graph().compile(checkpointer=memory) config = {"configurable": {"thread_id": "user-123"}} result = graph.invoke({"messages": [...]}, config) # 後で同じ会話を続ける result = graph.invoke({"messages": [new_message]}, config)
3. 人間の承認を入れるのも簡単
from langgraph.types import interrupt def human_approval_node(state: AgentState) -> AgentState: if state["requires_approval"]: approval = interrupt("5万円以上の返金なのでマネージャー承認待ち") return {"approved": approval} return state
LangGraphを使うべき場面
✅ おすすめ:
- フローを細かくコントロールしたい
- 監査ログやコンプライアンスが重要
- 複雑な分岐がたくさんある
- セッション維持が必要
- すでにLangChain使ってる
❌ 向いてない:
- とにかく早くプロトタイプ作りたい(学習コストあり)
- シンプルなフローなのにわざわざ?
CrewAI:チームみたいに役割分担
CrewAIは発想が違います。グラフとかないです。代わりにチームメンバーに役割を与えて仕事させる感じ。実際のチーム運営みたいに。
基本的な考え方
- Agent = メンバー(役割、ゴール、性格まで設定可能)
- Task = やること
- Crew = チーム
コードを見るとすぐ雰囲気わかると思います:
from crewai import Agent, Task, Crew, Process from crewai_tools import SerperDevTool # メンバー定義 classifier_agent = Agent( role="カスタマー意図アナリスト", goal="お客さんが何を求めているか正確に把握して分類する", backstory="""カスタマーサポート歴が長くて、 請求の問題なのか技術の問題なのかクレームなのか すぐ見分けられるプロ。""", verbose=True, allow_delegation=False ) researcher_agent = Agent( role="情報検索スペシャリスト", goal="問題解決に必要な情報を見つけてくる", backstory="""会社のポリシーや手順を熟知していて、 どんな質問にも関連情報を正確に探し出せる。""", tools=[SerperDevTool()], verbose=True ) response_agent = Agent( role="カスタマー対応エキスパート", goal="お客さんが満足する返答を作成", backstory="""怒ってるお客さんも落ち着かせる達人。 プロフェッショナルだけど温かみのある対応で お客さんに大切にされてると感じてもらう。""", verbose=True ) # タスク定義 classification_task = Task( description="""お客さんのメッセージを分析して: メッセージ:{customer_message} billing, technical, general, complaintのどれかに分類して 緊急度(low/medium/high)も教えて。""", expected_output="意図の分類と緊急度", agent=classifier_agent ) research_task = Task( description="""分類結果を見て関連情報を探して: {classification} 解決に必要なポリシーや手順をまとめて。""", expected_output="関連ポリシー情報と解決策", agent=researcher_agent, context=[classification_task] ) response_task = Task( description="""調査結果をもとに返答を作成: 元のメッセージ:{customer_message} 分類:{classification} 調査結果:{research} 丁寧でプロフェッショナルな返答をお願い。""", expected_output="お客さんに送る返答", agent=response_agent, context=[classification_task, research_task] ) # チーム編成 customer_service_crew = Crew( agents=[classifier_agent, researcher_agent, response_agent], tasks=[classification_task, research_task, response_task], process=Process.sequential, verbose=True ) # 実行 result = customer_service_crew.kickoff( inputs={"customer_message": "請求書がおかしいです!"} ) print(result)
CrewAIのいいところ
1. マネージャーエージェントも作れる
crew = Crew( agents=[classifier_agent, researcher_agent, response_agent], tasks=[...], process=Process.hierarchical, manager_llm=ChatOpenAI(model="gpt-4o"), verbose=True )
マネージャーが自動で誰に何をやらせるか判断してくれます。
2. メモリ機能
crew = Crew( agents=[...], tasks=[...], memory=True, embedder={ "provider": "openai", "config": {"model": "text-embedding-3-small"} } )
過去の会話を覚えて、どんどん賢くなります。
3. ツールが充実
from crewai_tools import ( SerperDevTool, # Web検索 ScrapeWebsiteTool, # クローリング FileReadTool, # ファイル読み込み CodeInterpreterTool # コード実行 )
CrewAIを使うべき場面
✅ おすすめ:
- 素早くプロトタイプ作りたい
- 役割ベースで考えるのが楽
- 非エンジニアにも理解してもらう必要がある
- メモリ/学習機能が欲しい
❌ 向いてない:
- フローを細かく制御したい
- 毎回100%同じ結果が欲しい
- 厳密な監査ログが必要
AutoGen:チャットで問題を解く
Microsoftが作ったAutoGenはアプローチがまた違います。エージェントたちが会話しながら問題を解いていくんです。Slackで複数人が議論するような感じ。
基本的な考え方
- エージェント同士がメッセージをやり取り
- 終了条件になるまで会話が続く
- 人間も参加者の一人として入れる
from autogen import AssistantAgent, UserProxyAgent, GroupChat, GroupChatManager import os config_list = [{"model": "gpt-4o", "api_key": os.environ["OPENAI_API_KEY"]}] llm_config = {"config_list": config_list} # エージェント作成 classifier = AssistantAgent( name="Classifier", system_message="""意図分類担当だよ。 メッセージ見てbilling/technical/general/complaintのどれか、 緊急度はどうか簡潔に教えて。""", llm_config=llm_config ) researcher = AssistantAgent( name="Researcher", system_message="""情報調査担当だよ。 意図がわかったら関連ポリシーや解決策を探してまとめて。""", llm_config=llm_config ) responder = AssistantAgent( name="Responder", system_message="""返答作成担当だよ。 調査内容をもとに丁寧に返答を書いて。 完了したら'TERMINATE'で終わらせて。""", llm_config=llm_config ) human_proxy = UserProxyAgent( name="Customer", human_input_mode="NEVER", max_consecutive_auto_reply=0, code_execution_config=False ) # グループチャット設定 group_chat = GroupChat( agents=[human_proxy, classifier, researcher, responder], messages=[], max_round=10, speaker_selection_method="round_robin" ) manager = GroupChatManager(groupchat=group_chat, llm_config=llm_config) # 会話開始 human_proxy.initiate_chat(manager, message="請求書がおかしいです!")
AutoGenのいいところ
1. コード書いて実行もできる
coder = AssistantAgent( name="Coder", system_message="Pythonエキスパートだよ。コードで問題解決して。", llm_config=llm_config ) executor = UserProxyAgent( name="Executor", human_input_mode="NEVER", code_execution_config={ "work_dir": "workspace", "use_docker": True } ) executor.initiate_chat(coder, message="複利計算の関数作って")
コード書いて、実行して、結果見て修正して...開発自動化にぴったり!
2. ディベートさせるのに向いてる
optimist = AssistantAgent(name="Optimist", system_message="いい面を探して...") critic = AssistantAgent(name="Critic", system_message="問題点を探して...") synthesizer = AssistantAgent(name="Synthesizer", system_message="意見をまとめて...") group_chat = GroupChat(agents=[optimist, critic, synthesizer], ...)
AutoGenを使うべき場面
✅ おすすめ:
- コード書いて実行する必要がある
- 繰り返しブラッシュアップが必要
- 議論を通じて答えを出したい
- 開発自動化ツールを作る
❌ 向いてない:
- 毎回同じ動作が必要
- トークン代が心配(会話が長くなりがち)
- フローをきっちり制御したい
3行まとめ比較
| 基準 | LangGraph | CrewAI | AutoGen |
|---|---|---|---|
| 一言で | グラフで設計 | チームで役割分担 | チャットで協力 |
| 学習コスト | ちょっとある | 低い | 普通 |
| トークン効率 | 良い | 普通 | 多め |
| デバッグ | 可視化◎ | ログで | ちょい難 |
| 本番運用 | すぐいける | 成長中 | 研究寄り |
いつ何を使う?
| シーン | おすすめ |
|---|---|
| カスタマーサポートbot | LangGraph(フロー制御+監査ログ) |
| コンテンツ制作パイプライン | CrewAI(役割分担が直感的) |
| コード生成・実行 | AutoGen(コード実行特化) |
| リサーチ自動化 | LangGraph(複雑な分岐処理) |
| 素早くMVP | CrewAI(覚えやすい) |
実践Tips
落とし穴1:エージェント作りすぎない
3つで済むのに20個作ったら管理地獄です。
# ❌ やめて # ✅ 2-3個でスタート simple_crew = Crew( agents=[classifier, responder], tasks=[classification_task, response_task] )
落とし穴2:無限ループ注意
エージェント同士でずっと投げ合うと永遠に終わらない。
# 終了条件を必ず入れる graph.invoke(state, config={"recursion_limit": 25}) group_chat = GroupChat(max_round=10, ...)
落とし穴3:コンテキスト爆発
会話全体を渡し続けるとトークン死。途中で要約しましょう。
def summarize_context(state): summary_llm = ChatOpenAI(model="gpt-4o-mini") summary = summary_llm.invoke([ {"role": "user", "content": f"100字で要約して:{state['context']}"} ]) return {"context": summary.content}
まとめ:何を選ぶ?
LangGraph = フロー制御が大事で、本番レベルが必要なとき
CrewAI = 素早く作りたくて、役割ベースが楽なとき
AutoGen = コード実行が必要、または議論型の問題解決が必要なとき
どれを選んでも原則は同じ:
- 2-3個でスタートして必要に応じて増やす
- エージェントごとに役割を明確に
- エラー処理は必須
- モニタリングも必須
エージェントは準備OK、フレームワークも成熟してます。さあ、作り始めましょう!