なぜADK for Go 2.0が今注目なのか
現実のエージェントアプリケーションは、単一のプロンプトで終わりません。分類、分岐、並列実行、人間の承認待ち、リトライ、ループといった複雑なオーケストレーションが必要です。これらをアドホックな制御フローで実装すると、すぐにメンテナンス不能になります。
ADK for Go 1.0は、強力な型システム、iter.Seq2イベントストリーム、既存のGoサービスに自然に統合できるランタイムで高く評価されました。そして、2.0が登場しました。
キーワードは「グラフ」です。
ADK 2.0は、マルチエージェントアプリケーションを構成するための第一級の方法として、グラフベースのワークフローエンジンを導入しました。Human-in-the-loop(HITL)、動的オーケストレーション、LLMエージェントモードも加わり、単一エージェントとフルグラフが同一の実行モデル上で動作します。
Python ADK 2.0をご存知の方なら、同じ方向性とお考えください。ただし、Go開発者向けに「Goらしい」APIとして設計されている点が最大の特徴です。
この記事では、ADK for Go 2.0のコアコンセプトとコード例を通じて、実際のプロジェクトへの適用方法を解説します。

グラフベースワークフローの核心:コードで理解する
ADK 2.0の最大の変更点は、アプリケーションの形状をノード(Node)とエッジ(Edge)で構成されるグラフとして記述し、スケジューラがそれを並行実行し、状態を保持し、人間の介入のために一時停止し、後で再開できるようにした点です。
基本チェーン:最もシンプルなグラフ
package main
import (
"context"
"fmt"
"google.golang.org/adk/v2/workflow"
"google.golang.org/adk/v2/agent"
)
// 大文字に変換するノード
func upperFn(ctx agent.Context, in string) (string, error) {
return strings.ToUpper(in), nil
}
// 文字列にサフィックスを追加するノード
func suffixFn(ctx agent.Context, in string) (string, error) {
return in + " - 完了!", nil
}
func main() {
upper := workflow.NewFunctionNode("upper", upperFn, workflow.NodeConfig{})
suffix := workflow.NewFunctionNode("suffix", suffixFn, workflow.NodeConfig{})
// 開始 -> upper -> suffix の順に接続
edges := workflow.Chain(workflow.Start, upper, suffix)
wf, err := workflowagent.New(workflowagent.Config{
Name: "simple_sequence_workflow",
Edges: edges,
})
if err != nil {
panic(err)
}
// wfはただの agent.Agent インターフェースです
// 既存のRunner、Launcher、Consoleでそのまま実行可能!
fmt.Println("ワークフロー作成完了")
}
重要なポイント: wfはagent.Agentインターフェースを実装しています。したがって、既存のRunner、Launcher、Consoleで特別な変更なしにそのまま実行できます。グラフ自体が1つのエージェントなのです。
ルーティング:条件分岐
エッジはルーティング条件を持つことができます。ノードがルーティング値を出力すると、一致するエッジが実行されます。この単純なアイデアで、あらゆる制御フローを表現できます。
b := workflow.NewEdgeBuilder()
b.AddRoutes(router, map[string]workflow.Node{
"question": answerNode,
"statement": commentNode,
"exclamation": reactNode,
})
b.AddFanOut(planner, researchA, researchB, researchC) // 並列分岐
b.AddFanIn(join, researchA, researchB, researchC) // 結果収集
- 順次チェーン、条件付きルーター、Fan-out/Fan-in、ネストされたサブグラフ、さらにはループ(完了したノードを再実行可能)まで、すべてエッジとルートで実現します。
- 標準ルートとして
StringRoute、IntRoute、BoolRoute、MultiRoute、Default(その他すべて)を提供します。
LLMをルーターとして活用:最も有用なパターン
// ユーザーメッセージを分類するLLMエージェント
// -> 質問ならanswerNode、感嘆ならreactNode、発言ならcommentNodeにルーティング
モデルが決定を下し、グラフがその決定を**信頼性(Reliable)、観測可能性(Observable)、再開可能性(Resumable)**にします。このパターンはexamples/workflow/routing/llm/で確認できます。
動的ノード(Dynamic Node):実行順序をランタイムに決定
greeter := workflow.NewDynamicNode("greeter_workflow",
func(nc agent.Context, in string, emit func(*session.Event) error) (string, error) {
return workflow.RunNode[string](nc, greeterNode, in)
},
workflow.NodeConfig{},
)
ループ、条件分岐、動的リストに対するFan-outなどを、慣れ親しんだGoコードでオーケストレーションできます。WithRunID、WithUseSubBranch、WithUseAsOutput、WithIsolationScopeオプションで、子ノードのアイデンティティ、履歴の分離、出力委任を精密に制御できます。
Human-in-the-loop(HITL):人間の承認を待つワークフロー
event := workflow.NewRequestInputEvent(ctx, session.RequestInput{
InterruptID: "approve_refund",
Message: "200ドルの払い戻しを承認しますか? (yes/no)",
ResponseSchema: schema,
})
// イベントを出力すると、ノードは "waiting" 状態に遷移
人間が後で応答すると、ワークフローが再開されます。実行状態はセッションに保存され、プロセス再起動後でも再開可能です。Python ADKと割り込み形式を共有しているため、異なるランタイム間でも再開が可能です。
リトライポリシー:組み込みの指数バックオフ
cfg := workflow.NodeConfig{
RetryConfig: workflow.DefaultRetryConfig(),
}
// 5回試行、初回遅延1秒、最大60秒、2倍バックオフ、フルジッター
Timeout、WithMaxConcurrency(n)でグラフ全体の並行性を制限し、分離された並列ブランチを構成できます。スケジューラがgoroutine、チャネル、バックプレッシャー、キャンセルをすべて処理します。

