- Authors

- Name
- Youngju Kim
- @fjvbn20031
- マルチエージェントが実際に必要な場面
- Framework 1: Microsoft AutoGen
- Framework 2: CrewAI
- Framework 3: LangGraph
- 比較表
- 選択ガイド
- 本番環境での共通の落とし穴(フレームワーク非依存)
- まとめ
「マルチエージェントシステムを使うべきですか?」という質問をよく受けます。正直な答えは:たいていの場合、不要です。 シングルエージェントで十分なケースがほとんどです。でも特定の状況ではマルチエージェントが本当に必要になり、その時はフレームワーク選択が重要になります。
マルチエージェントが実際に必要な場面
シングルエージェントでは本当に不十分な3つの状況:
状況1:タスクが大きすぎて1つのコンテキストウィンドウに収まらない
1万行のコードをリファクタリングする必要がある場合、コードベース全体が1つのエージェントのコンテキストウィンドウに収まりません。複数のエージェントが各モジュールを分担すれば解決します。
状況2:異なる専門性が必要
「ニュース記事を収集し、分析し、レポートを書け」というタスクを考えてください。検索に最適化されたエージェント、分析に集中するエージェント、ライティングに特化したエージェント — それぞれ異なるシステムプロンプトとツールを持つことで、全てをこなそうとする単一エージェントより優れた結果が得られます。
状況3:並列処理でスピードを上げたい
10カ国の市場調査を同時に行う場合、10のエージェントが並列で各国を調査すれば大幅に速くなります。
これら3つの状況に当てはまらなければ、シングルエージェントで十分です。不要な複雑さを追加しないでください。
Framework 1: Microsoft AutoGen
AutoGenはMicrosoftが作ったマルチエージェントフレームワークです。**会話(conversation)**をコアの抽象化として採用しています。
コアコンセプト
AutoGenの哲学:エージェントはチームメンバーのようにチャットで問題を解決します。
import autogen
llm_config = {
"model": "gpt-4",
"api_key": "your-api-key"
}
# エージェントの定義
coder = autogen.AssistantAgent(
name="Coder",
llm_config=llm_config,
system_message=(
"You are a Python expert. Write clean, well-tested code. "
"Always include error handling and type hints. "
"When you finish, say 'TERMINATE'."
)
)
reviewer = autogen.AssistantAgent(
name="Reviewer",
llm_config=llm_config,
system_message=(
"You are a senior software engineer. Review code for: "
"1. Bugs and edge cases "
"2. Security vulnerabilities "
"3. Performance issues "
"4. Code style and maintainability "
"Provide specific, actionable feedback."
)
)
# UserProxyAgentが実際のコード実行を担当
user_proxy = autogen.UserProxyAgent(
name="User",
human_input_mode="NEVER", # 完全自動化
max_consecutive_auto_reply=10,
code_execution_config={
"work_dir": "coding",
"use_docker": False # 本番環境ではTrueを推奨
},
is_termination_msg=lambda x: "TERMINATE" in x.get("content", "")
)
# 会話を開始
user_proxy.initiate_chat(
coder,
message="天気データを取得してmatplotlibで可視化するPythonスクリプトを書いて"
)
GroupChatで複数エージェントを調整
groupchat = autogen.GroupChat(
agents=[user_proxy, coder, reviewer],
messages=[],
max_round=20,
speaker_selection_method="auto" # LLMが次の発言者を決定
)
manager = autogen.GroupChatManager(
groupchat=groupchat,
llm_config=llm_config
)
user_proxy.initiate_chat(
manager,
message="REST APIクライアントライブラリを設計して実装してください"
)
AutoGenの長所と短所
長所:
- セットアップが簡単、素早くプロトタイプ可能
- UserProxyAgentによるコード実行が内蔵
- 直感的な会話モデル
短所:
- 無限ループに陥りやすい(TERMINATE条件の慎重な設計が必要)
- 会話ベースの状態管理は複雑なワークフローに限界あり
- グループチャットでエージェント間のフロー制御が不明確になりやすい
Framework 2: CrewAI
CrewAIは「AIチーム」の構築に焦点を当てたフレームワークです。明確な役割とゴールを持つエージェントが、明確に定義されたタスクを実行します。
コアコンセプト
CrewAIの哲学:AIシステムを明確な役割と責任を持つ会社のように構造化します。
from crewai import Agent, Task, Crew, Process
from crewai_tools import SerperDevTool, WebsiteSearchTool
search_tool = SerperDevTool()
web_tool = WebsiteSearchTool()
# エージェントは役割とゴールを持つ
researcher = Agent(
role="Research Analyst",
goal="あらゆるトピックについて正確で包括的な最新情報を見つける",
backstory=(
"10年の経験を持つ専門リサーチャーです。"
"複数の情報源から情報を検証し、必ず引用します。"
),
tools=[search_tool, web_tool],
llm="gpt-4",
verbose=True
)
analyst = Agent(
role="Data Analyst",
goal="情報を分析し、主要なトレンドとインサイトを特定する",
backstory=(
"パターンを見つけ、複雑な情報から"
"実用的な結論を導き出すことが得意なデータアナリストです。"
),
llm="gpt-4",
verbose=True
)
writer = Agent(
role="Technical Writer",
goal="明確で魅力的で、よく構造化されたコンテンツを書く",
backstory=(
"複雑なトピックを分かりやすくする技術ライターです。"
"精度と明確さを重視するエンジニア向けに書きます。"
),
llm="gpt-4",
verbose=True
)
# 明示的な依存関係を持つタスク
research_task = Task(
description=(
"AIエージェント開発における最新トレンドのトップ5を調査してください。"
"各トレンドには具体的な例と信頼できる情報源を含めてください。"
),
agent=researcher,
expected_output="5つのトレンド、各々2-3文の説明と情報源"
)
analysis_task = Task(
description=(
"調査されたトレンドを分析し、エンジニアへの影響度でランク付けしてください。"
"各トレンドの実用的な意味を説明してください。"
),
agent=analyst,
expected_output="各トレンドの実用的な意味を含むランク付けされた分析",
context=[research_task] # research_taskの出力をcontextとして使用
)
writing_task = Task(
description=(
"分析に基づいて1000語の技術ブログ記事を書いてください。"
"エンジニアがすぐに活用できる実用的なインサイトに焦点を当ててください。"
),
agent=writer,
expected_output="タイトル、見出し、コード例を含むMarkdownブログ記事",
context=[research_task, analysis_task]
)
crew = Crew(
agents=[researcher, analyst, writer],
tasks=[research_task, analysis_task, writing_task],
process=Process.sequential, # またはProcess.hierarchical
verbose=True
)
result = crew.kickoff()
print(result)
CrewAIの長所と短所
長所:
- 役割ベースの設計が直感的 — 非開発者も理解しやすい
- タスクの依存関係管理が明確
- 素早いプロトタイピングに最適
- コミュニティが急速に成長中
短所:
- 複雑な条件付きフローに制限あり
- 状態管理が基本的 — 長時間実行エージェントに限界
- LangGraphほど柔軟ではない
Framework 3: LangGraph
LangGraphはLangChainチームが作ったフレームワークで、エージェントワークフローをグラフとして表現します。最も柔軟ですが、学習曲線があります。
コアコンセプト
LangGraphの哲学:エージェントシステムを有向グラフとしてモデル化します。ノードは関数、エッジはフロー制御です。状態は明示的で型付けされています。
from langgraph.graph import StateGraph, END
from typing import TypedDict, List, Annotated
import operator
# グラフ全体で共有される型付き状態
class ResearchState(TypedDict):
messages: Annotated[List[str], operator.add] # メッセージが蓄積される
research_done: bool
analysis_done: bool
draft: str
final_report: str
workflow = StateGraph(ResearchState)
# ノード関数 — 状態の更新を返す純粋関数
def research_node(state: ResearchState) -> dict:
results = search_web(state["messages"][-1])
return {
"messages": [f"Research results: {results}"],
"research_done": True
}
def analysis_node(state: ResearchState) -> dict:
research = [m for m in state["messages"] if "Research results:" in m]
analysis = analyze_data(research)
return {
"messages": [f"Analysis: {analysis}"],
"analysis_done": True
}
def writing_node(state: ResearchState) -> dict:
all_context = "\n".join(state["messages"])
draft = write_report(all_context)
return {"draft": draft}
def review_node(state: ResearchState) -> dict:
reviewed = review_and_improve(state["draft"])
return {"final_report": reviewed}
# 条件付きルーティング関数
def route_after_research(state: ResearchState) -> str:
if len(state["messages"]) > 3:
return "analysis"
else:
return "research" # 更多くの調査が必要な場合はループバック
# ノードの追加
workflow.add_node("research", research_node)
workflow.add_node("analysis", analysis_node)
workflow.add_node("writing", writing_node)
workflow.add_node("review", review_node)
# エッジの追加(フロー定義)
workflow.set_entry_point("research")
workflow.add_conditional_edges(
"research",
route_after_research,
{
"analysis": "analysis",
"research": "research" # セルフループ
}
)
workflow.add_edge("analysis", "writing")
workflow.add_edge("writing", "review")
workflow.add_edge("review", END)
app = workflow.compile()
result = app.invoke({
"messages": ["AIエージェントの最新トレンドを調査"],
"research_done": False,
"analysis_done": False,
"draft": "",
"final_report": ""
})
print(result["final_report"])
チェックポインティングとストリーミング
LangGraphが際立って差別化されている機能:
from langgraph.checkpoint.sqlite import SqliteSaver
# チェックポインティング:中間状態の保存と復元
memory = SqliteSaver.from_conn_string(":memory:")
app = workflow.compile(checkpointer=memory)
# スレッドIDで再開可能な会話
config = {"configurable": {"thread_id": "session-123"}}
# 最初の実行
result = app.invoke(initial_state, config=config)
# 後で同じスレッドを継続
follow_up = app.invoke(
{"messages": ["分析セクションをもっと詳しくして"]},
config=config
)
グラフの可視化
# LangGraphはMermaidダイアグラムを出力できる
print(app.get_graph().draw_mermaid())
# 出力例:
# graph TD
# __start__ --> research
# research -->|調査不足| research
# research -->|十分| analysis
# analysis --> writing
# writing --> review
# review --> __end__
LangGraphの長所と短所
長所:
- 最も柔軟なフロー制御 — 条件分岐、ループ、並列実行全て可能
- 強力な状態管理 — チェックポイント、履歴、分岐
- 本番環境への準備度が高い:可観測性、Human-in-the-loopサポート
- LangSmithとの連携でトレーシングも
短所:
- 学習曲線が急 — グラフの概念理解が必要
- シンプルなワークフローには過剰設計
- CrewAIより冗長なコードになりがち
比較表
| 特性 | AutoGen | CrewAI | LangGraph |
|---|---|---|---|
| 学習曲線 | 低 | 低 | 高 |
| 柔軟性 | 中 | 中 | 高 |
| 状態管理 | 基本 | 基本 | 強力 |
| 本番環境準備度 | 中 | 中 | 高 |
| コード実行内蔵 | あり | 別途設定 | 別途設定 |
| コミュニティ規模 | 大型 | 急成長中 | 成長中 |
| 最適なユースケース | コード生成 | 役割ベースの作業 | 複雑なワークフロー |
選択ガイド
AutoGenを選ぶ場合:
- 素早いプロトタイプが必要
- コード生成と実行が中心のワークフロー
- チームがLLMフレームワークに不慣れ
CrewAIを選ぶ場合:
- 「役割分担」が自然に思い浮かぶ作業(調査者、分析者、ライター)
- 順次パイプライン(調査 → 分析 → 執筆)
- 中程度の複雑さで素早いMVPが必要
LangGraphを選ぶ場合:
- 複雑な条件付きロジックが必要
- チェックポイント/再開が重要な長時間実行エージェント
- 信頼性と可観測性が重要な本番デプロイ
- Human-in-the-loop承認ステップが必要
本番環境での共通の落とし穴(フレームワーク非依存)
どのフレームワークを選んでも直面する問題です。
1. コストの爆発
複数のエージェントがそれぞれLLM呼び出しを行います。想定よりはるかに多くのコストが発生します。常にコストを追跡してください。
import tiktoken
def estimate_cost(messages, model="gpt-4"):
enc = tiktoken.encoding_for_model(model)
total_tokens = sum(len(enc.encode(m["content"])) for m in messages)
cost_per_1k = 0.03 # GPT-4入力価格
return (total_tokens / 1000) * cost_per_1k
2. エージェント間のコンテキスト受け渡しの失敗
あるエージェントの出力が次のエージェントに正しく届かないと、パイプライン全体がサイレントに壊れます。常にコンテキストの受け渡しを明示的に確認してください。
3. パイプラインレベルのタイムアウトなし
個々のエージェントが無限に実行される可能性があります。パイプライン全体に対してハードタイムアウトを設定してください。
import asyncio
async def run_with_timeout(crew, timeout=300):
try:
return await asyncio.wait_for(
asyncio.to_thread(crew.kickoff),
timeout=timeout
)
except asyncio.TimeoutError:
raise RuntimeError(f"Crewが{timeout}秒後にタイムアウトしました")
4. 中間結果のモニタリングなし
5エージェントのパイプラインで、エージェント2がゴミを出力すると、エージェント3-5がそのゴミを増幅させます。全ノードの中間出力をログに記録してください。
まとめ
私の推薦:まずCrewAIから始めてください。 直感的で素早く結果が得られます。本番環境への移行が必要になったり複雑な条件付きフローが必要になったりしたらLangGraphに移行してください。AutoGenはコード生成中心のワークフローに特に強みがあります。
どのフレームワークを使うにしても:まず必ずシングルエージェントを試してください。マルチエージェントの複雑さは、本当にその限界に達したときにだけ追加するのが正しいアプローチです。
次の記事ではTool Calling実践ガイド — LLMが実際に外部ツールとどう連携するか、よくある落とし穴と本番環境で通用するパターンを解説します。