
同じエージェントをStrands・LangGraph・CrewAIの3フレームワークで書き比べたら、動きがまったく違った【27ラン実測】
結論から先に。
同一タスク「テックニュース収集→100語要約」をStrands・LangGraph・CrewAIで実装し、27回実行しました。
LLMの通信をすべて記録したところ、最終出力の安定性とLLM呼び出しの構造がフレームワークごとにまったく違うことが数字で確認できました。
一番印象的だったのはこれです。
LangGraphは緩い条件では語数のぶれが13語あったのに、検証ループが発火する条件ではぶれ3語に減少。
トークンとレイテンシは2.5倍になりました。「明示的な制御は決定論を金で買う」というのが、今回の実測です。
コードと実験データは全部公開しています。
なぜ3フレームワークを「同じもの」で書き比べたのか
AIエージェントフレームワークは2026年、海外の比較記事でも定番の3つが挙がります。
AWSのStrands、LangChainチームのLangGraph、そしてCrewAIです。
調べると設計思想はこう分かれます。
Strandsはmodel-drivenで、ツールとプロンプトを渡すとLLM自身が計画からツール呼び出し、完了判断まで回します。
LangGraphはgraph-drivenで、開発者が状態機械を明示定義し、分岐やループ、承認ゲートがコードの構造として保証されます。
CrewAIはrole-basedで、agentに役割を演じさせるチューメタファーです。
こうした「思想の違い」は記事にいくらでも書いてあります。
実際に同じタスクを3つで書いて、動きの違いを可観測なデータとして並べた記事はほとんどありません。そこで自分でやってみることにしました。
実験の設計
タスクは3フレームワーク共通のシンプルなものです。
fetch_headlinesツールでテックニュースの見出しを5本取得
100語前後のダイジェストに要約
word_countツールで語数を検証(範囲外なら修正)
ツールはローカルで完結する決定論的なものにしました。LLMのぶれだけを測りたいためです。
モデルは今回 inclusionai/ling-3.0-flash-fin で実行しました。
可観測性の中核が、全フレームワークのLLM通信を横断記録するローカルプロキシです。
各フレームワークがmodelに送った生のリクエストとレスポンス(プロンプト、スキーマ、履歴)を記録します。
フレームワークが違っても、形式は完全に同じJSONLに揃えます。
トークン数、レイテンシ、reasoningも記録。APIキーはプロキシが除去します。
3つのシナリオ
base(80〜120語)に加えて、2つテストシナリオを用意しました。
tightは95〜105語の厳しい語数 band。検証と修正のループを強制的に発火させます。
driftはword_countツールの引数名をtextからcontentにリネームするシナリオ。
ツールスキーマが変わったとき、モデルがどう追従するかを見ます。
各条件3ラン、3フレームワーク×3シナリオ×3ラン=27回実行です。
結果①出力の安定性
最終ダイジェストの語数ぶれ(3ランの最大値-最小値)です。
Strands: base 15語 / tight 11語 / drift 12語
LangGraph: base 13語 / tight 3語 / drift 16語
CrewAI: base 0語 / tight 2語 / drift 0語
LangGraphはbaseでは1回だけLLMを呼んで書き切るため、語数はモデルの判断次第でぶれます。
ところがtightにすると、開発者がワイヤしたグラフループが発火して、ぶれは3語まで縮みました。
コストはトークン平均2,007から5,262、レイテンシ4.7秒から11.8秒へと2.5倍。これが「明示的制御の価格」です。
CrewAIはbaseもdriftも3ラン完全に同一出力(96語/96/96)でした。
temperature=0と役割プロンプトが支配的で、見た目は最も決定論的。
ただしその裏返しとして、LLM呼び出しは常に4回固定で、柔軟性はありません。
Strandsは呼び出し数が3〜5回と可変で、モデル自身が完了を判断します。
tightでは3ランすべてループが発火し、ぶれを11語まで減らしつつ柔軟性を保ちました。
結果②呼び出し構造の違い(トレースの生データ)
可観測性プロキシに記録された実際の呼び出し構造です。
Strands: メッセージ履歴が2→4→6→8と成長。モデルが自分で「77語は80未満だ。
膨らませよう」とreasoningで判断し、自分で修正してから最終回答を出しました。
検証も修正もプロンプト指示だけで成立しています。
LangGraph: LLM呼び出しは下書き執筆の1回のみ。
ツール呼び出し、分岐、リトライは全部開発者がワイヤした決定論的ノードです。
面白いのは、モデルは毎回6,163文字ものreasoningを考えているのに、フレームワークは状態だけを見ている点です。
CrewAI: Researcher(2呼び出し: fetch+回答)→Writer(2呼び出し: 下書き+検証)の直列ハンドオフ。
各エージェントにはrole、goal、backstoryを織り込んだ独立したシステムプロンプトが注入されます。
その様子が、そのままトレースに現れます。
結果③スキーマドリフト耐性
引数名のリネーム(text→content)は、意外なほど完全に吸収されました。
3フレームワークすべてのモデルが新スキーマに100%追従し、誤引数は0。エラー復帰は一度も観測されませんでした。
ただしこれは「シンプルなリネーム」の話です。今回の実験で扱ったのは、引数1個のリネームだけです。
型の変更、引数の削除、戻り値の変更は試していません。
そこまでいくと、Strands/CrewAIのようなモデル駆動側はプロンプトの古い記述を信用して失敗する可能性が残ります。
LangGraphはツール呼び出し自体がコードなので、そもそもスキーマ変更の影響を受けません。
これも「コードでツールを呼ぶ」設計の利点のひとつです。
実装コストの比較
実装LOC: Strands 78行 / LangGraph 115行 / CrewAI 110行
venvサイズ(依存の重さ): Strands 262MB(81パッケージ) / LangGraph 71MB(45パッケージ) / CrewAI 699MB(142パッケージ)
CrewAIの依存の重さ(699MB)は、プロトタイプ最速の裏側です。LangGraphは最も軽く、Strandsはその中間。
この数字は初回インストール時の実測で、環境によって変わります。
正直な限界
3ラン×9セル=27ランは、統計的な意味での「決定的」を主張するには少なめです。
median推定の下限は30ラン程度とする説が多く、今回の数字は「トレンドの確認」として読むのが正確です。
タスクも1種類だけです。
ツール1個のシンプルエージェントは、Strandsのmodel-drivenが最も輝く領域です。
LangGraphのグラフ構造が本領を発揮する複雑な分岐・承認・並列ワークフローは未検証で、タスクが複雑になるほど結果は変わるはずです。
タスクが複雑になるほど結果は変わるはずです。
モデルも1つ(ling-3.0-flash-fin)に絞りました。
reasoningの量やツール呼び出しの傾向はモデルに強く依存するため、別のモデルでは傾向が変わる可能性があります。
実験ハーネス自体は公開しているので、誰でも最新のモデルで再実行できます。
再現手順
リポジトリのREADMEにすべて書いてありますが、概略はこれだけです。
3フレームワーク別のvenvを作成(Python 3.12)
記録プロキシを起動(python3 proxy/rec_proxy.py --port 8118)
各フレームワークのスクリプトをプロキシ経由で実行
python3 runs/run_matrix.py で27ラン一括実行、analyze_matrix.pyで集計
何かの比較をするとき、フレームワークが違うとログの形式も違って「比べられない」ことがよくあります。
1本のプロキシを全員の前に置くという設計は、この問題への一番シンプルな答えでした。
リポジトリ: sunnydachs/agent-framework-showdown
※個人開発の OSS のため、動作を保証するものではありません。ご利用は自己責任でお願いします。不具合や改善案は issue で教えてもらえると嬉しいです。