目 录CONTENT

文章目录

AG-UI 协议:Agent与前端交互的标准化之路

PySuper
2026-04-03 / 0 评论 / 0 点赞 / 0 阅读 / 0 字
温馨提示:
本文最后更新于2026-05-22,若内容或图片失效,请留言反馈。 所有牛逼的人都有一段苦逼的岁月。 但是你只要像SB一样去坚持,终将牛逼!!! ✊✊✊

作者:PySuper | 来源:zhengxingtao.com

日期:2026-09-15

目录

  • 1. 为什么需要 AG-UI?

  • 2. AG-UI 是什么

  • 3. 协议架构:事件流模型

  • 4. 协议三角:MCP + A2A + AG-UI

  • 5. 事件类型详解

  • 6. 实战1:用 CopilotKit + AG-UI 构建 Agent 驱动的 Web 应用

  • 7. 实战2:将 LangGraph Agent 通过 AG-UI 接入前端

  • 8. 适用场景 vs 不适用场景

  • 9. 生态支持现状

  • 10. 踩坑记录

  • 11. 总结与展望

1. 为什么需要 AG-UI?

2024-2025 年,AI Agent 生态经历了爆发式增长——LangGraph、CrewAI、Mastra、AG2、AutoGen 等框架百花齐放。但一个关键问题始终悬而未决:

Agent 和前端 UI 之间缺乏标准通信方式。

具体来说,开发者面临这些困境:

plaintext

┌──────────────────────────────────────────────────────────────┐
│  Agent 前端接入的 5 大痛点                                     │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  1. 格式碎片化                                                │
│     ├─ LangGraph 用自己的 stream_events                       │
│     ├─ CrewAI 用自定义 JSON WebSocket                        │
│     ├─ Mastra 用 REST + SSE                                  │
│     └─ 每个框架一个方言,前端需要逐个适配                        │
│                                                              │
│  2. 实时流式困难                                              │
│     ├─ LLM 逐 token 输出,UI 需要 token-by-token 渲染          │
│     ├─ WebSocket 双工但缺乏标准化事件格式                       │
│     └─ 纯轮询延迟太高,用户体验差                               │
│                                                              │
│  3. 工具调用不可见                                             │
│     ├─ Agent 调用了什么工具?前端看不到                          │
│     ├─ 需要用户审批的工具怎么暂停/恢复?                         │
│     └─ 工具执行进度怎么实时展示?                                │
│                                                              │
│  4. 状态同步混乱                                              │
│     ├─ Agent 内部状态怎么同步到前端?                            │
│     ├─ 全量快照太重,增量更新没规范                              │
│     └─ 前端修改状态怎么回传 Agent?                             │
│                                                              │
│  5. 并发与中断                                                │
│     ├─ 多个 Agent 同时运行怎么管理?                            │
│     ├─ 用户想中断某个 Agent 怎么发信号?                        │
│     └─ 中断后恢复上下文如何保持?                                │
│                                                              │
└──────────────────────────────────────────────────────────────┘

结果就是:每个团队都在重复造轮子——写 WebSocket 适配器、解析自定义 JSON 格式、处理 SSE 重连逻辑。CopilotKit 团队自己在构建产品时也踩了这些坑,所以他们决定抽出一个通用协议。

