UI 도구

adk-ui crate는 AI agents가 tool calls를 통해 동적으로 풍부한 사용자 인터페이스를 생성할 수 있도록 합니다. Agents는 폼, 카드, 알림, 테이블, 차트 등을 렌더링할 수 있으며, 이 모든 것은 JSON으로 직렬화되는 타입 안전한 Rust API를 통해 이루어집니다. 을 위해 프런트엔드 사용.

무엇을 만들게 될까요?

ADK UI Agent

주요 개념:

  • - 다양한 필드 유형으로 사용자 입력을 수집합니다.
  • 카드 - 액션 버튼과 함께 정보를 표시합니다.
  • 테이블 - 행/열로 구조화된 데이터를 제공합니다.
  • 차트 - 막대, 선, 영역, 원형 차트로 데이터를 시각화합니다.
  • 알림 - 알림 및 상태 메시지 표시
  • 모달 - 확인 대화 상자 및 집중적인 상호 작용
  • 토스트 - 간략한 상태 알림
  • 프로토콜 상호 운용 - UI를 A2UI, AG-UI, 또는 MCP 앱 페이로드로 내보내기

예시: 분석 대시보드

ADK UI 분석

예시: 등록 양식

ADK UI 등록


작동 방식

┌─────────────────────────────────────────────────────────────────────────────┐
│ STEP 1: User requests something                                             │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   User: "I want to register for an account"                                 │
│                                                                             │
│                              ↓                                              │
│                                                                             │
│   ┌──────────────────────────────────────┐                                  │
│   │         AI AGENT (LLM)              │                                  │
│   │  "I should show a registration form" │                                  │
│   └──────────────────────────────────────┘                                  │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────────────────┐
│ STEP 2: Agent calls render_form tool                                        │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   📞 Tool Call: render_form({                                               │
│     title: "Registration",                                                  │
│     fields: [                                                               │
│       {name: "email", type: "email"},                                       │
│       {name: "password", type: "password"}                                  │
│     ]                                                                       │
│   })                                                                        │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────────────────┐
│ STEP 3: Frontend renders the form                                           │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   ┌─────────────────────────────────────────────────┐                       │
│   │  📋 Registration                               │                       │
│   │  ────────────────────────────────────────────  │                       │
│   │  Email:    [________________________]          │                       │
│   │  Password: [________________________]          │                       │
│   │                                                │                       │
│   │  [           Register           ]              │                       │
│   └─────────────────────────────────────────────────┘                       │
│                                                                             │
│   ✅ User sees an interactive form, fills it out, clicks Register           │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────────────────┐
│ STEP 4: Form submission sent back to agent                                  │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   📩 Event: {                                                               │
│     type: "form_submit",                                                    │
│     data: { email: "user@example.com", password: "***" }                    │
│   }                                                                         │
│                                                                             │
│   Agent: "Great! I'll process your registration and show a success alert"  │
│                                                                             │
│   📞 Tool Call: render_alert({                                              │
│     title: "Registration Complete!",                                        │
│     variant: "success"                                                      │
│   })                                                                        │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

개요

UI 도구는 에이전트가 다음을 수행할 수 있도록 합니다:

  • 텍스트 영역 지원을 포함한 동적 양식을 통해 사용자 입력 수집
  • 카드, 알림 및 통지를 사용하여 정보 표시
  • 테이블 및 대화형 차트(Recharts)로 데이터 제시
  • 진행률 및 로딩 상태 표시 (스피너, 스켈레톤)
  • 여러 구성 요소로 대시보드 레이아웃 생성
  • 모달을 통해 사용자 확인 요청
  • 상태 업데이트를 위한 토스트 알림 표시

빠른 시작

Cargo.toml에 추가하세요:

[dependencies]
adk-ui = { git = "https://github.com/zavora-ai/adk-ui" }
adk-agent = "2.0.0"
adk-model = "2.0.0"

기본 사용법

