news 2026/9/13 6:13:37

CopilotKit × CrewAI 前端工具(Frontend Tools)实战:从 QA 检查单到 `useFrontendTool` 端到端实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CopilotKit × CrewAI 前端工具(Frontend Tools)实战:从 QA 检查单到 `useFrontendTool` 端到端实现

CopilotKit × CrewAI 前端工具(Frontend Tools)实战:从 QA 检查单到useFrontendTool端到端实现

【免费下载链接】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

本篇技术指南以 CrewAI(Crews)集成 showcase 中的frontend-tools演示为核心,完整还原该功能的 QA 检查流程,并逐层深入仓库源码:前端如何通过useFrontendTool注册浏览器端工具、CrewAI Flow 后端如何下发工具声明与执行结果、Playwright E2E 又如何把人工检查单自动化。读完你将掌握在 CopilotKit v2 应用中让 Agent 直接操控页面 UI(改变背景、查询本地数据等)的完整实现与验证方法。

一、这份 QA 检查单在验证什么

qa/frontend-tools.md是一份针对Frontend Tools(前端工具)功能的人工验收清单,它描述的核心场景非常典型:用户用自然语言要求 Agent 修改页面 UI,Agent 决定调用浏览器端注册的某个工具,工具 handler 在前端本地执行并立即改变页面状态。

完整检查步骤(原文档全文):

  1. 导航到/demos/frontend-tools
  2. 验证背景容器(data-testid="background-container")可见;
  3. 发送消息"Change the background to a blue-to-purple gradient";
  4. 验证背景样式已更新;
  5. 验证 Agent 确认了这次修改。

这五步覆盖了一次"前端工具"交互的完整链路:页面就绪 → 工具宿主可见 → 自然语言触发 → 副作用生效 → Agent 确认。它不检查聊天里说了什么花哨的话,而是盯住"页面真实状态变了没有"这一可观察结果——这也是后面 Playwright 测试的设计哲学。

注意:实际实现中背景容器的data-testidfrontend-tools-background(见 background.tsx),检查单里的background-container是同一语义的别名;你在按单验收时以页面 DOM 中实际的data-testid="frontend-tools-background"为准。

二、Demo 源码:一次useFrontendTool注册的全过程

该 demo 的页面入口是 page.tsx,整段核心代码只有几十行,却展示了前端工具的四个关键要素:宿主组件、工具注册、参数 schema、handler 副作用

2.1 工具宿主:一个可被 Agent 操纵的 Background 组件

// src/app/demos/frontend-tools/background.tsx "use client"; export const DEFAULT_BACKGROUND = "#4f46e5"; // 默认纯靛蓝(indigo) export function Background({ background, children }) { return ( <div >// src/app/demos/frontend-tools/page.tsx(节选) useFrontendTool({ name: "change_background", description: "Change the page background. Accepts any valid CSS background value — colors, linear or radial gradients, etc.", parameters: z.object({ background: z .string() .describe("The CSS background value. Prefer gradients."), }), handler: async ({ background }) => { setBackground(background); // 唯一的副作用:更新 React state return { status: "success" }; // 结果回传给 Agent }, });

拆解这四个字段,就能理解 CopilotKit v2 前端工具的模型:

字段作用在本 demo 中的取值
name工具的唯一标识,Agent(以及后端运行时)靠它路由调用change_background
description向 LLM 描述工具能力边界,直接影响模型是否决定调用明确允许纯色 / 线性渐变 / 径向渐变等合法 CSS background 值
parameters基于 Zod 的参数 schema,随工具声明一起下发到后端,作为函数调用的参数约束background: string,并提示"优先用渐变"
handler浏览器端执行体,返回结果会被回传给 Agent 继续对话调用setBackground更新页面,返回{ status: "success" }

页面其余部分把"宿主 + 聊天"组合起来:<Background>包裹<CopilotSidebar agentId="frontend_tools" defaultOpen />,最外层由<CopilotKit runtimeUrl="/api/copilotkit" agent="frontend_tools">提供运行时。也就是说,工具执行完全发生在浏览器,但工具声明与调用决策由 Agent 驱动——这正是"前端工具"与普通后端工具的本质区别。

