跳转到内容

Agent-to-UI(A2UI)协议

A2UI 是 A2A 的一个声明式 UI 协议扩展,允许智能体发出描述交互界面的结构化 JSON 消息。客户端接收这些消息后,会将其渲染为富 UI 组件,例如表单、卡片、列表、模态框等,而智能体无需了解客户端的渲染栈。

A2UI 建立在 A2A 扩展机制之上,使用 URI https://a2ui.org/a2a-extension/a2ui/v0.8 进行标识。

  1. 服务端扩展 扫描智能体输出中的 A2UI JSON 对象
  2. 有效消息会作为带有 application/json+a2ui MIME 类型的 DataPart 条目包装
  3. 客户端扩展 会把 A2UI 指令和组件目录附加到智能体的系统提示中
  4. 客户端会在会话轮次之间跟踪界面状态(活动界面和数据模型)

A2UIServerExtension 添加到 A2AServerConfig 中即可启用 A2UI 输出:

from crewai import Agent
from crewai.a2a import A2AServerConfig
from crewai.a2a.extensions.a2ui import A2UIServerExtension
agent = Agent(
role="Dashboard Agent",
goal="Present data through interactive UI surfaces",
backstory="Expert at building clear, actionable dashboards",
llm="gpt-4o",
a2a=A2AServerConfig(
url="https://your-server.com",
server_extensions=[A2UIServerExtension()],
),
)
catalog_ids list[str] | None default: None

服务端支持的组件目录标识符。设置后,只有这些目录会向客户端公开。

accept_inline_catalogs bool default: False

是否接受客户端传入的内联目录定义,除已命名目录外也允许。

A2UIClientExtension 添加到 A2AClientConfig 中即可启用 A2UI 渲染:

from crewai import Agent
from crewai.a2a import A2AClientConfig
from crewai.a2a.extensions.a2ui import A2UIClientExtension
agent = Agent(
role="UI Coordinator",
goal="Coordinate tasks and render agent responses as rich UI",
backstory="Expert at presenting agent output in interactive formats",
llm="gpt-4o",
a2a=A2AClientConfig(
endpoint="https://dashboard-agent.example.com/.well-known/agent-card.json",
client_extensions=[A2UIClientExtension()],
),
)
catalog_id str | None default: None

首选组件目录标识符。未设置时默认为 "standard (v0.8)"

allowed_components list[str] | None default: None

限制智能体可使用的组件。为 None 时,标准目录中的全部 18 个组件都可用。

A2UI 定义了四种服务端到客户端的消息类型。每条消息都指向一个由 surfaceId 标识的界面

beginRendering

初始化一个新界面,包含根组件和可选样式。

{
"beginRendering": {
"surfaceId": "dashboard-1",
"root": "main-column",
"catalogId": "standard (v0.8)",
"styles": {
"primaryColor": "#EB6658"
}
}
}
surfaceUpdate

在现有界面上发送或更新一个或多个组件。

{
"surfaceUpdate": {
"surfaceId": "dashboard-1",
"components": [
{
"id": "main-column",
"component": {
"Column": {
"children": { "explicitList": ["title", "content"] },
"alignment": "start"
}
}
},
{
"id": "title",
"component": {
"Text": {
"text": { "literalString": "Dashboard" },
"usageHint": "h1"
}
}
}
]
}
}
dataModelUpdate

更新绑定到界面的数据模型,从而启用动态内容。

{
"dataModelUpdate": {
"surfaceId": "dashboard-1",
"path": "/data/model",
"contents": [
{
"key": "userName",
"valueString": "Alice"
},
{
"key": "score",
"valueNumber": 42
}
]
}
}
deleteSurface

删除一个界面及其所有组件。

{
"deleteSurface": {
"surfaceId": "dashboard-1"
}
}

A2UI 内置 18 个标准组件,分为三类:

组件说明必填字段
Text渲染文本,可带标题/正文提示text (StringBinding)
Image显示图片,可配置适配和尺寸url (StringBinding)
Icon从 47 个图标中渲染指定图标name (IconBinding)
Video嵌入视频播放器url (StringBinding)
AudioPlayer嵌入音频播放器,可选描述url (StringBinding)
组件说明必填字段
Row水平 flex 容器children (ChildrenDef)
Column垂直 flex 容器children (ChildrenDef)
List可滚动列表(垂直或水平)children (ChildrenDef)
Card单子元素的抬升容器child (str)
Tabs选项卡容器tabItems (list of TabItem)
Divider视觉分隔线(水平或垂直)
Modal由入口点触发的覆盖层entryPointChild, contentChild (str)
组件说明必填字段
Button可点击按钮,触发操作child (str), action (Action)
CheckBox带标签的布尔开关label (StringBinding), value (BooleanBinding)
TextField支持类型和校验选项的文本输入框label (StringBinding)
DateTimeInput日期和/或时间选择器value (StringBinding)
MultipleChoice从选项列表中选择selections (ArrayBinding), options (list)
Slider数值范围滑块value (NumberBinding)

组件通过绑定而不是原始字面量来引用值。这样当数据模型变化时,界面就能动态更新。

有两种方式可以绑定值:

  • 字面量值 - 直接在组件定义中硬编码
  • 路径引用 - 指向界面数据模型中的某个键
{
"surfaceUpdate": {
"surfaceId": "profile-1",
"components": [
{
"id": "greeting",
"component": {
"Text": {
"text": { "path": "/data/model/userName" },
"usageHint": "h2"
}
}
},
{
"id": "status",
"component": {
"Text": {
"text": { "literalString": "Online" },
"usageHint": "caption"
}
}
}
]
}
}

在这个示例中,greeting 会从数据模型读取用户姓名(由 dataModelUpdate 更新),而 status 则使用硬编码字面量。

Button 这样的交互组件会触发回传给服务端的 userAction 事件。每个操作都包含 name、来源 surfaceIdsourceComponentId,以及一个可选的包含键值对的 context

{
"userAction": {
"name": "submitForm",
"surfaceId": "form-1",
"sourceComponentId": "submit-btn",
"timestamp": "2026-03-12T10:00:00Z",
"context": {
"selectedOption": "optionA"
}
}
}

操作上下文值也可以使用路径绑定,将当前数据模型值回传给服务端:

{
"Button": {
"child": "confirm-label",
"action": {
"name": "confirm",
"context": [
{
"key": "currentScore",
"value": { "path": "/data/model/score" }
}
]
}
}
}

使用 validate_a2ui_message 验证服务端到客户端的消息,使用 validate_a2ui_event 验证客户端到服务端的事件:

from crewai.a2a.extensions.a2ui import validate_a2ui_message
from crewai.a2a.extensions.a2ui.validator import (
validate_a2ui_event,
A2UIValidationError,
)
# Validate a server message
try:
msg = validate_a2ui_message({"beginRendering": {"surfaceId": "s1", "root": "r1"}})
except A2UIValidationError as exc:
print(exc.errors)
# Validate a client event
try:
event = validate_a2ui_event({
"userAction": {
"name": "click",
"surfaceId": "s1",
"sourceComponentId": "btn-1",
"timestamp": "2026-03-12T10:00:00Z",
}
})
except A2UIValidationError as exc:
print(exc.errors)

从简单开始

先使用一条 beginRendering 消息和一条 surfaceUpdate。等基础流程可用后,再加入数据绑定和交互。

用数据绑定承载动态内容

对于会变化的内容,优先使用路径绑定而不是字面量。通过 dataModelUpdate 推送新值,而不是重新发送完整组件树。

限制组件范围

A2UIClientExtension 上使用 allowed_components 选项限制智能体可输出的组件,从而减小提示词体积并保持输出可预测。

验证消息

使用 validate_a2ui_messagevalidate_a2ui_event 尽早捕获格式错误,尤其是在构建自定义集成时。