use adk_rust::prelude::*;
use adk_ui::UiToolset;
use std::sync::Arc;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let model = Arc::new(GeminiModel::from_env("gemini-2.5-flash")?);

    // Get all 10 UI tools
    let ui_tools = UiToolset::all_tools();

    // Create AI agent with UI tools
    let mut builder = LlmAgentBuilder::new("ui_agent")
        .model(model)
        .instruction(r#"
            You are a helpful assistant that uses UI components to interact with users.
            Use render_form for collecting information.
            Use render_card for displaying results.
            Use render_alert for notifications.
            Use render_modal for confirmation dialogs.
            Use render_toast for brief status messages.
        "#);

    for tool in ui_tools {
        builder = builder.tool(tool);
    }

let agent = builder.build()?;
Ok(())
}

A2UI JSONL (render_screen / render_page / render_kit)

이 도구들은 A2UI 렌더러와의 호환성을 위해 A2UI v0.9 JSONL을 내보냅니다.

render_screen (단일 표면)

{
  "surface_id": "main",
  "components": [
    { "id": "root", "component": "Column", "children": ["title", "cta"] },
    { "id": "title", "component": "Text", "text": "Welcome", "variant": "h1" },
    { "id": "cta_label", "component": "Text", "text": "Continue", "variant": "body" },
    { "id": "cta", "component": "Button", "child": "cta_label", "action": { "event": { "name": "continue" } } }
  ]
}

render_page (다중 섹션 페이지)

{
  "title": "Release Notes",
  "description": "Highlights for the latest launch.",
  "sections": [
    {
      "heading": "What’s new",
      "body": "Three big improvements shipped this week.",
      "bullets": ["Faster onboarding", "Better search", "New dashboards"],
      "actions": [{ "label": "View details", "action": "view_details", "variant": "borderless" }]
    }
  ]
}

render_kit (catalog + tokens + templates)

{
  "name": "Fintech Pro",
  "version": "0.1.0",
  "brand": { "vibe": "trustworthy", "industry": "fintech" },
  "colors": { "primary": "#2F6BFF" },
  "typography": { "family": "Source Sans 3" },
  "templates": ["auth_login", "dashboard"]
}

React 렌더러를 사용하여 A2UI JSONL을 소비합니다:

import {
  A2uiStore,
  A2uiSurfaceRenderer,
  applyParsedMessages,
  parseJsonl,
} from "@zavora-ai/adk-ui-react";

const store = new A2uiStore();
const parsed = parseJsonl(jsonl);
applyParsedMessages(store, parsed);

export function App() {
  return <A2uiSurfaceRenderer store={store} surfaceId="main" />;
}

사용 가능한 도구

render_form

사용자 입력을 수집하기 위해 대화형 양식을 렌더링합니다.

{
  "title": "Registration Form",
  "description": "Create your account",
  "fields": [
    {"name": "username", "label": "Username", "type": "text", "required": true},
    {"name": "email", "label": "Email", "type": "email", "required": true},
    {"name": "password", "label": "Password", "type": "password", "required": true},
    {"name": "newsletter", "label": "Subscribe to newsletter", "type": "switch"}
  ],
  "submit_label": "Register"
}

렌더링 결과:

┌─────────────────────────────────────────────────┐
│  📋 Registration Form                          │
│  Create your account                           │
│  ─────────────────────────────────────────────  │
│                                                │
│  Username *                                    │
│  ┌─────────────────────────────────────────┐   │
│  │                                         │   │
│  └─────────────────────────────────────────┘   │
│                                                │
│  Email *                                       │
│  ┌─────────────────────────────────────────┐   │
│  │                                         │   │
│  └─────────────────────────────────────────┘   │
│                                                │
│  Password *                                    │
│  ┌─────────────────────────────────────────┐   │
│  │ ••••••••                                │   │
│  └─────────────────────────────────────────┘   │
│                                                │
│  Subscribe to newsletter  [○]                  │
│                                                │
│  ┌─────────────────────────────────────────┐   │
│  │             Register                    │   │
│  └─────────────────────────────────────────┘   │
│                                                │
└─────────────────────────────────────────────────┘

필드 유형: text, email, password, number, date, select, multiselect, switch, slider, textarea

render_card

선택적 액션 버튼이 있는 정보 카드를 표시합니다.

{
  "title": "Order Confirmed",
  "description": "Order #12345",
  "content": "Your order has been placed successfully. Expected delivery: Dec 15, 2025.",
  "actions": [
    {"label": "Track Order", "action_id": "track", "variant": "primary"},
    {"label": "Cancel", "action_id": "cancel", "variant": "danger"}
  ]
}