据《Introducing AG-UI: The Protocol Where Agents Meet Users》(https://www.copilotkit.ai/blog/introducing-ag-ui-the-protocol-where-agents-meet-users),AG-UI 于 2025 年 5 月正式发布,CopilotKit 团队在获得 $27M A 轮融资后,将其开源并推动成为行业标准。

2. AG-UI 是什么

AG-UI(Agent-User Interaction Protocol)是一个开源、轻量的协议,定义了 AI Agent 与前端用户界面之间的标准通信方式。

核心设计原则:

plaintext

┌─────────────────────────────────────────────────────────────────┐
│  AG-UI 核心设计原则                                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. 单请求 → 事件流                                               │
│     客户端发一个 POST,后端回一个 SSE 事件流                        │
│     不需要 WebSocket,不需要自定义序列化                            │
│                                                                 │
│  2. 统一事件格式                                                  │
│     所有交互都编码为 JSON 事件                                    │
│     每个 event 有 type 字段 + 最小化 payload                      │
│     前端按 type 分发处理即可                                      │
│                                                                 │
│  3. 基于 HTTP                                                    │
│     走标准 HTTP/SSE,天然兼容:                                   │
│     ├─ CORS、认证 Token、审计日志                                 │
│     ├─ 负载均衡、CDN、API Gateway                                 │
│     └─ 可选二进制序列化用于性能敏感场景                             │
│                                                                 │
│  4. 框架无关                                                     │
│     后端可以是 LangGraph / CrewAI / Mastra / 自定义               │
│     前端可以是 React / Vue / 原生                                │
│     只要遵循协议,组件可互换                                      │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

一句话总结:AG-UI 是 Agent 世界的"HTTP"——一个把 Agent 和 UI 解耦的通信协议。

3. 协议架构:事件流模型

3.1 请求-响应模型

plaintext

┌───────────┐                           ┌───────────┐
│           │  POST /awp                 │           │
│  Frontend │  RunAgentInput (JSON)      │  Agent    │
│  (React)  │ ──────────────────────────>│  Backend  │
│           │                            │  (Python) │
│           │  SSE Stream                │           │
│           │ <──────────────────────────│           │
│           │  Event 1: RUN_STARTED      │           │
│           │  Event 2: TEXT_MESSAGE_     │           │
│           │           START             │           │
│           │  Event 3: TEXT_MESSAGE_     │           │
│           │           CONTENT           │           │
│           │  Event 4: TOOL_CALL_START   │           │
│           │  Event 5: TOOL_CALL_ARGS    │           │
│           │  Event 6: TOOL_CALL_END     │           │
│           │  Event 7: STATE_DELTA       │           │
│           │  Event 8: RUN_FINISHED      │           │
└───────────┘                           └───────────┘

3.2 RunAgentInput 结构

前端发往 Agent 的请求体:

python

# RunAgentInput - 前端发给 Agent 的标准输入
{
    "thread_id": "thread_abc123",       # 会话线程 ID
    "run_id": "run_xyz789",             # 本次运行 ID
    "messages": [                        # 对话历史
        {
            "role": "user",
            "content": "帮我分析这份销售报告"
        },
        {
            "role": "assistant",
            "content": "好的,让我来分析..."
        }
    ],
    "state": {                           # 共享状态
        "current_document": "report.xlsx",
        "analysis_mode": "detailed"
    },
    "tools": [                           # 前端可用工具(可选)
        {
            "name": "show_chart",
            "description": "在 UI 上展示图表",
            "parameters": {
                "type": "object",
                "properties": {
                    "chart_type": {"type": "string"},
                    "data": {"type": "object"}
                }
            }
        }
    ],
    "context": [],                       # 上下文信息(可选)
    "forwarded_props": {}                # 转发属性(可选)
}

3.3 事件基础结构

所有 AG-UI 事件共享一个 BaseEvent 结构:

python

# BaseEvent - 所有事件的基类
{
    "type": "TextMessageContent",        # 必填,事件类型标识
    "timestamp": 1705324800000,          # 可选,Unix 毫秒时间戳
    "rawEvent": null                     # 可选,原始事件载荷
}

3.4 CopilotKit 中的 Proxy 模式

CopilotKit 使用代理模式,前端不直连 Agent:

plaintext

┌──────────┐    useAgent()     ┌──────────────────────┐
│          │ ────────────────> │  ProxiedAgent         │
│  React   │   返回            │  (前端代理)            │
│  组件    │ <────────────────  │  ├─ 同一 AbstractAgent │
│          │   AbstractAgent   │  ├─ 同一 subscribe API │
└──────────┘                   │  └─ 同一属性接口       │
                               └──────────┬───────────┘
                                          │
                               HTTP POST + SSE
                                          │
                               ┌──────────▼───────────┐
                               │  CopilotKit Runtime   │
                               │  (服务端)              │
                               └──────────┬───────────┘
                                          │
                               AG-UI 事件流
                                          │
                               ┌──────────▼───────────┐
                               │  真实 Agent Backend   │
                               │  (LangGraph/CrewAI)   │
                               └──────────────────────┘

这样做的好处是前端代码完全不关心 Agent 跑在哪里——本地、远程、云端都一样。

4. 协议三角:MCP + A2A + AG-UI

这三个协议分别解决了 Agent 生态中不同层级的通信问题:

plaintext

┌──────────────────────────────────────────────────────┐
│                                                      │
│              ┌─────────────┐                         │
│              │    AG-UI     │  Agent ↔ User          │
│              │  (交互层)     │  "用户怎么和Agent交互"   │
│              └──────┬──────┘                         │
│                     │                                │
│              ┌──────┴──────┐                         │
│              │     A2A      │  Agent ↔ Agent         │
│              │  (协作层)     │  "Agent之间怎么协作"     │
│              └──────┬──────┘                         │
│                     │                                │
│              ┌──────┴──────┐                         │
│              │     MCP      │  Agent ↔ Tools         │
│              │  (工具层)     │  "Agent怎么调用工具"     │
│              └─────────────┘                         │
│                                                      │
└──────────────────────────────────────────────────────┘

自底向上:
  MCP    → 定义 Agent 与工具/API 的通信
  A2A    → 定义 Agent 与 Agent 之间的通信
  AG-UI  → 定义 Agent 与用户/前端的通信

据《AG-UI Is Redefining the Agent–User Interaction Layer》(https://webflow.copilotkit.ai/blog/ag-ui-is-redefining-the-agent-user-interaction-layer),A2A 和 AG-UI 已完成官方握手(handshake),首次将 Agent 间通信和 Agent-用户通信层连接起来。

它们不是竞争关系,而是互补关系。 一个完整的 Agent 系统通常三层都需要:

plaintext

场景示例:用户让 AI 团队协作完成市场调研

1. 用户输入任务 (AG-UI 层)
   ├─ 前端通过 AG-UI 发送 RUN_STARTED 事件
   └─ Agent 接收并开始执行

2. 多 Agent 协作 (A2A 层)
   ├─ 主 Agent 拆分任务给 子Agent
   ├─ 子Agent A: 数据收集
   ├─ 子Agent B: 竞品分析
   └─ 子Agent C: 报告生成

3. Agent 调用外部工具 (MCP 层)
   ├─ 通过 MCP 调用搜索引擎 API
   ├─ 通过 MCP 读取数据库
   └─ 通过 MCP 调用图表工具

4. 结果回传用户 (AG-UI 层)
   ├─ TEXT_MESSAGE_CONTENT: "调研完成,这是报告..."
   ├─ TOOL_CALL_END: 渲染图表
   └─ RUN_FINISHED: 运行完成

5. 事件类型详解

AG-UI 定义了以下标准事件类别:

5.1 生命周期事件

plaintext

┌──────────────────────────────────────────────────────┐
│  Agent 运行生命周期                                    │
├──────────────────────────────────────────────────────┤
│                                                      │
│  RUN_STARTED ──> STEP_STARTED ──> STEP_FINISHED      │
│       │              │                                │
│       │              ├─ (多个 Step 可嵌套)             │
│       │              │                                │
│       ├──────────────┴──> RUN_FINISHED               │
│       │                                               │
│       └──(异常)──> RUN_ERROR                          │
│                                                      │
└──────────────────────────────────────────────────────┘

python

# RUN_STARTED 事件
{
    "type": "RunStarted",
    "thread_id": "thread_abc123",
    "run_id": "run_xyz789",
    "parent_run_id": null,       # 父运行 ID(子 Agent 时有值)
    "input": {"query": "..."}    # 可选的输入信息
}

# STEP_STARTED 事件 - 标记一个处理步骤开始
{
    "type": "StepStarted",
    "step_name": "analyzing_data"   # 步骤名称
}

# STEP_FINISHED 事件
{
    "type": "StepFinished",
    "step_name": "analyzing_data"
}

# RUN_FINISHED 事件
{
    "type": "RunFinished",
    "thread_id": "thread_abc123",
    "run_id": "run_xyz789",
    "result": {"summary": "..."}   # 可选的运行结果
}

# RUN_ERROR 事件
{
    "type": "RunError",
    "message": "API rate limit exceeded",
    "code": "RATE_LIMIT"           # 可选错误码
}

5.2 文本消息事件

支持 token-by-token 流式输出:

python

# TEXT_MESSAGE_START - 开始一条新消息
{
    "type": "TextMessageStart",
    "message_id": "msg_001",
    "role": "assistant"
}

# TEXT_MESSAGE_CONTENT - 逐块推送文本
{
    "type": "TextMessageContent",
    "message_id": "msg_001",
    "delta": "你好"               # 增量文本
}

# TEXT_MESSAGE_CONTENT - 下一块
{
    "type": "TextMessageContent",
    "message_id": "msg_001",
    "delta": ",我正在分析"
}

# TEXT_MESSAGE_END - 消息结束
{
    "type": "TextMessageEnd",
    "message_id": "msg_001"
}

5.3 工具调用事件

python

# TOOL_CALL_START - Agent 开始调用工具
{
    "type": "ToolCallStart",
    "tool_call_id": "tc_001",
    "tool_call_name": "search_database",
    "parent_message_id": "msg_001"   # 可选,关联的消息
}

# TOOL_CALL_ARGS - 逐块推送工具参数
{
    "type": "ToolCallArgs",
    "tool_call_id": "tc_001",
    "delta": "{\"query\": \"sales data Q3\"}"   # 增量 JSON
}

# TOOL_CALL_END - 工具调用阶段完成
{
    "type": "ToolCallEnd",
    "tool_call_id": "tc_001"
}

# TOOL_CALL_RESULT - 工具返回结果
{
    "type": "ToolCallResult",
    "tool_call_id": "tc_001",
    "content": "{\"results\": [...]}",
    "message_id": "msg_002",
    "role": "tool"
}

5.4 状态管理事件

python

# STATE_SNAPSHOT - 完整状态快照(首次同步或全量刷新)
{
    "type": "StateSnapshot",
    "snapshot": {
        "current_step": 3,
        "total_steps": 5,
        "files_processed": ["report1.csv", "report2.csv"],
        "progress": 0.6
    }
}

# STATE_DELTA - 增量状态更新(JSON Patch 格式)
{
    "type": "StateDelta",
    "delta": [
        {"op": "replace", "path": "/progress", "value": 0.8},
        {"op": "add", "path": "/files_processed/-", "value": "report3.csv"}
    ]
}

5.5 Activity 事件

用于展示 Agent 的中间活动/进度指示:

python

# ACTIVITY_SNAPSHOT - 活动快照
{
    "type": "ActivitySnapshot",
    "message_id": "activity_001",
    "activity_type": "thinking",
    "content": {
        "step": "Searching database...",
        "progress": 45
    },
    "replace": false   # 是否替换之前的 activity
}

# ACTIVITY_DELTA - 活动增量更新
{
    "type": "ActivityDelta",
    "message_id": "activity_001",
    "activity_type": "thinking",
    "patch": [
        {"op": "replace", "path": "/progress", "value": 78}
    ]
}

5.6 自定义事件

python

# CUSTOM 事件 - 扩展用
{
    "type": "Custom",
    "name": "chart_update",
    "value": {
        "chart_type": "bar",
        "data_points": [10, 20, 30]
    }
}

5.7 事件类型汇总表

表格

类别

事件类型

说明

生命周期

RunStarted / RunFinished / RunError

Agent 运行起止和错误

步骤

StepStarted / StepFinished

子任务步骤边界

文本消息

TextMessageStart / Content / End

流式文本输出

工具调用

ToolCallStart / Args / End / Result

工具调用全生命周期

状态

StateSnapshot / StateDelta

全量快照和增量更新

Activity

ActivitySnapshot / ActivityDelta

中间活动/进度指示

消息快照

MessagesSnapshot

全量消息列表重同步

自定义

Custom / Raw

扩展和原始事件

6. 实战1:用 CopilotKit + AG-UI 构建 Agent 驱动的 Web 应用

6.1 项目结构

plaintext

ag-ui-demo/
├── frontend/                 # React 前端
│   ├── package.json
│   ├── src/
│   │   ├── App.tsx
│   │   ├── main.tsx
│   │   └── components/
│   │       ├── AgentChat.tsx
│   │       └── ProgressPanel.tsx
│   └── vite.config.ts
├── backend/                  # Python 后端
│   ├── requirements.txt
│   ├── main.py
│   └── agent.py
└── docker-compose.yml

6.2 后端:创建 AG-UI Agent 服务

python

# backend/requirements.txt
fastapi==0.115.0
uvicorn==0.32.0
copilotkit==0.1.40
langchain-openai==0.3.0
langchain-core==0.3.0
python-dotenv==1.0.1

python

# backend/agent.py
"""
AG-UI Agent 实现
定义 Agent 的工具和行为,通过 AG-UI 协议与前端通信
"""

import os
import json
from datetime import datetime
from typing import Any

from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain_core.messages import SystemMessage
from copilotkit.integrations.fastapi import add_fastapi_endpoint
from copilotkit import CopilotKitSDK, LangGraphAgent
from copilotkit import Action


# 定义 Agent 可用的工具
@tool
def search_knowledge_base(query: str) -> str:
    """搜索知识库获取相关信息"""
    # 模拟知识库搜索
    knowledge = {
        "定价策略": "我们提供三种定价方案:基础版¥99/月,专业版¥299/月,企业版¥999/月",
        "退款政策": "购买后30天内可申请全额退款,需提供购买凭证",
        "技术支持": "技术支持热线:400-xxx-xxxx,工作时间 9:00-18:00",
        "产品功能": "核心功能包括:数据分析、报表生成、API集成、团队协作",
    }

    results = []
    for key, value in knowledge.items():
        if query in key or key in query:
            results.append(f"【{key}】{value}")

    if not results:
        return f"未找到与 '{query}' 相关的信息,建议联系人工客服"

    return "\n".join(results)


@tool
def create_support_ticket(
    customer_name: str,
    issue_type: str,
    description: str,
    priority: str = "normal"
) -> str:
    """创建客服工单"""
    ticket_id = f"TK-{datetime.now().strftime('%Y%m%d%H%M%S')}"
    ticket = {
        "ticket_id": ticket_id,
        "customer_name": customer_name,
        "issue_type": issue_type,
        "description": description,
        "priority": priority,
        "status": "open",
        "created_at": datetime.now().isoformat()
    }
    # 实际场景中存入数据库
    print(f"[Ticket Created] {json.dumps(ticket, ensure_ascii=False)}")
    return f"工单创建成功!工单号: {ticket_id},我们将尽快处理。"


@tool
def check_order_status(order_id: str) -> str:
    """查询订单状态"""
    # 模拟订单查询
    orders = {
        "ORD-20260901": {"status": "已发货", "tracking": "SF1234567890", "eta": "2026-09-17"},
        "ORD-20260905": {"status": "处理中", "tracking": None, "eta": "2026-09-20"},
        "ORD-20260910": {"status": "已签收", "tracking": "SF9876543210", "eta": None},
    }

    if order_id in orders:
        info = orders[order_id]
        result = f"订单号: {order_id}\n状态: {info['status']}"
        if info["tracking"]:
            result += f"\n物流单号: {info['tracking']}"
        if info["eta"]:
            result += f"\n预计到达: {info['eta']}"
        return result

    return f"未找到订单号 {order_id},请确认订单号是否正确"


# 创建 LLM 实例
llm = ChatOpenAI(
    model="gpt-4o",
    temperature=0.3,
    api_key=os.environ.get("OPENAI_API_KEY")
)

# 绑定工具
llm_with_tools = llm.bind_tools(
    [search_knowledge_base, create_support_ticket, check_order_status]
)

# 系统提示词
SYSTEM_PROMPT = """你是一个专业的客服助手 Agent。你可以:

1. 搜索知识库回答常见问题(使用 search_knowledge_base 工具)
2. 查询订单状态(使用 check_order_status 工具)
3. 创建客服工单(使用 create_support_ticket 工具)

工作流程:
- 先判断用户意图
- 如果是常见问题,搜索知识库
- 如果是订单问题,查询订单状态
- 如果需要人工介入,创建工单
- 始终用友好、专业的语气回复

注意:创建工单前必须确认用户信息,不要随意填写。
"""


# 创建 CopilotKit Agent
def create_agent():
    """创建 AG-UI 兼容的 Agent"""
    from langgraph.prebuilt import create_react_agent

    agent = create_react_agent(
        llm,
        tools=[search_knowledge_base, create_support_ticket, check_order_status],
        prompt=SYSTEM_PROMPT,
    )
    return agent

python

# backend/main.py
"""
AG-UI Agent FastAPI 服务端
通过 CopilotKit SDK 将 Agent 暴露为 AG-UI 端点
"""

import os
from dotenv import load_dotenv
from fastapi import FastAPI
from copilotkit.integrations.fastapi import add_fastapi_endpoint
from copilotkit import CopilotKitSDK, LangGraphAgent

from agent import create_agent

load_dotenv()

app = FastAPI(title="AG-UI Customer Service Agent")

# 创建 Agent 实例
agent = create_agent()

# 初始化 CopilotKit SDK
sdk = CopilotKitSDK(
    agents=[
        LangGraphAgent(
            name="customer_service_agent",
            agent=agent,
            description="客服助手 Agent,支持知识库查询、订单查询、工单创建",
        )
    ]
)

# 添加 AG-UI 端点
add_fastapi_endpoint(app, sdk, "/api/copilotkit")

# 健康检查
@app.get("/health")
async def health():
    return {"status": "ok", "protocol": "AG-UI"}


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(
        "main:app",
        host="0.0.0.0",
        port=8000,
        reload=True
    )

6.3 前端:React + CopilotKit

json

// frontend/package.json
{
  "name": "ag-ui-frontend",
  "private": true,
  "version": "0.0.1",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build"
  },
  "dependencies": {
    "@copilotkit/react-core": "^1.3.0",
    "@copilotkit/react-ui": "^1.3.0",
    "@copilotkit/runtime-client-http": "^1.3.0",
    "react": "^18.3.0",
    "react-dom": "^18.3.0"
  },
  "devDependencies": {
    "@types/react": "^18.3.0",
    "@types/react-dom": "^18.3.0",
    "@vitejs/plugin-react": "^4.3.0",
    "typescript": "^5.5.0",
    "vite": "^5.4.0"
  }
}

tsx

// frontend/src/App.tsx
import { CopilotKit } from "@copilotkit/react-core";
import { CopilotPopup } from "@copilotkit/react-ui";
import "@copilotkit/react-ui/styles.css";
import { ProgressPanel } from "./components/ProgressPanel";
import { AgentChat } from "./components/AgentChat";

function App() {
  return (
    <CopilotKit runtimeUrl="http://localhost:8000/api/copilotkit">
      <div className="app-container">
        <header className="app-header">
          <h1>AG-UI 智能客服</h1>
          <span className="protocol-badge">AG-UI Protocol</span>
        </header>
        <main className="app-main">
          <div className="chat-area">
            <AgentChat />
          </div>
          <aside className="side-panel">
            <ProgressPanel />
          </aside>
        </main>
        <CopilotPopup
          instructions="你是一个专业的客服助手,帮助用户解决问题。"
          labels={{
            title: "客服助手",
            initial: "你好!有什么可以帮你的?"
          }}
        />
      </div>
    </CopilotKit>
  );
}

export default App;

tsx

// frontend/src/components/AgentChat.tsx
import { useAgent } from "@copilotkit/react-core";
import { useEffect, useState } from "react";

interface StepInfo {
  name: string;
  status: "running" | "finished" | "error";
}

interface ToolCallInfo {
  name: string;
  args: string;
  status: "started" | "finished";
}

export function AgentChat() {
  const { agent } = useAgent({ agentId: "customer_service_agent" });

  const [streamingText, setStreamingText] = useState("");
  const [steps, setSteps] = useState<StepInfo[]>([]);
  const [toolCalls, setToolCalls] = useState<ToolCallInfo[]>([]);
  const [agentState, setAgentState] = useState<Record<string, any>>({});

  useEffect(() => {
    if (!agent) return;

    const subscription = agent.subscribe({
      // 监听所有事件
      onEvent({ event }) {
        console.log("[AG-UI Event]", event.type, event);
      },

      // 流式文本
      onTextMessageContentEvent({ event, textMessageBuffer }) {
        setStreamingText(textMessageBuffer);
      },

      // 步骤追踪
      onStepStartedEvent({ event }) {
        setSteps(prev => [
          ...prev,
          { name: event.step_name, status: "running" }
        ]);
      },

      onStepFinishedEvent({ event }) {
        setSteps(prev =>
          prev.map(s =>
            s.name === event.step_name
              ? { ...s, status: "finished" }
              : s
          )
        );
      },

      // 工具调用
      onToolCallStartEvent({ event, toolCallName }) {
        setToolCalls(prev => [
          ...prev,
          { name: toolCallName, args: "", status: "started" }
        ]);
      },

      onToolCallEndEvent({ event, toolCallName, toolCallArgs }) {
        setToolCalls(prev =>
          prev.map((tc, i) =>
            i === prev.length - 1
              ? { ...tc, args: toolCallArgs, status: "finished" }
              : tc
          )
        );
      },

      // 状态同步
      onStateSnapshotEvent({ event, agent }) {
        setAgentState(agent.state);
      },

      // 运行完成
      onRunFinishedEvent({ event }) {
        console.log("Agent run finished:", event.run_id);
      },
    });

    return () => subscription.unsubscribe();
  }, [agent]);

  return (
    <div className="agent-chat">
      {/* 流式文本输出 */}
      {streamingText && (
        <div className="streaming-text">
          <div className="avatar">🤖</div>
          <div className="message">{streamingText}</div>
        </div>
      )}

      {/* 步骤追踪 */}
      {steps.length > 0 && (
        <div className="steps-tracker">
          <h4>执行步骤</h4>
          {steps.map((step, i) => (
            <div key={i} className={`step step-${step.status}`}>
              {step.status === "running" ? "⏳" : "✅"} {step.name}
            </div>
          ))}
        </div>
      )}

      {/* 工具调用展示 */}
      {toolCalls.length > 0 && (
        <div className="tool-calls">
          <h4>工具调用</h4>
          {toolCalls.map((tc, i) => (
            <div key={i} className={`tool-call tc-${tc.status}`}>
              <span>{tc.status === "started" ? "🔧" : "✅"}</span>
              <span className="tool-name">{tc.name}</span>
              {tc.args && (
                <pre className="tool-args">{tc.args}</pre>
              )}
            </div>
          ))}
        </div>
      )}

      {/* Agent 状态 */}
      {Object.keys(agentState).length > 0 && (
        <div className="agent-state">
          <h4>Agent 状态</h4>
          <pre>{JSON.stringify(agentState, null, 2)}</pre>
        </div>
      )}
    </div>
  );
}

tsx

// frontend/src/components/ProgressPanel.tsx
import { useAgent } from "@copilotkit/react-core";
import { useEffect, useState } from "react";

export function ProgressPanel() {
  const { agent } = useAgent({ agentId: "customer_service_agent" });
  const [isRunning, setIsRunning] = useState(false);
  const [lastActivity, setLastActivity] = useState<string>("");

  useEffect(() => {
    if (!agent) return;

    const subscription = agent.subscribe({
      onRunStartedEvent() {
        setIsRunning(true);
        setLastActivity("Agent 开始运行...");
      },

      onRunFinishedEvent() {
        setIsRunning(false);
        setLastActivity("Agent 运行完成");
      },

      onRunErrorEvent({ event }) {
        setIsRunning(false);
        setLastActivity(`运行错误: ${event.message}`);
      },

      onToolCallStartEvent({ toolCallName }) {
        setLastActivity(`调用工具: ${toolCallName}`);
      },

      onStepStartedEvent({ event }) {
        setLastActivity(`开始步骤: ${event.step_name}`);
      },
    });

    return () => subscription.unsubscribe();
  }, [agent]);

  return (
    <div className="progress-panel">
      <h3>Agent 监控面板</h3>
      <div className="status-row">
        <span>状态:</span>
        <span className={isRunning ? "status-running" : "status-idle"}>
          {isRunning ? "运行中" : "空闲"}
        </span>
      </div>
      <div className="activity-row">
        <span>最近活动:</span>
        <span>{lastActivity || "等待输入..."}</span>
      </div>
      <div className="message-count">
        消息数: {agent?.messages?.length ?? 0}
      </div>
    </div>
  );
}

6.4 Docker 部署

yaml

# docker-compose.yml
version: '3.8'

services:
  backend:
    build: ./backend
    ports:
      - "8000:8000"
    environment:
      - OPENAI_API_KEY=${OPENAI_API_KEY}
    volumes:
      - ./backend:/app
    command: uvicorn main:app --host 0.0.0.0 --port 8000 --reload

  frontend:
    build: ./frontend
    ports:
      - "5173:5173"
    volumes:
      - ./frontend:/app
      - /app/node_modules
    command: npm run dev -- --host
    depends_on:
      - backend

7. 实战2:将 LangGraph Agent 通过 AG-UI 接入前端

这个实战展示如何将已有的 LangGraph Agent 改造为 AG-UI 兼容端点,重点展示事件流的精细控制。

7.1 自定义 LangGraph Agent

python

# backend/research_agent.py
"""
研究型 LangGraph Agent
支持多步骤研究、实时进度汇报、中间结果预览
通过 AG-UI 事件流与前端实时交互
"""

import os
import json
import asyncio
from typing import TypedDict, Annotated, Sequence
from datetime import datetime

from langchain_openai import ChatOpenAI
from langchain_core.messages import BaseMessage, SystemMessage, HumanMessage, AIMessage
from langgraph.graph import StateGraph, END
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode

from copilotkit.integrations.fastapi import add_fastapi_endpoint
from copilotkit import CopilotKitSDK, LangGraphAgent


# --- 定义状态 ---
class ResearchState(TypedDict):
    messages: Annotated[Sequence[BaseMessage], add_messages]
    research_topic: str
    findings: list[str]
    current_phase: str   # "planning" | "searching" | "analyzing" | "synthesizing"
    progress: float       # 0.0 ~ 1.0


# --- 定义工具 ---
from langchain_core.tools import tool

@tool
def web_search(query: str) -> str:
    """搜索互联网获取信息"""
    # 模拟搜索结果
    mock_results = {
        "AI Agent": "AI Agent 市场预计 2026 年达到 50 亿美元,年增长率 45%。主要玩家包括 OpenAI、Anthropic、Google。",
        "MCP协议": "MCP(Model Context Protocol)由 Anthropic 提出,已有 1000+ 服务器实现,覆盖主流 SaaS 平台。",
        "AG-UI": "AG-UI 是 CopilotKit 提出的 Agent-用户交互协议,GitHub 星标 9000+,支持 7 种 SDK 语言。",
    }

    results = []
    for key, value in mock_results.items():
        if key.lower() in query.lower() or query.lower() in key.lower():
            results.append(value)

    if not results:
        return f"搜索 '{query}' 暂无直接结果,建议缩小搜索范围。"

    return "\n".join(results)


@tool
def analyze_data(data_description: str) -> str:
    """分析数据并生成洞察"""
    return f"数据分析完成:{data_description}\n关键发现:趋势向上,但存在季节性波动。建议持续监控。"


@tool
def generate_report(topic: str, findings: str) -> str:
    """生成研究报告"""
    return f"""## {topic} 研究报告

### 摘要
{findings}

### 建议
1. 持续关注市场动态
2. 建立技术评估框架
3. 制定分阶段实施计划

---
报告生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M')}
"""


# --- 定义节点 ---
llm = ChatOpenAI(model="gpt-4o", temperature=0.2)
tools = [web_search, analyze_data, generate_report]
llm_with_tools = llm.bind_tools(tools)


def planning_node(state: ResearchState) -> dict:
    """规划研究步骤"""
    messages = state["messages"]
    topic = messages[-1].content if messages else ""

    prompt = f"""你是一个研究助手。用户想要研究:{topic}

请制定一个研究计划,包括:
1. 需要搜索哪些信息
2. 需要分析哪些数据
3. 最终生成什么样的报告

用简洁的格式列出研究步骤。"""

    response = llm.invoke([
        SystemMessage(content=prompt),
        HumanMessage(content=topic)
    ])

    return {
        "messages": [response],
        "research_topic": topic,
        "current_phase": "searching",
        "progress": 0.2
    }


def research_node(state: ResearchState) -> dict:
    """执行研究搜索"""
    findings = state.get("findings", [])

    # 使用工具进行搜索
    response = llm_with_tools.invoke(state["messages"])

    # 提取搜索结果
    if hasattr(response, "tool_calls") and response.tool_calls:
        for tc in response.tool_calls:
            findings.append(f"[{tc['name']}] 已执行搜索")

    return {
        "messages": [response],
        "findings": findings,
        "current_phase": "analyzing",
        "progress": 0.5
    }


def analysis_node(state: ResearchState) -> dict:
    """分析研究结果"""
    findings_text = "\n".join(state.get("findings", []))

    prompt = f"""基于以下研究结果,进行深度分析:

{findings_text}

请总结关键洞察和趋势。"""

    response = llm.invoke([
        SystemMessage(content=prompt),
        *state["messages"]
    ])

    return {
        "messages": [response],
        "current_phase": "synthesizing",
        "progress": 0.8
    }


def synthesis_node(state: ResearchState) -> dict:
    """综合生成报告"""
    findings_text = "\n".join(state.get("findings", []))
    topic = state.get("research_topic", "")

    response = llm_with_tools.invoke([
        SystemMessage(content="请根据研究结果生成最终报告。使用 generate_report 工具。"),
        *state["messages"],
        HumanMessage(content=f"请为 '{topic}' 生成完整研究报告。关键发现:{findings_text}")
    ])

    return {
        "messages": [response],
        "current_phase": "completed",
        "progress": 1.0
    }


# --- 构建图 ---
def should_continue(state: ResearchState) -> str:
    """决定下一步"""
    phase = state.get("current_phase", "")
    if phase == "searching":
        return "research"
    elif phase == "analyzing":
        return "analysis"
    elif phase == "synthesizing":
        return "synthesis"
    return END


# 创建 LangGraph
workflow = StateGraph(ResearchState)

# 添加节点
workflow.add_node("planning", planning_node)
workflow.add_node("research", research_node)
workflow.add_node("analysis", analysis_node)
workflow.add_node("synthesis", synthesis_node)
workflow.add_node("tools", ToolNode(tools))

# 设置边
workflow.set_entry_point("planning")
workflow.add_conditional_edges("planning", should_continue)
workflow.add_edge("research", "tools")
workflow.add_edge("tools", "analysis")
workflow.add_edge("analysis", "synthesis")
workflow.add_edge("synthesis", END)

# 编译
research_agent = workflow.compile()

7.2 注册到 AG-UI

python

# backend/research_main.py
"""
研究 Agent 的 AG-UI 服务端
"""

from fastapi import FastAPI
from copilotkit.integrations.fastapi import add_fastapi_endpoint
from copilotkit import CopilotKitSDK, LangGraphAgent
from research_agent import research_agent

app = FastAPI(title="AG-UI Research Agent")

sdk = CopilotKitSDK(
    agents=[
        LangGraphAgent(
            name="research_agent",
            agent=research_agent,
            description="研究助手 Agent,支持多步骤研究、数据分析、报告生成",
        )
    ]
)

add_fastapi_endpoint(app, sdk, "/api/copilotkit")

if __name__ == "__main__":
    import uvicorn
    uvicorn.run("research_main:app", host="0.0.0.0", port=8001, reload=True)

7.3 前端订阅研究进度

tsx

// 前端监听研究 Agent 的进度
import { useAgent } from "@copilotkit/react-core";
import { useEffect, useState } from "react";

interface ResearchProgress {
  phase: string;
  progress: number;
  findings: string[];
}

export function ResearchTracker() {
  const { agent } = useAgent({ agentId: "research_agent" });
  const [progress, setProgress] = useState<ResearchProgress>({
    phase: "idle",
    progress: 0,
    findings: []
  });

  useEffect(() => {
    if (!agent) return;

    const subscription = agent.subscribe({
      // 监听状态快照 - 获取研究进度
      onStateSnapshotEvent({ agent }) {
        setProgress({
          phase: agent.state?.current_phase ?? "idle",
          progress: agent.state?.progress ?? 0,
          findings: agent.state?.findings ?? []
        });
      },

      // 监听状态增量更新
      onStateDeltaEvent({ event }) {
        // 根据 JSON Patch 更新本地状态
        console.log("State delta:", event.delta);
      },

      // 步骤追踪
      onStepStartedEvent({ event }) {
        console.log(`Research step started: ${event.step_name}`);
      },

      onStepFinishedEvent({ event }) {
        console.log(`Research step finished: ${event.step_name}`);
      },

      // 工具调用 - 展示 Agent 在用什么工具
      onToolCallStartEvent({ toolCallName }) {
        console.log(`Tool invoked: ${toolCallName}`);
      },
    });

    return () => subscription.unsubscribe();
  }, [agent]);

  const phaseLabels: Record<string, string> = {
    planning: "📋 规划中",
    searching: "🔍 搜索中",
    analyzing: "📊 分析中",
    synthesizing: "📝 生成报告",
    completed: "✅ 完成"
  };

  return (
    <div className="research-tracker">
      <h3>研究进度</h3>

      {/* 进度条 */}
      <div className="progress-bar">
        <div
          className="progress-fill"
          style={{ width: `${progress.progress * 100}%` }}
        />
      </div>

      {/* 当前阶段 */}
      <div className="phase">
        {phaseLabels[progress.phase] || progress.phase}
      </div>

      {/* 研究发现 */}
      {progress.findings.length > 0 && (
        <div className="findings">
          <h4>研究发现</h4>
          <ul>
            {progress.findings.map((f, i) => (
              <li key={i}>{f}</li>
            ))}
          </ul>
        </div>
      )}
    </div>
  );
}

8. 适用场景 vs 不适用场景

8.1 适用 AG-UI 的场景

plaintext

┌──────────────────────────────────────────────────────────────┐
│  ✅ 适合 AG-UI 的场景                                         │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  1. 用户协作型 Agent                                          │
│     ├─ AI 客服(实时对话 + 工具调用 + 状态更新)                 │
│     ├─ 代码助手(终端协作 + 文件编辑 + 运行结果)               │
│     └─ 数据分析师(进度汇报 + 图表渲染 + 中间预览)             │
│                                                              │
│  2. 需要中间干预的任务                                         │
│     ├─ Human-in-the-loop 审批流程                              │
│     ├─ 敏感操作确认(删除、支付、发布)                         │
│     └─ 多步骤任务的检查点恢复                                  │
│                                                              │
│  3. 多 Agent 编排场景                                          │
│     ├─ Agent 团队协作,用户需要看到整体进度                     │
│     ├─ 子 Agent 结果需要实时展示                               │
│     └─ Agent 间协作 + 用户交互同时存在                         │
│                                                              │
│  4. 需要实时反馈的长时任务                                     │
│     ├─ 大规模代码重构(进度百分比 + 当前文件)                   │
│     ├─ 研究报告生成(阶段展示 + 中间结果预览)                  │
│     └─ 数据 ETL 流程(步骤追踪 + 数据预览)                    │
│                                                              │
│  共同特征:Agent 和用户需要实时协作/通信                         │
│                                                              │
└──────────────────────────────────────────────────────────────┘

8.2 不适用 AG-UI 的场景

plaintext

┌──────────────────────────────────────────────────────────────┐
│  ❌ 不需要 AG-UI 的场景                                        │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  1. 后台批处理任务                                             │
│     ├─ 定时数据同步(无需用户交互)                             │
│     ├─ 日志分析(跑完看结果就行)                               │
│     └─ 批量邮件发送(纯后端执行)                               │
│                                                              │
│  2. 一次性 API 调用                                            │
│     ├─ 简单问答(请求-响应模式足够)                            │
│     ├─ 图片生成(等结果返回即可)                               │
│     └─ 翻译任务(无中间步骤)                                   │
│                                                              │
│  3. 纯后端 Agent-to-Agent 协作                                 │
│     ├─ 不涉及用户界面                                          │
│     ├─ 用 A2A 协议更合适                                      │
│     └─ 无需 SSE 流式推送                                       │
│                                                              │
│  4. 纯工具调用                                                 │
│     ├─ Agent 只需要调 API,不需要和用户交互                     │
│     ├─ 用 MCP 协议更合适                                      │
│     └─ 无需展示中间状态                                       │
│                                                              │
│  判断标准:如果没有"用户需要看到 Agent 在干什么"的需求,         │
│           AG-UI 就是过度设计。                                  │
│                                                              │
└──────────────────────────────────────────────────────────────┘

9. 生态支持现状

据《AG-UI Is Redefining the Agent–User Interaction Layer》和 Microsoft Agent Framework 文档,截至 2026 年中期:

9.1 支持方

表格

公司/组织

角色

具体贡献

CopilotKit

协议发起方

核心 SDK、TypeScript/Python SDK、文档

Google

生态支持方

ADK 官方接入 AG-UI

Microsoft

生态支持方

Agent Framework 集成 AG-UI

AWS

生态支持方

Bedrock AgentCore 集成

Oracle

生态支持方

企业级集成

LangChain

框架支持方

LangGraph Agent 直接接入

Mastra

框架支持方

TypeScript Agent 框架集成

AG2

框架支持方

多 Agent 框架集成

9.2 SDK 语言支持

表格

语言

状态

说明

TypeScript

✅ 稳定

首要支持,CopilotKit 核心

Python

✅ 稳定

LangGraph/CrewAI 集成

Kotlin

✅ 可用

Android 支持

Java

✅ 可用

企业后端

Golang

✅ 可用

高性能后端

Rust

🔄 开发中

社区贡献

C#

✅ 可用

Microsoft Agent Framework

9.3 关键里程碑

plaintext

时间线:
  2025-05 ─── AG-UI 正式发布
  2025-07 ─── CopilotKit $27M A 轮融资
  2025-09 ─── Google ADK 接入
  2025-10 ─── GitHub 9000+ Stars,周安装量 12万
  2025-11 ─── A2A ↔ AG-UI 官方握手
  2026-04 ─── Microsoft Agent Framework 集成
  2026-06 ─── CopilotKit 200万+ 周 Agent-用户交互
  2026-09 ─── 7 种语言 SDK 稳定版

10. 踩坑记录

坑1:SSE 连接在 Nginx 反代下断开

问题: Nginx 默认会缓冲代理响应,导致 SSE 事件被缓存而不是实时推送到前端。

nginx

# ❌ 错误配置 - SSE 会被缓冲
location /api/copilotkit {
    proxy_pass http://backend:8000;
}

# ✅ 正确配置 - 禁用缓冲,启用长连接
location /api/copilotkit {
    proxy_pass http://backend:8000;
    proxy_http_version 1.1;
    proxy_set_header Connection '';
    proxy_buffering off;
    proxy_cache off;
    proxy_read_timeout 86400s;    # SSE 长连接超时
    proxy_send_timeout 86400s;
    chunked_transfer_encoding on;
}

坑2:useAgent Hook 获取不到 agent 实例

问题: 组件挂载时 agent 为 undefined,直接调用 agent.subscribe() 报错。

tsx

// ❌ 错误写法 - agent 可能还没初始化
function MyComponent() {
  const { agent } = useAgent();
  agent.subscribe({ ... });  // TypeError: Cannot read properties of undefined
}

// ✅ 正确写法 - 等待 agent 初始化
function MyComponent() {
  const { agent } = useAgent();

  useEffect(() => {
    if (!agent) return;  // 先判断

    const subscription = agent.subscribe({ ... });
    return () => subscription.unsubscribe();
  }, [agent]);  // 依赖 agent
}

坑3:STATE_DELTA 的 JSON Patch 不生效

问题: 后端发送了 STATE_DELTA 事件,但前端状态没有更新。

原因: JSON Patch 的 path 必须以 / 开头,且路径必须与现有状态结构匹配。

python

# ❌ 错误 - 路径不以 / 开头
{
    "type": "StateDelta",
    "delta": [
        {"op": "replace", "path": "progress", "value": 0.8}
    ]
}

# ✅ 正确 - 路径以 / 开头
{
    "type": "StateDelta",
    "delta": [
        {"op": "replace", "path": "/progress", "value": 0.8}
    ]
}

# ❌ 错误 - 向不存在的数组添加元素用 add
# 如果 files_processed 不存在,需要先创建
{
    "type": "StateDelta",
    "delta": [
        {"op": "add", "path": "/files_processed/-", "value": "new.csv"}
    ]
}

# ✅ 正确 - 确保先有 StateSnapshot 初始化状态
# 先发送 StateSnapshot 创建完整状态结构
# 再发送 StateDelta 做增量更新

坑4:多 Agent 场景下事件流混淆

问题: 多个 Agent 同时运行,前端收到的事件无法区分来自哪个 Agent。

tsx

// ❌ 错误 - 全局监听不区分 Agent
const { agent } = useAgent();  // 默认获取第一个 agent
agent.subscribe({
  onEvent({ event }) {
    // 无法区分事件来源
  }
});

// ✅ 正确 - 用 agentId 指定特定 Agent
const { agent: researchAgent } = useAgent({ agentId: "research_agent" });
const { agent: supportAgent } = useAgent({ agentId: "support_agent" });

useEffect(() => {
  if (!researchAgent) return;
  const sub = researchAgent.subscribe({
    onEvent({ event }) {
      console.log("Research agent event:", event);
    }
  });
  return () => sub.unsubscribe();
}, [researchAgent]);

坑5:Human-in-the-Loop 实现不当导致死锁

问题: Agent 等待用户审批,但前端没有正确发送审批响应,导致 Agent 永远挂起。

python

# ❌ 错误 - 没有超时处理
@tool
def delete_user(user_id: str) -> str:
    """删除用户 - 需要审批"""
    # 如果前端不响应审批,这里永远阻塞
    approval = wait_for_approval(user_id)
    if approval:
        return f"用户 {user_id} 已删除"
    return "操作已取消"

# ✅ 正确 - 设置超时 + 默认行为
import asyncio

@tool
def delete_user(user_id: str) -> str:
    """删除用户 - 需要审批"""
    try:
        approval = asyncio.wait_for(
            wait_for_approval(user_id),
            timeout=300  # 5分钟超时
        )
        if approval:
            return f"用户 {user_id} 已删除"
        return "操作已取消"
    except asyncio.TimeoutError:
        return "审批超时,操作已取消(安全默认行为)"

坑6:CORS 配置问题

问题: 前端(localhost:5173)请求后端(localhost:8000)的 AG-UI 端点被 CORS 拦截。

python

# ✅ 正确 - FastAPI 添加 CORS 中间件
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:5173"],  # 开发环境
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
    expose_headers=["Content-Type"],  # SSE 需要暴露的 header
)

