クイックスタート
10 分で動く AI エージェントを作ります。スタブから始め、ストリーミングとバリデーションを追加し、最後に実際の LLM へ接続します。
Goa-AI は、Goa の design-first(設計を単一の真実の源にする)哲学を、エージェント型システムに拡張します。DSL でエージェント・ツールセット・サービス所有の completion・ポリシーを宣言し、型付けされたコントラクト、耐久性のあるワークフロー、ストリーミングイベントを備えたプロダクション品質の実装を生成します。
壊れやすいエージェントコードを書くのをやめ、コントラクトから始めましょう。
多くのエージェントフレームワークでは、プロンプト、ツール、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 Reference と Quickstart を参照してください。
構造化されたやり取りのすべてがツール呼び出しである必要はありません。
適切なコントラクトが、型付きの最終アシスタント応答であることもあります。ツール呼び出しも、手書き 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 で明示的に失敗します。
メリット:
OneOf を再利用→ 詳細は DSL Reference と Runtime を参照してください。
単純で観測可能な部品から、複雑なシステムを組み立てます。
現実の AI アプリケーションは、単一エージェントで完結しません。エージェントが別のエージェントへ委譲し、ツールがサブタスクを生成し、全体を追跡できることが求められます。
Goa-AI の ランツリー(run tree)モデルは、完全な可観測性を備えた階層実行を提供します。各ランは一意の ID を持ち、子ランは親にリンクされ、イベントはリアルタイムでストリーミングされます。失敗時はツリーを辿って原因に到達できます。
メリット:
→ 詳細は Agent Composition と Runtime を参照してください。
エージェントの意思決定をリアルタイムで可視化します。
ブラックボックスなエージェントはリスクです。ツール呼び出し、思考の開始、エラーの発生を 今すぐ 知る必要があります(タイムアウト後では遅い)。
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 により、サービス間で分散ストリーミングできます。
メリット:
RunID と SessionID によりルーティング・フィルタが可能→ 実装詳細は Production Streaming を参照してください。
クラッシュ、再起動、ネットワーク障害に耐えるエージェント実行。
耐久性がないと、プロセスのクラッシュで進捗が消えます。レートリミットでラン全体が失敗します。ツール実行中のネットワーク瞬断で、高価な推論をやり直すことになります。
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))
メリット:
→ セットアップとリトライ設定は Production を参照してください。
どこからでもツールを発見し、利用できます(クラスタ内でもパブリッククラウドでも)。
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 を介して自動的にクラスタを形成します。共有状態、協調ヘルスチェック、水平スケール——すべて自動です。
メリット:
→ 詳細は MCP Integration と Production を参照してください。
| 機能 | 得られるもの |
|---|---|
| Design-First Agents | DSL でエージェントを定義し、型安全なコードを生成 |
| MCP Integration | Model Context Protocol のネイティブサポート |
| Tool Registries | クラスタ対応のディスカバリ + 公開レジストリのフェデレーション |
| Run Trees | エージェントがエージェントを呼ぶ構成を完全に追跡 |
| Structured Streaming | UI と観測のためのリアルタイム型付きイベント |
| Temporal Durability | 障害に強い、耐久実行 |
| Typed Contracts | ツール操作のエンドツーエンド型安全性 |
| Typed Direct Completions | 生成 codec と helper を備えた構造化された最終アシスタント応答 |
| Bounded Results & Server Data | token 効率のよいモデル結果と、UI/監査向けの server-only data |
| Human-in-the-Loop | pause、resume、外部ツール結果、runtime-enforced confirmation |
| Bookkeeping & Terminal Tools | retrieval budget を消費しない progress/status tool と、run を原子的に終端できる tool |
| Prompt Overrides | baseline 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 Composition | agent-as-tool、ランツリー、ストリーミングトポロジ | ~1,400 |
| MCP Integration | MCP サーバ、トランスポート、生成ラッパ | ~1,200 |
| Memory & Sessions | トランスクリプト、メモリストア、セッション、ラン | ~1,600 |
| Production | Temporal セットアップ、ストリーミング UI、モデル統合 | ~2,200 |
| Testing & Troubleshooting | エージェント/プランナー/ツールのテスト、典型的なエラー | ~2,000 |
Total Section: ~21,400 tokens
Goa-AI は、宣言的な設計をプロダクション品質のエージェントシステムへ変換する define → generate → execute パイプラインに従います。
レイヤ概要:
| レイヤ | 目的 |
|---|---|
| DSL | バージョン管理された Go コードで、エージェント・ツール・ポリシー・外部統合を宣言 |
| Codegen | 型安全な spec/codec/workflow 定義/レジストリクライアントを生成(gen/ は編集しない) |
| Runtime | ポリシー適用、メモリ永続化、イベントストリーミングを伴う plan/execute ループの実行 |
| Engine | 実行バックエンドを交換(開発は in-memory、本番は Temporal) |
| Features | モデルプロバイダ(OpenAI/Anthropic/AWS Bedrock)、永続化(Mongo)、ストリーミング(Pulse)、レジストリなどをプラグイン |
主要な統合ポイント:
Goa-AI は 3 つの LLM プロバイダ向けにファーストクラスのアダプタを提供します。
features/model/openai)features/model/anthropic)features/model/bedrock)3 つはいずれも、プランナーが利用する同一の model.Client インターフェースを実装します。アプリケーションは rt.RegisterModel("provider-id", client) でモデルクライアントを登録し、プランナーや生成されたエージェント設定から ID で参照します。プロバイダ差し替えは設計変更ではなく設定変更になります。
新しいプロバイダを追加する手順も同様です。
model.Request / model.Response / ストリーミング model.Chunk にマッピングして model.Client を実装する。features/model/middleware.NewAdaptiveRateLimiter)でレート制限とメトリクスを付与する。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 を参照してください。