버튼 변형: primary, secondary, danger, ghost, outline

render_alert

알림 및 상태 메시지를 표시합니다.

{
  "title": "Payment Successful",
  "description": "Your payment of $99.00 has been processed.",
  "variant": "success"
}

변형: info, success, warning, error

render_confirm

작업 전에 사용자 확인을 요청합니다.

{
  "title": "Delete Account",
  "message": "Are you sure you want to delete your account? This action cannot be undone.",
  "confirm_label": "Delete",
  "cancel_label": "Keep Account",
  "variant": "danger"
}

render_table

표 형식 데이터를 표시합니다.

{
  "title": "Recent Orders",
  "columns": [
    {"header": "Order ID", "accessor_key": "id"},
    {"header": "Date", "accessor_key": "date"},
    {"header": "Amount", "accessor_key": "amount"},
    {"header": "Status", "accessor_key": "status"}
  ],
  "data": [
    {"id": "#12345", "date": "2025-12-10", "amount": "$99.00", "status": "Delivered"},
    {"id": "#12346", "date": "2025-12-11", "amount": "$149.00", "status": "Shipped"}
  ]
}

render_chart

데이터 시각화를 생성합니다.

{
  "title": "Monthly Sales",
  "chart_type": "bar",
  "x_key": "month",
  "y_keys": ["revenue", "profit"],
  "data": [
    {"month": "Jan", "revenue": 4000, "profit": 2400},
    {"month": "Feb", "revenue": 3000, "profit": 1398},
    {"month": "Mar", "revenue": 5000, "profit": 3800}
  ]
}

차트 유형: bar, line, area, pie

render_progress

선택적 단계를 포함하여 작업 진행 상황을 표시합니다.

{
  "title": "Installing Dependencies",
  "value": 65,
  "description": "Installing package 13 of 20...",
  "steps": [
    {"label": "Download", "completed": true},
    {"label": "Extract", "completed": true},
    {"label": "Install", "current": true},
    {"label": "Configure", "completed": false}
  ]
}

render_layout

여러 섹션으로 대시보드 레이아웃을 만듭니다.

{
  "title": "System Status",
  "description": "Current system health overview",
  "sections": [
    {
      "title": "Services",
      "type": "stats",
      "stats": [
        {"label": "API Server", "value": "Healthy", "status": "operational"},
        {"label": "Database", "value": "Degraded", "status": "warning"},
        {"label": "Cache", "value": "Down", "status": "error"}
      ]
    },
    {
      "title": "Recent Errors",
      "type": "table",
      "columns": [{"header": "Time", "key": "time"}, {"header": "Error", "key": "error"}],
      "rows": [{"time": "10:30", "error": "Connection timeout"}]
    }
  ]
}

섹션 유형: stats, table, chart, alert, text

render_modal

확인 또는 집중적인 상호작용을 위해 모달 대화 상자를 표시합니다.

{
  "title": "Confirm Deletion",
  "message": "Are you sure you want to delete this item? This action cannot be undone.",
  "size": "medium",
  "closable": true,
  "confirm_label": "Delete",
  "cancel_label": "Cancel",
  "confirm_action": "delete_confirmed"
}

크기: small, medium, large, full

render_toast

상태 업데이트를 위한 간략한 토스트 알림을 표시합니다.

{
  "message": "Settings saved successfully",
  "variant": "success",
  "duration": 5000,
  "dismissible": true
}

변형: info, success, warning, error

필터링된 도구

Agent가 필요로 하는 도구만 선택하세요:

let toolset = UiToolset::new()
    .without_chart()      // Disable charts
    .without_table()      // Disable tables
    .without_progress()   // Disable progress
    .without_modal()      // Disable modals
    .without_toast();     // Disable toasts

// Or use forms only
let forms_only = UiToolset::forms_only();

UI 이벤트 처리

사용자가 렌더링된 UI(양식 제출, 버튼 클릭)와 상호 작용할 때, 이벤트는 에이전트로 다시 전송됩니다:

use adk_ui::{UiEvent, UiEventType};

// UiEvent structure
pub struct UiEvent {
    pub event_type: UiEventType,  // FormSubmit, ButtonClick, InputChange
    pub action_id: Option<String>,
    pub data: Option<HashMap<String, Value>>,
}

