Goa-AI フレームワーク

Go でエージェント型・ツール駆動システムを構築するための design-first フレームワーク。

概要

Goa-AI は、Goa の design-first(設計を単一の真実の源にする)哲学を、エージェント型システムに拡張します。DSL でエージェント・ツールセット・サービス所有の completion・ポリシーを宣言し、型付けされたコントラクト耐久性のあるワークフローストリーミングイベントを備えたプロダクション品質の実装を生成します。


なぜ Goa-AI なのか?

Design-First Agents

壊れやすいエージェントコードを書くのをやめ、コントラクトから始めましょう。

多くのエージェントフレームワークでは、プロンプト、ツール、API 呼び出しを命令的につなぎ合わせます。壊れたとき (そして壊れます) には、明確な真実の情報源がない散在したコードをデバッグすることになります。

Goa-AI はこれを反転します。エージェントの能力を型付き DSL で定義し、実装を生成します。設計がそのままドキュメントになり、コントラクトがそのまま検証になります。変更は自動的に反映されます。

Agent("assistant", "A helpful coding assistant", func() {
    Use("code_tools", func() {
        Tool("analyze", "Analyze code for issues", func() {
            Args(func() {
                Attribute("code", String, "Source code to analyze", func() {
                    MinLength(1)           // Can't be empty
                    MaxLength(100000)      // Reasonable size limit
                })
                Attribute("language", String, "Programming language", func() {
                    Enum("go", "python", "javascript", "typescript", "rust", "java")
                })
                Required("code", "language")
            })
            Return(AnalysisResult)
        })
    })
})

プランナーがこのツールを不正な引数で呼び出した場合、たとえば code が空文字だったり language: "cobol" だったりすると、Goa-AI は型付き境界で呼び出しを拒否し、構造化された retry hint を返します。プランナーはその hint を使って、正確な追加質問をしたり、修正した引数で再試行したりできます。手作業の文字列パースや、手で保守する JSON schema は不要です。

メリット:

  • 単一の真実の情報源 — DSL が振る舞い、型、ドキュメントを定義
  • コンパイル時の安全性 — 実行前に payload の不整合を検出
  • 自動生成クライアント — 手配線なしで型安全なツール呼び出し
  • 一貫したパターン — すべてのエージェントが同じ構造に従う
  • 修復可能なツール呼び出し — 検証エラーが feedback 付きの構造化 retry hint を生成

→ 詳細は DSL ReferenceQuickstart を参照してください。


型付き直接 Completion

構造化されたやり取りのすべてがツール呼び出しである必要はありません。

適切なコントラクトが、型付きの最終アシスタント応答であることもあります。ツール呼び出しも、手書き JSON パースも、プロンプト文に隠した並行スキーマ定義も不要です。

Goa-AI はそれをサービス上の Completion(...) として明示的にモデル化します:

var TaskDraft = Type("TaskDraft", func() {
    Attribute("name", String, "Task name")
    Attribute("goal", String, "Outcome-style goal")
    Required("name", "goal")
})

var _ = Service("tasks", func() {
    Completion("draft_from_transcript", "Produce a task draft directly", func() {
        Return(TaskDraft)
    })
})

completion 名は structured-output contract の一部です。1-64 文字の ASCII で、英字、数字、_- を使え、先頭は英字または数字でなければなりません。

codegen は gen/<service>/completions/ に JSON schema、型付き codec、provider-enforced structured output を要求して最終アシスタント応答を生成 codec で decode する helper を出力します。streaming helper は raw model.Streamer surface に留まります。completion_delta chunk は preview 専用で、正規なのは最後の 1 つの completion chunk だけです。生成 Decode<Name>Chunk(...) helper はその最終 payload だけを decode します。structured output を実装しない provider は model.ErrStructuredOutputUnsupported で明示的に失敗します。

メリット:

  • 1 つの契約面 — 直接 assistant output にも Goa 型、validation、OneOf を再利用
  • 手書き JSON パース不要 — 生成 codec が encode/decode/validation を所有
  • provider-neutral structured output — helper が provider wiring を型付き API の背後に隠す

→ 詳細は DSL ReferenceRuntime を参照してください。


Run Trees

単純で観測可能な部品から、複雑なシステムを組み立てます。

現実の AI アプリケーションは、単一エージェントで完結しません。エージェントが別のエージェントへ委譲し、ツールがサブタスクを生成し、全体を追跡できることが求められます。