2.3 提示词药丸:降低 LLM 输入不确定性的配套设计

demo 还通过 suggestions.ts 提供了三个建议消息(suggestion pill):

useConfigureSuggestions({ suggestions: [ { title: "Sunset theme", message: "Make the background a sunset gradient." }, { title: "Forest theme", message: "Switch to a deep green forest gradient." }, { title: "Cosmic theme", message: "Make it a navy → magenta cosmic gradient." }, ], available: "always", });

这些药丸把用户输入收敛为少数几个确定句式,既提升演示体验,也大幅降低了 LLM 生成随机提示词对 E2E 测试稳定性的影响(下文会看到测试正是基于它们做确定性断言)。

三、后端视角:CrewAI Flow 如何配合前端工具

前端工具并非纯前端把戏,工具调用指令来自 Agent。后端对应实现是 frontend_tool_flow.py,并在 agent_server.py 中通过add_crewai_flow_fastapi_endpoint(app, frontend_tool_flow, "/frontend-tools")注册为 FastAPI 端点,前端runtimeUrl="/api/copilotkit"与之打通。

这段 Flow 代码值得细读,其中有三个与前端工具强相关的设计点:

SYSTEM_PROMPT = ( "You are a concise showcase assistant. When a supplied frontend tool can " "fulfill the user's request, you MUST call it; never claim that you lack " "access and never substitute a prose answer. After the browser returns a " "tool result, summarize it briefly." )
  1. 系统提示强制工具优先:只要前端工具能满足用户请求,"必须调用,禁止用文字敷衍"。这直接保证了检查单第 3 步"Change the background…"能触发真正的工具调用,而不是模型回答一段"抱歉我做不到"。

  2. 工具声明来自运行时tools=self.state.copilotkit.actions or None——Agent 可用的工具清单由 CopilotKit 运行时注入(即前端useFrontendTool注册的change_background声明会以 AG-UI actions 的形式出现在这里),Flow 本身不重复定义工具。

  3. tool_choice 的策略切换:当存在工具声明且最后一条消息来自用户时,tool_choice="required"(强制本次必须走工具),否则回落"auto"。这意味着用户一发消息,模型就会被引导着调用前端工具,第二次对话轮(携带工具结果)时才允许自由总结——对应检查单第 5 步"Agent 确认修改"。

  4. 前端工具结果不在后端伪造:Flow 里明确注释"不要在这里制造 tool result"。流式的前端工具调用会直接结束本次 Flow 运行,由 CopilotKit 在浏览器执行 handler,并把权威结果在下一个请求中带回续跑self.state.messages.append(response.choices[0].message)只保留消息本身。这就是"浏览器拥有前端工具执行权"这一架构决策的源码证据。

四、从人工检查单到自动化:Playwright E2E 如何逐条对应

人工 QA 清单容易漏测,仓库用 frontend-tools.spec.ts 把五步检查单完整自动化了。对照关系如下:

QA 检查单步骤对应自动化断言
导航到/demos/frontend-toolstest.beforeEachpage.goto("/demos/frontend-tools")
背景容器可见page.locator('[data-testid="frontend-tools-background"]').toBeVisible(),且初始 inline style 含默认值#4f46e5
提问改变背景点击 Sunset / Forest / Cosmic 药丸(等价于发送自然语言提示词)
背景样式更新expect.poll轮询 inline style:不再包含#4f46e5,或匹配/linear-gradient\|radial-gradient/
Agent 确认修改断言不依赖 LLM 文本,而是以副作用为准(见下)

4.1 断言策略:测副作用,不测模型措辞

测试注释明确写出了设计哲学:"We assert on the observable side effect (inline style changes) rather than on any LLM-generated text."例如 Sunset 主题的断言:

await expect .poll(async () => { const s = (await bg.getAttribute("style")) ?? ""; return /linear-gradient|radial-gradient/.test(s); }, { timeout: 45000 }) .toBe(true);

