CopilotKit × Google ADK 实战:Tool-Based Generative UI(gen-ui-tool-based)端到端 QA 测试指南
【免费下载链接】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
本文基于 CopilotKit 仓库中 Google ADK 集成示例的官方 QA 文档(showcase/integrations/google-adk/qa/gen-ui-tool-based.md),系统讲解 Tool-Based Generative UI(工具驱动型生成式 UI)演示的完整验收测试流程。文章会逐条拆解 QA 清单中的前置条件、功能测试与预期结果,并结合仓库内的 Agent 源码、前端注册代码与 Playwright E2E 测试,说明每一步该验证什么、为什么这样验证,帮助测试工程师与开发者快速掌握"Agent 调用工具 → 前端把工具结果渲染为自定义 React 组件"这一核心交互的验收方法。
一、被测对象:gen-ui-tool-based 演示是什么
在开始执行 QA 清单之前,先理解被测页面。gen-ui-tool-based(Tool-Based Generative UI)是 Google ADK 集成演示之一,其核心思想是:Agent 调用一个后端工具,工具返回结构化数据,前端把工具结果渲染为自定义 React 组件(而不是普通文本)。
仓库的展示清单 manifest.yaml 中对该演示的定义如下:
- 名称:Tool-Based Generative UI
- 描述:Agent uses tools to trigger UI generation(Agent 使用工具触发 UI 生成)
- 标签:controlled-generative-ui
- 路由:
/demos/gen-ui-tool-based - 高亮源码文件:
src/agents/gen_ui_tool_based_agent.py(后端 Agent)src/app/demos/gen-ui-tool-based/page.tsx(前端页面)src/app/api/copilotkit/route.ts(运行时代理)
从源码结构看,该演示的"工具驱动"体现在两个层面:
前端(page.tsx)通过@copilotkit/react-core/v2的useComponent注册了两个前端工具:
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, });后端(gen_ui_tool_based_agent.py)是一个基于 Google ADKLlmAgent的"数据可视化助手":
gen_ui_tool_based_agent = LlmAgent( name="GenUiToolBasedAgent", model=get_model(), instruction=_INSTRUCTION, tools=[AGUIToolset()], after_model_callback=stop_on_terminal_text, )其中的AGUIToolset()会把前端注册的工具注入到模型的每次请求中,让 Agent 在运行时"看得到、调得动"这些渲染工具;after_model_callback=stop_on_terminal_text则是防止 Gemini 在工具调用成功后无限循环重发同一工具调用的终止保护(详见 shared_chat.py)。
Agent 的指令(_INSTRUCTION)对图表工具的使用做了明确约定:
- 用户请求图表时调用
render_bar_chart或render_pie_chart,传入简短的标题、描述以及{label, value}形式的数据数组; - 小规模类别间的比较用柱状图,整体构成 / 占比用饼图;
- 若用户只给了图表主题而没有具体数字(例如"按来源展示网站流量饼图"),不要反问用户要数据,而是自行编造合理的示意性样例值立即渲染图表,并在回复中注明数据是示意性的;
- 保持聊天回复简短,"让图表本身说话"。
也就是说,QA 清单验证的本质是:前端注册的工具声明 → ADK 中间件注入 → 模型调用工具 → 前端按工具名渲染对应 React 组件这条完整链路是否通畅。
二、前置条件:演示部署与后端健康检查
QA 文档要求执行测试前满足两个前置条件:
- Demo 已部署且可访问:即能打开
/demos/gen-ui-tool-based页面。 - Agent 后端健康:检查
/api/health。
这两个条件在仓库中都有对应的实现依据。
/api/health端点在 src/app/api/copilotkit/route.ts 中实现,它返回:
{ "status": "ok", "agent_url": "http://localhost:8000", "agent_status": "reachable", "agent_count": 47, "env": { "GOOGLE_API_KEY": "set", "NODE_ENV": "development" } }其中agent_status是对后端AGENT_URL/health的实际探活结果(超时 3 秒),GOOGLE_API_KEY字段用于确认 Gemini 凭据是否已配置。如果GOOGLE_API_KEY显示为NOT SET或agent_status为unreachable,则测试不会通过,应先修复后端。
后端健康检查还有一层:Python 侧 agent_server.py 通过HealthMiddleware在路由解析前直接短路返回/health,确保即使某个 Agent 挂载异常,健康探针依然可达。
建议:在浏览器中打开
/api/health确认上述 JSON 返回后再开始执行功能测试,这能提前隔离"前端问题"与"后端问题"。
三、基础功能测试:页面加载与基本对话
QA 文档的第一步是验证页面基础功能:
- 导航到 gen-ui-tool-based 演示页面
- 验证 CopilotSidebar 默认打开,标题为 "Haiku Generator"
- 验证主区域显示占位俳句卡片
- 通过侧边栏发送一条基础消息
- 验证 Agent 有响应
需要特别说明的是:QA 文档中关于 "Haiku Generator" 侧边栏、占位俳句卡片的描述与当前仓库源码已不一致。从源码看,该演示页面如今没有侧边栏,而是渲染一个居中的CopilotChat聊天组件(见 page.tsx):
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> );同时,仓库中的共享探针测试 d5-gen-ui-custom.test.ts 明确记载:旧版的generate_haiku/ HaikuCard 路径已被移除,全部 21 个 gen-ui-tool-based 页面现在统一注册render_bar_chart+render_pie_chart,共享契约就是"饼图契约"。
因此,执行本条测试时应按当前实现验证:
- 打开
/demos/gen-ui-tool-based,页面加载一个居中的CopilotChat聊天界面(无侧边栏/无页头装饰) - 消息输入框可见(textarea 或含 message placeholder 的输入控件)
- 发送一条基础消息(如 "Hello")
- 验证 Agent 在合理时间内返回助理消息
对应地,仓库 E2E 测试 gen-ui-tool-based.spec.ts 正是这样断言的:
test("sends message and gets assistant response", async ({ page }) => { const input = page.locator('textarea, [placeholder*="message"]').first(); await input.fill("Hello"); await input.press("Enter"); await expect( page.locator('[data-testid="copilot-assistant-message"]').first(), ).toBeVisible({ timeout: 30000 }); });四、特性专项检查
4.1 Suggestions(建议提示)
QA 文档要求验证 "Nature Haiku"、"Ocean Haiku"、"Spring Haiku" 三个建议按钮可见。当前实现中,建议按钮由 suggestions.ts 通过useConfigureSuggestions配置,主题已从俳句替换为图表:
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", });对应测试步骤(按当前实现调整):
- 验证 "Sales bar chart" 建议按钮可见
- 验证 "Traffic pie chart" 建议按钮可见
- 验证 "Market share" 建议按钮可见
E2E 测试 gen-ui-tool-based.spec.ts 对建议按钮的断言使用选择器[data-testid="copilot-suggestion"]并按标题文本过滤,可作为手工测试时定位元素的参考。
4.2 工具驱动的图表生成(核心链路)
QA 文档的本节标题为 "Haiku Generation (useFrontendTool)",期望点击建议按钮后渲染一张data-testid="haiku-card"的卡片,内含三行日文(haiku-japanese-line)与三行英文(haiku-english-line)。与 4.1 同理,当前实现已从"俳句生成"演化为"图表渲染":Agent 通过工具调用返回结构化数据,前端将其渲染为 SVG 图表组件。
点击 "Traffic pie chart" 建议(或直接输入 "Show me a pie chart of revenue by category")后,应当验证:
- 助理消息内渲染出 SVG 可视化(饼图/环形图)
- 图表包含标题与描述文本
- 图例区域展示各分片的标签、数值与百分比
- Agent 的随附文字简述了图表结论(例如哪个类别占比最大)
两个渲染组件的实现细节值得测试时留意:
- 饼图 pie-chart.tsx:纯 SVG 手绘环形图,通过
strokeDasharray/strokeDashoffset计算每个扇区,颜色取自固定调色板;数据为空时展示 "No data available" 的空态卡片。 - 柱状图 bar-chart.tsx:基于 Recharts 的
ResponsiveContainer,柱体高度 280px,带有barSlideIn入场动画——只有新到达的柱子才播放动画(通过useRef记录已渲染索引)。
两组件的 props 均由 zod schema 约束(title、description、data: {label, value}[]),这就是 Agent 必须返回的结构化数据契约:
export const pieChartPropsSchema = 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(), }), ), });E2E 对图表渲染的断言方式(gen-ui-tool-based.spec.ts):
test("pie chart request renders SVG visualization", async ({ page }) => { const input = page.locator('textarea, [placeholder*="message"]').first(); await input.fill("Show me a pie chart of revenue by category"); await input.press("Enter"); const assistantMessage = page .locator('[data-testid="copilot-assistant-message"]') .first(); await expect(assistantMessage.locator("svg").first()).toBeVisible({ timeout: 60000, }); });4.3 多张图表的堆叠与替换
QA 文档要求:生成第二首俳句后,新卡片出现在顶部、旧卡片仍保留在下方、初始占位卡片被移除。对应到当前图表实现:
- 生成第一张图表(如 "Sales bar chart"),确认图表卡片出现
- 再生成第二张图表(如 "Traffic pie chart"),确认新的图表卡片出现在消息流顶部
- 确认上一条图表消息仍在其下可见(历史消息不被清除)
- 确认初始的占位内容(如果有)已被移除
这一行为本质上是聊天消息流本身的追加语义——每条工具渲染结果附着在对应助理消息中,新消息追加在顶部,旧消息保留。手工测试时重点观察消息顺序与组件是否随消息一起持久化。
4.4 空消息与错误处理
QA 文档的错误处理部分:
- 发送空消息,应被优雅处理(不崩溃、不报错)
- 正常使用过程中控制台无报错(no console errors)
执行建议:
- 在输入框为空时直接按回车,确认界面不抛异常、不出现未捕获的错误
- 打开浏览器 DevTools Console,在完成一次完整的"发消息 → 生成图表"流程后检查是否有红色错误输出;服务端侧的错误会被 route.ts 记录为含
errorId的结构化日志,且不会把内部堆栈回显给客户端——若控制台出现internal runtime error响应,可到服务端日志按errorId关联排查。
五、预期结果与验收标准
QA 文档给出的最终验收标准如下:
| 预期结果 | 说明 |
|---|---|
| 侧边栏 3 秒内加载 | 当前实现为聊天界面,可理解为页面与聊天组件在 3 秒内就绪 |
| Agent 10 秒内响应并生成俳句 | 当前实现为 10 秒内响应并渲染图表 |
| 俳句卡片同时显示日文与英文 | 当前实现为图表卡片正确渲染标题/描述/数据 |
| 生成的俳句按最新在上堆叠 | 当前实现为多条图表消息按最新在上堆叠 |
| 无 UI 错误或布局破损 | 无报错、无错位、无空态异常 |
其中"10 秒内响应"与"60 秒内图表可见"的时间口径在 E2E 测试中也有体现:助理消息可见的超时设置为 30000ms(gen-ui-tool-based.spec.ts),SVG 图表可见的超时设置为 60000ms(同文件 L41-L43)。手工测试时可参考这些阈值判断"慢"是 Agent 推理慢还是链路故障。
六、QA 文档与当前实现的差异说明(重要)
由于 qa/gen-ui-tool-based.md 中多处描述(Haiku Generator 侧边栏、Nature/Ocean/Spring 俳句建议、haiku-card、haiku-japanese-line、haiku-english-line、haiku-image、/images/图片渲染)与仓库当前源码不一致,特此汇总差异清单,避免测试者按过时步骤误判:
| QA 文档描述 | 当前源码实现 | 依据 |
|---|---|---|
| CopilotSidebar,标题 "Haiku Generator" | 居中的CopilotChat聊天界面 | page.tsx |
| Nature/Ocean/Spring 俳句建议 | Sales bar chart / Traffic pie chart / Market share | suggestions.ts |
useFrontendTool生成俳句卡片 | Agent 调用render_bar_chart/render_pie_chart,前端渲染 SVG 图表 | gen_ui_tool_based_agent.py |
haiku-image图片渲染 | 无图片渲染逻辑 | 源码无/images/图片引用 |
| 俳句卡片日文/英文行 | 图表的标题、描述、图例 | pie-chart.tsx |
这一差异也得到仓库探针测试的佐证:d5-gen-ui-custom.test.ts 明确指出旧generate_haiku路径"is GONE",所有集成统一走饼图契约,且探针断言要求渲染出<svg>且 SVG 绘制子元素数量健康(5 个 circle,对应环形图扇区)。
七、如何复用这套 QA 方法论
7.1 自动化层面:两条可复用的验证路径
仓库为这个演示提供了两层自动化验证,手工 QA 之外可以对照使用:
- 集成级 E2E(tests/e2e/gen-ui-tool-based.spec.ts):Playwright 驱动真实页面,验证页面加载、三个建议按钮、饼图/柱状图 SVG 渲染、基础对话四条用例。
- 跨集成探针(d5-gen-ui-custom.test.ts):作为所有集成的共享契约,固定发送 "Show me a pie chart of revenue by category",断言 SVG 形状与助理回复中的关键 token(如提及占比最大的类别),防止某个集成在图表渲染上退化。
7.2 测试视角:本用例覆盖的验收要点
从测试设计角度,本 QA 清单实际覆盖了工具驱动型生成式 UI 的五个关键风险点:
- 工具注册与注入:前端
useComponent注册的工具名能否被后端AGUIToolset()注入到模型请求(对应 4.1/4.2 的建议与生成用例); - 结构化参数契约:zod schema 定义的
{title, description, data}能否被 Agent 正确填满(对应 4.2 的图表内容校验); - 渲染状态:工具结果从"调用中"到"渲染完成"的状态切换是否正确(README 提到
useRenderTool会把args、result、status传给渲染器以展示加载与完成态,参见 gen-ui-tool-based/README.md); - 消息流语义:多轮工具渲染结果的堆叠与顺序(对应 4.3);
- 健壮性:空输入、异常路径不产生崩溃与控制台错误(对应 4.4)。
对于想要在自建项目上复刻该模式的开发者,后端设置可参考 docs/setup/frontend-tools-setup.mdx,其中给出了AGUIToolset()的接入方式与完整的stop_on_terminal_text终止回调实现——这是让 Gemini 在工具调用后正确结束 agentic loop 的关键一环;前端则只需像本文 4.1/4.2 所示,用useComponent注册工具并绑定 React 渲染组件即可。
结语
Tool-Based Generative UI 是 CopilotKit 生成式 UI 体系中最经典的一条实现路径:Agent 不直接"生成界面",而是调用工具、返回结构化数据,由前端把数据渲染成丰富的自定义组件。本文以 Google ADK 集成的官方 QA 清单为主线,逐项说明了前置条件、功能验证、错误处理与验收标准,并结合仓库源码澄清了文档与当前实现的差异。测试人员可据此清单直接执行验收,开发者则可从这些用例反推该模式落地时最值得关注的工程细节——工具注入、参数契约与消息流语义。
【免费下载链接】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),仅供参考