Goa-AI の ランツリー(run tree)モデルは、完全な可観測性を備えた階層実行を提供します。各ランは一意の ID を持ち、子ランは親にリンクされ、イベントはリアルタイムでストリーミングされます。失敗時はツリーを辿って原因に到達できます。

Hierarchical agent execution with run trees showing parent-child relationships

メリット:

  • Agent-as-tool — 任意のエージェントを別エージェントからツールとして呼び出せる
  • 階層トレーシング — エージェント境界を跨いだ実行を追跡できる
  • 失敗の分離 — 子ランの失敗は独立し、親はリトライや回復を選べる
  • ストリーミング・トポロジ — UI のためにツリーを遡ってイベントを流せる

→ 詳細は Agent CompositionRuntime を参照してください。


Structured Streaming

エージェントの意思決定をリアルタイムで可視化します。

ブラックボックスなエージェントはリスクです。ツール呼び出し、思考の開始、エラーの発生を 今すぐ 知る必要があります(タイムアウト後では遅い)。

Goa-AI は実行中に 型付けされたイベントを発行します。たとえば、ストリーミングテキストの assistant_reply、ツールのライフサイクルを表す tool_start/tool_end、推論の可視化のための planner_thought、トークン消費の usage などです。イベントはシンプルな Sink インターフェースを介して任意のトランスポートへ流せます。プロダクションでは UI は セッション所有ストリームsession/<session_id>)を 1 本購読し、アクティブ run の run_stream_end を観測したら SSE/WebSocket を終了します。

// Wire a sink at startup — all events from all runs flow through it
rt := runtime.New(runtime.WithStream(mySink))

Stream profiles は消費者ごとにイベントをフィルタします。エンドユーザ UI 用の UserChatProfile()、開発者向けの AgentDebugProfile()、観測基盤向けの MetricsProfile() など。Pulse(Redis Streams)用の組み込み sink により、サービス間で分散ストリーミングできます。

メリット:

  • トランスポート非依存 — WebSocket / SSE / Pulse / 独自バックエンドで同一イベントを利用
  • 型付きコントラクト — 文字列パースなし。ドキュメント化された強い型
  • 選択的配信 — プロファイルで消費者ごとに必要なイベントだけを配信
  • マルチテナント対応RunIDSessionID によりルーティング・フィルタが可能

→ 実装詳細は Production Streaming を参照してください。


Temporal Durability

クラッシュ、再起動、ネットワーク障害に耐えるエージェント実行。

耐久性がないと、プロセスのクラッシュで進捗が消えます。レートリミットでラン全体が失敗します。ツール実行中のネットワーク瞬断で、高価な推論をやり直すことになります。

Goa-AI は Temporal による耐久実行を採用します。エージェントランはワークフローになり、ツール呼び出しはリトライ設定可能なアクティビティになります。すべての状態遷移が永続化され、ツールがクラッシュしても LLM 呼び出しを再実行することなく 自動的にリトライできます。

// Development: in-memory (no dependencies)
rt := runtime.New()

// Production: Temporal for durability
eng, _ := temporal.NewWorker(temporal.Options{
    ClientOptions: &client.Options{HostPort: "localhost:7233"},
    WorkerOptions: temporal.WorkerOptions{TaskQueue: "my-agents"},
})
rt := runtime.New(runtime.WithEngine(eng))

メリット:

  • 推論の無駄を削減 — ツール失敗は LLM を再呼び出しせずにリトライ
  • クラッシュリカバリ — ワーカーを再起動しても最後のチェックポイントから再開
  • レート制限耐性 — 指数バックオフで API スロットリングを吸収
  • 安全なデプロイ — ローリングデプロイでも進行中の作業を失わない

→ セットアップとリトライ設定は Production を参照してください。


Tool Registries

どこからでもツールを発見し、利用できます(クラスタ内でもパブリッククラウドでも)。

AI エコシステムが拡大すると、ツールはあらゆる場所に散らばります。社内サービス、サードパーティ API、公開 MCP レジストリ。ツール定義をハードコードする方法はスケールしません。動的ディスカバリが必要です。

Goa-AI は、自社ツールセット向けの クラスタ対応の内部レジストリと、Anthropic の MCP カタログのような外部レジストリと連携する フェデレーションを提供します。一度定義すれば、どこからでも発見できます。

