A2UI 自定义组件实战:从业务痛点到跑通的完整指南
【免费下载链接】a2ui 项目地址: https://gitcode.com/GitHub_Trending/a2/a2ui
A2UI 自定义组件开发指南:教你四步把业务组件接入 AI 界面。A2UI 是一个让 Agent 直接把 UI 投递给客户端的协议——Agent 决定"画什么",客户端负责"怎么画"。它的标准目录覆盖了 Text、Button、Card 这类基础组件,但一旦业务需要物流追踪面板、图表、地图这类组件,就得自己扩展。

先分清三类场景
不是所有缺口都要靠自定义组件补,先对号入座:
| 领域组件 | 物流追踪面板、医疗图表 | 自己写实现 + Schema |
| 第三方集成 | 地图、支付表单 | 用沙箱 iframe 封装成组件 |
| 品牌定制 | 企业风格的输入框、卡片 | 按标准类型名覆盖默认实现 |
A2UI 的扩展模型是"客户端优先":组件实现在客户端,Agent 只发数据。所以开发工作几乎全在客户端,Agent 侧只需要让它"知道"你的组件。

流程速览:四步把自定义组件接入 AI 界面
| 1 | 实现组件 | 继承客户端框架基类,拿到类型安全的属性信号 |
| 2 | 定义 JSON Schema | 组件契约,Agent 靠它知道属性和类型 |
| 3 | 客户端注册 | 类型名 → 实现类 → DOM 标签名,挂进注册表 |
| 4 | Agent 握手感知 | 客户端把目录随 A2A 握手带上,注入 LLM 上下文 |
最小可运行示例:物流追踪面板
下面是一个基于 Lit 的 TrackPanel(追踪面板)骨架,代码只保留主干:
// track-panel.ts
import {html, css} from 'lit';
import {property} from 'lit/decorators.js';
import {Root} from '@a2ui/lit/ui';
export class TrackPanel extends Root {
@property() accessor status = ''; // 当前状态,如"运输中"
@property() accessor events: Array<{time: string; desc: string}> = [];
static styles = […Root.styles, css`
:host { display: block; border: 1px solid #ddd; border-radius: 8px; }
`];
render() {
return html`
<div>
<h3>物流追踪:${this.status}</h3>
<ol>
${this.events.map(e => html`<li>${e.time} ${e.desc}</li>`)}
</ol>
</div>`;
}
}
两个容易踩的点:
- 组件继承 Root,框架自动解析数据绑定和表达式,你只写渲染逻辑。
- 不要加 @customElement 装饰器——标签名由注册表统一定义,重复注册会直接报 NotSupportedError。
客户端注册只需三步
// register-components.ts
import {componentRegistry} from '@a2ui/lit/ui';
import {TrackPanel} from './track-panel.js';
componentRegistry.register('TrackPanel', TrackPanel, 'track-panel', {
type: 'object',
properties: {
status: {type: 'string'},
events: {
type: 'array',
items: {
type: 'object',
properties: {time: {type: 'string'}, desc: {type: 'string'}},
required: ['time', 'desc'],
},
},
},
required: ['status', 'events'],
});
四行注册里做了三件事:第一,把类型名 TrackPanel(Agent 消息里用的名字)映射到实现类;第二,指定 DOM 标签名 track-panel;第三,传入 JSON Schema,客户端会把这份 Schema 随内联目录一起发布给 Agent。
Schema 单独看就是这个结构,它只声明"有哪些属性、什么类型、哪些必填":
{
"type": "object",
"properties": {
"status": {"type": "string"},
"events": {
"type": "array",
"items": {
"type": "object",
"properties": {"time": {"type": "string"}, "desc": {"type": "string"}},
"required": ["time", "desc"]
}
}
},
"required": ["status", "events"]
}
Agent 握手时发生了什么
Agent 侧只需要一小段胶水代码,从客户端元数据取目录并注入提示词:
# 客户端连接握手时
@adk.on_event("client_connected")
async def on_connect(event):
# 客户端元数据里带了内联目录
catalog = event.metadata.get("inlineCatalog")
if catalog:
# 注入 LLM 上下文:告诉模型可用哪些自定义组件及属性格式
adk.update_llm_context(custom_components=catalog)
握手的实质是:客户端在 A2A 握手时上报"我支持哪些组件",Agent 拿到清单后生成系统提示词,告诉模型"你有 TrackPanel,它需要 status 和 events"。之后 Agent 每次发 UI 消息,客户端查注册表即可渲染。客户端没带内联目录时,Agent 就从本地目录库里挑一个匹配的。
一个 A2UI Surface(表面)就是 Agent 投递 UI 的一块独立渲染区域,可以同时维护多个:主 Surface 放订单摘要和物流面板,点"查看地图"后 Agent 再开一个 Surface 放地图,两边互不干扰。
本地跑通:三条命令 + 一个端口
仓库里自带可运行的端到端示例,照着启动即可:
cd samples/agent/adk/custom-components-example
echo "GEMINI_API_KEY=你的key" > .env
uv run . # Agent 监听 10004 端口
客户端这边只需改一处配置:samples/client/lit/shell/middleware/a2a.ts 里的 Agent Card 地址,指向 http://localhost:10004/.well-known/agent-card.json,然后 yarn install && yarn dev 启动开发服务器。连上后输入"我的包裹到哪了",Agent 返回 TrackPanel 消息,客户端查注册表渲染出追踪面板。
上线前的 4 条安全 checklist 🔒
自定义组件把 A2UI 从"Agent 能画标准组件"扩展到"Agent 能画业务需要的 UI",核心就是组件、Schema、注册表这三件套——Schema 写清楚,LLM 才用得上。
下一步建议读这两篇文档深入细节:自定义组件编写指南 和 Lit 自定义组件示例。
【免费下载链接】a2ui 项目地址: https://gitcode.com/GitHub_Trending/a2/a2ui
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



