OpenGenerativeUI - 完整学习教程

OpenGenerativeUI - 完整学习教程

教程级别: 从零到一 预计学习时间: 8-10 小时 前置知识: React 基础、Next.js 基础、TypeScript 基础、命令行操作 技术版本: 基于 GitHub 主分支(截至 2026-04-07 最后推送)


环境搭建指南

系统要求

  • 操作系统: macOS、Linux 或 Windows(WSL2 推荐)
  • Node.js: >= 20.0.0(推荐使用 LTS 版本)
  • 包管理器: pnpm >= 8.0.0(项目使用 Turborepo + pnpm 管理)
  • Git: >= 2.30
  • 浏览器: Chrome/Edge/Firefox 最新版
  • LLM API Key: 需要至少一个支持的模型 API Key(OpenAI、Anthropic 或 Google)

安装步骤

# 第一步:克隆仓库
git clone https://github.com/CopilotKit/OpenGenerativeUI.git
cd OpenGenerativeUI

# 第二步:运行一键设置脚本(安装依赖 + 初始化配置)
make setup

# 第三步:配置环境变量
# 编辑 app/.env 文件,填入你的 API Key

app/.env 配置示例:

# 必填:至少配置一个 LLM API Key
OPENAI_API_KEY=sk-your-openai-key-here
# 或
ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here
# 或
GOOGLE_API_KEY=your-google-key-here

# CopilotKit 运行时地址(默认值,通常无需修改)
NEXT_PUBLIC_COPILOT_RUNTIME_URL=http://localhost:3000/api/copilotkit

# Agent 服务地址(默认值)
COPILOT_AGENT_URL=http://localhost:8123

agent/.env 配置示例:

# Agent 使用的 LLM 模型
MODEL_NAME=openai/gpt-4o

# 对应的 API Key
OPENAI_API_KEY=sk-your-openai-key-here

验证安装

# 启动所有三个应用(前端 + Agent + MCP 服务器)
make dev

预期输出:

✓ App (Next.js)   → http://localhost:3000
✓ Agent (LangGraph) → http://localhost:8123
✓ MCP Server      → running on configured port

打开浏览器访问 http://localhost:3000,应看到一个带有聊天界面的页面。在聊天框中输入"画一个柱状图",如果 Agent 正确响应并生成图表可视化,说明环境搭建成功。


第一部分:入门篇

1.1 理解生成式 UI(Generative UI)

概念讲解:

生成式 UI(Generative UI)是一种 UI 模式,用户界面的部分或全部由 AI Agent 在运行时动态生成,而非由开发者预先编写。传统 AI 聊天只能输出文本,而生成式 UI 让 Agent 能直接生成交互式组件(图表、动画、表单等)。

OpenGenerativeUI 支持三种生成式 UI 模式,控制权从高到低:

  1. 静态生成式 UI(AG-UI) — 开发者预定义 UI 组件,Agent 只选择显示哪个组件并填充数据。安全性最高。
  2. 声明式生成式 UI(A2UI/Open-JSON-UI) — Agent 返回结构化的 UI 描述(JSON 格式),前端按规范渲染。灵活性与安全性的平衡。
  3. 开放式生成式 UI(MCP Apps) — Agent 返回完整的 HTML/代码,前端在沙箱中直接渲染。灵活性最高。

代码示例:(静态模式 — 基于 CopilotKit 官方文档)

// app/components/WeatherTool.tsx
// 基于 CopilotKit 官方文档
// 使用 useFrontendTool 注册一个前端工具,Agent 可调用并触发预定义的天气卡片渲染

"use client";

import { useFrontendTool } from "@copilotkit/react";
import { z } from "zod";

// 预定义的天气卡片组件
function WeatherCard({ location, temperature, conditions }: {
  location: string;
  temperature: number;
  conditions: string;
}) {
  return (
    <div className="rounded-lg border p-4 shadow-sm">
      <h3 className="text-lg font-semibold">{location}</h3>
      <p className="text-3xl font-bold">{temperature}°C</p>
      <p className="text-gray-500">{conditions}</p>
    </div>
  );
}