// Connect to public registries
var AnthropicRegistry = Registry("anthropic", func() {
    Description("Anthropic MCP Registry")
    URL("https://registry.anthropic.com/v1")
    Security(AnthropicOAuth)
    Federation(func() {
        Include("web-search", "code-execution", "filesystem")
        Exclude("experimental/*")
    })
    SyncInterval("1h")
    CacheTTL("24h")
})

// Or run your own clustered registry
var CorpRegistry = Registry("corp", func() {
    Description("Internal tool registry")
    URL("https://registry.corp.internal")
    Security(CorpAPIKey)
    SyncInterval("5m")
})

内部レジストリのクラスタリング:

同じ名前の複数ノードは、Redis を介して自動的にクラスタを形成します。共有状態、協調ヘルスチェック、水平スケール——すべて自動です。

Agent-registry-provider topology showing gRPC and Pulse Streams connections

メリット:

  • 動的ディスカバリ — コンパイル時ではなく実行時にツールを発見
  • マルチクラスタ・スケール — ノードが Redis 経由で自動協調
  • 公開レジストリ連携 — Anthropic/OpenAI など、任意の MCP レジストリからインポート
  • ヘルス監視 — しきい値を持つ ping/pong の自動チェック
  • 選択的インポート — include/exclude パターンで粒度の細かい制御

→ 詳細は MCP IntegrationProduction を参照してください。


機能概要

機能得られるもの
Design-First AgentsDSL でエージェントを定義し、型安全なコードを生成
MCP IntegrationModel Context Protocol のネイティブサポート
Tool Registriesクラスタ対応のディスカバリ + 公開レジストリのフェデレーション
Run Treesエージェントがエージェントを呼ぶ構成を完全に追跡
Structured StreamingUI と観測のためのリアルタイム型付きイベント
Temporal Durability障害に強い、耐久実行
Typed Contractsツール操作のエンドツーエンド型安全性
Typed Direct Completions生成 codec と helper を備えた構造化された最終アシスタント応答
Bounded Results & Server Datatoken 効率のよいモデル結果と、UI/監査向けの server-only data
Human-in-the-Looppause、resume、外部ツール結果、runtime-enforced confirmation
Bookkeeping & Terminal Toolsretrieval budget を消費しない progress/status tool と、run を原子的に終端できる tool
Prompt Overridesbaseline prompt spec と scoped Mongo-backed override/provenance

ドキュメントガイド

ガイド説明~Tokens
Quickstartインストールと最初のエージェント~2,700
DSL Reference完全な DSL: agents / toolsets / policies / MCP~3,600
Runtimeランタイム構造、plan/execute ループ、エンジン~2,400
Toolsetsツールセット種別、実行モデル、トランスフォーム~2,300
Agent Compositionagent-as-tool、ランツリー、ストリーミングトポロジ~1,400
MCP IntegrationMCP サーバ、トランスポート、生成ラッパ~1,200
Memory & Sessionsトランスクリプト、メモリストア、セッション、ラン~1,600
ProductionTemporal セットアップ、ストリーミング UI、モデル統合~2,200
Testing & Troubleshootingエージェント/プランナー/ツールのテスト、典型的なエラー~2,000

Total Section: ~21,400 tokens

アーキテクチャ

Goa-AI は、宣言的な設計をプロダクション品質のエージェントシステムへ変換する define → generate → execute パイプラインに従います。

Goa-AI Architecture

レイヤ概要:

レイヤ目的
DSLバージョン管理された Go コードで、エージェント・ツール・ポリシー・外部統合を宣言
Codegen型安全な spec/codec/workflow 定義/レジストリクライアントを生成(gen/ は編集しない)
Runtimeポリシー適用、メモリ永続化、イベントストリーミングを伴う plan/execute ループの実行
Engine実行バックエンドを交換(開発は in-memory、本番は Temporal)
Featuresモデルプロバイダ(OpenAI/Anthropic/AWS Bedrock)、永続化(Mongo)、ストリーミング(Pulse)、レジストリなどをプラグイン

