ARTICLE DETAIL

资讯详情

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

CopilotKit Open Generative UI 实战:用 .NET Agent 流式生成沙盒化教育可视化组件

CopilotKit Open Generative UI 实战:用 .NET Agent 流式生成沙盒化教育可视化组件 CopilotKit Open Generative UI 实战用 .NET Agent 流式生成沙盒化教育可视化组件【免费下载链接】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 仓库中的open-gen-ui演示位于 MS Agent Framework .NET 集成 showcase 中为主体完整拆解 Open Generative UI 的最小可用链路一个 .NET 后端 Agent 如何通过 AG-UI 协议流式调用前端工具generateSandboxedUi把 LLM 即时生成的 HTML CSS SVG 渲染进聊天中的沙盒 iframe。读完本文你能掌握前端 Provider 的最小配置、Runtime 侧openGenerativeUI开关与中间件的事件转换机制、内置OpenGenerativeUIActivityRenderer的沙盒渲染细节以及自定义 design skill 引导 LLM 产出“教科书级”可视化图表的完整方法。一、演示定位Agent 直接“画”出可视化组件该演示showcase/integrations/ms-agent-dotnet/src/app/demos/open-gen-ui/README.md展示的是A .NET-backed agent that streams on-the-fly HTML CSS SVG visualisations into a sandboxed iframe inside the chat.一个 .NET 驱动的 Agent把即时生成的 HTML CSS SVG 可视化流式渲染进聊天中的沙盒 iframe。交互方式是点击四个预置建议3D 坐标轴、神经网络、快速排序、傅里叶级数或直接输入任意教学可视化需求Agent 每轮都会生成一个自运行、带动画的组件。与“声明式 Generative UI”JSON 结构映射到预定义组件不同Open Generative UI 让 LLM 直接编写前端代码自由度更高。整条链路从源码看如下CopilotChatagentIdopen-gen-ui │ 用户消息 ▼ /api/copilotkit-ogui ── openGenerativeUI: { agents: [...] } 开启 │ AG-UI HttpAgent 代理重写 toolCallId ▼ .NET Agent 端点 /open-gen-uiMapAGUI │ ChatClientAgent 系统提示词 ▼ LLM 调用前端工具 generateSandboxedUi流式参数 │ OpenGenerativeUIMiddleware 拦截 ▼ ACTIVITY_SNAPSHOT / ACTIVITY_DELTAactivityType open-generative-ui ▼ OpenGenerativeUIActivityRenderer → Websandbox 沙盒 iframe 渲染下面按“前端 → Agent → Runtime → 中间件 → 渲染器”的顺序逐层展开。二、前端接线最小 Provider 配置演示页面 page.tsx 的核心代码只有几行return ( CopilotKit runtimeUrl/api/copilotkit-ogui agentopen-gen-ui openGenerativeUI{{ designSkill: VISUALIZATION_DESIGN_SKILL }} div classNameflex justify-center items-center h-screen w-full div classNameh-full w-full max-w-4xl flex flex-col p-3 Chat / /div /div /CopilotKit );三点关键说明对应文件内注释内置活动渲染器由CopilotKitProvider自动注册——只要 Runtime 开启了openGenerativeUI一个普通的CopilotChat /就够了无需自定义 tool renderer、无需手动注册 activity rendererruntimeUrl指向专用路由/api/copilotkit-ogui而不是默认 runtime原因见第四节openGenerativeUI.designSkill用于替换默认的 shadcn 风格 design skill注入面向教育可视化的设计约束见第三节。配套的聊天组件 chat.tsx 仅两行有效逻辑export function Chat() { useOpenGenUISuggestions(); return CopilotChat agentIdopen-gen-ui classNameflex-1 rounded-2xl /; }而四个预置建议定义在 suggestions.ts 中const minimalSuggestions [ { title: 3D axis visualization, message: 3D axis visualization (model airplane) }, { title: How a neural network works, message: How a neural network works }, { title: Quicksort visualization, message: Quicksort visualization }, { title: Fourier: square wave from sines, message: Fourier: square wave from sines }, ];这些message字符串同时被用作确定性 aimock fixture 的键保证每次点击 pill 都能产生稳定的generateSandboxedUi工具调用见该文件顶部注释。三、Design Skill把 LLM 调教成“可视化设计师”README 指出该页面用VISUALIZATION_DESIGN_SKILL覆盖了默认的 shadcn 风格 design skill以把 LLM 导向教育可视化。完整提示词在 design-skill.ts 中它作为 Agent 上下文注入generateSandboxedUi工具。其约束体系可以概括为七个方面原文为英文提示词此处归纳并摘录关键条目几何与渲染优先内联 SVG或canvas绝不允许用几十个div堆叠画图形内容控制在约 600×400 区域、留 16–24px 边距用viewBox preserveAspectRatio保证缩放3D 场景用 SVG 手动透视或 CSS 3D transformtransform-style: preserve-3d。动画优先 CSSkeyframes transition 而非 JSsetInterval单周期 300–900ms周期性概念用animation-iteration-count: infinite循环必须用 JS 计时时用requestAnimationFrame用animation-delay让相关元素错峰。标签与图例每条轴必须有标签如 Pitch (X)每个颜色序列必须配图例色块和短说明加入文字标注解释“观众正在看什么”顶部一行标题 一行副标题。语义色板固定 hex 值保持一致- 主运动/强调: indigo #6366f1 - 成功/稳定: emerald #10b981 - 警示/活跃: amber #f59e0b - 错误/对比: rose #ef4444 - 中性轴/网格: slate #64748b - 表面: 白 #ffffff / 容器底 #f8fafc / 文字 #0f172a排版system-ui 字体族标题 16–18px/600副标题 12–13px/500轴与图例 11–12px标注 11–13px数字读数用tabular-nums。输出契约严格按顺序- 先发 initialHeight可视化通常 480–560 - placeholderMessages: 2–3 行短句如 [Sketching the scene…, Labelling axes…] - css: 完整且自包含 - html: 单一根容器标题 副标题 SVG/canvas 图例 Chart.js / D3 等 CDN script 标签写在 html 内部无障碍文字对比度 ≥ 4.5:1不单独依赖颜色区分序列需配合形状、线型或标签。此外提示词明确了两条“不变量”动画必须“为了教学”每个动画元素对应概念的一个步骤以及本最小演示没有任何宿主侧 sandbox 函数——可视化必须自运行、自循环禁止 fetch / XHR / localStorage / cookie /Websandbox.connection.remote调用。四、.NET 后端 AgentOpenGenUiAgentFactoryAgent 实现在 agent/OpenGenUiAgent.cs 中。README 的核心描述是这是一个ChatClientAgent其系统提示词约束 LLM每轮恰好调用一次generateSandboxedUi前端工具且不注册任何后端工具。CreateAgent()的关键部分对应 OpenGenUiAgent.cspublic AIAgent CreateAgent() { var chatClient _openAiClient.GetChatClient(gpt-4o-mini).AsIChatClient(); // No backend tools. The generateSandboxedUi tool is registered // on the frontend by CopilotKitProvider (when openGenerativeUI // is enabled on the runtime) and merged into the agents tool // list by the AG-UI protocol as a frontend-side action. return new ChatClientAgent( chatClient, name: OpenGenUiAgent, instructions: SystemPrompt); }值得注意的设计点generateSandboxedUi对 .NET 后端而言是“不存在”的工具——它由前端CopilotKitProvider注册AG-UI 协议在握手时将其合并进 Agent 的可见工具列表作为 frontend-side action 返回前端执行。后端的职责只是“提示词工程”系统提示词OpenGenUiAgent.cs复述了 design skill 的关键不变量SVG 优先、轴标签、keyframes优先、动画即教学、无网络访问并规定输出顺序initialHeight → placeholderMessages → css → html同时要求 LLM 的聊天消息保持一句话——真正的输出是渲染出来的可视化本身。模型与凭据从配置解析构造函数通过ApiKeyResolver.ResolveApiKey/ResolveEndpoint读取配置并创建OpenAIClient见 OpenGenUiAgent.cs默认模型为gpt-4o-mini。.NET 服务侧通过MapAGUI暴露 AG-UI 端点agent/Program.csvar openGenUiFactory new OpenGenUiAgentFactory(builder.Configuration); app.MapAGUI(/open-gen-ui, openGenUiFactory.CreateAgent()); var openGenUiAdvancedFactory new OpenGenUiAdvancedAgentFactory(builder.Configuration); app.MapAGUI(/open-gen-ui-advanced, openGenUiAdvancedFactory.CreateAgent());五、Runtime 路由开启openGenerativeUI开关专用路由 src/app/api/copilotkit-ogui/route.ts 是整条链路的枢纽。核心配置runtime: new CopilotRuntime({ agents, openGenerativeUI: { agents: [open-gen-ui, open-gen-ui-advanced], }, }),配合basePath: /api/copilotkit-ogui与mode: single-route由createCopilotRuntimeHandler导出POST处理器。该文件顶部注释解释了两个重要实现细节为什么需要独立路由openGenerativeUI运行时会把 probe 响应中的openGenerativeUIEnabled: true全局置位这会导致CopilotKitProvider的setToolseffect 清掉默认 runtime 里其他演示的useFrontendTool/useComponent注册。因此把该开关隔离在专用 runtime 中避免互相干扰。OpenGenUiHttpAgent的 toolCallId 重写路由对ag-ui/client的HttpAgent做了包装route.ts对所有generateSandboxedUi的工具调用 ID 追加__ogui_run_{runId}后缀常量OGUI_TOOL_CALL_ID_SUFFIX /__ogui_run_[0-9a-f-]$/i并在回放历史消息时剥掉该后缀。从源码结构看其意图是让每一轮 run 的 OGUI 活动消息 ID 全局唯一、避免跨 run 复用同一 toolCallId 造成的活动冲突。两个 agent 分别代理到 .NET 后端的/open-gen-ui与/open-gen-ui-advanced端点AGENT_URL环境变量可覆盖默认的http://localhost:8000。六、中间件原理OpenGenerativeUIMiddleware把工具调用转成活动事件README 提到“runtime 的OpenGenerativeUIMiddleware把流式的generateSandboxedUi工具调用转换为open-generative-uiactivity 事件”。实现位于 packages/runtime/src/v2/runtime/open-generative-ui-middleware.ts核心常量const TOOL_NAME generateSandboxedUi; const ACTIVITY_TYPE open-generative-ui;其工作机制均可在该文件中验证增量 JSON 解析每个TOOL_CALL_START工具名为generateSandboxedUi时创建ArgsParser内部用clarinet流式 JSON 解析器逐个消费TOOL_CALL_ARGS的delta在参数或数组元素解析完成时立即发出事件无需等整个 JSON 结束ArgsParser。快照先于增量AG-UI 活动消息要求ACTIVITY_SNAPSHOT必须先于任何ACTIVITY_DELTA存在客户端会丢弃没有快照的 delta而 LLM 控制流式参数的键顺序因此emitParamDelta内部会在需要时补发快照快照内容为{ initialHeight, generating: true }open-generative-ui-middleware.ts。HTML 特殊流式处理html参数不会等完整字符串解析完而是直接读解析器内部textNode缓冲区把增量内容以/{/html}/-的 JSON Patch 数组追加方式持续发出emitPendingHtml字符串结束后发htmlComplete: true。数组参数placeholderMessages与jsExpressions在onopenarray时先 patch 一个空数组之后每个元素用add /key/-追加。完成信号TOOL_CALL_END到达时发出{ op: add, path: /generating, value: false }的 delta标记生成结束。保序策略TOOL_CALL_START事件被暂存held直到首个活动事件发出后才随活动流一起放行RUN_FINISHED同样被压后保证活动事件先于结束事件到达前端processStream。解析出错时会重置解析器状态并继续parser.resume()保证流不中断。七、渲染器原理OpenGenerativeUIActivityRenderer与沙盒 iframe前端渲染器实现位于 packages/react-core/src/v2/components/OpenGenerativeUIRenderer.tsx由CopilotKitProvider针对 activityTypeopen-generative-ui自动注册。内容契约活动内容由 Zod schema 约束OpenGenerativeUIContentSchema字段为initialHeight、generating、css/cssComplete、html字符串数组/htmlComplete、jsFunctions/jsFunctionsComplete、jsExpressions数组/jsExpressionsComplete。渲染流程的关键设计节流与即时刷新的双轨机制外层组件用 ref 吸收父组件重渲染默认对内容更新做 1 秒节流THROTTLE_MS 1000但shouldFlushImmediately判定若干关键状态首个 html chunk、cssComplete、htmlComplete、generating false、jsFunctions出现、jsExpressions增长时同步刷新保证关键帧不延迟。预览流式渲染在cssComplete之前显示占位CSS 就绪后processPartialHtmlextractCompleteStyles处理不完整的 HTML 片段注入预览沙盒 iframe 实时呈现“正在写出的”文档。最终沙盒HTML 完整后动态import(jetbrains/websandbox)创建沙盒动态导入是为规避 websandbox 在模块顶层引用self导致的 SSR 问题通过allowAdditionalAttributes: 限制 iframe 属性——从源码结构看即 iframe 仅允许脚本运行对应 README 所述iframe sandboxallow-scripts语义。CSS 通过injectCssIntoHtml注入head。高度自适应initialHeight默认回退 200生成结束后在沙盒内执行一段测量脚本用body.scrollHeight而非被 iframe 视口钳制的documentElement.scrollHeight计算真实高度经postMessage({ type: __ck_resize, height })回传宿主并一次性生效。高级变体的 JS 通道jsFunctions会整段注入沙盒jsExpressions按序执行沙盒未就绪时进 pending 队列就绪后冲刷。最小演示不使用这两个字段。占位符渲染同文件的OpenGenerativeUIToolRenderer在工具执行期间轮播placeholderMessages完成时返回 null把舞台交给活动渲染器。八、进阶变体让生成的 UI 调用宿主函数README 末尾指向open-gen-ui-advanced演示open-gen-ui-advanced/README.md进阶版让生成的 UI 通过Websandbox.connection.remote.name(args)回调宿主页面函数如evaluateExpression计算器求值、notifyHost通知。其接线差异仅在前端——Provider 增加openGenerativeUI{{ sandboxFunctions: openGenUiSandboxFunctions }}每个宿主函数用 Zod schema 描述Provider 会把描述注入 Agent 上下文让 LLM 知道有哪些 remote 可用服务端openGenerativeUI开关配置与最小版完全相同见 route.ts 注释。九、验证与延伸阅读该演示配有 Playwright E2E 用例 tests/e2e/open-gen-ui.spec.ts 与 tests/e2e/open-gen-ui-advanced.spec.ts可通过仓库的 showcase 测试体系回归“建议点击 → 沙盒组件出现”的完整链路。Runtime 侧中间件的行为由 packages/runtime/src/v2/runtime/tests/open-generative-ui-middleware.e2e.test.ts 覆盖前端 Provider 的工具注册行为有 packages/react-core/src/v2/providers/tests/CopilotKitProvider.openGenerativeUIToolLoss.test.tsx 与 packages/react-core/src/v2/components/tests/OpenGenerativeUIRenderer.test.tsx 佐证。前端 Provider 侧的openGenerativeUI能力入口在 packages/react-core/src/v2/providers/CopilotKitProvider.tsx设计 skill 的注入逻辑可在此文件中检索designSkill定位。相关但不同的 Generative UI 路线声明式组件注册、工具渲染可对照本 showcase 中的 gen-ui-tool-based 演示说明 与 declarative-gen-ui 演示。适用前提小结该链路要求前端使用copilotkit/react-core/v2的CopilotKitCopilotChatRuntime 使用copilotkit/runtime/v2的CopilotRuntime并显式声明openGenerativeUI.agents白名单后端任意能暴露 AG-UIMapAGUI端点的 Agent 框架本演示为 Microsoft Agent Framework .NET OpenAIgpt-4o-mini生成物运行在仅允许脚本的沙盒 iframe 中无同源网络与存储访问initialHeight、placeholderMessages、css、html的输出顺序由 design skill 与系统提示词共同约束。【免费下载链接】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),仅供参考
返回列表