## Agent-User Interaction Protocol: Architecture, Implementation & Ecosystem
---
## 目录
1. [å议概述与设计哲å¦](#一å议概述与设计哲å¦)
2. [æ ¸å¿ƒæž¶æž„ï¼šäº‹ä»¶é©±åŠ¨çš„ç¥žç»ç³»ç»Ÿ](#äºŒæ ¸å¿ƒæž¶æž„äº‹ä»¶é©±åŠ¨çš„ç¥žç»ç³»ç»Ÿ)
3. [17ç§æ ‡å‡†äº‹ä»¶ç±»åž‹å®Œå…¨è§£æž](#三17ç§æ ‡å‡†äº‹ä»¶ç±»åž‹å®Œå…¨è§£æž)
4. [状æ€åŒæ¥æœºåˆ¶ï¼šJSON Patch与事件溯æº](#四状æ€åŒæ¥æœºåˆ¶json-patch与事件溯æº)
5. [ä¼ è¾“å±‚å®žçŽ°ï¼šSSEã€WebSocket与HTTP](#äº”ä¼ è¾“å±‚å®žçŽ°ssewebsocket与http)
6. [与MCPã€A2Açš„åè®®æ ˆå¯¹æ¯”](#å…与mcpa2açš„åè®®æ ˆå¯¹æ¯”)
7. [代ç 实现:从入门到生产](#七代ç 实现从入门到生产)
8. [性能优化与最佳实践](#八性能优化与最佳实践)
9. [生æ€ç³»ç»Ÿä¸Žæ¡†æž¶é›†æˆ](#ä¹ç”Ÿæ€ç³»ç»Ÿä¸Žæ¡†æž¶é›†æˆ)
10. [未æ¥å±•望与开放问题](#åæœªæ¥å±•望与开放问题)
---
## 一ã€å议概述与设计哲å¦
### 1.1 什么是AG-UI?
AG-UI(Agent-User Interaction Protocol)是一个**开放的ã€è½»é‡çº§çš„ã€åŸºäºŽäº‹ä»¶**çš„åè®®ï¼Œç”¨äºŽæ ‡å‡†åŒ–AI Agent与用户界é¢ä¹‹é—´çš„实时通信。它由CopilotKit团队于2025å¹´5月å‘èµ·å¹¶å¼€æºã€‚
### 1.2 设计哲å¦
AG-UI的设计éµå¾ªå‡ ä¸ªæ ¸å¿ƒåŽŸåˆ™ï¼š
| 原则 | 说明 |
|-----|------|
| **事件驱动** | 一切通信都以事件为基本å•ä½ï¼Œè€Œéžä¼ 统的请求-å“åº”æ¨¡å¼ |
| **æµå¼ä¼˜å…ˆ** | 原生支æŒå®žæ—¶æµå¼ä¼ è¾“ï¼Œå»¶è¿Ÿå¯æŽ§åˆ¶åœ¨100ms以内 |
| **状æ€å³æµ** | 状æ€å˜æ›´é€šè¿‡äº‹ä»¶æµä¼ æ’,而éžè½®è¯¢æˆ–完整快照 |
| **æ¡†æž¶æ— å…³** | ä¸ç»‘å®šä»»ä½•ç‰¹å®šæ¡†æž¶æˆ–æŠ€æœ¯æ ˆ |
| **ä¼ è¾“æ— å…³** | 支æŒSSEã€WebSocketã€HTTP/2ç‰å¤šç§ä¼ è¾“æ–¹å¼ |
### 1.3 å议定ä½
在现代Agentåè®®æ ˆä¸ï¼ŒAG-UIå æ®ç‹¬ç‰¹çš„ä½ç½®ï¼š
```
┌─────────────────────────────────────────────────────────────â”
│ 用户界é¢å±‚ │
│ ┌──────────────────────────────────────────────────────┠│
│ │ AG-UI (Agent ↔ 用户) │ │
│ │ 实时交互ã€çжæ€åŒæ¥ã€äººæœºå作 │ │
│ └──────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ 工具与数æ®å±‚ │
│ ┌──────────────────┠┌──────────────────────────────┠│
│ │ MCP │ │ A2A │ │
│ │ Agent ↔ 工具/æ•°æ® â”‚ │ Agent ↔ Agent │ │
│ └──────────────────┘ └──────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
- **MCP**(Anthropic):解决Agent如何调用工具和访问数æ®
- **A2A**(Google):解决Agent之间如何å作
- **AG-UI**(CopilotKit):解决Agent如何与用户界é¢äº¤äº’
---
## äºŒã€æ ¸å¿ƒæž¶æž„:事件驱动的神ç»ç³»ç»Ÿ
### 2.1 事件信å°ç»“æž„
æ¯ä¸ªAG-UI事件都éµå¾ªæ ‡å‡†ä¿¡å°æ ¼å¼ï¼š
```json
{
"protocol": "AG-UI/1.0",
"type": "TEXT_MESSAGE_CONTENT",
"timestamp": 1709827200000,
"runId": "run_abc123",
"threadId": "thread_xyz789",
"payload": {
// 事件特定数æ®
},
"extensions": {
// å¯é€‰æ‰©å±•å—æ®µ
}
}
```
### 2.2 æ ¸å¿ƒç»„ä»¶
```
┌─────────────────────────────────────────────────────────────â”
│ AG-UI架构图 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┠┌──────────────┠│
│ │ AgentåŽç«¯ │◄───────►│ AG-UI事件 │ │
│ │ (ä»»æ„æ¡†æž¶) │ │ ç¼–ç 器 │ │
│ └──────────────┘ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┠│
│ │ ä¼ è¾“å±‚æŠ½è±¡ │ │
│ │ (SSE/WS/HTTP)│ │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┠│
│ │ AG-UI事件 │ │
│ │ è§£ç 器 │ │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┠┌──────────────┠│
│ │ å‰ç«¯UI │◄───────►│ 状æ€ç®¡ç† │ │
│ │ (React/Vue) │ │ (Store) │ │
│ └──────────────┘ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
```
### 2.3 事件编ç 器
AG-UIæä¾›äº†æ ‡å‡†åŒ–的编ç 器:
```python
# Python示例
from ag_ui.core import BaseEvent
from ag_ui.encoder import EventEncoder
encoder = EventEncoder()
# ç¼–ç 事件
encoded = encoder.encode(event)
# ç”Ÿæˆæµå¼å“应
yield encoder.encode(TextMessageContentEvent(
type=EventType.TEXT_MESSAGE_CONTENT,
content="Hello"
))
```
```typescript
// TypeScript示例
import { EventEncoder } from '@ag-ui/core';
const encoder = new EventEncoder();
// ç¼–ç 事件æµ
const stream = encoder.encodeStream(events);
```
---
## 三ã€17ç§æ ‡å‡†äº‹ä»¶ç±»åž‹å®Œå…¨è§£æž
AG-UI定义了17ç§ï¼ˆå«ç‰¹æ®Šå˜ä½“ï¼‰æ ‡å‡†äº‹ä»¶ç±»åž‹ï¼Œåˆ†ä¸ºäº”å¤§ç±»åˆ«ï¼š
### 3.1 生命周期事件(Lifecycle Events)
| 事件类型 | æè¿° | 使用场景 |
|---------|------|---------|
| `RUN_STARTED` | Agent执行开始 | æ˜¾ç¤ºåŠ è½½çŠ¶æ€ |
| `STEP_STARTED` | 啿¥æ‰§è¡Œå¼€å§‹ | 多æ¥ä»»åŠ¡è¿›åº¦è·Ÿè¸ª |
| `STEP_FINISHED` | 啿¥æ‰§è¡Œå®Œæˆ | æ›´æ–°è¿›åº¦æ¡ |
| `RUN_FINISHED` | Agentæ‰§è¡Œå®Œæˆ | 清ç†åŠ è½½çŠ¶æ€ |
| `RUN_ERROR` | 执行错误 | 错误处ç†å’Œæ¢å¤ |
**示例æµç¨‹**:
```
RUN_STARTED
├── STEP_STARTED (æ¥éª¤1)
│ ├── ...工具调用事件...
│ └── STEP_FINISHED
├── STEP_STARTED (æ¥éª¤2)
│ ├── ...状æ€å˜æ›´äº‹ä»¶...
│ └── STEP_FINISHED
└── RUN_FINISHED
```
### 3.2 文本消æ¯äº‹ä»¶ï¼ˆText Message Events)
| 事件类型 | æè¿° | å—æ®µ |
|---------|------|-----|
| `TEXT_MESSAGE_START` | 消æ¯å¼€å§‹ | `messageId`, `role` |
| `TEXT_MESSAGE_CONTENT` | 文本内容片段 | `content` (token) |
| `TEXT_MESSAGE_END` | 消æ¯ç»“æŸ | `messageId` |
**æµå¼è¾“出实现**:
```python
yield encoder.encode(TextMessageStartEvent(
type=EventType.TEXT_MESSAGE_START,
message_id="msg_001",
role="assistant"
))
for token in llm_stream():
yield encoder.encode(TextMessageContentEvent(
type=EventType.TEXT_MESSAGE_CONTENT,
message_id="msg_001",
content=token
))
yield encoder.encode(TextMessageEndEvent(
type=EventType.TEXT_MESSAGE_END,
message_id="msg_001"
))
```
### 3.3 工具调用事件(Tool Call Events)
| 事件类型 | æè¿° | å—æ®µ |
|---------|------|-----|
| `TOOL_CALL_START` | 工具调用开始 | `toolCallId`, `toolName` |
| `TOOL_CALL_ARGS` | 工具傿•°ï¼ˆæµå¼ï¼‰ | `toolCallId`, `delta` |
| `TOOL_CALL_END` | å·¥å…·è°ƒç”¨ç»“æŸ | `toolCallId` |
| `TOOL_CALL_RESULT` | 工具返回结果 | `toolCallId`, `content` |
**完整工具调用æµç¨‹**:
```python
# 1. 开始调用
yield encoder.encode(ToolCallStartEvent(
type=EventType.TOOL_CALL_START,
tool_call_id="tool_123",
tool_call_name="fetch_weather"
))
# 2. æµå¼å‚æ•°ï¼ˆå¤§å‚æ•°æ—¶åˆ†ç‰‡ä¼ 输)
yield encoder.encode(ToolCallArgsEvent(
type=EventType.TOOL_CALL_ARGS,
tool_call_id="tool_123",
delta=json.dumps({"city": "San Francisco"})
))
# 3. 调用结æŸ
yield encoder.encode(ToolCallEndEvent(
type=EventType.TOOL_CALL_END,
tool_call_id="tool_123"
))
# 4. 返回结果
yield encoder.encode(ToolCallResultEvent(
type=EventType.TOOL_CALL_RESULT,
tool_call_id="tool_123",
content="72°F, Sunny"
))
```
**å‰ç«¯å¤„ç†**:
```typescript
async function handleToolEvents(event: AGUIEvent) {
switch(event.type) {
case 'TOOL_CALL_START':
showLoadingSpinner(`Calling ${event.tool_call_name}...`);
break;
case 'TOOL_CALL_ARGS':
displayToolParams(event.tool_call_id, event.delta);
break;
case 'TOOL_CALL_RESULT':
displayToolResult(event.content);
hideLoadingSpinner();
break;
}
}
```
### 3.4 状æ€ç®¡ç†äº‹ä»¶ï¼ˆState Management Events)
这是AG-UI最精妙的设计之一:
| 事件类型 | æè¿° | 使用场景 |
|---------|------|---------|
| `STATE_SNAPSHOT` | 完整状æ€å¿«ç…§ | åˆå§‹åŒæ¥ã€å…¨é‡åˆ·æ–° |
| `STATE_DELTA` | 状æ€å¢žé‡ï¼ˆJSON Patch) | 高频更新ã€ååŒç¼–辑 |
| `MESSAGES_SNAPSHOT` | 消æ¯åކå²å¿«ç…§ | ä¼šè¯æ¢å¤ |
**状æ€åŒæ¥æ¨¡å¼**:
```
STATE_SNAPSHOT (åˆå§‹çжæ€)
│
├── STATE_DELTA (增é‡1)
├── STATE_DELTA (增é‡2)
├── STATE_DELTA (增é‡3)
│
└── STATE_SNAPSHOT (周期性全é‡ï¼Œé˜²æ¼‚ç§»)
```
**Python示例**:
```python
# å‘é€å®Œæ•´å¿«ç…§
yield encoder.encode(StateSnapshotEvent(
type=EventType.STATE_SNAPSHOT,
snapshot={
"score": 0,
"tasks_completed": 0,
"current_step": "fetching_data",
"document": {
"title": "Draft",
"content": ""
}
}
))
# å‘é€å¢žé‡å˜æ›´ï¼ˆJSON Patchæ ¼å¼ï¼‰
yield encoder.encode(StateDeltaEvent(
type=EventType.STATE_DELTA,
delta=[
{"op": "replace", "path": "/score", "value": 42},
{"op": "replace", "path": "/current_step", "value": "analyzing_data"},
{"op": "add", "path": "/document/content", "value": "New text"}
]
))
```
### 3.5 特殊事件(Special Events)
| 事件类型 | æè¿° | 用途 |
|---------|------|-----|
| `HUMAN_IN_THE_LOOP` / `INTERRUPT` | æš‚åœç‰å¾…用户输入 | 人机å作ã€å®¡æ‰¹æµç¨‹ |
| `HUMAN_RESPONSE` | 用户å“应 | æ¢å¤Agent执行 |
| `CUSTOM` | 自定义事件 | å议扩展 |
| `RAW` | é€ä¼ 外部事件 | ç¬¬ä¸‰æ–¹ç³»ç»Ÿé›†æˆ |
**人机å作æµç¨‹**:
```python
# Agentæš‚åœç‰å¾…用户确认
yield encoder.encode(HumanInTheLoopEvent(
type=EventType.HUMAN_IN_THE_LOOP,
reason="USER_CONFIRMATION_NEEDED",
message="确认执行数æ®åº“åˆ é™¤æ“作?"
))
# ...ç‰å¾…用户å“应...
# 收到用户å“应åŽç»§ç»
yield encoder.encode(HumanResponseEvent(
type=EventType.HUMAN_RESPONSE,
response="confirmed"
))
```
**自定义事件**:
```python
# 多Agent交接
custom_event = CustomEvent(
type=EventType.CUSTOM,
name="AGENT_HANDOFF",
value={
"from_agent": "Planner",
"to_agent": "Executor",
"context": {...}
}
)
```
---
## å››ã€çжæ€åŒæ¥æœºåˆ¶ï¼šJSON Patch与事件溯æº
### 4.1 为什么选择JSON Patch?
AG-UI使用 **JSON Patch(RFC 6902)** 作为状æ€å¢žé‡æ ¼å¼ï¼Œç›¸æ¯”完整快照的优势:
| 对比项 | 完整快照 | JSON Patch |
|-------|---------|-----------|
| 带宽消耗 | O(完整状æ€å¤§å°) | O(å˜æ›´å¤§å°) |
| 延迟 | 高(大状æ€ï¼‰ | 低(æ’定) |
| å†²çªæ£€æµ‹ | å›°éš¾ | 相对容易 |
| ç¦»çº¿æ”¯æŒ | 需é¢å¤–实现 | 天然支æŒï¼ˆpatch队列) |
| 审计追溯 | 需å˜å‚¨å¤šç‰ˆæœ¬ | å¤©ç„¶å®Œæ•´åŽ†å² |
**实际效果**ï¼šåœ¨åŸºå› åºåˆ—比对场景ä¸ï¼Œå¸¦å®½å‡å°‘**92%**。
### 4.2 JSON Patchæ“作类型
```json
// 替æ¢å€¼
{"op": "replace", "path": "/score", "value": 100}
// æ·»åŠ å—æ®µ
{"op": "add", "path": "/tags/-", "value": "new_tag"}
// åˆ é™¤å—æ®µ
{"op": "remove", "path": "/temp_data"}
// ç§»åŠ¨å—æ®µ
{"op": "move", "from": "/old_path", "path": "/new_path"}
// 测试(æ¡ä»¶æ›´æ–°ï¼‰
{"op": "test", "path": "/version", "value": 1}
```
### 4.3 äº‹ä»¶æº¯æºæ¨¡å¼
AG-UI的状æ€ç®¡ç†å€Ÿé‰´äº† **事件溯æºï¼ˆEvent Sourcing)** 架构:
```
┌─────────────────────────────────────────────────────────────â”
│ äº‹ä»¶æº¯æºæž¶æž„ │
├─────────────────────────────────────────────────────────────┤
│ │
│ ä¼ ç»Ÿæ–¹å¼ï¼š │
│ State ──► State ──► State ──► State │
│ │
│ 事件溯æºï¼š │
│ Event1 ──► Event2 ──► Event3 ──► Event4 │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ State1 State2 State3 State4 │
│ (派生) (派生) (派生) (派生) │
│ │
│ 当å‰çŠ¶æ€ = fold(所有事件) │
│ │
└─────────────────────────────────────────────────────────────┘
```
**好处**:
1. **时间旅行**:å¯ä»¥å›žåˆ°ä»»æ„历å²çжæ€
2. **调试å‹å¥½**:完整的事件日志å¯è¿½æº¯
3. **ååŒç¼–辑**:类似Google Docs的实时å作
4. **离线优先**:本地应用patch,è”网åŽåŒæ¥
### 4.4 å‰ç«¯çжæ€åˆå¹¶å®žçް
```typescript
import { applyPatch } from 'fast-json-patch';
class AGUIStateManager {
private state: any = {};
private eventLog: AGUIEvent[] = [];
handleEvent(event: AGUIEvent) {
switch(event.type) {
case 'STATE_SNAPSHOT':
this.state = event.snapshot;
this.eventLog = [event];
break;
case 'STATE_DELTA':
// 应用JSON Patch
applyPatch(this.state, event.delta);
this.eventLog.push(event);
break;
}
// 通知UI更新
this.notifySubscribers();
}
// 时间旅行:回到第n个事件
timeTravel(eventIndex: number) {
this.state = {};
for(let i = 0; i <= eventIndex; i++) {
this.handleEvent(this.eventLog[i]);
}
}
}
```
---
## 五ã€ä¼ 输层实现:SSEã€WebSocket与HTTP
### 5.1 Server-Sent Events (SSE) - 推è
AG-UIçš„å‚考实现使用SSEï¼ŒåŽŸå› ï¼š
| 特性 | SSE | WebSocket |
|-----|-----|-----------|
| 基于HTTP | ✅ 是 | âŒ å¦ |
| 自动é‡è¿ž | ✅ 内置 | âš ï¸ éœ€å®žçŽ° |
| 防ç«å¢™å‹å¥½ | ✅ 是 | âš ï¸ å¯èƒ½å—阻 |
| åŒå‘通信 | âŒ å¦ | ✅ 是 |
| äºŒè¿›åˆ¶æ”¯æŒ | âš ï¸ Base64 | ✅ 原生 |
| 夿‚度 | 低 | 较高 |
**SSE实现示例**:
```python
# FastAPI + SSE
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from ag_ui.encoder import EventEncoder
app = FastAPI()
encoder = EventEncoder()
@app.post("/agent")
async def run_agent(request: AgentRequest):
async def event_stream():
# å‘é€äº‹ä»¶æµ
async for event in agent.execute(request):
yield encoder.encode(event) + "\n\n"
return StreamingResponse(
event_stream(),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
}
)
```
### 5.2 WebSocket支æŒ
对于需è¦åŒå‘高频通信的场景:
```typescript
// å‰ç«¯WebSocket客户端
import { AGUIWebSocketClient } from '@ag-ui/ws';
const client = new AGUIWebSocketClient({
url: 'wss://api.example.com/agent',
onEvent: (event) => {
console.log('Received:', event);
}
});
// å‘é€ç”¨æˆ·è¾“å…¥
client.send({
type: 'USER_MESSAGE',
content: 'Hello, Agent!'
});
```
### 5.3 HTTP长轮询(Fallback)
```python
@app.post("/agent/poll")
async def poll_agent(request: AgentRequest, last_event_id: str = None):
events = await get_events_since(last_event_id)
return {
"events": events,
"last_event_id": events[-1].id if events else None
}
```
---
## å…ã€ä¸ŽMCPã€A2Açš„åè®®æ ˆå¯¹æ¯”
### 6.1 三大å议完整对比
| 维度 | AG-UI | MCP | A2A |
|-----|-------|-----|-----|
| **å‘èµ·æ–¹** | CopilotKit (2025) | Anthropic (2024) | Google (2025) |
| **æ ¸å¿ƒé—®é¢˜** | Agent如何与用户交互 | Agent如何调用工具 | Agent之间如何å作 |
| **通信模å¼** | å•å‘äº‹ä»¶æµ | 请求-å“应 | 请求-å“应 + æŽ¨é€ |
| **åè®®æ ¼å¼** | JSON事件 | JSON-RPC 2.0 | JSON-RPC 2.0 |
| **ä¼ è¾“æ–¹å¼** | SSE/WebSocket/HTTP | stdio/SSE/HTTP | HTTP/SSE |
| **状æ€ç®¡ç†** | äº‹ä»¶æº¯æº | æ— çŠ¶æ€ | 有状æ€ä»»åŠ¡ |
| **æµå¼æ”¯æŒ** | 原生 | 通过SSE | 原生 |
| **主è¦ç”¨ä¾‹** | 实时UIã€ååŒç¼–辑 | å·¥å…·è°ƒç”¨ã€æ•°æ®è®¿é—® | 多Agent编排 |
### 6.2 åè®®å作架构
```
┌─────────────────────────────────────────────────────────────â”
│ 用户层 │
│ ┌──────────┠│
│ │ 用户 │ │
│ └────┬─────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┠│
│ │ AG-UI: Agent ↔ UI │ │
│ │ 实时交互ã€çжæ€åŒæ¥ã€äººæœºå作 │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ │
├─────────────────────────┼───────────────────────────────────┤
│ Agent层 │
│ ┌─────────────────┠│ ┌─────────────────────────┠│
│ │ Agent A │◄───┼───►│ Agent B │ │
│ │ (规划者) │ │ │ (执行者) │ │
│ └────────┬────────┘ │ └──────────┬──────────────┘ │
│ │ │ │ │
│ │ ┌──────────┴──────────┠│ │
│ │ │ A2A: Agent ↔ Agent │ │ │
│ │ │ 任务委托ã€å作 │ │ │
│ │ └───────────────────────┘ │ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────────────────────────────────────────────┠│
│ │ MCP: Agent ↔ 工具/æ•°æ® â”‚ │
│ │ æ•°æ®åº“ã€APIã€æ–‡ä»¶ç³»ç»Ÿã€æœç´¢ç‰ │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ │
├─────────────────────────┼───────────────────────────────────┤
│ 基础设施层 │
│ ┌───────────────┼───────────────┠│
│ ▼ ▼ ▼ │
│ ┌──────────┠┌──────────┠┌──────────┠│
│ │ PostgreSQL│ │ REST API │ │ File System│ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
```
### 6.3 ä½¿ç”¨åœºæ™¯å†³ç–æ ‘
```
ä½ éœ€è¦ä»€ä¹ˆï¼Ÿ
│
├── 用户界é¢äº¤äº’?
│ └── 使用 AG-UI
│
├── 调用外部工具/API?
│ └── 使用 MCP
│
├── 多个Agentå作?
│ └── 使用 A2A
│
└── 全部都需è¦ï¼Ÿ
└── AG-UI + MCP + A2A 组åˆä½¿ç”¨
```
### 6.4 AG-UI vs A2UI
还有一个容易混淆的å议:**A2UI**(Agent-to-User Interface),由Googleæå‡ºã€‚
| 维度 | AG-UI | A2UI |
|-----|-------|------|
| **性质** | ä¼ è¾“åè®® | UIæè¿°è§„范 |
| **关注点** | "å¦‚ä½•ä¼ è¾“" | "显示什么" |
| **类比** | HTTP | HTML |
| **关系** | AG-UIå¯ä»¥æ‰¿è½½A2UIæ•°æ® | A2UI定义UI组件抽象 |
**互补关系**:
```
AG-UI (ä¼ è¾“å±‚)
│
├── 事件: TEXT_MESSAGE_CONTENT
├── 事件: STATE_DELTA
└── 事件: CUSTOM
│
└── payload: A2UIæè¿°
{
"type": "form",
"fields": [...]
}
```
---
## 七ã€ä»£ç 实现:从入门到生产
### 7.1 最å°å¯è¡Œç¤ºä¾‹
**åŽç«¯ï¼ˆPython + FastAPI)**:
```python
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from ag_ui import EventEncoder, EventType
import asyncio
app = FastAPI()
encoder = EventEncoder()
@app.post("/chat")
async def chat(message: str):
async def generate():
# 开始事件
yield encoder.encode({
"type": EventType.RUN_STARTED,
"runId": "run_001"
})
# 文本消æ¯å¼€å§‹
yield encoder.encode({
"type": EventType.TEXT_MESSAGE_START,
"messageId": "msg_001",
"role": "assistant"
})
# 模拟æµå¼è¾“出
response = "Hello! I'm an AI assistant."
for token in response.split():
yield encoder.encode({
"type": EventType.TEXT_MESSAGE_CONTENT,
"messageId": "msg_001",
"content": token + " "
})
await asyncio.sleep(0.1)
# 文本消æ¯ç»“æŸ
yield encoder.encode({
"type": EventType.TEXT_MESSAGE_END,
"messageId": "msg_001"
})
# è¿è¡Œç»“æŸ
yield encoder.encode({
"type": EventType.RUN_FINISHED,
"runId": "run_001"
})
return StreamingResponse(
generate(),
media_type="text/event-stream"
)
```
**å‰ç«¯ï¼ˆReact)**:
```tsx
import { useAGUI } from '@ag-ui/react';
function Chat() {
const { messages, sendMessage, isLoading } = useAGUI({
endpoint: '/api/chat'
});
return (
<div className="chat">
{messages.map(msg => (
<div key={msg.id} className={`message ${msg.role}`}>
{msg.content}
</div>
))}
{isLoading && <div className="loading">...</div>}
<input
onKeyPress={(e) => {
if (e.key === 'Enter') {
sendMessage(e.target.value);
e.target.value = '';
}
}}
/>
</div>
);
}
```
### 7.2 LangGraph集æˆ
```python
from langgraph.graph import StateGraph
from ag_ui import EventEncoder, EventType
encoder = EventEncoder()
class AgentState:
messages: list
current_step: str
graph = StateGraph(AgentState)
@graph.node()
def planner(state: AgentState):
# å‘逿¥éª¤å¼€å§‹äº‹ä»¶
yield encoder.encode({
"type": EventType.STEP_STARTED,
"step": "planning"
})
# 执行规划逻辑...
plan = generate_plan(state.messages)
# å‘é€çŠ¶æ€æ›´æ–°
yield encoder.encode({
"type": EventType.STATE_DELTA,
"delta": [
{"op": "add", "path": "/plan", "value": plan}
]
})
# å‘逿¥éª¤ç»“æŸ
yield encoder.encode({
"type": EventType.STEP_FINISHED,
"step": "planning"
})
return {"current_step": "executing"}
# 更多节点...
```
### 7.3 生产级错误处ç†
```python
from contextlib import asynccontextmanager
@asynccontextmanager
async def safe_agent_execution():
try:
yield
except AgentError as e:
yield encoder.encode({
"type": EventType.RUN_ERROR,
"error": {
"code": e.code,
"message": str(e),
"recoverable": e.recoverable
}
})
except Exception as e:
# 未知错误
yield encoder.encode({
"type": EventType.RUN_ERROR,
"error": {
"code": "INTERNAL_ERROR",
"message": "An unexpected error occurred",
"recoverable": False
}
})
logger.exception("Unexpected error in agent execution")
```
### 7.4 人机å作实现
```python
import asyncio
class HumanInTheLoopManager:
def __init__(self):
self.pending_confirmations = {}
async def request_confirmation(self, context: dict) -> str:
confirmation_id = generate_id()
# å‘é€ä¸æ–事件
yield encoder.encode({
"type": EventType.HUMAN_IN_THE_LOOP,
"confirmationId": confirmation_id,
"context": context
})
# ç‰å¾…用户å“应
future = asyncio.Future()
self.pending_confirmations[confirmation_id] = future
try:
response = await asyncio.wait_for(future, timeout=300)
return response
except asyncio.TimeoutError:
raise HumanTimeoutError("User did not respond in time")
def handle_human_response(self, confirmation_id: str, response: str):
if confirmation_id in self.pending_confirmations:
future = self.pending_confirmations.pop(confirmation_id)
future.set_result(response)
```
---
## å…«ã€æ€§èƒ½ä¼˜åŒ–与最佳实践
### 8.1 æ€§èƒ½æŒ‡æ ‡
| æŒ‡æ ‡ | ç›®æ ‡å€¼ | 说明 |
|-----|-------|------|
| 首å—延迟 | <100ms | 从å‘é€åˆ°é¦–token返回 |
| 事件处ç†å»¶è¿Ÿ | <10ms | å‰ç«¯å¤„ç†å•个事件 |
| 状æ€åŒæ¥å¸¦å®½ | å‡å°‘90%+ | 相比完整快照 |
| å¹¶å‘连接 | 10K+ | 啿œåС噍 |
### 8.2 优化ç–ç•¥
**1. 事件批处ç†**
```python
# å°tokenåˆå¹¶å‘é€ï¼Œå‡å°‘网络开销
buffer = []
for token in llm_stream():
buffer.append(token)
if len(buffer) >= 5 or time_since_last_send() > 50:
yield encoder.encode({
"type": EventType.TEXT_MESSAGE_CONTENT,
"content": "".join(buffer)
})
buffer = []
```
**2. 状æ€åŽ‹ç¼©**
```python
import gzip
import base64
# 大状æ€å¿«ç…§åŽ‹ç¼©
def compress_large_snapshot(snapshot: dict) -> str:
json_str = json.dumps(snapshot)
compressed = gzip.compress(json_str.encode())
return base64.b64encode(compressed).decode()
```
**3. å¢žé‡æ›´æ–°ç–ç•¥**
```python
# 高频更新åˆå¹¶
class StateBatcher:
def __init__(self, flush_interval=100):
self.pending_deltas = []
self.flush_interval = flush_interval
def add_delta(self, delta):
self.pending_deltas.extend(delta)
if len(self.pending_deltas) >= self.flush_interval:
return self.flush()
return None
def flush(self):
if not self.pending_deltas:
return None
deltas = self.pending_deltas
self.pending_deltas = []
return deltas
```
**4. è¿žæŽ¥æ± ç®¡ç†**
```typescript
// å‰ç«¯è¿žæŽ¥å¤ç”¨
class AGUIConnectionPool {
private connections: Map<string, Connection> = new Map();
getConnection(endpoint: string): Connection {
if (!this.connections.has(endpoint)) {
this.connections.set(endpoint, new Connection(endpoint));
}
return this.connections.get(endpoint)!;
}
}
```
### 8.3 安全最佳实践
**1. 事件验è¯**
```python
from pydantic import BaseModel, validator
class AGUIEvent(BaseModel):
type: str
timestamp: int
@validator('type')
def validate_type(cls, v):
allowed_types = [t.value for t in EventType]
if v not in allowed_types:
raise ValueError(f"Invalid event type: {v}")
return v
```
**2. 速率é™åˆ¶**
```python
from ratelimit import limits, sleep_and_retry
@sleep_and_retry
@limits(calls=100, period=60)
def send_event(event):
# å‘é€äº‹ä»¶
pass
```
**3. æ•æ„Ÿæ•°æ®è¿‡æ»¤**
```python
def sanitize_event(event: dict) -> dict:
"""è¿‡æ»¤æ•æ„Ÿä¿¡æ¯"""
sensitive_keys = ['password', 'token', 'secret', 'api_key']
def redact(obj):
if isinstance(obj, dict):
return {
k: '[REDACTED]' if k in sensitive_keys else redact(v)
for k, v in obj.items()
}
elif isinstance(obj, list):
return [redact(item) for item in obj]
return obj
return redact(event)
```
---
## ä¹ã€ç”Ÿæ€ç³»ç»Ÿä¸Žæ¡†æž¶é›†æˆ
### 9.1 官方支æŒçš„æ¡†æž¶
| 框架 | çŠ¶æ€ | SDK | 文档 |
|-----|------|-----|------|
| LangGraph | ✅ å®˜æ–¹æ”¯æŒ | Python/TS | docs.ag-ui.com |
| CrewAI | ✅ å®˜æ–¹æ”¯æŒ | Python | docs.ag-ui.com |
| Mastra | ✅ å®˜æ–¹æ”¯æŒ | TypeScript | docs.ag-ui.com |
| Pydantic AI | ✅ å®˜æ–¹æ”¯æŒ | Python | docs.ag-ui.com |
| Google ADK | ✅ å®˜æ–¹æ”¯æŒ | Python | docs.ag-ui.com |
| Microsoft Agent Framework | ✅ å®˜æ–¹æ”¯æŒ | .NET | docs.ag-ui.com |
| AWS Strands Agents | ✅ å®˜æ–¹æ”¯æŒ | Python | docs.ag-ui.com |
| Oracle Agent Spec | ✅ å®˜æ–¹æ”¯æŒ | Java | docs.ag-ui.com |
| AG2 | ✅ å®˜æ–¹æ”¯æŒ | Python | docs.ag-ui.com |
### 9.2 SDK支æŒ
| è¯è¨€/å¹³å° | SDK | çŠ¶æ€ |
|----------|-----|------|
| TypeScript | `@ag-ui/core` | ✅ 稳定 |
| Python | `ag-ui` | ✅ 稳定 |
| Kotlin Multiplatform | `ag-ui-4k` | ✅ 稳定 |
| Go | `ag-ui-go` | 🔄 Beta |
| Rust | `ag-ui-rs` | 🔄 Beta |
| Dart (Flutter) | `ag_ui` | 🔄 Beta |
| Java | `ag-ui-java` | 🔄 Beta |
| Ruby | `ag-ui-ruby` | 🔄 Alpha |
| .NET | `AGUI.NET` | 🔄 Alpha |
### 9.3 ä¼ä¸šé‡‡ç”¨æ¡ˆä¾‹
| å…¬å¸/组织 | 用例 | 规模 |
|----------|------|------|
| JPMorgan Chase | 交易å°å®žæ—¶é£Žé™©ç›‘控 | 生产环境 |
| Clifford Chance | 法律文件审查助手 | 生产环境 |
| Stanford BMI Lab | 神ç»å‡è‚¢æŽ§åˆ¶ç³»ç»Ÿ | ç ”ç©¶é˜¶æ®µ |
| Shopify | 商家助手 | 试点阶段 |
| Walmart | 供应链Agent | 试点阶段 |
---
## åã€æœªæ¥å±•望与开放问题
### 10.1 路线图
| 版本 | 特性 | 预计时间 |
|-----|------|---------|
| v1.1 | è¯éŸ³/è§†é¢‘æµæ”¯æŒ | 2025 Q3 |
| v1.2 | ç«¯åˆ°ç«¯åŠ å¯† | 2025 Q4 |
| v2.0 | 边缘计算优化 | 2026 Q1 |
| v2.1 | 多模æ€äº‹ä»¶ç±»åž‹ | 2026 Q2 |
### 10.2 开放问题
1. **å议治ç†**:多个竞争å议(AG-UIã€A2UIã€MCP-UI)如何统一或共å˜ï¼Ÿ
2. **安全边界**ï¼šå¦‚ä½•é˜²æ¢æ¶æ„Agent通过UI事件进行攻击?
3. **跨域兼容**:ä¸åŒåŽ‚å•†çš„å®žçŽ°æ˜¯å¦å˜åœ¨ç¢Žç‰‡åŒ–风险?
4. **性能边界**:在超低延迟场景(如AR/VRï¼‰ä¸‹èƒ½å¦æ»¡è¶³è¦æ±‚?
### 10.3 å‚与社区
| èµ„æº | 链接 |
|-----|------|
| GitHub | github.com/ag-ui-protocol/ag-ui |
| 官方文档 | docs.ag-ui.com |
| Discord社区 | discord.gg/ag-ui |
| AG-UI Dojo(示例)| dojo.ag-ui.com |
| è´¡çŒ®æŒ‡å— | github.com/ag-ui-protocol/ag-ui/blob/main/CONTRIBUTING.md |
---
## 附录:快速å‚考å¡
### 事件类型速查表
```
生命周期:RUN_STARTED, STEP_STARTED, STEP_FINISHED, RUN_FINISHED, RUN_ERROR
文本消æ¯ï¼šTEXT_MESSAGE_START, TEXT_MESSAGE_CONTENT, TEXT_MESSAGE_END
工具调用:TOOL_CALL_START, TOOL_CALL_ARGS, TOOL_CALL_END, TOOL_CALL_RESULT
状æ€ç®¡ç†ï¼šSTATE_SNAPSHOT, STATE_DELTA, MESSAGES_SNAPSHOT
特殊事件:HUMAN_IN_THE_LOOP, HUMAN_RESPONSE, CUSTOM, RAW
```
### JSON Patchæ“作速查表
```json
{"op": "add", "path": "/field", "value": "data"} // æ·»åŠ
{"op": "remove", "path": "/field"} // åˆ é™¤
{"op": "replace", "path": "/field", "value": "new"} // 替æ¢
{"op": "move", "from": "/old", "path": "/new"} // 移动
{"op": "copy", "from": "/src", "path": "/dst"} // å¤åˆ¶
{"op": "test", "path": "/field", "value": "expected"} // 测试
```
### 最å°å¯è¿è¡Œä»£ç
```bash
# 安装
npm install @ag-ui/core
pip install ag-ui
# 快速开始
npx create-ag-ui-app my-app
```
---
*报告版本:v1.0*
*æœ€åŽæ›´æ–°ï¼š2026å¹´3月29æ—¥*
*作者:AI Research Assistant*
*å议版本:AG-UI/1.0*
---
#AG-UI #Agentåè®® #MCP #A2A #AIæž¶æž„ #æŠ€æœ¯æ·±åº¦è§£æž #å°å‡¯
登录åŽå¯å‚与表æ€
讨论回å¤
0 æ¡å›žå¤è¿˜æ²¡æœ‰äººå›žå¤ï¼Œå¿«æ¥å‘è¡¨ä½ çš„çœ‹æ³•å§ï¼