// 加载状态组件
function LoadingCard({ location }: { location?: string }) {
  return (
    <div className="rounded-lg border p-4 animate-pulse">
      <p>正在获取 {location || "天气数据"}...</p>
    </div>
  );
}

export function WeatherTool() {
  // 注册前端工具,Agent 可以调用 get_weather
  useFrontendTool({
    name: "get_weather",
    description: "获取指定城市的当前天气信息",
    parameters: z.object({
      location: z.string().describe("城市名称,如'北京'或'Tokyo'"),
    }),
    handler: async ({ location }) => {
      // 模拟天气 API 调用
      await new Promise((resolve) => setTimeout(resolve, 500));
      return JSON.stringify({
        location,
        temperature: 22,
        conditions: "晴天",
      });
    },
    render: ({ status, args, result }) => {
      // 根据工具执行状态渲染不同的 UI
      if (status === "inProgress" || status === "executing") {
        return <LoadingCard location={args?.location} />;
      }
      if (status === "complete" && result) {
        const data = JSON.parse(result);
        return (
          <WeatherCard
            location={data.location}
            temperature={data.temperature}
            conditions={data.conditions}
          />
        );
      }
      return <></>;
    },
  });

  return null;
}

执行结果:(用户在聊天框输入"北京天气怎么样?"后)

┌─────────────────────┐
│ 北京                 │
│ 22°C                │
│ 晴天                │
└─────────────────────┘

Agent 调用了 get_weather 工具,前端自动渲染了预定义的 WeatherCard 组件。

练习题: 1. 修改 WeatherCard 组件,增加湿度和风速显示字段 2. 尝试注册一个新的 get_time 工具,返回当前时间并用自定义组件渲染


1.2 理解三应用架构

概念讲解:

OpenGenerativeUI 使用 Turborepo monorepo 管理 three 个独立应用,每个应用有明确的职责划分:

  • app/(前端应用) — Next.js 16 应用,负责用户界面和 CopilotKit 集成。端口 3000
  • agent/(Agent 后端) — LangGraph Deep Agent,负责 AI 推理和代码生成。端口 8123
  • mcp/(MCP 服务器) — 提供 MCP 协议工具和资源,支持外部集成

三个应用通过 AG-UI 协议(前端 ↔ Agent)和 MCP 协议(Agent ↔ MCP 服务器)协同工作。

代码示例:(查看项目目录结构)

# 查看 OpenGenerativeUI 的目录结构
cd OpenGenerativeUI
find . -maxdepth 3 -type f -name "*.ts" -o -name "*.tsx" -o -name "*.py" | head -30

执行结果:

./app/page.tsx
./app/layout.tsx
./app/components/GenerativeUI.tsx
./app/api/copilotkit/route.ts
./agent/main.py
./agent/skills/advanced-visualization/SKILL.md
./agent/skills/master-playbook/SKILL.md
./agent/skills/svg-diagrams/SKILL.md
./mcp/server.py
./mcp/tools/assemble_document.py

练习题: 1. 打开 agent/skills/advanced-visualization/SKILL.md,阅读其中的决策矩阵内容 2. 查看 app/api/copilotkit/route.ts,找到 CopilotKit 运行时的配置


第二部分:进阶篇

2.1 SKILL.md 技能系统与决策矩阵

详细讲解:

OpenGenerativeUI 的 Agent 通过 SKILL.md 文件定义技能。每个技能是一个 Markdown 文件,包含技能描述、适用场景、决策矩阵和渲染策略。Agent 在推理时读取这些技能文件,根据用户需求选择最优的可视化方案。

advanced-visualization 技能是核心技能,它包含一个将 22 种视觉输出类型映射到最优渲染技术的决策矩阵。

代码示例:(创建自定义技能文件)