// Convert to message for agent
let message = ui_event.to_message();

스트리밍 UI 업데이트

실시간 UI 업데이트를 위해, UiUpdate을(를) 사용하여 ID로 컴포넌트를 패치합니다:

use adk_ui::{UiUpdate, UiOperation};

let update = UiUpdate {
    target_id: "progress-bar".to_string(),
    operation: UiOperation::Patch,
    payload: Some(Component::Progress(Progress {
        id: Some("progress-bar".to_string()),
        value: 75,
        label: Some("75%".to_string()),
    })),
};

작업: Replace, Patch, Append, Remove

컴포넌트 스키마

모든 28가지 컴포넌트 유형은 스트리밍 업데이트를 위한 선택적 id 필드를 지원합니다:

아톰: Text, Button, Icon, Image, Badge 입력: TextInput, NumberInput, Select, MultiSelect, Switch, DateInput, Slider, Textarea 레이아웃: Stack, Grid, Card, Container, Divider, Tabs 데이터: Table, List, KeyValue, CodeBlock 시각화: 차트 (막대, 선, 영역, 파이 Recharts를 통해) 피드백: Alert, Progress, Toast, Modal, Spinner, Skeleton

React 클라이언트

독립형 React 참조 구현은 adk-ui 저장소에서 제공됩니다:

npm install @zavora-ai/adk-ui-react

React 클라이언트에는 다음이 포함됩니다:

  • TypeScript Rust 스키마와 일치하는 타입
  • 28가지 모든 타입에 대한 컴포넌트 렌더러
  • 대화형 차트를 위한 Recharts 통합
  • Markdown 렌더링 지원
  • 다크 모드 지원
  • 폼 제출 처리
  • 모달 및 토스트 컴포넌트

아키텍처

Agent ──[render_* tool]──> UiResponse (JSON)
                              │
                              │ SSE
                              ▼
                         Client (React)
                              │
                              └──> UiEvent (user action) ──> Agent

프로토콜 상호 운용성

모든 13개의 렌더링 도구는 protocol 인자를 통해 프로토콜 인식 출력을 지원합니다:

Protocol설명
a2uiA2UI v0.9 정렬 JSONL 표면 (기본값: render_screen, render_page)
ag_ui하이브리드 AG-UI 지원: 기본적으로 호환성 래퍼 제공, adk-server 클라이언트를 위한 추가적인 프로토콜-네이티브 런타임 전송 지원
mcp_apps호환성 MCP Apps 페이로드와 ui:// resources, 추가 브리지 헬퍼, 알림 흐름, 런타임 요청 필드 및 HTML/resource 어댑터

protocol가 생략되면, tools는 기본 출력 형식을 사용합니다 (대부분의 tools의 경우 레거시 UiResponse JSON, render_screen/render_page/render_kit의 경우 A2UI).

프로토콜 선택 예시:

{
  "protocol": "mcp_apps",
  "mcp_apps": {
    "resource_uri": "ui://demo/surface"
  }
}

상호 운용 어댑터

adk-ui는 프로토콜 변환을 위한 어댑터 프리미티브를 포함합니다:

  • A2uiAdapter — 정식 표면을 A2UI JSONL로 변환합니다
  • AgUiAdapter — AG-UI 이벤트 페이로드로 변환합니다
  • McpAppsAdapter — MCP Apps 리소스 페이로드로 변환합니다

이들은 모든 도구에서 일관된 변환을 위해 공유되는 UiProtocolAdapter trait를 구현합니다.

지원 중단 타임라인

레거시 adk_ui runtime profile은 지원 중단 메타데이터를 포함합니다:

날짜마일스톤
2026-02-07사용 중단 발표
2026-12-31서비스 종료 목표

대체 항목: a2ui, ag_ui, mcp_apps

이 메타데이터는 UI_PROTOCOL_CAPABILITIES 상수를 통해 노출되며, adk-server/api/ui/capabilities에서 제공합니다. 역량 응답은 또한 implementationTier, specTrack, summary, limitations를 보고하여 클라이언트가 하이브리드 또는 호환성 하위 집합을 완전한 네이티브 프로토콜 지원과 구별할 수 있도록 합니다.

