多段のAIエージェントを組み始めると、多くの人が最初に書くのは「収集して、分析して、検証する」という一直線のパイプラインです。ところが、この直線は独立した処理まで直列で待たせてしまい、待ち時間が積み上がります。本記事は、エージェントの処理をグラフ(状態機械)として設計するという考え方を、OSSで実現する手段として Apache Burr(apache/burr)を主役に整理します。ノード=処理、エッジ=データ依存という視点で組み直すと、並列・分岐・検証・ループを型として持てるようになります。
- ・グラフエンジニアリングとは:エージェントの処理を「ノード=処理/エッジ=データ依存」のグラフとして設計する見方。直線を、並列 fan-out・分岐・検証・ループへ組み直す。
- ・Apache Burrの正体:アプリを状態機械(=グラフ)として書くPythonライブラリ。
@action=ノード、with_transitions=エッジ、条件付き遷移で分岐・ループ。GitHubスター約2,486、ライセンスはApache-2.0。 - ・Burrならでは:実行を可視化・追跡するOSSのテレメトリUIを同梱し、状態を永続化して途中から再開できる。LLMを使わない用途にも使える。
- ・他OSSとの住み分け:エコシステムの厚さならLangGraph、イベント駆動ならLlamaIndex Workflows、最小構成ならPocketFlow。持ち方・状態管理・可視化・ライセンス・成熟度で選ぶ。
- ・使えるか:Apache-2.0で無料。ただしASFのincubating段階で、コミュニティ規模はLangGraphより小さい点は織り込む。
エージェントを「グラフとして設計する」という発想そのものは、プロプライエタリな実行基盤でも語られています。Claude Code の動的ワークフローを題材に同じ考え方を掘り下げた姉妹記事 エージェントをグラフとして設計する|Claude Code動的ワークフローで多段処理を並列化する考え方 と本記事は対になっており、あちらがネイティブ/プロプライエタリ側、本記事がOSS側の実現手段を扱います。フレームワーク全体像を俯瞰したい場合は、まず AIエージェントフレームワーク比較2026|LangGraph・CrewAI・Dify等9種をStar数・実コードで検証 を読むと本記事の位置づけがつかみやすくなります。
1. なぜ直線的な多段エージェントは詰まるのか
直線チェーンが生まれるのは、手順を言葉にするときの自然な語り口だからです。「Aして、それからBして、それからC」——この「それから」を、そのままエージェントの依存関係に写してしまいます。けれど「それから」には2つの意味が混ざっています。ひとつは因果の依存(Bの入力はAの出力そのもの)、もうひとつは単に書いた順序(Aを先に書いただけで、BはAの結果を読まない)。前者だけが本物のエッジで、後者はエッジではありません。直線化のコストは、この後者まで直列にしてしまうところにあります。
たとえば「3つの情報源を調べてから要約する」というタスクを考えます。3つの調査は互いに独立しているのに、直線で書けば1つ目→2つ目→3つ目と順番に待ちます。3つを並列に fan-out すれば、全体の待ち時間は最も遅い1本の調査時間に縮みます。ここで効いてくるのが、処理をグラフとして捉える視点です。
・何ができるか:独立した処理を洗い出して並列化し、分岐・検証・ループを設計として持てる
・何を解決するか:「書いた順=実行順」という思い込みが生む、不要な待ち時間
・何を代替するか:if文とtry/exceptを手で積み上げる自前オーケストレーションを、宣言的なグラフ定義に置き換える
2. 「グラフ/状態機械」でエージェントを設計するとは
グラフとしてエージェントを設計するとき、押さえる部品は少数です。ノード(処理の単位)、エッジ(ノード間の依存=データの受け渡し)、そしてトポロジ(ノードとエッジの組み方の型)。トポロジには繰り返し現れる型があります。
・pipeline(直列):前段の出力を次段が読む、本物のエッジで結ばれた並び
・fan-out / 並列:独立したノードを同時に走らせ、あとで集約する(扇形に開いて畳む形が diamond)
・router(分岐):分類・判定の結果に応じて次に進む先を選ぶ
・verifier(検証):生成物を別のノードで批判的に検証し、通ったものだけ先へ進める
・cycle(ループ):条件を満たすまで同じ経路を回す(収束・再試行・自己修正)
これらは特定のフレームワークの用語ではなく、設計の語彙です。AIエージェントの設計パターンを体系的に押さえたい場合は AIエージェント設計パターン入門|プロンプトチェーンからマルチエージェントまで21の型を体系理解する が参考になります。本記事の焦点は、この語彙をOSSのコードとしてどう書くかです。
たとえば「fan-out → 集約」という最も基本的なグラフ(diamond)は、次のように描けます。
タスクを受け取る"] --> A["調査ノードA
情報源1"] S --> B["調査ノードB
情報源2"] S --> C["調査ノードC
情報源3"] A --> R["集約ノード
3つの結果を統合"] B --> R C --> R R --> V{"検証ノード
品質は十分か?"} V -- いいえ --> S V -- はい --> O["出力"]
入口から3本に開き(fan-out)、集約で畳み(reduce)、検証で品質を測り、足りなければ入口へ戻す(cycle)。直線で書くと3本の調査が直列になり、検証で戻すループも表現しづらい。グラフとして設計すれば、この構造をそのまま宣言できます。
① 何ができる:pipeline・fan-out・router・verifier・cycle という型で、エージェントの処理を組める。② 何を解決する:直線化による無駄な待ちと、分岐・検証・ループの書きにくさ。③ 何を代替する:状態遷移を手書きのフラグとif文で管理する、見通しの悪い自前実装。
3. Apache Burrの正体——アプリを状態機械(グラフ)として書く
Apache Burr(apache/burr)は、この「グラフとして設計する」を素直に実装したOSSです。公式READMEは冒頭で「アプリケーションを状態機械(=グラフ/フローチャート)として表現する」と明言しています。もともとDAGWorks社が開発し、現在はApache Software Foundationのインキュベーションプロジェクト(Apache Burr, incubating)として開発が続いています。名前は、Apache Hamilton(同じ作者陣によるDAGライブラリ)の宿敵アーロン・バーに由来し、「DAGにはサイクルが無い」ため状態+ループを扱うハーネスとして生まれた、という経緯が語られています。
READMEによれば、Burrは大きく3つの部品からなります。
・状態機械ライブラリ:依存の少ない低抽象なPythonライブラリ。単純な関数で状態機械を組み立てる
・テレメトリUI:実行の様子を可視化・追跡し、内省とデバッグに使う(記事冒頭のFVがそのUI)
・統合:状態の永続化・テレメトリ連携・他システム連携(Apache Hamilton など)を容易にする一連の連携
Burrの語彙はシンプルです。@action で飾った関数がノードで、reads(読む状態)と writes(書く状態)を宣言します。この reads / writes こそが、グラフ設計でいう「エッジ=データ契約」をコード上で明示する部分です。ノード同士を結ぶエッジは with_transitions で定義し、条件を付ければ分岐やループになります。
最小の「hello-world」は、ユーザー入力ノードとAI応答ノードを相互に遷移させるチャットボットです。human_input と ai_response を with_transitions で双方向に結ぶと、それがそのままサイクル(ループ)を持つグラフになります。
from burr.core import action, State, ApplicationBuilder
@action(reads=[], writes=["prompt", "chat_history"])
def human_input(state: State, prompt: str) -> State:
chat_item = {"role": "user", "content": prompt}
return state.update(prompt=prompt).append(chat_history=chat_item)
@action(reads=["chat_history"], writes=["response", "chat_history"])
def ai_response(state: State) -> State:
response = _query_llm(state["chat_history"]) # LLMの呼び方は自由
chat_item = {"role": "system", "content": response}
return state.update(response=response).append(chat_history=chat_item)
app = (
ApplicationBuilder()
.with_actions(human_input, ai_response)
.with_transitions(
("human_input", "ai_response"),
("ai_response", "human_input"),
)
.with_state(chat_history=[])
.with_entrypoint("human_input")
.build()
)
導入は pip で行い、同梱のUIサーバーを立ち上げると、デフォルトデータ入りの状態でグラフの実行を眺められます。
pip install "apache-burr[start]"
burr # テレメトリUIサーバーが立ち上がる
Burrは「モデルの作り方」「APIの叩き方」「データの持ち方」を指示しません。それらをつなぎ合わせて、システムのロジックを追いやすくするための骨格に徹します。だからこそLLMの有無に依存せず、時系列シミュレーションやハイパーパラメータ探索のような非LLM用途にも同じ枠組みが使えます。
4. Apache Burrで分岐・検証・ループを組む
第2節のトポロジ(pipeline・fan-out・router・verifier・cycle)を、Burrの語彙に落とすと次のように対応します。設計の型が、そのままコードの型になるのが要点です。
・pipeline(直列):with_transitions(("A","B"), ("B","C")) と素直に結ぶ
・router(分岐):遷移に条件を付け、状態の値に応じて次のノードを選ぶ(例:分類結果が spam なら破棄ノードへ、そうでなければ処理ノードへ)
・verifier(検証):生成ノードの後ろに検証ノードを置き、検証結果を状態に書く。合格なら出力へ、不合格なら生成ノードへ戻す遷移を条件付きで張る
・cycle(ループ):("verify","generate") のように後ろ向きの遷移を条件付きで張れば、収束するまで回るループになる
・fan-out / 並列:独立した処理を個別のアクションに分け、集約ノードで畳む。Burrは「サブグラフ」や並列実行の仕組みも用意する(詳細な並列APIの成熟度は用途により差があるため、要件次第で公式ドキュメントの該当機能を確認する)
具体的に「生成→検証→(不合格なら)やり直し」というエージェント グラフを組む流れを、Burr 使い方の基本に沿って言葉で追ってみます。まず生成ノード generate を @action(reads=["prompt"], writes=["draft"]) として定義し、生成物を状態 draft に書きます。次に検証ノード verify を @action(reads=["draft"], writes=["verdict"]) として置き、合否を状態 verdict に書きます。あとは遷移に条件を付けるだけです。verdict が「合格」なら出力ノードへ、「不合格」なら generate へ戻す——この後ろ向きの条件付き遷移が、そのまま cycle(収束するまで回るループ)になります。router(分岐)も verifier(検証)も cycle(ループ)も、新しい概念を足すのではなく「遷移に条件を付ける」という同じ操作で表現できるのが、状態機械としてグラフを持つことの効きどころです。そしてこの一連の遷移は、記事冒頭のUIでそのまま可視化・追跡できます。
エージェントの挙動はループと分岐で見えづらくなります。どのノードで失敗したか、なぜそのルートを通ったかを後から追えないと運用が破綻します。Burrがテレメトリを最初から同梱しているのは、この「可観測性を後付けにしない」という思想の表れです。状態は pluggable persister で保存でき、途中から再開する冪等なワークフローも組めます。
READMEの「あらゆるアプリに使える」という表現は設計思想の説明であり、あなたのユースケースで最適化された並列実行やスケーリングが自動で手に入るという意味ではありません。並列・分散が要件の中心なら、Burr単体ではなく、後述のイベント駆動系や専用オーケストレータ(Temporal 等)との比較も含めて判断してください。裏が取れない機能は「未確認」として扱い、公式ドキュメントで確認するのが安全です。
5. LangGraph・Burr・LlamaIndex Workflows・PocketFlowを比べる
「グラフでエージェントを組む」OSSはBurrだけではありません。代表的な4つを、グラフの持ち方・状態管理・可視化・ライセンス・成熟度で並べます。裏の取れない欄は「未確認」と明記します(数値は各公式リポジトリで確認した2026年7月時点の値)。
| フレームワーク | グラフの持ち方 | 状態管理 | 可視化 | ライセンス | 成熟度(★・活性) |
|---|---|---|---|---|---|
| Apache Burr | 状態機械。@action=ノード、with_transitions=エッジ、条件でループ |
State+pluggable persisters(永続化・再開) |
同梱のOSSテレメトリUI(監視・トレース) | Apache-2.0 | 約2,486★。活発(2026-07更新)。ASF incubating・v0.42.0-incubating |
| LangGraph | 明示的な StateGraph。ノード+条件付きエッジ |
Checkpointer(メモリ/SQLite/Postgres) | グラフ描画+LangGraph Studio(トレースの中心はホスト型のLangSmith) | MIT | 約34K★とされる。活発でエコシステムが厚い |
| LlamaIndex Workflows | イベント駆動のstep(厳密なDAGでなく、イベントの送受で制御) | ワークフローの Context に状態を保持 |
フロー可視化ユーティリティあり(UIの充実度は未確認) | MIT | 約424★(run-llama/workflows-py)。活発 |
| PocketFlow | 最小の Node+Flow(有向グラフ+共有ストア) |
shared 辞書(永続化は基本的に自前) |
専用UIは未確認(なし) | MIT | 約11,008★と多いが、最終更新は2026-03で停滞気味 |
読み取りのポイントを補足します。
・可視化で分かれる:Burrは監視・トレース用のUIをOSSとして同梱するのが差別化点。LangGraphはグラフ描画やStudioを持つ一方、トレースの中心はホスト型のLangSmith(=完全なOSSではない)とされる。ここは思想の違いで、優劣ではない
・グラフの厳密さで分かれる:Burr・LangGraph・PocketFlowが「ノードとエッジの明示的なグラフ」なのに対し、LlamaIndex Workflowsはイベント駆動で、ステップがイベントを送受して進む。厳密な遷移グラフを描きたいか、イベントで疎結合にしたいかで選ぶ
・成熟度はスター数だけで測らない:PocketFlowはスター数こそ多いが最終更新が数か月前で停滞気味。「100行フレームワーク」という最小主義が魅力だが、本番採用ではメンテ活性とバス係数を確認したい
・単一フレームワークの入門:LangGraph単体を最初の1本から動かしたい場合は LangGraph入門|マルチエージェント・ステートマシン構築の基本と他フレームワークとの違い が、宣言的に手早く組みたい場合は CrewAI入門|マルチエージェント協調フレームワークの基本とLangGraph/AutoGenとの違い が対応します
なお、この比較表の一部はBurrの公式READMEにある自己比較表を出発点にしていますが、そのまま中立の事実として扱うのは避け、各リポジトリの公開情報で裏を取れた範囲に限定し、取れない欄は「未確認」としています。
6. Apache Burrは実務で「使えるか」
最後に「使えるか」を、ライセンス・依存・活性度・バス係数・学習コストの観点で確認します。
・ライセンス:Apache License 2.0(寛容ライセンス。商用利用・改変・再配布可)。READMEにもASFライセンス条項が明記されている
・依存:コアの状態機械ライブラリは「依存が少ない(dependency-free)」低抽象設計。LLMやベクトルDBを強制せず、好きなライブラリを @action の中で呼べる
・活性度:2026年7月時点でスター約2,486・フォーク約173。直近も更新が続き(本記事確認時点で前日にpush)、最新リリースは v0.42.0-incubating(2026-05)。コントリビューターは数十名規模
・バス係数:ASFのインキュベーションに入ったことで、単一ベンダー(DAGWorks)依存から公共ガバナンスへ移行しつつある。ただしコミュニティ規模はLangGraph等より小さく、周辺エコシステム(連携・事例・日本語情報)は薄い
・学習コスト:action・transition・State の3概念に絞られ、宣言的フレームワーク(CrewAI等)よりは制御を書く分だけ概念が要るが、LangGraphと同程度に「状態遷移を自分で支配する」タイプ
① 可観測性(実行トレース)を最初から欲しいか=同梱UIが効くか。② LLM以外の処理(シミュレーション等)も同じ枠組みで扱いたいか。③ incubating段階と小さめのコミュニティを許容できるか。④ 状態の永続化・再開が要件か。①②④が「はい」でBurrは映え、③が許容できるなら有力候補になる。
逆に、Burrが向かない場面もはっきりしています。厚いエコシステムと豊富な事例・周辺ツールを最優先するなら、LangGraph 比較の観点ではLangGraphに分があります。非同期のイベント駆動を主軸に疎結合で組みたいならLlamaIndex Workflows、とにかく最小構成の学習用途ならPocketFlow、というように、同じ「AIエージェント OSS」でも重心が違います。Burrが際立つのは「状態機械としての明示性」と「監視・トレース用のOSS UIを最初から同梱している」という2点の交差であり、ここが要件に刺さるかどうかが採用の分かれ目です。優劣ではなく、可観測性と状態設計をどれだけ前に出したいかで選ぶのが健全です。
現時点で日本語の解説はほとんど見当たらず、一次情報(公式README・ドキュメント)を読むのが最短です。逆に言えば、状態機械としてエージェントを設計し、その実行を同梱UIで可視化する、という組み合わせをOSSで完結させたいなら、Apache Burrは今すぐ試す価値があります。プロプライエタリな実行基盤で同じ思想を追った Claude Code動的ワークフローの姉妹記事 と読み比べると、「グラフとして設計する」という考え方が、実装手段(ネイティブ/OSS)を越えて共通していることが見えてきます。
7. まとめ——設計の出発点をグラフに置く
多段エージェントの詰まりは、腕の問題ではなく設計の出発点の問題です。「Aして、それからB」を素直に直線化すると、独立した処理まで直列で待ちます。処理をグラフ(状態機械)として捉え、pipeline・fan-out・router・verifier・cycle の型で組み直すと、並列化・分岐・検証・ループが「最初から書ける型」になります。
・エージェントの処理は本来グラフ。直線は「並列の余地をゼロにした退化グラフ」にすぎない
・Apache Burrはアプリを状態機械として書くOSS。`@action`=ノード、`with_transitions`=エッジ、条件で分岐・ループ。Apache-2.0で、監視・トレース用のOSS UIを同梱する
・LangGraph(厚いエコシステム)・LlamaIndex Workflows(イベント駆動)・PocketFlow(最小構成・ただし停滞気味)と、持ち方・状態管理・可視化・ライセンス・成熟度で住み分ける
・BurrはASFの incubating 段階でコミュニティは小さめ。可観測性・非LLM用途・永続化が要件なら映える
・持ち帰る問いは1つ:「この"それから"は本当にデータ依存か?——次段が前段の出力を読まないなら、並列にできる」
参照ソース
・apache/burr(公式リポジトリ・README) — 状態機械モデル・3部品・自己比較表・ライセンス・最小コードの一次情報
・Apache Burr Documentation(burr.apache.org) — インストール・getting started・概念の公式ドキュメント
・the-pocket/PocketFlow(公式リポジトリ) — 比較表のスター数・ライセンス・更新状況の確認元
・run-llama/workflows-py(公式リポジトリ) — LlamaIndex Workflowsのイベント駆動設計・スター数・ライセンスの確認元