<!-- agent/skills/custom-charts/SKILL.md -->
<!-- 基于官方 advanced-visualization 技能格式 -->

# Custom Charts 技能

## 描述
根据用户的数据描述生成交互式图表,支持柱状图、折线图、饼图和散点图。

## 适用场景
- 用户要求展示数据对比 → 柱状图
- 用户要求展示趋势变化 → 折线图
- 用户要求展示占比分布 → 饼图
- 用户要求展示数据相关性 → 散点图

## 决策矩阵
| 用户意图关键词 | 推荐图表类型 | 渲染技术 | 理由 |
|---------------|-------------|---------|------|
| 对比、比较、排名 | 柱状图 | Recharts BarChart | 直观展示数值差异 |
| 趋势、变化、增长 | 折线图 | Recharts LineChart | 清晰展示时间序列 |
| 占比、比例、分布 | 饼图 | Recharts PieChart | 直观展示整体与部分 |
| 关联、关系、相关 | 散点图 | Recharts ScatterChart | 展示两个变量的关系 |

## 渲染策略
1. 分析用户意图,提取关键词
2. 匹配决策矩阵,确定图表类型
3. 从用户描述中提取数据
4. 使用 Recharts 生成完整的 React 组件代码
5. 确保图表支持交互(hover 提示、点击详情)

## 代码模板
生成图表时使用以下结构:
- 导入 Recharts 组件
- 定义数据数组
- 配置 ResponsiveContainer 包裹
- 添加 Tooltip 和 Legend
- 使用项目配色方案(明暗主题自适应)

注意事项: - SKILL.md 文件必须放在 agent/skills/ 目录下,目录名即为技能名 - 技能名称只能使用小写字母、数字和连字符 - 决策矩阵中的渲染技术必须是项目中已安装的库(Recharts、Three.js、D3.js 等) - 技能文件会在 Agent 启动时加载,修改后需重启 Agent 服务

练习题: 1. 在 agent/skills/ 目录下创建一个 math-formula 技能,使用 KaTeX 渲染数学公式 2. 为 custom-charts 技能添加面积图(Area Chart)的决策规则


2.2 沙箱化 iframe 渲染机制

详细讲解:

当用户请求生成可视化时,Agent 生成的 HTML/SVG/JavaScript 代码会在一个独立的沙箱化 iframe 中渲染。这个机制确保:

  1. 安全隔离 — AI 生成的代码无法访问主应用的 DOM、Cookie 或 localStorage
  2. 样式隔离 — 生成的 CSS 不会污染主应用的样式
  3. 主题适配 — iframe 自动检测主应用的明暗主题并应用对应样式
  4. 响应式尺寸 — iframe 会根据生成内容自动调整大小

代码示例:(基于官方沙箱渲染器简化版)

// app/components/SandboxRenderer.tsx
// 基于 OpenGenerativeUI README 描述的渲染机制
// 简化的沙箱渲染器实现

"use client";

import { useEffect, useRef, useState } from "react";

interface SandboxRendererProps {
  // AI 生成的 HTML 代码
  htmlContent: string;
  // 是否启用渐进式揭示动画
  enableAnimation?: boolean;
}

export function SandboxRenderer({
  htmlContent,
  enableAnimation = true,
}: SandboxRendererProps) {
  const iframeRef = useRef<HTMLIFrameElement>(null);
  const [isVisible, setIsVisible] = useState(!enableAnimation);

  // 渐进式揭示动画:内容加载后渐入显示
  useEffect(() => {
    if (enableAnimation && htmlContent) {
      const timer = setTimeout(() => setIsVisible(true), 100);
      return () => clearTimeout(timer);
    }
  }, [enableAnimation, htmlContent]);

  // 检测系统主题偏好,传递给 iframe
  useEffect(() => {
    if (!iframeRef.current) return;
    const darkMode = window.matchMedia("(prefers-color-scheme: dark)").matches;
    const theme = darkMode ? "dark" : "light";

    // 向 iframe 注入主题变量
    iframeRef.current.contentWindow?.postMessage(
      { type: "theme-update", theme },
      "*"
    );
  }, [htmlContent]);

  return (
    <div
      className={`sandbox-container transition-opacity duration-500 ${
        isVisible ? "opacity-100" : "opacity-0"
      }`}
    >
      <iframe
        ref={iframeRef}
        srcDoc={htmlContent}
        sandbox="allow-scripts allow-same-origin"
        className="w-full border-0 rounded-lg"
        title="AI Generated Visualization"
      />
    </div>
  );
}

