CopilotKit 与 AG2 集成实战:用 Tool-Based Generative UI 让 Agent 工具调用渲染出 React 图表组件
2026/9/12 0:30:09 网站建设 项目流程

CopilotKit 与 AG2 集成实战:用 Tool-Based Generative UI 让 Agent 工具调用渲染出 React 图表组件

【免费下载链接】CopilotKitThe Frontend Stack for Agents & Generative UI. React, Angular, Mobile, Slack, and more. Makers of the AG-UI Protocol项目地址: https://gitcode.com/GitHub_Trending/co/CopilotKit

Tool-Based Generative UI(工具驱动的生成式 UI)是 CopilotKit 生成式 UI 体系中的核心模式之一:Agent 在对话过程中调用后端工具返回结构化数据,前端不把结果展示成普通文本,而是将工具结果交给自定义 React 组件渲染。本文以 AG2 集成 showcase 中的gen-ui-tool-based演示为骨架,从组件注册、Schema 定义、后端工具契约到端到端验证,完整讲解如何在 CopilotKit 中把「工具结果」变成「可交互的图表 UI」。

这个 Demo 在解决什么问题

在传统 Chat UI 里,Agent 调用工具后用户看到的是大段 JSON 或纯文本。而 Tool-Based Generative UI 的目标是:Agent 只负责返回结构化数据,前端负责决定这些数据长什么样。这也正是 CopilotKit 官方文档中对该模式的定位——"The agent calls a backend tool that returns structured data; the frontend renders that tool result as a custom React component instead of plain text"(见 README)。

在这个 demo 中:

  • Agent(AG2 的 ConversableAgent)通过query_data等后端工具返回销售、流量等 JSON 结构化数据;
  • 前端通过useComponent将工具名(如render_bar_chartrender_pie_chart)映射到 BarChart / PieChart 两个 React 组件;
  • 用户发出"Show me a bar chart of quarterly sales"这类自然语言请求后,Agent 调用工具,聊天流里直接渲染出带标题、图例、动画的图表卡片。

该 demo 在集成清单 manifest.yaml 中被登记为gen-ui-tool-based,路由为/demos/gen-ui-tool-based,属于generative-ui(生成式 UI)能力分类,与gen-ui-agent(Agent 驱动的长任务生成 UI)、tool-rendering(工具结果渲染)等并列。

前端:用 useComponent 注册「工具名 → 组件」映射

Demo 的入口页面 page.tsx 是整个模式的核心,全部逻辑不过几十行:

"use client"; import React from "react"; import { CopilotChat, CopilotKit, useComponent, } from "@copilotkit/react-core/v2"; import { BarChart, barChartPropsSchema } from "./bar-chart"; import { PieChart, pieChartPropsSchema } from "./pie-chart"; import { useSuggestions } from "./suggestions"; function Chat() { useComponent({ name: "render_bar_chart", description: "Display a bar chart with labeled numeric values.", parameters: barChartPropsSchema, render: BarChart, }); useComponent({ name: "render_pie_chart", description: "Display a pie chart with labeled numeric values.", parameters: pieChartPropsSchema, render: PieChart, }); useSuggestions(); return ( <div className="flex justify-center items-center h-screen w-full"> <div className="h-full w-full max-w-4xl"> <CopilotChat agentId="gen-ui-tool-based" className="h-full rounded-2xl" /> </div> </div> ); } export default function ControlledGenUiDemo() { return ( <CopilotKit runtimeUrl="/api/copilotkit" agent="gen-ui-tool-based"> <Chat /> </CopilotKit> ); }

useComponent 的底层原理

