跳转到内容

AG-UI 事件驱动协议:Agent 与 UI 的通信标准

AG-UI 事件驱动协议

学习目标

理解 AG-UI 协议如何定义 Agent 与 UI 之间的标准化通信:

  • 事件生命周期的五个阶段
  • SSE 流式传输的编码与解码
  • 工具调用如何通过协议在前端和后端之间协同
  • 传输模式的自动协商策略

前置知识

本章涉及事件驱动架构和流式传输的通用原理,建议先阅读:

下文假设你已理解上述概念,直接聚焦 CopilotKit 的 AG-UI 协议实现。

项目实践

AG-UI 协议是什么

AG-UI 是一个独立的事件协议标准(由 CopilotKit 团队维护,包名 @ag-ui/core),定义了 Agent 和 UI 之间的结构化通信方式。CopilotKit 的前端和运行时层都通过 AG-UI 事件进行交互。

协议的核心设计理念:Agent 的输出不是一次性的”回复”,而是一系列结构化事件的流

事件生命周期

每个 Agent 运行遵循固定的事件生命周期:

AG-UI 协议通过 EventType 枚举定义所有事件类型:

事件类型生命周期位置说明
RUN_STARTED运行开始携带 threadIdrunId
STEP_STARTED步骤开始一个 step 对应一次 LLM 调用
TEXT_MESSAGE_START文本消息消息开始,标记 rolemessageId
TEXT_MESSAGE_CONTENT文本消息流式内容增量(delta 字段)
TEXT_MESSAGE_END文本消息消息结束
TOOL_CALL_START工具调用携带 toolCallIdtoolCallName
TOOL_CALL_ARGS工具调用流式参数增量
TOOL_CALL_END工具调用参数完整
TOOL_CALL_RESULT工具调用工具执行结果
STEP_FINISHED步骤结束
RUN_FINISHED运行结束
RUN_ERROR异常协议级错误事件
CUSTOM自定义框架自定义事件(如 HITL 中断)

SSE 传输编码

事件通过 Server-Sent Events(SSE)流式传输到前端。编码规则:

事件格式(伪代码):
event: {EventType}
id: {eventId}
data: {JSON 序列化的事件载荷}
(空行分隔)

前端通过 EventSource 或自定义 HTTP 请求(带 Accept: text/event-stream)接收流。

传输模式协商

CopilotKit 支持三种传输模式,由客户端的 runtimeTransport 配置控制:

模式说明端点格式
rest(默认)每个操作独立 REST 端点/agent/{id}/run/agent/{id}/connect/agent/{id}/stop
single所有操作统一 POST 到单端点/api/copilotkit,body 中 method 字段区分
auto自动检测:先试 REST,失败降级到 single首次请求 /info 探测

自动协商流程(源码验证):

  1. 客户端发送 GET /info(REST 模式)
  2. 若 2xx 成功 → 使用 rest 模式
  3. 若失败 → 发送 POST {url} + body: { method: "info" }(single 模式)
  4. 若 single 也成功 → 使用 single 模式
  5. 若两者都失败 → 抛出异常

工具调用的前后端协同

AG-UI 协议的关键设计:工具可以在前端执行,也可以在后端执行

流程:

  1. Agent 在推理过程中生成 TOOL_CALL_START + TOOL_CALL_ARGS 事件
  2. 前端 CopilotKitCore 收到事件,在工具注册表中查找 toolCallName
  3. 若找到前端 handler → 在浏览器执行,结果通过 HTTP 回传给 Agent
  4. 若未找到 → 事件继续传输到后端,后端查找并执行

前端工具执行的结果传递:

前端执行工具 → 结果回传 → Agent 继续推理 → 生成下一个事件

这种设计让 Agent 能安全地操作 DOM、触发用户交互、读取浏览器状态——这些是后端无法完成的操作。

问题与规避

问题规避策略
SSE 连接在 CDN/代理后被缓冲服务器响应头设置 X-Accel-Buffering: noCache-Control: no-cache
并发 Agent 运行导致事件交错前端使用 detachActiveRun() 确保每次只有一个活跃 run;isRunning 状态通过生命周期事件桥接
Agent 工具执行超时前端设置合理的 AbortController 超时;ZodError 和 AbortError 在 Observable 管道中被静默处理(EMPTY
传输模式协商失败auto 模式的降级逻辑只在首次运行触发,之后缓存结果;若运行时切换模式需要重新协商
RUN_ERROR 事件未重置前端状态前端 onRunErrorEvent 回调负责重置 isRunning;与 onRunFailed(本地异常)分开处理

设计取舍

为什么用 AG-UI 协议而非直接调用 LLM API?

优势

  • 标准化事件层屏蔽不同 Agent 框架的差异(LangGraph、CrewAI、OpenAI 等)
  • 事件驱动的细粒度 UI 更新比”等待完整回复”用户体验更好
  • 前端工具执行模型让 Agent 能操作浏览器

代价

  • 增加了一层抽象,调试时需要理解事件流而非直接的请求/响应
  • 前端需要维护事件解析和状态管理逻辑

为什么提供三种传输模式?

REST 模式(默认)

  • 优势:符合 RESTful 设计,每个操作有明确语义,便于 HTTP 中间件处理
  • 代价:多个端点增加服务器配置复杂度

Single 模式

  • 优势:一个端点处理所有操作,简化部署(尤其 Serverless 环境)
  • 代价:请求 body 需要 method 字段包装,非标准 REST

Auto 模式

  • 优势:开发者无需关心传输细节
  • 代价:首次请求有额外的协商延迟

参考来源

  • @ag-ui/core 包源码(EventType 枚举定义)
  • @ag-ui/client 包(HttpAgent、事件流转换)
  • CopilotKit 架构文档