AG-UI 协议
云开发 Agent 完全兼容 AG-UI 协议,这是一个标准化的前后端通信协议,用于 Agent 与客户端之间的实时交互。
协议概述
AG-UI 协议基于 SSE(Server-Sent Events)实现流式通信,支持:
- 实时推送 Agent 执行过程
- 工具调用和结果返回
- 人机交互场景
- 状态同步
请求格式
HTTP 请求
POST /agent HTTP/1.1
Content-Type: application/json
Accept: text/event-stream
{
"threadId": "thread-xxx",
"runId": "run-xxx",
"messages": [
{
"id": "msg-1",
"role": "user",
"content": "你好"
}
],
"tools": [],
"context": [],
"forwardedProps": {}
}
请求参数说明
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
threadId | string | 否 | 会话 ID,用于多轮对话 |
runId | string | 否 | 本次运行 ID |
messages | array | 是 | 消息列表 |
tools | array | 否 | 前端工具定义 |
context | array | 否 | 上下文信息 |
forwardedProps | object | 否 | 透传参数 |
消息格式
interface Message {
id: string; // 消息 ID
role: "user" | "assistant" | "system" | "tool";
content: string; // 消息内容
name?: string; // 工具名称(role 为 tool 时)
toolCallId?: string; // 工具调用 ID(role 为 tool 时)
}
响应格式
响应采用 SSE 格式,每个事件以 data: 开头:
data: {"type":"TEXT_MESSAGE_START","messageId":"msg-1"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"msg-1","delta":"你好"}
data: {"type":"TEXT_MESSAGE_END","messageId":"msg-1"}
data: {"type":"RUN_FINISHED"}
事件类型
生命周期事件
| 事件类型 | 说明 |
|---|---|
RUN_STARTED | Agent 开始运行 |
RUN_FINISHED | Agent 运行结束 |
RUN_ERROR | Agent 运行出错 |
消息事件
| 事件类型 | 说明 |
|---|---|
TEXT_MESSAGE_START | 文本消息开始 |
TEXT_MESSAGE_CONTENT | 文本消息内容(增量) |
TEXT_MESSAGE_END | 文本消息结束 |
工具调用事件
| 事件类型 | 说明 |
|---|---|
TOOL_CALL_START | 工具调用开始 |
TOOL_CALL_ARGS | 工具调用参数(增量) |
TOOL_CALL_END | 工具调用结束 |
状态事件
| 事件类型 | 说明 |
|---|---|
STATE_SNAPSHOT | 状态快照 |
STATE_DELTA | 状态增量更新 |
MESSAGES_SNAPSHOT | 消息快照 |
步骤事件
| 事件类型 | 说明 |
|---|---|
STEP_STARTED | 步骤开始 |
STEP_FINISHED | 步骤结束 |
工具调用
服务端工具
服务端工具由 Agent 后端直接执行:
前端工具
前端工具需要客户端执行后返回结果:
前端工具定义示例:
const tools = [
{
name: "get_location",
description: "获取用户当前位置",
parameters: {
type: "object",
properties: {},
required: []
}
}
];
人机交互
AG-UI 协议支持多种人机交互场景:
用户确认
Agent 可以请求用户确认后再执行操作:
// 服务端发送确认请求
{
type: "TOOL_CALL_START",
toolCallId: "call-1",
toolCallName: "confirm_action"
}
// 客户端返回确认结果
{
role: "tool",
toolCallId: "call-1",
content: JSON.stringify({ confirmed: true })
}
用户输入
Agent 可以请求用户提供额外输入:
// 服务端请求输入
{
type: "TOOL_CALL_START",
toolCallId: "call-2",
toolCallName: "request_input",
args: { prompt: "请输入您的邮箱地址" }
}
// 客户端返回输入
{
role: "tool",
toolCallId: "call-2",
content: JSON.stringify({ input: "user@example.com" })
}
状态管理
状态快照
Agent 可以发送完整状态快照:
{
type: "STATE_SNAPSHOT",
snapshot: {
currentStep: "analyzing",
progress: 50,
results: []
}
}
状态增量
Agent 可以发送状态增量更新:
{
type: "STATE_DELTA",
delta: [
{ op: "replace", path: "/progress", value: 75 }
]
}
错误处理
错误事件
{
type: "RUN_ERROR",
error: {
code: "TOOL_EXECUTION_ERROR",
message: "工具执行失败"
}
}
常见错误码
| 错误码 | 说明 |
|---|---|
INVALID_REQUEST | 请求格式错误 |
TOOL_NOT_FOUND | 工具不存在 |
TOOL_EXECUTION_ERROR | 工具执行失败 |
MODEL_ERROR | 模型调用失败 |
TIMEOUT | 请求超时 |
最佳实践
1. 消息 ID 管理
确保每条消息都有唯一的 ID,便于追踪和调试:
const messageId = `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
2. 会话管理
使用 threadId 管理多轮对话:
// 新会话
const threadId = `thread-${Date.now()}`;
// 后续请求使用相同的 threadId
{
threadId: threadId,
messages: [...]
}
3. 超时处理
设置合理的超时时间:
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 60000);
fetch('/agent', {
signal: controller.signal,
// ...
});
4. 重试机制
实现指数退避重试:
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fetch(url, options);
} catch (error) {
if (i === maxRetries - 1) throw error;
await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
}
}
}