ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CopilotKit × AG2 集成实战:Shared State 只读模式的完整 QA 验证指南

CopilotKit × AG2 集成实战:Shared State 只读模式的完整 QA 验证指南 CopilotKit × AG2 集成实战Shared State 只读模式的完整 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 仓库中 AG2 集成 showcase 的 QA 文档 为主线完整讲解「Shared State只读——AI 配方助手」演示应用的功能验证方法。文章先给出可直接照做的分步测试清单与预期指标再从源码层面剖析「前端通过agent.setState发布状态、后端 Agent 只读不写」这一模式的实现原理并结合 Playwright E2E 测试说明如何把手工 QA 清单自动化。读完你可以独立完成该演示的验收测试并理解 CopilotKit v2useAgent共享状态机制的底层工作方式。一、功能定位什么是「Shared State 只读」模式在 AG2 集成中CopilotKit 支持多种 Agent 状态协作方式。manifest.yaml 的features字段列出了两类状态能力readonly-state-agent-context前端通过useAgentContext向 Agent 提供只读上下文shared-state-read-write双向共享状态UI 写入偏好、Agent 通过 AG2ContextVariables回写笔记。本 QA 文档覆盖的shared-state-read演示则属于其中只读变体的一种UI 通过agent.setState把配方recipe发布到共享状态Agent 在每一轮对话中读取这份状态来回答用户但从不改写它。正如 page.tsx 顶部注释所描述单一事实来源single source of truth是agent.state.recipe。表单是一个纯受控组件每一次编辑都直接流入agent.setState({...})下一次渲染立即反映出来。因此这份 QA 文档的核心价值在于验证前端发布状态 → Agent 读取状态 → 回答反映当前状态这条链路是否端到端贯通。二、前置条件Prerequisites在开始验证前QA 文档要求满足两项前置条件演示应用已部署且可访问shared-state-read演示页位于/demos/shared-state-read路由由 page.tsx 提供。Agent 后端健康检查GET /api/copilotkit健康探针。关于健康检查route.ts 中的GET处理器会向后端AGENT_URL默认http://localhost:8000的/health端点发起带 3 秒超时的探测返回形如{ status: ok, agent_url: http://localhost:8000, agent_status: reachable, env: { OPENAI_API_KEY: set, NODE_ENV: development } }agent_status字段只有reachable时才代表后端就绪。后端健康端点由 agent_server.py 中的HealthMiddleware提供——它特意用中间件而非app.get(/health)实现因为根路径会被app.mount(/, ...)的 catch-all 挂载遮蔽只有跑在路由解析层之上的中间件才能保证/health永远可达。三、Step 1基础功能验证按 QA 清单逐项勾选导航到shared-state-read演示页路由/demos/shared-state-read验证配方卡片表单加载成功data-testidrecipe-card验证CopilotSidebar默认打开标题为AI Recipe Assistant通过侧边栏发送一条消息验证 Agent 正常响应。页面骨架对应 page.tsxCopilotKit runtimeUrl/api/copilotkit agentshared-state-read div classNamemin-h-screen w-full bg-gray-50 Recipe / CopilotSidebar defaultOpen labels{{ modalHeaderTitle: AI Recipe Assistant }} / /div /CopilotKitCopilotSidebar通过defaultOpen默认展开labels.modalHeaderTitle即侧边栏标题——这两项直接对应 QA 清单的校验点。消息发送与 Agent 响应则走CopilotKit运行时到后端HttpAgent的 AG-UI 协议链路详见第六节路由分析。四、Step 2功能特性专项检查4.1 初始配方状态Initial Recipe State配方标题输入框显示Make Your Recipe烹饪时间下拉框默认为45 min技能水平下拉框默认为Intermediate默认配料正确显示Carrots3 large, grated带胡萝卜 emojiAll-Purpose Flour2 cups带小麦 emoji默认烹饪步骤显示Preheat oven to 350 F。这些默认值并非魔法数字而是定义在 types.ts 的INITIAL_RECIPE常量中export const INITIAL_RECIPE: RecipeData { title: Make Your Recipe, skill_level: SkillLevel.INTERMEDIATE, cooking_time: CookingTime.FortyFiveMin, special_preferences: [], ingredients: [ { icon: , name: Carrots, amount: 3 large, grated }, { icon: , name: All-Purpose Flour, amount: 2 cups }, ], instructions: [Preheat oven to 350°F (175°C)], };同时 types.ts 定义了完整的状态模型SkillLevel枚举Beginner/Intermediate/AdvancedCookingTime枚举5 min/15 min/30 min/45 min/60 mincookingTimeValues数组将其映射为下拉框选项默认索引 3 即 45 minSpecialPreferences枚举High Protein/Low Carb/Spicy/Budget-Friendly/One-Pot Meal/Vegetarian/VeganRecipeData接口与RecipeAgentState仅含recipe字段——后者即agent.state的 TypeScript 形态。4.2 建议Suggestions可见Create Italian recipe建议可见Make it healthier建议可见Suggest variations建议。三条建议由 page.tsx 中的useConfigureSuggestions声明available: always表示建议常驻可用useConfigureSuggestions({ suggestions: [ { title: Create Italian recipe, message: Create a delicious Italian pasta recipe. }, { title: Make it healthier, message: Make the recipe healthier with more vegetables. }, { title: Suggest variations, message: Suggest some creative variations of this recipe. }, ], available: always, });4.3 配方编辑本地状态编辑配方标题并验证实时更新切换技能水平下拉框并验证更新切换烹饪时间下拉框并验证更新切换某个饮食偏好复选框如 Vegetarian并验证被勾选点击 Add Ingredientdata-testidadd-ingredient-button并验证出现新的空行编辑配料的名称与用量点击 x 按钮删除一个配料点击 Add Step并验证出现新的步骤行编辑一条步骤并验证保存点击 x 按钮删除一条步骤。这些编辑操作全部由 recipe-card.tsx 这个纯受控组件完成RecipeCard接收recipe、isLoading、onChange、onImprove四个 props内部update(partial)通过onChange({ ...recipe, ...partial })把每一次局部修改合并后上抛。新增配料时默认追加一个空行{ icon: , name: , amount: }删除则用filter重建数组。因为组件不持有任何本地副本agent.state.recipe是唯一状态源所以 QA 中验证更新/删除实际上都是在验证setState后的重渲染是否正确。4.4 AI 驱动的配方更新useAgent shared state点击Create Italian recipe建议验证 Agent 更新了配方标题、配料与步骤验证变更区域出现ping 指示器高亮标记验证Improve with AI按钮data-testidimprove-button在加载中变为Please Wait...点击Improve with AI并验证配方被增强。useAgent是这一节的核心。看 page.tsx 的用法const { agent } useAgent({ agentId: shared-state-read, updates: [UseAgentUpdate.OnStateChanged, UseAgentUpdate.OnRunStatusChanged], });UseAgentUpdate枚举定义在 use-agent.tsxexport enum UseAgentUpdate { OnMessagesChanged OnMessagesChanged, OnStateChanged OnStateChanged, OnRunStatusChanged OnRunStatusChanged, }本演示订阅了OnStateChanged状态变化触发重渲染与OnRunStatusChanged运行状态变化触发重渲染。ping 指示器的来源正是这种订阅机制当 Agent 的回复触发OnStateChanged后React 重渲染由agent.state.recipe派生的 UI 部分被修改过的字段即可高亮QA 文档称之为 ping indicator对应use-agent.tsx中状态变更通知驱动重渲染的行为。Improve with AI 按钮的行为在 page.tsx 中定义const handleImprove () { if (agent.isRunning) return; agent.addMessage({ id: crypto.randomUUID(), role: user, content: Improve the recipe, }); void copilotkit.runAgent({ agent }) .catch((err) console.error([shared-state-read] runAgent failed, err)); };对应在 recipe-card.tsx 中按钮disabled{isLoading}加载时渲染Spinner / Please Wait...——这就是 QA 清单中加载中显示 Please Wait...与加载期间按钮禁用的实现依据Button>编辑配方改标题、添加配料向 Agent 提问What recipe am I making?验证 Agent 的回答引用当前配方状态。这是本演示的灵魂测试Agent 必须真正读到agent.state.recipe并据此作答而不是笼统回复。其底层链路是前端agent.setState({ recipe: next })→ 通过/api/copilotkit运行时把初始状态随 AG-UI 协议发给后端 → AG2 的AGUIStream把状态映射为 ContextVariables → Agent 在每一轮对话中读取。而只读的关键在于后端没有任何会改写 recipe 的工具——可对照 shared_state_read_write.py 的读写版本那边后端注册了get_current_preferences与set_notes两个工具来读写状态而本只读演示没有对应后端工具因此 Agent 只能读、不能写。五、Step 3错误处理验证发送空消息应被优雅处理不崩溃、不破坏 UI正常使用过程中无控制台报错加载过程中 Improve with AI 按钮处于禁用状态。空消息的优雅处理由 CopilotKit 运行时负责兜底按钮禁用已在 4.4 节说明disabled{isLoading}。QA 的无控制台错误标准同时覆盖前端 React 错误与后端运行时报错——后端一旦抛错route.ts 会返回带errorId的 500 响应并仅把详细堆栈记录在服务端日志{ error: internal runtime error, errorId }前端可通过控制台日志中的errorId与服务端日志关联排查。六、预期结果Expected ResultsQA 文档给出的验收指标配方卡片与侧边栏在3 秒内加载完成Agent 在10 秒内响应配方状态在 UI 与 Agent 之间双向同步UI 变更立即反映Agent 回答引用最新状态ping 指示器高亮显示变更区域无 UI 错误或布局破损。这些时间指标也是 Playwright E2E 测试的超时参考见下节。七、源码纵深运行链路与路由注册shared-state-read之所以能用只读Agent关键在于 route.ts 中的注册表shared-state-read被列入sharedAgentNames数组与agentic_chat、prebuilt-sidebar等一起复用同一个默认 AG2ConversableAgent由src/agents/agent.py中的AGUIStream包装统一指向根路径后端const sharedAgentNames [ agentic_chat, human_in_the_loop, tool-rendering, gen-ui-tool-based, shared-state-read, shared-state-write, shared-state-streaming, ... ]; // ... for (const name of sharedAgentNames) { agents[name] createAgent(); // 默认路径 / }而真正需要独立状态槽的演示如shared-state-read-write则走dedicatedAgents映射挂到后端独立子应用路径const dedicatedAgents: Recordstring, string { shared-state-read-write: /shared-state-read-write/, subagents: /subagents/, headless-complete: /headless-complete/, // ... };后端侧agent_server.py 通过app.mount(/shared-state-read-write, shared_state_read_write_app)等把各子应用挂在具名路径下/根路径留给默认 Agent。文件头部的注释还解释了中间件顺序CORS → RequestUserMessage → HeaderForwarding → Health → routes与install_executor_contextvar_propagation()的原因autogen 的ConversableAgent会通过loop.run_in_executor把 LLM 调用派发到线程池而 ContextVar 不会自动传播到工作线程必须显式打补丁才能让请求头如 aimock 上下文在出站 httpx 调用中保持可见。这些是理解后端如何为Agent 读取状态提供稳定运行环境的关键细节。八、源码纵深E2E 测试如何自动化 QA 清单手工 QA 清单中的大部分检查点已经在 shared-state-read.spec.ts 中被 Playwright 自动化二者通过data-testid一一对应test(recipe card loads with default ingredients and the sidebar mounts, async ({ page }) { await page.goto(/demos/shared-state-read); await expect(page.locator([data-testidrecipe-card])).toBeVisible({ timeout: 15000 }); await expect(page.getByText(AI Recipe Assistant)).toBeVisible({ timeout: 10000 }); await expect(page.locator([data-testidingredients-container])).toBeVisible(); await expect(page.locator([data-testidinstructions-container])).toBeVisible(); }); test(starter suggestions render, async ({ page }) { for (const title of [Create Italian recipe, Make it healthier, Suggest variations]) { await expect(page.getByRole(button, { name: title })).toBeVisible({ timeout: 15000 }); } }); test(clicking Add Ingredient appends a new ingredient-card row, async ({ page }) { const ingredientCards page.locator([data-testidingredient-card]); const initialCount await ingredientCards.count(); await page.locator([data-testidadd-ingredient-button]).click(); await expect(ingredientCards).toHaveCount(initialCount 1, { timeout: 5000 }); }); test(sending a sidebar message returns an assistant response, async ({ page }) { const input page.getByPlaceholder(Type a message); await input.fill(What recipe am I making?); await input.press(Enter); await expect(page.locator([data-testidcopilot-assistant-message]).first()) .toBeVisible({ timeout: 30000 }); });可以看到测试的3 秒加载 / 10 秒响应预期在 E2E 中以timeout: 15000/timeout: 30000的形式体现首屏与首次响应的超时放宽到 2~3 倍以保证 CI 稳定性。测试配置见 playwright.config.tstestDir: ./tests/e2e、本地模式通过webServer自动执行pnpm dev启动 Next.js端口 3000且统一注入X-AIMock-Context: ag2请求头用于后端 fixture 匹配。九、对照阅读与「读写」双向状态的区别若想理解只读与双向的边界建议对照 shared-state-read-write.md 与后端实现 shared_state_read_write.py。后者演示了完整的双向链路UI → Agent写UI 通过agent.setState({...})写入preferencesAGUIStream在每次 run 时把初始状态映射进ContextVariablesAgent 通过get_current_preferences工具读取Agent → UI读/写回Agent 调用set_notes更新notes槽位每次调用返回携带更新后ContextVariables的ReplyResultAGUIStream将其传回 UI触发useAgent({ updates: [OnStateChanged] })重渲染。两者的 QA 验证点也因此不同只读版验证Agent 的回答引用了当前状态读写版还要验证Agent 写的笔记实时出现在 UI 面板、UI 清空笔记后 Agent 下一轮能感知。这组对照恰好勾勒出 CopilotKit 共享状态能力的完整光谱前端发布、后端读取只读→ 前端发布 后端读写双向。十、快速上手与排错要点本地运行前端仓库pnpm dev启动见 playwright.config.ts后端agent_server.py以PORT8000默认运行前端通过AGENT_URL环境变量指向它默认http://localhost:8000。两个进程都就绪后健康探针GET /api/copilotkit应返回agent_status: reachable。依赖密钥后端依赖OPENAI_API_KEY及可选OPENAI_BASE_URLAgent 的LLMConfig在模块导入时即构造客户端因此 agent_server.py 特意在导入任何 Agent 模块之前调用load_dotenv()否则密钥读不到。验证套路总结凡是涉及状态的问题标题改了没生效、Agent 回答不引用最新配方优先检查三点——①useAgent是否订阅了UseAgentUpdate.OnStateChanged② 每次编辑是否真正调用了agent.setState本演示中即handleChange③ 后端/health是否reachable、OPENAI_API_KEY是否 set。QA 与代码的对应索引手工清单 shared-state-read.md → 前端实现 page.tsx / recipe-card.tsx / types.ts → 自动化测试 shared-state-read.spec.ts三者共享同一组data-testid形成需求 → 实现 → 测试的可追踪闭环。【免费下载链接】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),仅供参考
返回列表