ARTICLE DETAIL

资讯详情

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

基于 CopilotKit 的 Agentic Generative UI:用 `useAgent` 将代理状态实时渲染进聊天对话

基于 CopilotKit 的 Agentic Generative UI:用 `useAgent` 将代理状态实时渲染进聊天对话 基于 CopilotKit 的 Agentic Generative UI用useAgent将代理状态实时渲染进聊天对话【免费下载链接】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 仓库中crewai-conversational-flows集成的gen-ui-agent演示展开讲解代理式生成式 UIAgentic Generative UI的完整落地模式后端 Agent 在执行长任务时不断发布结构化状态前端通过useAgentv2 API订阅该状态并将其渲染为内嵌于聊天记录中的状态卡片。读完本文你将掌握从后端状态模型、set_steps工具定义、STATE_SNAPSHOT 事件发射到前端messageView.children自定义渲染的端到端实现方法可直接复用到 Mastra、Strands、AG2、Agno、LangGraph、Pydantic AI 等其他集成仓库内各集成的gen-ui-agent演示均遵循同一模式。一、核心思想让 Agent 拥有渲染什么的最终决定权传统 AI 聊天中Agent 只能输出文本界面组件与对话内容彼此割裂。Agentic Generative UI 反转了这一关系Agent 在推进长任务时自行决定在对话流中呈现何种 UI。关联文档 README 对演示的定位是Agent 在处理长任务时渲染自定义 UI将状态更新与中间结果流式地推送到聊天中。具体机制包含两条核心链路状态即协议后端 Agent 定义自己的状态 schemasteps: list[Step]并提供自定义工具set_steps供模型调用以变更状态每次set_steps调用都会把更新后的steps流式推送到客户端。前端即渲染器前端订阅实时状态useAgent并借助messageView.children在聊天记录内部渲染一张InlineAgentStateCard状态到达时卡片原地刷新——不产生逐消息的重复声明也不会出现重复卡片。值得注意的是README 中提到Frontend usesuseAgentRender而该演示当前的实际源码page.tsx使用的是 v2 的useAgentmessageView.children组合同时page.tsx 的注释明确指出这一方案取代了早期会产生每张状态变更消息一张卡片的useCoAgentStateRender方式。下文以当前源码实现为准展开。二、前端实现从useAgent订阅到卡片渲染2.1 顶层挂载CopilotKitProvider 与 Agent 绑定page.tsx 中页面通过CopilotKit组件声明运行时地址与默认 Agentexport default function GenUiAgentDemo() { return ( CopilotKit runtimeUrl/api/copilotkit agentgen-ui-agent div classNameflex justify-center items-center h-screen w-full div classNameh-full w-full max-w-4xl Chat / /div /div /CopilotKit ); }关键点runtimeUrl/api/copilotkit指向 Next.js 侧的 CopilotKit Runtime 路由详见第四节agentgen-ui-agent声明会话默认绑定的 Agent与后端 Flow 一一对应。2.2 订阅实时状态useAgent与UseAgentUpdate.OnStateChangedChat组件通过useAgent订阅 Agent 的实时状态type AgentState { steps?: Step[]; }; function Chat() { const { agent } useAgent({ agentId: gen-ui-agent, updates: [UseAgentUpdate.OnStateChanged], }); useSuggestions(); const steps (agent.state as AgentState | undefined)?.steps ?? []; const status agent.isRunning ? inProgress : complete; // ... }值得注意的细节updates: [UseAgentUpdate.OnStateChanged]声明订阅状态变更事件。这与后端每次set_steps后发射的STATE_SNAPSHOT事件精准对应见第三节。agent.isRunning被映射为卡片的inProgress/complete状态驱动卡片头部在进行中/完成两种视觉之间切换。状态读取使用可选链兜底?.steps ?? []在首帧无状态时也能安全渲染空卡片占位。2.3 自定义消息列表messageView.childrenCopilotChat的messageView.children允许完全接管消息列表的组装逻辑把 Agent 状态卡片嵌入聊天记录内部CopilotChat agentIdgen-ui-agent classNameh-full rounded-2xl messageView{{ children: ({ messageElements, interruptElement }) ( MessageListWithState messageElements{messageElements} interruptElement{interruptElement} steps{steps} status{status} / ), }} /对应的 message-list-with-state.tsx 把消息元素 状态卡片 中断元素按顺序组装为纵向 flex 布局export function MessageListWithState({ messageElements, interruptElement, steps, status, }) { return ( div>export type Step { id: string; title: string; status: pending | in_progress | completed; };id稳定不透明的句柄作为 Reactkeykey{step.id ?? idx}保证跨状态迁移时 React 不会重建节点status三态枚举pending → in_progress → completed与后端工具 schema 中的enum完全一致见第三节。卡片根据状态计算头部文案const total steps.length; const done steps.filter((s) s.status completed).length; const headline status complete || (total 0 done total) ? All ${total} steps complete : total 0 ? Step ${Math.min(done 1, total)} of ${total} : Planning…;即全部完成时显示All N steps complete进行中显示Step N of M尚无步骤时显示Planning…。每行步骤条目StepMarker按状态呈现三种视觉completed绿色圆底对勾标题文字灰色并加删除线line-throughin_progress紫色圆底旋转 spinner标题加粗深色pending白色圆底序号数字标题为次级灰。这一组件树含data-testidagent-state-card、data-testidagent-step、data-status等属性同时服务于 UI 展示与端到端测试断言是测试可驱动的典型写法。2.5 入口建议useConfigureSuggestionssuggestions.ts 通过useConfigureSuggestions注入三个演示建议产品发布规划、团队 offsite 组织、竞品调研available: always表示建议常驻。这为无头演示提供了可点击的冷启动入口。三、后端实现CrewAI Flow 中的set_steps工具与状态发射后端核心位于 gen_ui_agent.py。它没有使用 CrewAI 的 Crew 端点而是实现为一个crewai.flow.Flow直接掌控 LLM 调用、工具 schema 与状态变更。文件头的注释解释了原因一个 Crew 端点无法承载该演示ChatWithCrewFlow不会把逐工具的per-tool状态变更透传给 AG-UI 桥——它唯一的状态变更是当模型调用特殊的crew_name工具时把result.raw追加到state[outputs]。这也是shared_state_read_write.py、subagents.py共用的后端策略专用 Flow 通过add_crewai_flow_fastapi_endpoint挂载到独立路径。3.1 状态模型Step与AgentStateclass Step(BaseModel): id: str title: str status: Literal[pending, in_progress, completed] pending class AgentState(CopilotKitState): steps: List[Step] Field(default_factorylist)Step直接镜像 LangGraph 参照实现中的GenUiAgentState.steps[i]与微软 Agent Framework 的STATE_SCHEMA.steps.items三套集成的状态形状保持一致AgentState继承自CopilotKitState来自ag_ui_crewai桥接包并追加steps字段作为前端agent.state.steps读取的数据源。3.2 工具 schemaSET_STEPS_TOOL这里刻意选用OpenAI 兼容的 JSON Schema 工具定义而非 CrewAIBaseTool因为监督 LLM 调用直接走litellm.acompletionJSON schema 是最合适的原语与shared_state_read_write.SET_NOTES_TOOL一致SET_STEPS_TOOL { type: function, function: { name: set_steps, description: ( Publish the current plan and step statuses. Call this every time a step transitions (including the first enumeration of steps). Always include the FULL list of steps on each call (this is the complete source of truth — not a diff). ), parameters: { type: object, properties: { steps: { type: array, items: { type: object, properties: { id: {type: string}, title: {type: string}, status: { type: string, enum: [pending, in_progress, completed], }, }, required: [id, title, status], }, } }, required: [steps], }, }, }两个设计要点值得借鉴全量语义非 diffdescription 中反复强调每次都传完整步骤列表即set_steps是唯一事实源source of truth客户端按全量替换而不是增量合并天然避免同步错位状态枚举约束enum限定了三态配合后端的_coerce_steps防御性解析单条坏数据不会炸掉整个 Flow。3.3 系统提示词约束模型的行为序列SYSTEM_PROMPT要求模型执行严格序列参见 gen_ui_agent.py规划恰好 3 个具体步骤先set_steps一次全量发布三个pending步骤对第 1/2/3 步依次执行in_progress → completed两次调用全部完成后发送一条总结性的最终助手消息并终止。同时提示词明确禁止并行调用set_steps必须等待上一次调用返回代码中同时设置parallel_tool_callsFalse双保险因为部分 Provider 会忽略该参数每个步骤的id在计划生命周期内必须保持稳定步骤标题要保留用户场景关键词如产品发布须含launch、marketing团队 offsite 须含venue、agenda保证演示视觉上贴合用户输入。3.4 Flow 主循环工具执行、状态替换与 STATE_SNAPSHOTGenUiAgentFlowgen_ui_agent.py实现了一个与 LangGraph 参照 ReAct 循环等价的结构start() async def chat(self) - None: tools [*self.state.copilotkit.actions, SET_STEPS_TOOL] for _iteration in range(self._MAX_ITERATIONS): # 20 次上限 messages [system_message, *_active_turn_messages(self.state.messages)] response await copilotkit_stream( await acompletion( modelopenai/gpt-5.4, messagesmessages, toolstools, parallel_tool_callsFalse, streamTrue, ) ) message response.choices[0].message self.state.messages.append(message) tool_calls message.get(tool_calls) or [] if not tool_calls: return # 无工具调用 → 最终文本响应本回合结束 for tool_call in tool_calls: # 逐个处理工具调用防止部分 Provider 多返回时静默丢调用 if tool_name ! set_steps: # 前端注册的 action由 AG-UI 客户端完成往返这里仅补占位 tool result ... continue new_steps _coerce_steps(args.get(steps)) self.state.steps new_steps # 全量替换last-write-wins steps_changed True await copilotkit_emit_tool_result(tool_call_id, result_content) if steps_changed: await copilotkit_emit_state(self.state) # 发射 STATE_SNAPSHOT各环节的工程细节迭代上限_MAX_ITERATIONS 20。名义脚本为 1 次枚举 3×2 次状态迁移 1 次最终文本 8 次往返20 提供约 2.5 倍余量应对模型重试工具调用格式对齐 LangGraph 参照实现的recursion_limit50启发式约 3 倍名义值。防御性迭代尽管设置parallel_tool_callsFalse代码仍遍历全部tool_calls而非取[0]——否则会静默丢弃多余调用留下无匹配role: tool回复的 assistanttool_calls消息大多数聊天 API 会在下一轮拒绝与shared_state_read_write.py相同的防御模式。状态归约self.state.steps new_steps是全量替换last-write-wins对应 LangGraph 的_last_stepsreducer 与 MAF 的state_update形状测试探针明确断言 swap-not-accumulate 语义。快照发射时机仅在steps_changed为真时调用copilotkit_emit_state(self.state)让 UI 的useAgent({updates: [OnStateChanged]})订阅立即触发、卡片即时重绘而纯前端工具轮次不污染共享状态。防御解析_coerce_steps丢弃非 dict、缺 key、非法 status 的条目而不是抛异常——一行坏数据不应毁掉整个 Flow。会话裁剪_active_turn_messages只保留最近一个用户回合及其后的消息。这是因为 AIMock 的确定性多步 fixture 按最新工具结果作为切换键若把旧的完成步骤带入新一轮 Flow 运行旧工具 id 会与新的链路竞争并重绘过期步骤。文件末尾的模块级单例gen_ui_agent_flow GenUiAgentFlow()配合add_crewai_flow_fastapi_endpoint按请求深拷贝初始化成本只在 import 时支付一次。四、端到端链路路由注册、代理与后端挂载4.1 Next.js 侧Agent 别名注册api/copilotkit/route.ts 将gen-ui-agent映射到后端专用 Flow 路径// gen-ui-agent routes to a dedicated CrewAI Flow backend that owns the // set_steps tool per-call STATE_SNAPSHOT emit (see // src/agents/gen_ui_agent.py). agents[gen-ui-agent] createAgent(/gen-ui-agent);createAgent(path)构造HttpAgent将请求代理到AGENT_URL默认http://localhost:8000下的/conversational_flows/${feature}通过 AG-UI 协议与 Python 后端通信。注释同时提醒若某个别名静默回退到根 chat 端点UI 看似连接成功实际会丢掉该演示所依赖的专用 AG-UI 事件——因此每个别名都必须显式注册。4.2 Python 侧Flow 挂载agent_server.py 遍历CONVERSATIONAL_FLOW_TYPES为每个 Flow 调用add_crewai_flow_fastapi_endpoint( app, flow_type(), f/conversational_flows/{feature}, conversationalTrue, emit_interrupt_outcomeinterrupt_feature, enable_legacy_on_interrupt_eventnot interrupt_feature, )于是gen-ui-agentFlow 被挂载到/conversational_flows/gen-ui-agent与 Next.js 侧createAgent(/gen-ui-agent)的 URL 拼装严格对应完成前后端闭环。4.3 数据流全景一次典型交互的完整链路为用户在聊天框发起任务或点击useConfigureSuggestions注入的建议CopilotKitRuntime 经/api/copilotkit将请求以 AG-UI 协议转发到/conversational_flows/gen-ui-agentFlow 内 LLM 首轮枚举 3 个pending步骤并调用set_steps→ 工具执行 →copilotkit_emit_state发射 STATE_SNAPSHOT前端useAgent的OnStateChanged订阅收到快照agent.state.steps更新CopilotChat.messageView.children中挂载的MessageListWithState检测到steps.length 0在聊天记录内渲染/原地刷新InlineAgentStateCardLLM 依次推进in_progress/completed每步都重复步骤 3-5卡片逐步打勾第 3 步完成后 LLM 输出最终总结文本并终止卡片头部显示All 3 steps complete。五、契约与验证探针如何约束该模式该演示不是写完就算的 UI 玩具而是有明确自动化契约的。文档与源码中暴露的验证点包括gen_ui_agent.py 头部注释声明的契约探针位于probe harness/src/probes/scripts/d5-gen-ui-agent.tsAgent 规划恰好 3 个步骤且逐一遍历pending → in_progress → completed每次迁移都通过set_steps(steps[...])发布并作为 STATE_SNAPSHOT 发射前端渲染[data-testidagent-state-card]与每个state.steps[i]对应的[data-testidagent-step]。前端组件上的data-testid/data-status属性见 InlineAgentStateCard.tsx正是为了让探针与端到端测试能够稳定定位 DOM 节点。_coerce_steps的容错逻辑丢弃坏条目而非抛异常与_active_turn_messages的回合裁剪都是基于 AIMock 确定性 fixture 与真实 Provider 行为总结出的健壮性增强。六、迁移参照从useCoAgentStateRender到useAgentpage.tsx 明确记录了本模式与旧方案的差异这镜像了其他所有集成的gen-ui-agent演示mastra、strands、ag2、agno、crewai-conversational-flows、langgraph-typescript、pydantic-ai……所用的模式并取代了早期会产生每张状态变更消息一张卡片的useCoAgentStateRender方案。两者的本质区别旧方案useCoAgentStateRender为每条状态变更消息各渲染一张卡片状态推进时聊天记录里堆积多张卡片新方案useAgentmessageView.children单张卡片原地更新状态只是流过卡片消息记录保持干净。如果你的项目正在维护基于useCoAgentStateRender的旧代码迁移方向就是用useAgent({updates: [UseAgentUpdate.OnStateChanged]})订阅共享状态再通过messageView.children在消息列表内挂载一个就地渲染的状态组件。七、复用到你的项目最小实现清单要在自己的 CopilotKit CrewAI 集成中复刻该模式需要四件套后端实现一个Flow持有结构化状态如steps定义全量语义的状态工具set_steps在每次工具执行后调用copilotkit_emit_state发射快照并通过add_crewai_flow_fastapi_endpoint挂载到专用路径Runtime 路由在 Next.jsroute.ts中显式注册 Agent 别名并指向该路径参照 api/copilotkit/route.ts前端订阅useAgent({ agentId, updates: [UseAgentUpdate.OnStateChanged] })读取agent.state就地渲染CopilotChat的messageView.children内按steps.length 0条件渲染状态卡片卡片 key 绑定稳定的步骤id。按照此清单你可以把规划中 / 执行中 / 已完成的多步任务可视化直接嵌入任意聊天界面获得与本文演示一致的流式 Agentic UI 体验。关联源码索引关联文档README前端页面与状态订阅page.tsx状态卡片组件InlineAgentStateCard.tsx消息列表组装message-list-with-state.tsx入口建议配置suggestions.ts后端 Flow 实现gen_ui_agent.pyRuntime 路由与别名注册route.tsFlow 挂载入口agent_server.py【免费下载链接】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),仅供参考
返回列表