执行结果:(当 Agent 生成一个 SVG 柱状图时)

┌──────────────────────────────────────┐
│  (iframe 沙箱)                       │
│                                      │
│  ██                                  │
│  ██  ██                              │
│  ██  ██      ██                      │
│  ██  ██  ██  ██                      │
│  ██  ██  ██  ██  ██                  │
│  Q1  Q2  Q3  Q4                      │
│                                      │
└──────────────────────────────────────┘

注意事项: - sandbox 属性必须包含 allow-scripts,否则生成的 JavaScript 无法执行 - allow-same-origin 允许 iframe 访问主题信息,但要注意安全边界 - 生成内容的大小不可预测,建议使用 min-heightmax-height 限制 iframe 尺寸 - 大量同时渲染的 iframe 会消耗浏览器资源,建议限制同时显示的数量

练习题: 1. 为 SandboxRenderer 添加错误边界处理,当生成内容包含无效 HTML 时显示错误提示 2. 实现一个 resize 监听器,让 iframe 高度根据内容自动调整


第三部分:高级篇

3.1 集成 LangGraph Deep Agent

OpenGenerativeUI 的 Agent 层使用 LangChain Deep Agents + LangGraph 构建。LangGraph 管理多步骤推理流程,根据用户需求自动选择和组合技能。

代码示例:(Agent 入口配置 — 基于 OpenGenerativeUI README)

# agent/main.py
# 基于 OpenGenerativeUI README 中的 Agent 配置
# LangGraph Deep Agent 入口配置

from langchain_deep_agents import DeepAgent
from langgraph.graph import StateGraph

# 加载技能定义
from skills.advanced_visualization import AdvancedVisualizationSkill
from skills.master_playbook import MasterPlaybookSkill
from skills.svg_diagrams import SVGRDiagramsSkill

# 创建 Deep Agent 实例
agent = DeepAgent(
    model="openai/gpt-4o",
    skills=[
        AdvancedVisualizationSkill(),
        MasterPlaybookSkill(),
        SVGRDiagramsSkill(),
    ],
)

# 构建状态图
graph = StateGraph(agent.get_state_schema())

# 添加节点:意图分析 → 技能选择 → 代码生成 → 质量检查
graph.add_node("analyze_intent", agent.analyze_intent)
graph.add_node("select_skill", agent.select_skill)
graph.add_node("generate_code", agent.generate_code)
graph.add_node("quality_check", agent.quality_check)

# 定义执行边
graph.add_edge("analyze_intent", "select_skill")
graph.add_edge("select_skill", "generate_code")
graph.add_edge("generate_code", "quality_check")

# 编译并运行
app = graph.compile()

注意事项: - Agent 的模型选择直接影响生成质量。gpt-4o 是最低推荐配置,gpt-5.4 效果最佳 - 技能加载顺序不影响选择逻辑,Agent 会根据用户意图自动匹配 - LangGraph 的状态图可以添加条件边,实现更复杂的推理流程 - Agent 配置修改后需要重启 agent 服务(make dev 会自动重启)


3.2 MCP 服务器与工具集成

MCP(Model Context Protocol)服务器是 OpenGenerativeUI 的第三个应用,提供标准化的工具和资源接口。

代码示例:(自定义 MCP 工具)

# mcp/tools/custom_tool.py
# 基于 MCP 协议规范
# 自定义 MCP 工具示例:数据聚合工具