为什么用 45 秒轮询而不是立即断言?因为链路是:药丸点击 → 提示词发给 Agent → CrewAI Flow 调 LLM → 模型决定调用change_background→ 声明回到浏览器 → handler 执行setBackground。整条链路耗时不定,轮询(poll)正是对这种"最终一致"副作用的正确断言方式。

4.2 前端工具与 aimock 夹具的关系

测试还提到 aimock 特性对齐夹具(feature-parity fixture)覆盖了 "sunset-themed gradient" 提示词,真实 LLM 则处理自由输入。这意味着该集成支持确定性夹具与真实模型两套运行模式:夹具模式下工具调用由预录数据驱动,便于 CI 稳定复现;真实模型模式(如 Railway 部署)则走完整 LLM 决策。这也是为什么人工 QA 和自动化测试都可以放心依赖"药丸句式"。

五、异步变体:query_notes——前端工具的另一半能力

frontend-tools是"同步副作用"的经典案例;而 frontend-tools-async 演示了前端工具的异步 + 自定义渲染能力,其 QA 检查单为:

  1. 导航到/demos/frontend-tools-async
  2. 提问 "Find my notes about project planning";
  3. 验证NotesCarddata-testid="notes-card")随查询关键词渲染;
  4. 验证匹配的笔记(n1、n5、n7)出现在data-testid="notes-list"中;
  5. 再问 "Search my notes for auth",验证结果更新。

对应实现 frontend-tools-async/page.tsx 展示了两个新特性:

5.1 异步 handler:纯客户端数据查询