adk-server가 호스트 대면 경계일 때, 또한 /api/ui/initialize, /api/ui/message, /api/ui/update-model-context, /api/ui/notifications/poll, /api/ui/notifications/resources-list-changed, /api/ui/notifications/tools-list-changed에서 추가적인 MCP 앱 브리지 헬퍼를 노출합니다. 이러한 엔드포인트는 기존 ADK 런타임을 보존합니다. 계약은 직접 요청 본문 또는 JSON-RPC와 같은 봉투를 ui/... 메서드와 함께 허용합니다.

런타임 소비자들을 위해, adk-server은 다음도 지원합니다:

  • AG-UI 네이티브 SSE serialization을 위한 x-adk-ui-transport: protocol_native 또는 uiTransport: "protocol_native"
  • 기존 newMessage 외에 input / agUiInput을 통한 AG-UI 이중 경로 요청 입력
  • MCP 앱은 /api/run_sse 내부에서 엔벨로프를 mcpAppsInitialize, mcpAppsRequest, mcpAppsInitialized를 통해 연결합니다.

이 추가 기능은 선택 사항입니다. 기존 /api/run/api/run_sse 소비자는 네이티브 AG-UI 전송 모드를 명시적으로 요청하지 않는 한 일반 ADK 래퍼를 계속 받습니다.

프레임워크 소유의 MCP Apps Tool responses의 경우, adk-server::ui_types는 이제 다음을 노출합니다:

  • McpUiBridgeSnapshot: 타입이 지정된 호스트/앱 브리지 상태용
  • McpUiToolResult: 부가적인 응답 엔벨로프용
  • McpUiToolResultBridge 브릿지 메타데이터를 위한 (protocolVersion, structuredContent, hostInfo, hostCapabilities, hostContext, appInfo, appCapabilities, initialized)

bridge/session 상태를 도구 응답으로 승격할 때 McpUiBridgeSnapshot::build_tool_result(...)을 선호합니다. 이는 호환성 지향 호스트를 위해 resourceUri 및 인라인 html 대체(fallback)를 보존하면서 도구 결과 형태를 표준화합니다.

임베디드 또는 브라우저 호스트 매핑의 경우, 가산적인 HTTP 브릿지는 다음과 같이 호스트/앱 흐름에 해당합니다:

  • ui/initialize -> /api/ui/initialize
  • ui/message -> /api/ui/message
  • ui/update-model-context -> /api/ui/update-model-context
  • notifications/resources/list_changed -> /api/ui/notifications/resources-list-changed
  • notifications/tools/list_changed -> /api/ui/notifications/tools-list-changed
  • 대기 중인 호스트 알림 -> /api/ui/notifications/poll

직접 /api/ui/* 브리지 엔드포인트는 MCP Apps 호스트를 위한 선호되는 수명 주기 경로입니다. 런타임 측 MCP Apps 요청 필드는 혼합 또는 레거시 클라이언트를 위한 추가적인 호환성 경로로 계속 사용할 수 있습니다.

예시

독립형 adk-ui 리포지토리에는 실행 가능한 UI 예제가 포함되어 있습니다:

예시설명실행 명령
ui_agent콘솔 데모cargo run --bin ui_agent
ui_serverHTTP 서버 (SSE 포함)cargo run --bin ui_server
ui_react_clientReact 프런트엔드cd ui_react_client && npm run dev

Rust 및 React 패키지가 동일한 릴리스 라인을 유지하도록 adk-ui 리포지토리에서 해당 예제를 실행하세요.

샘플 프롬프트

다음 프롬프트로 UI 도구를 테스트하세요:

# Forms
"I want to register for an account"
"Create a contact form"
"Create a feedback form with a comments textarea"

# Cards
"Show me my profile"
"Display a product card for a laptop"

# Alerts
"Show a success message"
"Display a warning about expiring session"

# Modals
"I want to delete my account" (shows confirmation modal)
"Show a confirmation dialog before submitting"

# Toasts
"Show a success toast notification"
"Display an error toast"

# Tables
"Show my recent orders"
"List all users"

# Charts
"Show monthly sales chart"
"Display traffic trends as a line chart"
"Show revenue breakdown as a pie chart"

# Progress & Loading
"Show upload progress at 75%"
"Display a loading spinner"
"Show skeleton loading state"

# Dashboards
"Show system status dashboard"

이전: ← Browser Tools | 다음: MCP Tools →