AG-UI(Agent–User Interaction Protocol)は、AIエージェントのバックエンドと、ユーザーが触るフロントエンドの間のやり取りを決めるオープンなプロトコルです。エージェントの応答文・ツール呼び出し・共有状態・実行の開始と終了を、型の決まったイベントの列としてフロントへ流します。名前から「UIを自動で作る技術」と誤解されがちですが、UIを生成する仕様ではありません。2026年9月17日に仕様が1.0として確定し、標準イベントは31種になりました。0.x時代の「17種」の解説はもう当てはまりません。本記事では1.0を前提に、定義、MCP・A2Aとの違い、1.0の変更点、イベント一覧、そして中断と再開まで動かすコードを順に説明します。
まとめ:AG-UI 1.0の要点
- AG-UIは「Agent–User Interaction Protocol」の略。エージェントとユーザー向けアプリをつなぐイベント通信の規格で、UIを生成する仕様ではない。
- 2026年9月17日に仕様が1.0として凍結され、npm
@ag-ui/coreと PyPIag-ui-protocolも同日に1.0.0が出た(2026年10月30日時点の最新は npm 1.0.3・PyPI 1.0.0)。 - 標準イベントは31種。1.0で推論(REASONING_*)・進捗(ACTIVITY_*)・サブエージェント(SUBAGENT_*)が正式に加わり、THINKING_* は廃止された。
- 1.0の目玉は
RUN_FINISHEDのoutcome。承認待ちで実行を止め、回答をresumeに入れて再開する流れが仕様で決まった。 - MCPは「エージェントとツール」、A2Aは「エージェント同士」、AG-UIは「エージェントとユーザー」をつなぐ。役割が違うので併用する。
AG-UIの定義:エージェントとフロントをつなぐイベント規格
AG-UIの1.0仕様は、自身を「1つのリクエストを受け取り、型付きイベントの順序つきストリームを1本返す」プロトコルと定義しています。ストリームに載るのは、ユーザーに見せるエージェントの出来事すべてです。具体的には応答テキスト、ツール呼び出し、推論、共有状態、進捗が対象になります。フロントはこのイベントを受けて画面を更新するだけでよく、バックエンドが LangGraph でも Mastra でも受け口は同じです。
仕様はCopilotKitが中心となって策定し、ag-ui-protocol/ag-ui リポジトリでMITライセンスとして公開されています。リポジトリの作成は2025年5月7日で、2026年10月30日時点のスター数は約1万6,900です。
AG-UIの伝送機能とA2UI・MCP Appsの役割分担
公式ドキュメントのGenerative UIのページは、名前が似ていても「AG-UI is not a generative UI specification」と明記しています。画面の部品をエージェントに組み立てさせる仕様は別にあり、AG-UIはそれを運ぶ側です。
| 仕様 | 提供元 | 役割 |
|---|---|---|
| AG-UI | CopilotKit中心 | エージェントとアプリの間の双方向の通信路 |
| A2UI | JSONLで流す宣言的な生成UIの形式 | |
| MCP-UI | Microsoft+Shopify | MCPを拡張するiframe型の生成UI |
| Open-JSON-UI | OpenAI | 宣言的な生成UIスキーマの公開版 |
A2UIの公式説明も「AG-UIが伝送、A2UIが生成UIの形式」という組み合わせを示しています。MCP-UIの流れは、MCPの公式拡張であるMCP Appsとして標準化されました。AG-UIの統合一覧には、生成UIとしてA2UIとMCP Appsが載っています。なおA2UIのREADMEでは、2026年10月30日時点の本番向け版はv0.9.1で、v1.0仕様はリリース候補の段階です。iframe型の対話UIについてはMCP Appsの仕組みと採用判断、生成UIのフレームワークはOpenUIとGenerative UIの選び方で扱っています。
AG-UIとMCP・A2Aの違い
3つのプロトコルは、つなぐ相手で分担しています。競合ではないため、要件に応じて1つのアプリで併用できます。
| プロトコル | つなぐ相手 | 流れるもの |
|---|---|---|
| AG-UI | エージェント ↔ ユーザー(フロント) | 応答・ツール実行・状態・中断 |
| MCP | エージェント ↔ ツール・データ | ツール定義と呼び出し結果 |
| A2A | エージェント ↔ エージェント | タスクの委譲と結果 |
たとえば、MCPで社内DBを読み、A2Aで別のエージェントに見積もりを頼み、その途中経過をAG-UIで画面に流す構成が成り立ちます。1.0で加わったサブエージェントのイベントは、この「委譲した先の出力」を画面上で親の実行と区別するためのものです。MCPの仕組みはMCP(Model Context Protocol)とは、A2AはA2A(Agent2Agent)プロトコルとはで解説しています。
AG-UI 1.0の変更点と2026年9月の仕様確定
1.0の公開日と版
リポジトリでは2026年9月17日のコミット「freeze the draft as 1.0」で仕様が凍結され、SDKの定数 PROTOCOL_VERSION の値は “draft” から “1.0” に変わりました。同日に npm の @ag-ui/core 1.0.0 と PyPI の ag-ui-protocol 1.0.0 が公開されています。告知は翌18日のDiscussion #2792(「AG-UI 1.0 is now officially released and frozen」)、CopilotKitの発表記事は9月30日付です。
2026年10月30日時点の最新は npm 1.0.3(10月16日)と PyPI 1.0.0 です。リポジトリでは10月1日に次の1.1ドラフトが1.0と別の場所で始まっています。日本語の解説記事には「1.0はドラフトで未批准」と書いたものが残っていますが、凍結後の現在は1.0が確定版です。
0.xからの主な変更点
1.0のKey Changesが挙げる主要な変更のうち、アプリの作りに効くものは次のとおりです。
- 仕様書ができた:0.xでは振る舞いがTypeScriptクライアントの実装に埋まっていた。1.0では順序やエラー処理のルールをMUST/SHOULDで定め、構造はJSON Schemaが正になった。
- 実行の終わり方を返す:
RUN_FINISHED.outcomeが success・interrupt・cancelled を区別する。ユーザーが止めた実行は失敗ではなく cancelled で届く。 - サブエージェント:委譲した処理のイベントに
subagentRunIdが付き、開始と終了をSUBAGENT_*で通知できる。 - 推論イベント:THINKING_* を廃止し REASONING_* に置き換えた。プロバイダーの暗号化された推論は REASONING_ENCRYPTED_VALUE で中身を読まずに保持できる。
- Activityイベント:構造化した進捗をメッセージとして送り、JSON Patchで更新する。
- Protobufの伝送:JSON over SSEに加え、HTTP+Protobufの形式が仕様に入った。
- 版の申告:クライアントは
RunAgentInput.protocolVersion、エージェントはRUN_STARTED.protocolVersionで自分の版を名乗る。
このほか、実行の終了イベントにプロバイダーごとのトークン使用量を載せられるようになり、ツール結果には文字列だけでなく画像や文書の部品も返せるようになりました。
0.xで作った実装への影響
移行ガイドによると、0.xのエージェントは1.0のクライアントでそのまま動きます。TypeScriptクライアントが受信時に古い形を変換するためで、THINKING_* の5種は対応するREASONING_*へ置き換えられ、そのたびに警告が出ます。ただしこの互換処理には期限があり、DEPRECATIONS.mdでは1.0の公開日から12か月後の2027年9月17日に統一されています。期限後のリリースで互換処理が外されると、古い形は受け付けられなくなります。
手を入れるべき点は2つです。1つ目は、エージェント側で RUN_STARTED を自前で組み立てている場合、SDKの定数 PROTOCOL_VERSION を protocolVersion に入れることです。1.0のエージェントは版の申告がMUSTで、SDKは自動では付けません。2つ目は、省略可能な項目に null を入れず、項目ごと省くことです。CopilotKitを使っているなら、v1.76.0でAG-UI 1.0に対応しています。
AG-UIの標準イベント31種
1.0のスキーマ(spec/1.0/schema.json)の EventType は31値です。TypeScriptとPythonのSDKでも列挙は31件で、どちらもこのスキーマから生成されています。下表は公式ドキュメントの章立てに沿って分類し、推論は件数が多いため2行に分けました。
| 分類 | 数 | イベント型 |
|---|---|---|
| ライフサイクル | 5 | RUN_STARTED / FINISHED / ERROR、STEP_STARTED / FINISHED |
| テキストメッセージ | 4 | TEXT_MESSAGE_START / CONTENT / END / CHUNK |
| ツール呼び出し | 5 | TOOL_CALL_START / ARGS / END / RESULT / CHUNK |
| 状態管理 | 3 | STATE_SNAPSHOT / STATE_DELTA / MESSAGES_SNAPSHOT |
| Activity(1.0) | 2 | ACTIVITY_SNAPSHOT / ACTIVITY_DELTA |
| 推論(1.0) | 3 | REASONING_START / END / ENCRYPTED_VALUE |
| 推論メッセージ(1.0) | 4 | REASONING_MESSAGE_START / CONTENT / END / CHUNK |
| サブエージェント(1.0) | 3 | SUBAGENT_STARTED / SUBAGENT_FINISHED / SUBAGENT_ERROR |
| 特殊 | 2 | RAW / CUSTOM |
旧来の「17種」は、0.xの主要イベントを数えた値です。CHUNK系は開始・本文・終了を1種で兼ねる簡略形で、1.0では「最初のチャンクにmessageIdやtoolCallIdを必ず入れる」というルールが付きました。イベントの解説ページには、仕様に入っていない提案中のDraftイベントも載っていますが、上の31種には含まれません。
1回の実行で流れる順序
応答を1つ返す最小の実行は、RUN_STARTED → TEXT_MESSAGE_START → TEXT_MESSAGE_CONTENT(差分を複数回)→ TEXT_MESSAGE_END → RUN_FINISHED の順です。Python SDKの EventEncoder は既定で text/event-stream(SSE)として書き出し、TypeScriptの HttpAgent はリクエストに Accept: text/event-stream を付けて送ります。状態を毎回丸ごと送らずに済ませたいときは、STATE_DELTA でJSON Patchの差分だけを流します。
AG-UIの実装例:Pythonと@ag-ui/clientによる中断・再開
1.0で加わった中断と再開を、Webフレームワークを使わないPythonサーバー(標準ライブラリの http.server)と @ag-ui/client の組み合わせで動かします。次のコードは node v26.5.0、Python 3.9.6、@ag-ui/client 1.0.3、ag-ui-protocol 1.0.0 で実行し、出力を確認しています。TypeScriptは npm install -D typescript @types/node を入れたうえで npx tsc --noEmit --strict --module nodenext --target es2022 --types node client.mts の型検査も通しています。ただし購読者の引数は any で受けているため、コールバック内部の型までは検査されません。
Python側:中断・再開イベントを返すサーバー実装
1回目の実行ではメール送信の承認を求めて outcome を interrupt にして終え、2回目に届いた resume を読んで続きを返します。このサンプルは通信の流れを確かめるためのもので、承認画面・回答内容の検証・実際のメール送信は実装していません。本番では interruptId が直前の中断と一致するか、payload が期待した形かをサーバー側で確かめてから処理を進めてください。
pip install ag-ui-protocol==1.0.0
# server.py
import uuid
from http.server import BaseHTTPRequestHandler, HTTPServer
from ag_ui.core import (
RunAgentInput, PROTOCOL_VERSION,
RunStartedEvent, RunFinishedEvent, TextMessageStartEvent,
TextMessageContentEvent, TextMessageEndEvent,
RunFinishedInterruptOutcome, RunFinishedSuccessOutcome, Interrupt,
)
from ag_ui.encoder import EventEncoder
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
body = self.rfile.read(int(self.headers["Content-Length"]))
run = RunAgentInput.model_validate_json(body)
encoder = EventEncoder(accept=self.headers.get("Accept"))
self.send_response(200)
self.send_header("Content-Type", encoder.get_content_type())
self.end_headers()
def send(event):
self.wfile.write(encoder.encode(event).encode("utf-8"))
self.wfile.flush()
# 1.0では自分のプロトコル版を RUN_STARTED で名乗る
send(RunStartedEvent(thread_id=run.thread_id, run_id=run.run_id,
protocol_version=PROTOCOL_VERSION))
if not run.resume:
# 1回目: 送信前に人の承認を求めて中断する
send(RunFinishedEvent(
thread_id=run.thread_id, run_id=run.run_id,
outcome=RunFinishedInterruptOutcome(type="interrupt", interrupts=[
Interrupt(id="approve-1", reason="confirmation",
message="メールを送信してよいですか?")])))
return
# 2回目: resume の回答を読んで続きを返す
answer = run.resume[0]
msg_id = str(uuid.uuid4())
send(TextMessageStartEvent(message_id=msg_id, role="assistant"))
for chunk in ["承認", f"結果: {answer.status}"]:
send(TextMessageContentEvent(message_id=msg_id, delta=chunk))
send(TextMessageEndEvent(message_id=msg_id))
send(RunFinishedEvent(thread_id=run.thread_id, run_id=run.run_id,
outcome=RunFinishedSuccessOutcome(type="success")))
HTTPServer(("127.0.0.1", 8000), Handler).serve_forever()
FastAPIなどで書く場合も、やることは同じです。RunAgentInput で受け、EventEncoder でSSEに変換して順に書き出します。
TypeScript側:HttpAgentによる実行と再開
runAgent の第2引数に購読者を渡すと、イベントの種類ごとに処理を書けます。中断で返った interrupts のidを、2回目の resume に入れて送り返します。
npm install @ag-ui/[email protected]
// client.mts
import { HttpAgent } from "@ag-ui/client";
const agent = new HttpAgent({ url: "http://127.0.0.1:8000/agent" });
agent.addMessage({ id: "u1", role: "user", content: "見積書をメールで送って" });
let pending: string[] = [];
const subscriber = {
onTextMessageContentEvent: ({ event }: any) => {
process.stdout.write(event.delta);
},
onRunFinishedEvent: (params: any) => {
console.log(`\n[RUN_FINISHED] outcome=${params.outcome}`);
if (params.outcome === "interrupt") {
pending = params.interrupts.map((i: any) => i.id);
console.log(`承認待ち: ${params.interrupts[0].message}`);
}
},
};
// 1回目: エージェントが承認を求めて中断する
await agent.runAgent({}, subscriber);
// 2回目: 承認結果を resume に入れて再実行する
await agent.runAgent(
{ resume: pending.map((id) => ({ interruptId: id, status: "resolved", payload: { approved: true } })) },
subscriber,
);
サーバーを起動してから node client.mts を実行すると、次のように出力されました。node v26は型注釈を外してTypeScriptを直接実行できますが、検証環境の package.json は npm init -y の既定で "type": "commonjs" になっており、拡張子を .ts にすると import の行で SyntaxError になりました。拡張子を .mts にすれば、package.json の指定に関係なくES Modulesとして読まれます。
[RUN_FINISHED] outcome=interrupt
承認待ち: メールを送信してよいですか?
承認結果: resolved
[RUN_FINISHED] outcome=success
HttpAgentの版申告と終了イベントの扱い
最初の2点は上のコードの実行で確かめた挙動、3点目は1.0のKey Changesに書かれた仕様です。
HttpAgentは送信するJSONに"protocolVersion":"1.0"を自動で入れる。版を自前で付ける必要があるのは、イベントを組み立てるエージェント側だけ。onRunFinishedEventの引数には、生のイベントとは別にoutcome(”success” / “interrupt” / “cancelled”)が文字列で入る。分岐はこちらで書くと短い。- ブラウザで実行するツール(フロントエンドツール)の呼び出しで止まった実行は、interruptではなく success で終わる。答えていない呼び出しは
pendingToolCallIdsに並ぶ。承認待ちとツール待ちを同じ分岐で扱わないこと。
LangGraphやCrewAIなど対応フレームワークを使う場合は、各アダプタがこのイベント発行を代わりに行います。上のような手書きが要るのは、独自のバックエンドをつなぐときです。
AG-UIの対応フレームワークとSDK(2026年10月時点)
公式ドキュメントの統合一覧で「Supported」となっている主なものを分類しました。
| 区分 | 対応先 |
|---|---|
| パートナー | LangChain / CrewAI |
| ファーストパーティ(大手) | Microsoft Agent Framework / Google ADK(Python・JS) |
| ファーストパーティ(AWS) | AWS Strands Agents / AWS Bedrock AgentCore |
| ファーストパーティ(OSS) | Mastra / Pydantic AI / Agno / LlamaIndex / AG2 |
| コミュニティ | Claude Agent SDK / Cloudflare Agents / Langroid / Omnara |
| 生成UI | A2UI / MCP Apps |
| SDK(コミュニティ) | Kotlin / Go / Dart / Java / Rust / Ruby / C++ / .NET |
| クライアント | CopilotKit / React Native / Slack・Microsoft Teams |
OpenAI Agent SDKとAWS Bedrock Agentsは「In Progress」で、まだ対応済みではありません。AWSは2026年3月13日にBedrock AgentCore RuntimeのAG-UI対応を発表しています。MicrosoftはAgent FrameworkのAG-UI統合を公式ドキュメントで説明しています(Microsoft Agent Framework 1.0とは)。状態遷移型のエージェントを組むLangGraphや、TypeScript製のMastraも一覧に入っています。
フロントのUI部品はCopilotKitが中心です。npmの最新は @copilotkit/react-core 1.83.0(2026年10月28日)で、Vue 3向けの @copilotkit/vue も同じリポジトリから2026年5月に公開されています。React以外でも公式の部品が使えるようになりました。
AG-UIを採用すべき場面と避けるべき場面
採用すべき場面。ツール実行の途中経過や共有状態を画面に出したいエージェントアプリです。特に1.0では、送金・メール送信・削除のように取り消せない操作の前で止め、人の承認を受けてから続ける流れを標準の形で書けます。独自のWebSocketメッセージで同じ流れを作っているなら、承認待ち・取り消し・サブエージェントのメッセージ形式を自前で保守し続ける費用と、イベントを1.0の型に置き換える移行費用を比べて判断してください。複数のフレームワークのエージェントを1つのフロントで受けたい場合も向いています。
避けるべき場面。状態同期もツールの可視化も要らない一問一答のチャットは、素のSSEで足ります。AG-UIを入れると、イベントの順序規則や版の申告を守る手間だけが増えます。「画面のレイアウト自体をAIに作らせたい」要件はA2UIやMCP Appsの領域で、AG-UIだけでは満たせません。また、2026年10月時点で OpenAI Agent SDK はまだ対応中です。主力のフレームワークが一覧で「Supported」でないなら、アダプタを自作する工数を先に見積もってください。
社内システムとつなぐエージェントの画面を設計する段階なら、AIエージェント開発の支援で、MCP・A2A・AG-UIの分担を含めた構成からご相談いただけます。
よくある質問
AG-UIは何の略ですか?
Agent–User Interaction Protocol(エージェントとユーザーのやり取りのプロトコル)の略です。「Agent-Generated UI」のような、UIを自動生成する仕組みの名前ではありません。
AG-UIとA2UIの違いは何ですか?
AG-UIはエージェントとアプリの間でイベントを運ぶ通信の規格、A2UIはGoogleが公開する生成UIの記述形式です。A2UIで書いたUIをAG-UIで運ぶ、という組み合わせで使います。
AG-UIはReact以外(Vueなど)でも使えますか?
使えます。プロトコルはフロントの種類を問わず、@ag-ui/client はフレームワークに依存しないTypeScriptのライブラリです。UI部品もCopilotKitがVue 3向けの @copilotkit/vue やAngular向けのパッケージを出しています。
AG-UIの標準イベントはいくつありますか?
1.0では31種です。0.xの解説でよく見る「16種」「17種」は、推論・Activity・サブエージェントのイベントが入る前の数です。
AG-UIは無料で使えますか?
無料です。仕様とSDKはMITライセンスのオープンソースで、npmとPyPIから入手できます。費用がかかるのは、つなぐLLMやホスティングの利用料です。