from mcp.server import Server
from mcp.types import Tool, TextContent

server = Server("custom-tools")

@server.tool()
async def aggregate_data(
    source: str,
    metric: str,
    time_range: str,
) -> list[TextContent]:
    """
    聚合指定数据源的指标数据。

    参数:
        source: 数据源名称(如 'sales', 'traffic', 'users')
        metric: 聚合指标(如 'sum', 'average', 'count')
        time_range: 时间范围(如 '7d', '30d', '90d')

    返回:
        聚合后的数据,供 Agent 生成可视化图表
    """
    # 模拟数据聚合逻辑
    mock_data = {
        "sales": {"7d": [120, 150, 180, 140, 200, 170, 190]},
        "traffic": {"7d": [5000, 6200, 7100, 5800, 8000, 7500, 6900]},
        "users": {"7d": [50, 62, 71, 58, 80, 75, 69]},
    }

    data = mock_data.get(source, {}).get(time_range, [])

    return [
        TextContent(
            type="text",
            text=f"数据源: {source}, 指标: {metric}, "
            f"时间范围: {time_range}, 数据: {data}",
        )
    ]

注意事项: - MCP 工具的参数描述会被传递给 LLM,描述越清晰,Agent 调用越准确 - 工具返回的数据格式建议使用 JSON 字符串,便于 Agent 解析和生成可视化 - MCP 服务器默认在 make dev 时自动启动,端口可在 mcp/.env 中配置 - 工具修改后需重启 MCP 服务器


3.3 最佳实践

  1. 选择合适的生成式 UI 模式 — 安全性要求高用静态 AG-UI(预定义组件),灵活性要求高用开放式 MCP Apps,介于两者之间用声明式 A2UI
  2. 优化 API 成本 — 对重复的查询结果实施缓存,减少 LLM 调用次数;对简单图表使用模板化生成替代完全由 LLM 生成
  3. 限制沙箱权限 — 仅开放必要的 iframe sandbox 权限(allow-scripts),避免开放 allow-top-navigation 等高风险权限
  4. 技能设计原则 — 每个 SKILL.md 技能应聚焦单一领域,决策矩阵要覆盖该领域的主要场景,避免创建过于泛化的技能
  5. 错误处理 — 在 CopilotKit 的 render 函数中始终处理 error 状态,在 Agent 层实现重试机制

第四部分:实战项目

项目需求

构建一个 AI 数据分析仪表盘,用户通过自然语言描述数据需求,系统自动生成对应的可视化图表并展示在仪表盘中。项目综合运用以下知识点:

  1. CopilotKit 前端工具注册(useFrontendTool)— 入门篇 1.1
  2. SKILL.md 技能系统 — 进阶篇 2.1
  3. 沙箱化 iframe 渲染 — 进阶篇 2.2

项目设计

  • 前端: Next.js 页面,包含聊天界面和可视化展示区域
  • Agent: 使用 advanced-visualization 技能生成图表代码
  • 渲染: 通过沙箱化 iframe 安全渲染 AI 生成的图表

完整实现代码

文件一:前端页面组件

// app/dashboard/page.tsx
// 综合运用:知识点1(CopilotKit 前端工具)+ 知识点3(沙箱化渲染)

"use client";

import { useFrontendTool } from "@copilotkit/react"; <!-- reviewed: 移除未使用的 useCopilotChat 导入 -->
import { z } from "zod";
import { SandboxRenderer } from "../components/SandboxRenderer";
import { useState } from "react";

// 图表展示卡片
function ChartCard({
  title,
  htmlContent,
}: {
  title: string;
  htmlContent: string;
}) {
  return (
    <div className="rounded-xl border bg-white dark:bg-gray-800 p-4 shadow-sm">
      <h3 className="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2">
        {title}
      </h3>
      {/* 知识点3:使用沙箱化 iframe 渲染 AI 生成的图表 */}
      <SandboxRenderer htmlContent={htmlContent} enableAnimation={true} />
    </div>
  );
}

