UI 工具
adk-ui crate 使 AI 代理能够通过工具调用动态生成丰富的用户界面。代理可以渲染表单、卡片、警告、表格、图表等内容——所有这些都通过类型安全的 Rust API 实现,并序列化为 JSON 供前端使用。
你将构建的内容

核心概念:
- 表单 - 使用各种字段类型收集用户输入
- 卡片 - 使用操作按钮展示信息
- 表格 - 按行和列呈现结构化数据
- 图表 - 使用柱状图、折线图、面积图和饼图可视化数据
- 警告 - 显示通知和状态消息
- 模态框 - 确认对话框和聚焦交互
- Toast 通知 - 简短的状态通知
- 协议互操作 - 将 UI 作为 A2UI、AG-UI 或 MCP Apps 负载发送
示例:分析仪表板

示例:注册表单

工作原理
┌─────────────────────────────────────────────────────────────────────────────┐
│ 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 工具允许代理:
- 通过支持 textarea 的动态表单收集用户输入
- 使用卡片、警告和通知展示信息
- 在表格和交互式图表(Recharts)中呈现数据
- 显示进度和加载状态(spinner、skeleton)
- 使用多个组件创建仪表板布局
- 通过模态框请求用户确认
- 显示 Toast 通知以更新状态
快速开始
添加到你的 Cargo.toml:
[dependencies]
adk-ui = { git = "https://github.com/zavora-ai/adk-ui" }
adk-agent = "2.1.0"
adk-model = "2.1.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-3.7-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 v0.9 JSONL,以兼容 A2UI 渲染器。
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(目录 + tokens + 模板)
{
"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
显示用于状态更新的简短 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 交互时(提交表单、点击按钮),事件会发送回 agent:
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 字段,以实现流式更新:
原子组件:文本、按钮、图标、图像、徽章
输入组件:TextInput、NumberInput、选择框、MultiSelect、开关、DateInput、滑块、文本区域
布局组件:堆叠、网格、卡片、容器、分隔线、标签页
数据组件:表格、列表、KeyValue、CodeBlock
可视化组件:图表(通过 Recharts 支持柱状图、折线图、面积图和饼图)
反馈组件:警告、进度、提示、模态框、加载器、骨架屏
React 客户端
独立的 adk-ui 仓库提供了一个参考 React 实现:
npm install @zavora-ai/adk-ui-react
React 客户端包括:
- 与 Rust 架构匹配的 TypeScript 类型
- 支持全部 28 种类型的组件渲染器
- 用于交互式图表的 Recharts 集成
- Markdown 渲染支持
- 深色模式支持
- 表单提交处理
- 模态框和提示组件
架构
Agent ──[render_* tool]──> UiResponse (JSON)
│
│ SSE
▼
Client (React)
│
└──> UiEvent (user action) ──> Agent
协议互操作性
所有 13 个渲染工具都支持通过 protocol 参数生成协议感知的输出:
| 协议 | 描述 |
|---|---|
a2ui | 与 A2UI v0.9 对齐的 JSONL 接口(render_screen、render_page 的默认接口) |
ag_ui | 混合 AG-UI 支持:默认提供兼容性包装器,并为 adk-server 客户端提供附加的协议原生运行时传输 |
mcp_apps | 兼容 MCP 应用负载与 ui:// 资源,新增桥接辅助工具、通知流程、运行时请求字段,以及 HTML/资源适配器 |
当省略 protocol 时,工具会使用其默认输出格式(大多数工具使用旧版 UiResponse JSON,render_screen/render_page/render_kit 使用 A2UI)。
协议选择示例:
{
"protocol": "mcp_apps",
"mcp_apps": {
"resource_uri": "ui://demo/surface"
}
}
互操作适配器
adk-ui 包含用于协议转换的适配器原语:
A2uiAdapter— 将规范化表面转换为 A2UI JSONLAgUiAdapter— 转换为 AG-UI 事件有效负载McpAppsAdapter— 转换为 MCP Apps 资源有效负载
这些适配器实现了共享的 UiProtocolAdapter trait,以确保所有工具之间的一致转换。
弃用时间线
旧版 adk_ui 运行时配置文件包含弃用元数据:
| 日期 | 里程碑 |
|---|---|
| 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 Apps 桥接辅助方法。这些端点保留现有的 ADK 运行时契约,并接受直接请求正文或类似 JSON-RPC 的信封格式,且使用 ui/... 方法。
对于运行时使用者,adk-server 还支持:
x-adk-ui-transport: protocol_native或uiTransport: "protocol_native",用于 AG-UI 原生的 SSE 序列化- 通过
input/agUiInput提供 AG-UI 双路径请求输入,同时保留现有的newMessage - 通过
mcpAppsInitialize、mcpAppsRequest和mcpAppsInitialized,在/api/run_sse内使用 MCP Apps 桥接信封
这些新增功能均需选择启用。除非明确请求原生 AG-UI 传输模式,否则现有的 /api/run 和 /api/run_sse 使用者仍会接收通用的 ADK 包装器。
对于框架拥有的 MCP Apps 工具响应,adk-server::ui_types 现在提供:
McpUiBridgeSnapshot,用于类型化的主机/App 桥接状态McpUiToolResult,用于附加的响应信封McpUiToolResultBridge,用于桥接元数据(protocolVersion、structuredContent、hostInfo、hostCapabilities、hostContext、appInfo、appCapabilities、initialized)
将桥接/会话状态提升为工具响应时,优先使用 McpUiBridgeSnapshot::build_tool_result(...)。这会统一工具结果的结构,同时保留 resourceUri 和内联 html 回退机制,以兼容面向兼容性的主机。
对于嵌入式或浏览器主机映射,附加的 HTTP bridge 对应的主机/应用流程如下:
ui/initialize->/api/ui/initializeui/message->/api/ui/messageui/update-model-context->/api/ui/update-model-contextnotifications/resources/list_changed->/api/ui/notifications/resources-list-changednotifications/tools/list_changed->/api/ui/notifications/tools-list-changed- 排队的主机通知 ->
/api/ui/notifications/poll
直接的 /api/ui/* bridge 端点是 MCP Apps 主机首选的生命周期路径。运行时端的 MCP Apps 请求字段仍可作为混合客户端或旧版客户端的附加兼容路径使用。
示例
独立的 adk-ui repo 包含可运行的 UI 示例:
| 示例 | 描述 | 运行命令 |
|---|---|---|
ui_agent | 控制台演示 | cargo run --bin ui_agent |
ui_server | 使用 SSE 的 HTTP 服务器 | cargo run --bin ui_server |
ui_react_client | React 前端 | cd ui_react_client && npm run dev |
运行 adk-ui 仓库中的示例,使 Rust 和 React 软件包保持在同一发布线上。
示例提示词
使用以下提示词测试 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"