LLMエージェントモードと統合されたランタイム
ADK 2.0はLLMエージェント向けのモード(Chat、Task、SingleTurn)を導入しました。コーディネーターはユーザーとチャットしながら、サブエージェントは静かにTaskを完了したりSingle-shotで実行されます。各エージェントの役割に応じて、適切なヘルパーツール(finish_task、single_turn、task)が自動的にインストールされます。
最大の変更点: Runnerが通常のLlmAgentをワークフローと同じノードランタイムで駆動するようになりました。結果として、単一エージェントアプリとフルグラフが1つの実行モデルを共有し、HITLが通常のLLMエージェントでも動作します(ワークフロー内部だけでなく)。
APIの簡素化:ToolContextとCallbackContextが1つに
ToolContextとCallbackContextが廃止され、agent.Contextに統合されました。ツール、コールバック、ワークフローノードはすべてagent.Contextを直接受け取ります。- ノード/エージェントの実行が1つの一貫したテレメトリスパンツリーで表示され、グラフが何をしたかを正確に追跡できます。
マイグレーションガイド(核心のみ):
// 変更前: func(ctx agent.InvocationContext, in string) (string, error)
// 変更後: func(ctx agent.Context, in string) (string, error)
InvocationContextを埋め込んでいるため、既存のメソッドはすべて使用可能です。agent/context_mock.goのStrictContextMockをテストダブルとして使用できます。
すぐに試す
go run ./examples/workflow/basic/
go run ./examples/workflow/routing/llm/ # LLM-as-router
go run ./examples/workflow/dynamic/hitl/ # 動的 + HITL
go run ./examples/workflow/hitl_rerun/ # 再エントリー再開HITL
go run ./examples/workflow/complex/ # 大規模マルチグラフ

日本開発コミュニティにおける適用コンテキスト
日本では、SIerや金融機関を中心に、長時間実行プロセス(Long-running Process)と人間承認ワークフローが非常に重要なドメインです。
- 例: 保険金請求処理、金融取引承認、ローン審査など。
- ADK 2.0のHITLとdurable resume機能は、これらの要件に完全に合致します。特にプロセス再起動後も状態が維持される点は、金融系システムで極めて重要な要素です。
- ただし、国内クラウド環境でGoランタイムを運用する際は、メモリプロファイリングとgoroutineリークに常に注意が必要です。ADK 2.0のグラフスケジューラは多数のgoroutineを生成する可能性があるため、
WithMaxConcurrencyで適切に制限することを推奨します。
この技術の限界または注意点
- 学習曲線: グラフの概念自体は直感的ですが、複雑なワークフローを設計する際は、ノード間のデータフローを明確に定義する必要があります。特に動的ノードを乱用すると、かえってメンテナンスが難しくなります。
- テストの複雑さ: グラフ全体を結合テストするよりも、個々のノード単位で集中テストする戦略が効果的です。
session.Eventの新しいフィールド(IsolationScope、Output、Routesなど)に注意してください。 - Python ADKとの差異: Go 2.0はPython 2.0と同じ方向性を共有しますが、Go固有の静的型システムと
iter.Seq2を活用します。Pythonのように動的型変換を期待してはいけません。
次のステップとしての学習方向
- 公式サンプルの実行: 上記で紹介した
go run ./examples/workflow/コマンドで基本パターンを実際に実行してみてください。 - マイグレーションガイドの習得: ADK Go 2.0マイグレーションガイドを参照し、1.0コードを2.0に移行する練習をしてみてください。
- 複合パターンの設計: 実際の業務ドメインで1つのワークフローをグラフとして設計し、HITLが必要なポイントを特定してみてください。
合わせて読みたい記事