export default function DashboardPage() {
  // 存储所有生成的图表
  const [charts, setCharts] = useState<
    Array<{ id: string; title: string; content: string }>
  >([]);

  // 知识点1:注册前端工具,Agent 调用时在仪表盘中添加图表
  useFrontendTool({
    name: "add_chart",
    description:
      "向仪表盘添加一个可视化图表。提供图表标题和完整的 HTML/SVG 渲染代码。",
    parameters: z.object({
      title: z.string().describe("图表标题"),
      html_content: z
        .string()
        .describe("完整的 HTML 渲染代码,包含 SVG 或 Canvas 元素"),
    }),
    handler: async ({ title, html_content }) => {
      // 将图表添加到仪表盘
      const id = `chart-${Date.now()}`;
      setCharts((prev) => [...prev, { id, title, content: html_content }]);
      return JSON.stringify({ success: true, chartId: id });
    },
    render: ({ status, args }) => {
      if (status === "inProgress") {
        return (
          <div className="animate-pulse rounded-lg border p-4">
            正在生成图表: {args?.title}...
          </div>
        );
      }
      if (status === "complete") {
        return (
          <div className="text-sm text-green-600">
            图表 "{args?.title}" 已添加到仪表盘
          </div>
        );
      }
      return <></>;
    },
  });

  // 清空仪表盘工具
  useFrontendTool({
    name: "clear_dashboard",
    description: "清空仪表盘中的所有图表",
    parameters: z.object({}),
    handler: async () => {
      setCharts([]);
      return JSON.stringify({ success: true });
    },
    render: ({ status }) => {
      if (status === "complete") {
        return (
          <div className="text-sm text-blue-600">仪表盘已清空</div>
        );
      }
      return <></>;
    },
  });

  return (
    <div className="min-h-screen bg-gray-50 dark:bg-gray-900 p-6">
      <h1 className="text-2xl font-bold mb-6 text-gray-900 dark:text-white">
        AI 数据分析仪表盘
      </h1>

      {/* 图表展示区域 */}
      {charts.length === 0 ? (
        <div className="text-center text-gray-400 py-20">
          在右侧聊天框中输入数据需求,例如:
          <br />
          "画一个柱状图展示 Q1-Q4 的销售数据"
          <br />
          "用饼图展示各部门的预算分配"
        </div>
      ) : (
        <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
          {charts.map((chart) => (
            <ChartCard
              key={chart.id}
              title={chart.title}
              htmlContent={chart.content}
            />
          ))}
        </div>
      )}
    </div>
  );
}

文件二:自定义技能

<!-- agent/skills/dashboard-charts/SKILL.md -->
<!-- 知识点2:SKILL.md 技能系统 -->

# Dashboard Charts 技能

## 描述
为 AI 数据分析仪表盘生成各种类型的图表。所有图表通过 `add_chart` 工具添加到仪表盘。

## 适用场景
- 用户要求展示数据 → 图表可视化
- 用户描述趋势、对比、占比 → 对应图表类型
- 用户说"画图"、"展示数据"、"可视化" → 触发本技能

## 决策矩阵
| 用户意图 | 图表类型 | SVG 结构 |
|---------|---------|---------|
| 数值对比 | 柱状图 | rect 元素组 |
| 趋势变化 | 折线图 | polyline/path |
| 占比分布 | 饼图 | circle + stroke-dasharray |
| 数据分布 | 直方图 | rect 元素组 |

## 渲染策略
1. 从用户描述中提取数据点
2. 匹配决策矩阵确定图表类型
3. 生成完整的 SVG 代码(包含交互效果)
4. 调用 add_chart 工具添加到仪表盘

## 代码模板
生成 SVG 时必须:
- 使用 viewBox 属性确保响应式
- 包含 hover 交互效果(CSS :hover)
- 使用项目配色:主色 #6366f1,辅色 #8b5cf6
- 支持暗色模式(使用 currentColor 和 CSS 变量)