handler: async ({ keyword }) => { await sleep(500); // 模拟本地 DB 往返延迟 const q = keyword.toLowerCase(); const matches = NOTES_DB.filter((n) => n.title.toLowerCase().includes(q) || n.excerpt.toLowerCase().includes(q) || (n.tags ?? []).some((t) => t.toLowerCase().includes(q)) ).slice(0, 5); // 最多返回 5 条 return { keyword, count: matches.length, notes: matches }; },

NOTES_DB来自 fake-notes-db.ts,是内存中的 7 条假笔记;工具完全在浏览器内完成查询,后端零参与。sleep(500)让加载态可见,也顺带验证了异步路径的时序。

5.2 render:为工具结果定制 UI 卡片

render: ({ args, result, status }) => { const loading = status !== "complete"; const parsed = parseJsonResult<{ keyword?: string; count?: number; notes?: Note[] }>(result); return ( <NotesCard loading={loading} keyword={args?.keyword ?? parsed.keyword ?? ""} notes={parsed.notes} /> ); },

render回调让前端工具不只是"改个样式",还能把工具返回的结构化结果画成专属组件。NotesCard 暴露data-testid="notes-card"notes-keywordnotes-listnote-n1note-n7等一系列测试锚点,加载中显示 "Querying local notes DB...",完成显示匹配数并逐条渲染标题、摘录和标签胶囊。

对应的 frontend-tools-async.spec.ts 做了更彻底的验证:断言关键词标题为Matching "project planning"、列表中出现note-n1/note-n5、auth 场景出现note-n2、reading 场景出现note-n4(含 "Book recommendations" 与《Thinking Fast and Slow》等书目文本),并包含一个反回归断言——通用模板文案不得误出现。最后一个测试甚至在同一线程里依次点击三个药丸,验证每次点击都渲染出自己的 NotesCard(这是对 aimock 多药丸 bug 的回归测试,原 bug 是工具结果门控导致首轮夹具被跳过、卡片永不渲染)。

六、功能在集成中的定位与运行方式

在 manifest.yaml 中,frontend-toolsfrontend-tools-async作为两个独立 demo 注册在interactivity(交互性)类别下:

- id: frontend-tools name: Frontend Tools (In-App Actions) description: Agent invokes client-side handlers registered with useFrontendTool route: /demos/frontend-tools - id: frontend-tools-async name: Frontend Tools (Async) description: useFrontendTool with an async handler route: /demos/frontend-tools-async

同时manifest.yaml声明该集成整体具备frontend-toolsfrontend-tools-asynchitl-in-app(通过useFrontendTool实现的应用内人工审批弹窗)等能力,说明前端工具是这套 CrewAI 集成中"应用内交互"体系的基础设施。

想本地体验该演示,可按 manifest 提供的标准方式初始化并运行:

# 克隆官方 starter(基于本集成模板) npx copilotkit@latest init --framework crewai-crews # 在仓库内直接运行本 showcase 则需要: # 1) 安装 Python 依赖(含 copilotkit、crewai、litellm 与 ag_ui_crewai) # 2) 配置 LLM 环境变量(Flow 中使用 openai/gpt-5.4 等模型) # 3) 启动 FastAPI 后端与 Next.js 前端,然后访问 /demos/frontend-tools

进入页面后,可依次按第一节的检查单人工验收;本地起好 Playwright 后,也可直接执行 frontend-tools.spec.ts 与 frontend-tools-async.spec.ts 完成自动化验收。

七、小结:把"前端工具"复用到你自己的页面

回到frontend-tools这份 QA 检查单,它的五步背后其实是一套可复用的最小模式,任何希望"Agent 能操纵我的页面"的应用都可以照搬:

  1. 准备宿主:用 React state 持有页面中 Agent 要操控的值,把它渲染进带data-testid的容器;
  2. 注册工具useFrontendTool+ Zod schema,description写清能力边界,handler里只做前端副作用并返回结果;
  3. 提示引导:用useConfigureSuggestions提供确定性提示词药丸;
  4. 后端放权:CrewAI Flow 通过copilotkit_stream拿到运行时注入的 actions,强制工具调用,但不伪造工具结果,把执行权留给浏览器;
  5. 以副作用验收:人工 QA 看页面状态,自动化 QA 用expect.poll轮询 DOM 副作用——两边盯住同一件事。

change_background改背景,到query_notes的异步查询与自定义卡片渲染,这套机制把"LLM 决策"与"页面执行"优雅地分层:模型负责决定,浏览器负责动手。当你需要 Agent 操作本地数据、弹出审批、切换主题或渲染结构化结果时,frontend-tools 与 frontend-tools-async 两份源码就是可直接参考的完整范本。

【免费下载链接】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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 6:13:32

Agent Skills实战指南:从提示词工程到技能库的多平台迁移

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 6:13:07

C++ tuple深度解析:从使用技巧到底层实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 6:12:09

FPGA数字闹钟设计:从分频器到状态机的完整工程实践

简介&#xff1a;一套基于FPGA的简易数字闹钟设计工程&#xff0c;采用Verilog语言在Vivado环境下完成&#xff0c;并以EGo1开发板为硬件载体&#xff0c;适合FPGA初学者、电子类专业学生或数字电路设计入门者。项目覆盖了数字钟常用的计时计数、时间比较、闹钟触发及按键输入等…

作者头像 李华
网站建设 2026/9/13 6:11:30

生成式AI在网络安全培训中的创新应用:反钓鱼教官

1. 项目背景与研究价值巴里大学的这项研究揭示了生成式AI在网络安全培训领域的新应用方向——作为"反钓鱼教官"。随着钓鱼邮件攻击手段的日益复杂化&#xff0c;传统安全培训方式面临三大挑战&#xff1a;培训内容更新速度跟不上攻击手段演变模拟攻击的真实性不足培训…

作者头像 李华
网站建设 2026/9/13 6:10:20

Linux虚拟串口通信中0x1A字符问题解析与解决方案

1. 项目背景与问题描述在Linux系统开发中&#xff0c;虚拟串口&#xff08;Virtual Serial Port&#xff09;是一种常用的通信模拟技术。它允许两个应用程序通过虚拟的串行接口进行数据交换&#xff0c;就像它们通过物理串口连接一样。这种技术在嵌入式开发、设备调试和通信协议…

作者头像 李华