useComponent并不是一个独立的新机制,而是对useFrontendTool便捷封装。在源码 packages/react-core/src/v2/hooks/use-component.tsx#L59-L92 中可以看到它的实现方式:

  1. 自动为工具拼接面向模型(model-facing)的描述前缀:Use this tool to display the "<name>" component in the chat. This tool renders a visual UI component for the user.,开发者传入的description会追加在该前缀之后;
  2. parameters(任何符合 Standard Schema V1 规范的类型库,例如 zod)透传给底层 frontend tool,模型据此知道该工具需要哪些参数;
  3. 渲染时把工具调用的args展开后作为 props 传给注册的 React 组件;
  4. 还支持agentId(限定只对某个 Agent 生效)与followUp(是否允许模型在渲染后继续追问),以及第二个参数deps(与useEffect相同的依赖刷新语义)。

也就是说,useComponent把「注册一个带 Schema 的渲染组件」这件事压缩成了一次声明,底层依然是 CopilotKit 的 frontend tool 体系在驱动。

Schema 与组件解耦

图表组件的 Schema 定义在组件文件里,与页面解耦。柱状图 bar-chart.tsx:

export const barChartPropsSchema = z.object({ title: z.string().describe("Chart title"), description: z.string().describe("Brief description or subtitle"), data: z.array( z.object({ label: z.string(), value: z.number(), }), ), }); export type BarChartProps = z.infer<typeof barChartPropsSchema>;

饼图 pie-chart.tsx 使用完全相同的 schema 形状。这意味着:

  • Schema 即契约:zod schema 一方面驱动模型生成参数(describe注释会被当作对模型的提示),另一方面通过z.infer推导出 TypeScript 类型,让render组件的 props 在编译期就类型安全;
  • 数据形状统一{ label, value }的结构对模型友好,柱状图与饼图可以共用同一份数据。

图表组件的实现细节