代码解析

知识点1 运用处: DashboardPage 组件中使用 useFrontendTool 注册了 add_chartclear_dashboard 两个前端工具。Agent 推理后调用这些工具,前端自动渲染对应的 UI 状态(加载中、完成提示)。

知识点2 运用处: agent/skills/dashboard-charts/SKILL.md 定义了仪表盘图表生成技能。Agent 根据决策矩阵选择图表类型,按照渲染策略生成 SVG 代码,然后调用 add_chart 工具。

知识点3 运用处: ChartCard 组件使用 SandboxRenderer 在沙箱化 iframe 中渲染 AI 生成的 SVG/HTML 代码。每个图表独立隔离,支持渐进式揭示动画和自动主题适配。

扩展挑战

  1. 添加数据持久化 — 将生成的图表保存到 localStorage,刷新页面后自动恢复仪表盘状态
  2. 支持图表导出 — 添加"导出为 PNG"按钮,利用 html2canvas 将 iframe 内容导出为图片
  3. 实现多轮对话编辑 — 允许用户在生成图表后通过对话修改图表(如"把颜色改成红色"、"添加图例")

第五部分:常见问题与排查指南

常见错误及解决方案

错误信息 原因 解决方案
ECONNREFUSED localhost:8123 Agent 服务未启动 在项目根目录运行 make dev 确保三个应用同时启动
401 Unauthorized API Key 无效或未配置 检查 app/.envagent/.env 中的 API Key 是否正确
Module not found: '@copilotkit/react' 依赖未安装 运行 make setup 或手动执行 pnpm install
iframe content not rendering 沙箱权限不足 检查 iframe 的 sandbox 属性是否包含 allow-scripts
Agent response timeout LLM 响应超时 检查网络连接,或切换到延迟更低的模型(如 gpt-4o 替代 gpt-5.4)
Skill not found: xxx 技能目录名称不匹配 确保 SKILL.md 所在的目录名与代码中引用的技能名一致(区分大小写)
Chart not appearing in dashboard add_chart 工具未被调用 检查 Agent 的提示是否包含 add_chart 工具的使用说明

调试技巧

  1. 查看 AG-UI 协议消息 — 打开浏览器开发者工具的 Network 标签页,筛选 WebSocket 连接,可以看到前端与 Agent 之间的实时消息流(工具调用、状态更新等)。这是排查"Agent 是否收到请求"和"工具是否被正确调用"的最佳方式

  2. 使用 CopilotKit DevConsole — 在 CopilotKit Provider 配置中设置 showDevConsole={true},会显示一个开发者控制台,实时展示 Agent 的推理过程、工具调用链和状态变化

  3. 单独测试 Agent — 使用 curl 直接向 Agent 服务发送请求,隔离前端排查 Agent 问题:

# 直接向 Agent 发送测试请求
curl -X POST http://localhost:8123/chat \
  -H "Content-Type: application/json" \
  -d '{"messages": [{"role": "user", "content": "画一个柱状图"}]}'

第六部分:学习路线推荐

官方文档推荐阅读顺序

  1. OpenGenerativeUI README — 快速入门、架构概览、三应用配置
  2. 重点:make setup 流程、.env 配置、三应用端口映射
  3. CopilotKit 官方文档(docs.copilotkit.ai) — Generative UI 章节
  4. 重点:useFrontendTooluseCopilotChat 的 API 参考、三种生成式 UI 模式详解
  5. CopilotKit Blog: The Developer's Guide to Generative UI in 2026 — 生成式 UI 三种模式的深度对比
  6. 重点:静态 AG-UI vs 声明式 A2UI vs 开放式 MCP Apps 的选择指南
  7. LangGraph 官方文档 — 状态图构建和多步骤推理
  8. 重点:StateGraph API、条件边、Agent 状态管理
  9. MCP 协议规范 — Model Context Protocol 工具和资源定义
  10. 重点:工具注册、资源暴露、提示模板

推荐进阶资源