ARTICLE DETAIL

资讯详情

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

CopilotKit 共享状态双向读写实战:CrewAI Flows 下 Preferences 与 Scratch Pad 的完整 QA 指南

CopilotKit 共享状态双向读写实战:CrewAI Flows 下 Preferences 与 Scratch Pad 的完整 QA 指南 CopilotKit 共享状态双向读写实战CrewAI Flows 下 Preferences 与 Scratch Pad 的完整 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共享状态Shared State是 CopilotKit 连接 UI 与 Agent 的核心机制而「读 写」双向数据流则是把侧边栏表单、Agent 记忆便签和对话上下文串成一体的关键能力。本文以 CopilotKit 仓库中 CrewAI 集成示例crewai-crews的共享状态双向读写演示/demos/shared-state-read-write为主干完整继承其 QA 测试清单并结合前端useAgent/agent.setState与后端SharedStateReadWriteFlow源码说明该功能的正确行为预期、端到端验证方法以及背后的双向数据流原理。一、功能定位这个 Demo 在验证什么「Shared State (Read Write)」演示的核心是同一份 agent state 对象被 UI 与 Agent 双向读写UI → Agent写入侧边栏表单姓名、语气、语言、兴趣通过agent.setState(...)写入state.preferences后端在每个回合读取该对象并注入系统提示词从而影响 Agent 的回复Agent → UI写入Agent 通过set_notes工具写入state.notes侧边栏的笔记卡片实时重渲染展示双向回环在侧边栏修改偏好后Agent 下一轮回复会显著跟随这些偏好语气、语言、称呼姓名。该演示对应仓库中的 QA 清单 qa/shared-state-write.md同时配套 Playwright 端到端用例 tests/e2e/shared-state-read-write.spec.ts以及演示页面 src/app/demos/shared-state-read-write/page.tsx。二、前置条件在开始执行任何验证步骤之前需确保以下条件成立Demo 已部署并可访问演示应用已完成构建并运行/demos/shared-state-read-write路由可正常打开Agent 后端健康后端服务已启动且/api/health返回正常状态。关于后端的健康契约可以在 src/agent_server.py 中看到它是独立于 Agent 端点维护的if request.url.path /health and request.method GET:分支专门处理健康检查请求这意味着健康检查与各 Agent 端点的可用性相互独立验证时应先确认健康检查通过、再进入功能测试。提示后端 FastAPI 服务通过add_crewai_flow_fastapi_endpoint(app, shared_state_read_write_flow, /shared-state-read-write)挂载共享状态读写 Flow见 src/agent_server.py前端路由 src/app/api/copilotkit-shared-state-read-write/route.ts 通过HttpAgent({ url: ${AGENT_URL}/shared-state-read-write })将其代理为/api/copilotkit下的专用运行时。三、基础功能验证Basic FunctionalityQA 清单的第一步是确认页面骨架与默认交互状态正确导航至/demos/shared-state-read-write验证偏好卡片与笔记卡片均已渲染且聊天侧边栏默认展开验证data-testidpreferences-card可见标题为Your preferences验证data-testidnotes-card可见标题为Agent Scratch pad验证data-testidnotes-empty文本为the agent will make observations about you and note them here!验证聊天输入框占位符为Chat with the agent...验证建议按钮Greet me、Remember something、Plan a weekend均可见发送Hello验证出现一条助手回复。这些断言在源码中有精确对应偏好卡片由 preferences-card.tsx 渲染其根节点带data-testidpreferences-card卡片标题为 Your preferences笔记卡片由 notes-card.tsx 渲染根节点带data-testidnotes-card当notes数组为空时渲染带data-testidnotes-empty的空态占位文本非空时渲染data-testidnotes-list与逐条data-testidnote-item聊天侧边栏由 demo-layout.tsx 中的CopilotSidebar agentIdshared-state-read-write defaultOpen{true} labels{{ chatInputPlaceholder: Chat with the agent... }} /提供defaultOpen{true}正是侧边栏默认展开的实现来源三个建议按钮由 suggestions.ts 中的useConfigureSuggestions配置available: always保证建议常驻展示。对应的 Playwright 用例见 tests/e2e/shared-state-read-write.spec.tspreferences panel and agent scratch pad both mount与starter suggestions render分别覆盖卡片挂载与建议渲染断言。四、核心场景UI 写入 → Agent 读取4.1 操作步骤在data-testidpref-name输入框输入Atai将语气Tone设置为formal语言Language设置为Spanish并勾选Cooking与Travel两个兴趣验证data-testidpref-state-json立即反映全部四项偏好变更发送What do you know about me?验证回复中使用了通过共享状态提供的姓名、语气、语言与兴趣。4.2 源码级原理解读前端写入链路偏好卡片本身是一个完全受控的表单组件每次编辑都会触发onChange由父页面 page.tsx 的handlePreferencesChange直接汇入agent.setState({ preferences: next, notes })。注意这里显式携带了notes以保证 UI 写入偏好时不会覆盖 Agent 已写入的笔记——这是双向共享状态写入时最容易踩的坑。pref-state-json区域直接JSON.stringify(value, null, 2)展示当前偏好对象见 preferences-card.tsx因此表单任何变化都会在界面上即时可见这与 QA 中立即反映的断言一致。偏好对象的数据模型为interface Preferences { name: string; tone: formal | casual | playful; language: string; interests: string[]; }后端读取链路后端 Flow src/agents/shared_state_read_write.py 的chat方法在每个回合开始时从self.state.preferences取出偏好由于请求 JSON 跨 AG-UI 边界传输后是普通 dict代码先做 Pydantic 反序列化if isinstance(prefs, dict): prefs Preferences(**prefs)_build_prefs_block(prefs)将姓名、语气、语言、兴趣拼装成一段系统提示块如- Name: Atai、- Preferred tone: formal、- Preferred language: Spanish、- Interests: Cooking, Travel并在末尾追加指令Tailor every response to these preferences. Address the user by name when appropriate.该提示块与基础系统提示拼接后作为system消息放到messages最前面messages [system_message, *self.state.messages]。因此 Agent 的回复天然会使用姓名、语气、语言与兴趣——这正是UI 写入 → Agent 读取在实现层面的闭环。注意后端代码中模型指定为modelopenai/gpt-5.4见 shared_state_read_write.py实际推理依赖用户配置的模型服务可用性若更换模型需同步调整该常量。五、核心场景Agent 写入 → UI 读取5.1 操作步骤点击Remember something建议验证data-testidnotes-list出现并包含data-testidnote-item条目内容涉及morning meetings与dairy发送Also remember I live in Berlin.验证笔记列表保留先前条目并新增 Berlin。5.2 源码级原理解读Remember something 建议对应的用户消息是Remember that I prefer morning meetings and that I dont eat dairy.见 suggestions.tsAgent 收到后应调用set_notes工具写入笔记。工具定义后端以纯 OpenAI 兼容 JSON Schema 定义set_notes工具而非 CrewAIBaseTool因为监督 LLM 调用直接走litellm.acompletion。工具描述中特别强调两条约定必须传入完整列表已有笔记 新增笔记而不是 diff即Replace the notes array in shared state with the FULL updated list每条笔记保持简短 120 chars。这正是保留先前条目并新增 Berlin能够成立的前提工具语义是整体替换Agent 每次调用都要带上全部已有条目。工具执行与状态快照SharedStateReadWriteFlow内部实现了与 LangGraph 参考实现一致的工具循环_MAX_ITERATIONS 5防止无限循环调用copilotkit_stream(await acompletion(...))获取 LLM 输出若存在tool_calls遍历所有工具调用即使parallel_tool_callsFalse部分 provider 仍可能返回多个索引[0]会静默丢弃其余调用导致消息线程非法对set_notes调用解析notes参数、清洗为非空字符串列表后写入self.state.notes追加role: tool占位回复并调用copilotkit_emit_tool_result当笔记确实变化时调用copilotkit_emit_state(self.state)发射 STATE_SNAPSHOT使前端订阅立即触发无需等待下一回合循环回到第 1 步让 LLM 基于工具结果产出确认性文本如 Got it — I noted …否则前端永远看不到工具调用后的确认回复。前端读取链路页面通过useAgent({ agentId: shared-state-read-write, updates: [UseAgentUpdate.OnStateChanged] })订阅 Agent 的每次状态变更见 page.tsx并把agentState?.notes ?? []传给 notes-card.tsx。笔记非空时渲染有序列表每条以两位编号前缀01、02…展示——Agent 写入 → UI 实时重渲染的整条链路就此打通。六、核心场景UI 写回 Agent 状态笔记清空6.1 操作步骤点击data-testidnotes-clear-button验证笔记列表消失data-testidnotes-empty空态回归提问What do you remember about me?验证已清空的笔记不再被引用。6.2 源码级原理解读Clear 按钮是笔记卡片上的回写write-back演示在同一个notes字段上同时演示 Agent → UIAgent 写入、UI 展示与 UI → AgentUI 清空、Agent 状态同步两个方向。前端handleClearNotes调用agent.setState({ preferences, notes: [] })同样保留现有preferences不覆盖见 page.tsx后端chat方法在每个新回合从self.state读取此时notes已被清空Agent 的系统提示与上下文不再包含旧笔记因此后续轮次不会再引用它们注意set_notes的语义是整体替换清空在工具层面等价于传入空数组[]self.state.notes cleaned后notes_changed True同样会发射状态快照让 UI 空态即时回归。这一用例验证的是状态同步的一致性清空操作必须同时反映在 UI列表消失与 Agent 的后续行为不再引用上缺一不可。七、错误处理验证Error Handling尝试发送空消息验证其为no-op无任何副作用不产生回复、不修改状态清空姓名并取消勾选全部兴趣验证后续一轮对话仍可正常完成、不报错在整个流程中验证浏览器控制台无未捕获错误。对应源码中的防御性设计偏好为空时_build_prefs_block返回Nonehas_any判断为空即不生成提示块系统提示退化为纯_BASE_SYSTEM_PROMPTAgent 仍可正常回复——这是清空姓名与兴趣后对话不中断的实现基础见 shared_state_read_write.py工具参数解析使用try/except json.JSONDecodeError兜底notes非列表时回退为空数组列表元素逐个str(n)清洗非字符串值避免模型偶发异常输出破坏状态结构前端路由POST处理器route.ts对所有异常统一捕获以errorId关联日志并返回结构化{ error, errorId }不向客户端泄露消息与堆栈内容从而避免未捕获异常流向浏览器控制台。八、预期结果总结Expected Results完整跑通上述验证后应观察到UI 偏好编辑在下一回合到达 Agent修改姓名、语气、语言、兴趣后Agent 的回复随之适配Agent 编写的笔记出现在共享状态中并保留先前条目set_notes的整体替换语义 状态快照发射保证新增笔记时旧条目不丢失、UI 即时更新清空笔记从 UI 回环到 Agent 状态agent.setState({ notes: [] })后UI 空态回归Agent 后续回合不再引用已清空笔记无 UI 错误与布局破坏空消息为 no-op空偏好下对话可用控制台无未捕获错误。九、端到端自动化验证的额外视角仓库为同一功能提供了 Playwright 自动化覆盖tests/e2e/shared-state-read-write.spec.ts其中两条用例揭示了 QA 手册之外的一个重要回归场景Greet me 建议应返回共享状态感知的问候断言包含shared-state co-pilot并且不得回退为通用 showcase 助手回复断言不包含 showcase assistant. I can help with weather, charts…Plan a weekend 建议应返回基于兴趣的周末计划断言包含interests panel并且不得回退为通用的内容营销计划断言不包含 Research the topic…。测试注释明确记录了该 bug 的根因带空格的建议消息如 Say hi and introduce yourself.曾被 fixture 匹配逻辑错误地落入feature-parity.json中裸hi/plan的兜底 fixture从而返回了与共享状态无关的通用回复。修复方式是新增d5-all.json中子串匹配更长、优先级更高的 fixture。这一视角对 QA 的启示是验证共享状态功能时不仅要断言正确的回复出现还要断言错误的兜底回复不出现——双重断言才能捕获 fixture 匹配回退这类隐性回归。【免费下载链接】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),仅供参考
返回列表