BarChart 基于 Recharts 实现,值得注意的几个工程细节(bar-chart.tsx):

  • 空数据降级:当data为空时渲染一张占位卡片("No data available"),避免图表库在空数组上抛错;
  • 增量动画:通过useRef(new Set<number>())记录已经渲染过的柱子 index,只有新到达的数据柱才触发barSlideIn关键帧动画(translateY(40px) → 0),避免流式更新时整图反复重播动画;
  • 品牌配色:固定 7 色板(#BEC2FF#85ECCE#FFAC4D等),按 index 取模循环上色。

PieChart 则是手写的 SVG 环形图(pie-chart.tsx),用strokeDasharray/strokeDashoffset计算每个扇区的弧长与间隔,底部附带图例列表,显示每个类目的数值和百分比。组件自带完整的降级 UI,并且通过Number(item.value) || 0做了数据容错。

后端:Agent 工具如何返回结构化数据

前端注册好render_bar_chart/render_pie_chart后,Agent 端需要有一个能被模型调用的工具来产生数据。AG2 侧的核心 agent 定义在 src/agents/agent.py,其中query_data就是图表数据入口:

async def query_data( query: Annotated[str, "Natural language query for financial data"], ) -> str: """Query financial database for chart data.""" # Return a JSON string (not a list): autogen serializes non-str returns # with str(), producing a Python repr (single quotes) that the frontend's # parseJsonResult/JSON.parse cannot parse. Same pattern as get_weather. return json.dumps(query_data_impl(query))

源码注释里透露了一个非常关键的跨端契约细节(agent.py):工具必须返回 JSON 字符串(json.dumps),而不能直接返回 Python list 或 dict。原因在于 autogen/AG2 对非字符串返回值会用str()序列化,生成带单引号的 Python repr(如"{'label': 'Q1', 'value': 100}"),前端JSON.parse无法解析。这个坑同样适用于manage_sales_todosget_sales_todosschedule_meetingsearch_flights等其余工具。

整个 agent 的装配方式如下(agent.py):

  • 使用 AG2 的ConversableAgent承载全部工具;
  • 通过AGUIStream(agent)以 AG-UI 协议把 Agent 暴露给 CopilotKit runtime;
  • 前端通过<CopilotKit runtimeUrl="/api/copilotkit" agent="gen-ui-tool-based">连接到该 runtime,聊天请求经由/api/copilotkit路由(见 route.ts)转发给 agent。

提示词引导:让 Agent 主动产出图表

为了让用户开箱即用地看到图表效果,demo 还用useConfigureSuggestions配置了三条建议提示词(suggestions.ts):

"use client"; import { useConfigureSuggestions } from "@copilotkit/react-core/v2"; export function useSuggestions() { useConfigureSuggestions({ suggestions: [ { title: "Sales bar chart", message: "Show me a bar chart of quarterly sales for Q1, Q2, Q3, Q4.", }, { title: "Traffic pie chart", message: "Show me a pie chart of website traffic by source.", }, { title: "Market share", message: "Show a pie chart of smartphone market share by brand.", }, ], available: "always", }); }

available: "always"表示建议始终可见(而非仅在输入框聚焦或空态时出现)。这些建议文案同时在端到端测试中被断言,是验证 demo 行为的一部分。

端到端验证:测试如何证明「工具结果渲染为 UI」

Playwright 测试 tests/e2e/gen-ui-tool-based.spec.ts 把该模式的可验收行为固化成了断言:

  1. 页面加载即出现三条建议 pillSales bar chartTraffic pie chartMarket share必须通过[data-testid="copilot-suggestion"]可见;
  2. 饼图请求:输入Show me a pie chart of revenue by category后,在[data-testid="copilot-assistant-message"]内应出现一个可见的svg(PieChart 的渲染结果),超时 60 秒;
  3. 柱状图请求:输入Show me a bar chart of monthly expenses,同样断言 assistant 消息内出现svg
  4. 基础对话:普通消息能收到 assistant 回复。

测试的断言方式(在 assistant 消息里查找svg)精准对应了本文模式的定义:图表不是聊天窗口外部的静态页面,而是作为一条 assistant 消息内容被动态渲染进对话流的。这说明useComponent渲染的组件会作为消息的一部分参与对话历史与流式输出。

运行与查看方式

该 demo 属于 AG2 集成 showcase。查看它的推荐路径:

  1. 阅读 showcase 根目录 README 了解 AG2 集成的整体结构与启动方式;
  2. 本地运行时启动 Next.js 应用与 AG2 agent 后端(agent通过AGUIStream暴露),访问/demos/gen-ui-tool-based
  3. 后端健康检查可通过/api/health(见 QA 文档 qa/gen-ui-tool-based.md),QA 清单还给出了加载时间预期(sidebar 3 秒内、agent 10 秒内回复)等可观察指标;
  4. 运行 Playwright e2e 测试验证核心行为。

模式小结:Tool-Based Generative UI 的关键要点

  • 前后端各司其职:后端工具只返回 JSON 结构化数据;前端用useComponent声明「工具名 → 渲染组件 → 参数 Schema」三元组,把展示逻辑完全留在客户端。
  • Schema 即双端契约:zod 等 Standard Schema V1 兼容库既指导模型生成参数,又为 React 组件提供类型推导,一处定义两端受益。
  • 注意序列化边界:AG2 工具返回值务必json.dumps成 JSON 字符串,避免 Python repr 破坏前端解析(agent.py 中的注释是该坑的一手记录)。
  • 渲染是消息流的一部分:组件以 assistant 消息形态内联渲染(e2e 测试对copilot-assistant-messagesvg的断言即是证明),因此流式更新、加载与完成状态天然融入对话体验。

如果需要在项目里复刻该模式,只需三步:后端提供一个返回 JSON 字符串的工具;前端用 zod 定义参数 Schema 并用useComponent注册渲染组件;在<CopilotKit>内挂载<CopilotChat>即可。全部源码均可在此仓库的 showcase/integrations/ag2/src/app/demos/gen-ui-tool-based/ 目录下查阅。

【免费下载链接】CopilotKitThe Frontend Stack for Agents & Generative UI. React, Angular, Mobile, Slack, and more. Makers of the AG-UI Protocol项目地址: https://gitcode.com/GitHub_Trending/co/CopilotKit

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询