主要な統合ポイント:

  • Model Clients — LLM プロバイダを統一インターフェースの裏に抽象化し、OpenAI/Anthropic/Bedrock を設計変更なしに差し替え
  • Registry — プロセス境界を跨いでツールセットを発見・呼び出し。Redis でクラスタ化し水平スケール
  • Pulse Streaming — UI 更新、観測パイプライン、サービス間通信のためのリアルタイムイベントバス
  • Temporal Engine — 自動リトライ、リプレイ、クラッシュリカバリを備えた耐久ワークフロー実行

モデルプロバイダと拡張性

Goa-AI は 3 つの LLM プロバイダ向けにファーストクラスのアダプタを提供します。

  • OpenAI (features/model/openai)
  • Anthropic Claude (features/model/anthropic)
  • AWS Bedrock (features/model/bedrock)

3 つはいずれも、プランナーが利用する同一の model.Client インターフェースを実装します。アプリケーションは rt.RegisterModel("provider-id", client) でモデルクライアントを登録し、プランナーや生成されたエージェント設定から ID で参照します。プロバイダ差し替えは設計変更ではなく設定変更になります。

新しいプロバイダを追加する手順も同様です。

  1. プロバイダ SDK の型を model.Request / model.Response / ストリーミング model.Chunk にマッピングして model.Client を実装する。
  2. 必要に応じて共有ミドルウェア(例: features/model/middleware.NewAdaptiveRateLimiter)でレート制限とメトリクスを付与する。
  3. エージェント登録前に rt.RegisterModel("my-provider", client) を呼び出し、プランナーやエージェント設定から "my-provider" を参照する。

プランナーとランタイムは model.Client のみに依存するため、新しいプロバイダは Goa の設計や生成コードの変更なしに追加できます。

クイック例

package design

import (
    . "goa.design/goa/v3/dsl"
    . "goa.design/goa-ai/dsl"
)

var _ = Service("calculator", func() {
    Description("Calculator service with an AI assistant")

    // Define a service method that the tool will bind to
    Method("add", func() {
        Description("Add two numbers")
        Payload(func() {
            Attribute("a", Int, "First number")
            Attribute("b", Int, "Second number")
            Required("a", "b")
        })
        Result(Int)
    })

    // Define the agent within the service
    Agent("assistant", "A helpful assistant agent", func() {
        // Use a toolset with tools bound to service methods
        Use("calculator", func() {
            Tool("add", "Add two numbers", func() {
                Args(func() {
                    Attribute("a", Int, "First number")
                    Attribute("b", Int, "Second number")
                    Required("a", "b")
                })
                Return(Int)
                BindTo("add")  // Bind to the service method
            })
        })

        // Configure the agent's run policy
        RunPolicy(func() {
            DefaultCaps(MaxToolCalls(10))
            TimeBudget("5m")
        })
    })
})

はじめに

まずは Quickstart を参照し、Goa-AI をインストールして最初のエージェントを構築してください。

DSL の全体像は DSL Reference を参照してください。

ランタイムアーキテクチャは Runtime を参照してください。

このセクションの内容

クイックスタート

10 分で動く AI エージェントを作ります。スタブから始め、ストリーミングとバリデーションを追加し、最後に実際の LLM へ接続します。

DSLリファレンス

Goa-AI の DSL 関数(エージェント、ツールセット、ポリシー、MCP 連携)を網羅した完全リファレンス。

ランタイム

Goa-AI ランタイムがエージェントをオーケストレーションし、ポリシーを強制し、状態を管理する仕組みを理解します。

ツールセット

Goa-AI におけるツールセットの種類、実行モデル、検証、再試行ヒント、ツールカタログについて学びます。

エージェントの構成

Agent-as-Tool パターン、ランツリー、ストリーミングトポロジーを使ったエージェントの合成方法を学びます。

MCP 統合

生成されたラッパーと caller を使って、外部 MCP サーバーをエージェントへ統合します。

記憶とセッション

Manage state with transcripts, memory stores, sessions, and runs in Goa-AI.

プロダクション

Temporal による耐久性のあるワークフロー、UI へのイベントストリーミング、適応型レート制限、システムリマインダー。

Tool Payload Defaults

How Goa-AI applies Goa-style defaults to tool payloads (decode-body + transform) and what codegen contracts must hold.

テストとトラブルシューティング

エージェント、プランナー、ツールのテスト方法と、よくある問題のトラブルシューティングを学びます。

内部ツールレジストリ

プロセス境界をまたぐツールセットの発見と呼び出しのために、クラスタ化されたゲートウェイをデプロイします。