坑7:事件顺序依赖导致 UI 闪烁

问题: STATE_SNAPSHOT 和 STATE_DELTA 事件到达顺序不确定,导致 UI 闪烁(先显示旧状态再更新)。

tsx

// ✅ 解决方案 - 用版本号确保事件有序处理
const [stateVersion, setStateVersion] = useState(0);
const [agentState, setAgentState] = useState({});

useEffect(() => {
  if (!agent) return;

  const subscription = agent.subscribe({
    onStateSnapshotEvent({ event }) {
      // 全量快照 - 重置状态
      setAgentState(event.snapshot);
      setStateVersion(v => v + 1);
    },

    onStateDeltaEvent({ event }) {
      // 增量更新 - 应用 JSON Patch
      setAgentState(prev => applyPatch(prev, event.delta));
      setStateVersion(v => v + 1);
    },
  });

  return () => subscription.unsubscribe();
}, [agent]);

11. 总结与展望

AG-UI 解决了什么问题?

AG-UI 的核心价值在于标准化。就像 HTTP 标准化了客户端和服务器的通信一样,AG-UI 标准化了 Agent 和前端的通信。

没有 AG-UI 的世界:

  • 每个 Agent 框架有自己的流式输出格式

  • 前端为每个后端写适配器

  • 工具调用不可见,状态同步靠猜测

  • Human-in-the-loop 需要自己实现全套

有 AG-UI 的世界:

  • 统一的事件流模型,一套代码适配所有后端

  • 工具调用、状态更新、进度汇报都有标准事件

  • Human-in-the-loop 是协议原生支持

  • 切换后端框架(LangGraph → CrewAI)前端零改动

局限性

  1. 协议还年轻:2025年5月才发布,部分场景的事件定义还在迭代

  2. 生态覆盖不均:TypeScript/Python SDK 成熟,其他语言相对滞后

  3. 性能瓶颈:SSE 在极端高并发场景下不如 WebSocket 灵活

  4. 调试工具缺失:事件流的调试目前主要靠 console.log,缺乏可视化工具

展望

据 CopilotKit 团队的规划,AG-UI 接下来的重点方向是:

  • Rust SDK:高性能后端场景

  • 更深的 MCP 集成:AG-UI 事件流中直接嵌入 MCP 工具发现和调用

  • 多模态事件:图片、音频、视频的流式交互事件

  • 协作编辑:Agent 和用户同时编辑同一文档的状态同步

AG-UI 是 Agent 生态从"能用"到"好用"的关键一环。当 Agent 需要和人协作时,一个标准化的交互协议不再是锦上添花,而是基础设施。

——PySuper | zhengxingtao.com

参考链接:

0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区