news 2026/9/14 13:58:40

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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 直接编写前端代码,自由度更高。整条链路从源码看如下:

<CopilotChat>(agentId="open-gen-ui") │ 用户消息 ▼ /api/copilotkit-ogui ── openGenerativeUI: { agents: [...] } 开启 │ AG-UI HttpAgent 代理(重写 toolCallId) ▼ .NET Agent 端点 /open-gen-ui(MapAGUI) │ ChatClientAgent + 系统提示词 ▼ LLM 调用前端工具 generateSandboxedUi(流式参数) │ OpenGenerativeUIMiddleware 拦截 ▼ ACTIVITY_SNAPSHOT / ACTIVITY_DELTA(activityType = "open-generative-ui") ▼ OpenGenerativeUIActivityRenderer → Websandbox 沙盒 iframe 渲染

下面按“前端 → Agent → Runtime → 中间件 → 渲染器”的顺序逐层展开。

二、前端接线:最小 Provider 配置

演示页面 page.tsx 的核心代码只有几行:

return ( <CopilotKit runtimeUrl="/api/copilotkit-ogui" agent="open-gen-ui" openGenerativeUI={{ designSkill: VISUALIZATION_DESIGN_SKILL }} > <div className="flex justify-center items-center h-screen w-full"> <div className="h-full w-full max-w-4xl flex flex-col p-3"> <Chat /> </div> </div> </CopilotKit> );

三点关键说明(对应文件内注释):

  1. 内置活动渲染器由CopilotKitProvider自动注册——只要 Runtime 开启了openGenerativeUI,一个普通的<CopilotChat />就够了,无需自定义 tool renderer、无需手动注册 activity renderer;
  2. runtimeUrl指向专用路由/api/copilotkit-ogui,而不是默认 runtime(原因见第四节);
  3. openGenerativeUI.designSkill用于替换默认的 shadcn 风格 design skill,注入面向教育可视化的设计约束(见第三节)。

配套的聊天组件 chat.tsx 仅两行有效逻辑:

export function Chat() { useOpenGenUISuggestions(); return <CopilotChat agentId="open-gen-ui" className="flex-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工具。其约束体系可以概括为七个方面(原文为英文提示词,此处归纳并摘录关键条目):

  1. 几何与渲染:优先内联 SVG(或<canvas>),绝不允许用几十个<div>堆叠画图形;内容控制在约 600×400 区域、留 16–24px 边距,用viewBox + preserveAspectRatio保证缩放;3D 场景用 SVG 手动透视或 CSS 3D transform(transform-style: preserve-3d)。
  2. 动画:优先 CSS@keyframes+ transition 而非 JSsetInterval,单周期 300–900ms,周期性概念用animation-iteration-count: infinite循环;必须用 JS 计时时用requestAnimationFrame;用animation-delay让相关元素错峰。
  3. 标签与图例:每条轴必须有标签(如 "Pitch (X)");每个颜色序列必须配图例色块和短说明;加入文字标注解释“观众正在看什么”;顶部一行标题 + 一行副标题。
  4. 语义色板(固定 hex 值,保持一致):
- 主运动/强调: indigo #6366f1 - 成功/稳定: emerald #10b981 - 警示/活跃: amber #f59e0b - 错误/对比: rose #ef4444 - 中性轴/网格: slate #64748b - 表面: 白 #ffffff / 容器底 #f8fafc / 文字 #0f172a
  1. 排版:system-ui 字体族;标题 16–18px/600,副标题 12–13px/500,轴与图例 11–12px,标注 11–13px;数字读数用tabular-nums
  2. 输出契约(严格按顺序)
- 先发 initialHeight(可视化通常 480–560) - placeholderMessages: 2–3 行短句(如 ["Sketching the scene…", "Labelling axes…"]) - css: 完整且自包含 - html: 单一根容器(标题 + 副标题 + SVG/canvas + 图例); Chart.js / D3 等 CDN <script> 标签写在 html 内部
  1. 无障碍:文字对比度 ≥ 4.5:1;不单独依赖颜色区分序列,需配合形状、线型或标签。

此外提示词明确了两条“不变量”:动画必须“为了教学”(每个动画元素对应概念的一个步骤),以及本最小演示没有任何宿主侧 sandbox 函数——可视化必须自运行、自循环,禁止 fetch / XHR / localStorage / cookie /Websandbox.connection.remote调用。

四、.NET 后端 Agent:OpenGenUiAgentFactory

Agent 实现在 agent/OpenGenUiAgent.cs 中。README 的核心描述是:这是一个ChatClientAgent,其系统提示词约束 LLM每轮恰好调用一次generateSandboxedUi前端工具,且不注册任何后端工具

CreateAgent()的关键部分(对应 OpenGenUiAgent.cs):

public 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 agent's 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.cs):

var 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处理器。

该文件顶部注释解释了两个重要实现细节:

  1. 为什么需要独立路由openGenerativeUI运行时会把 probe 响应中的openGenerativeUIEnabled: true全局置位,这会导致CopilotKitProvidersetToolseffect 清掉默认 runtime 里其他演示的useFrontendTool/useComponent注册。因此把该开关隔离在专用 runtime 中,避免互相干扰。
  2. OpenGenUiHttpAgent的 toolCallId 重写:路由对@ag-ui/clientHttpAgent做了包装(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_ARGSdelta,在参数(或数组元素)解析完成时立即发出事件,无需等整个 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
  • 数组参数placeholderMessagesjsExpressionsonopenarray时先 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),字段为initialHeightgeneratingcss/cssCompletehtml(字符串数组)/htmlCompletejsFunctions/jsFunctionsCompletejsExpressions(数组)/jsExpressionsComplete

渲染流程的关键设计:

  1. 节流与即时刷新的双轨机制:外层组件用 ref 吸收父组件重渲染,默认对内容更新做 1 秒节流(THROTTLE_MS = 1000);但shouldFlushImmediately判定若干关键状态(首个 html chunk、cssCompletehtmlCompletegenerating === falsejsFunctions出现、jsExpressions增长)时同步刷新,保证关键帧不延迟。
  2. 预览流式渲染:在cssComplete之前显示占位;CSS 就绪后,processPartialHtml+extractCompleteStyles处理不完整的 HTML 片段,注入预览沙盒 iframe 实时呈现“正在写出的”文档。
  3. 最终沙盒:HTML 完整后动态import("@jetbrains/websandbox")创建沙盒(动态导入是为规避 websandbox 在模块顶层引用self导致的 SSR 问题),通过allowAdditionalAttributes: ""限制 iframe 属性——从源码结构看,即 iframe 仅允许脚本运行,对应 README 所述<iframe sandbox="allow-scripts">语义。CSS 通过injectCssIntoHtml注入<head>
  4. 高度自适应initialHeight默认回退 200;生成结束后在沙盒内执行一段测量脚本,用body.scrollHeight(而非被 iframe 视口钳制的documentElement.scrollHeight)计算真实高度,经postMessage({ type: "__ck_resize", height })回传宿主并一次性生效。
  5. 高级变体的 JS 通道jsFunctions会整段注入沙盒,jsExpressions按序执行(沙盒未就绪时进 pending 队列,就绪后冲刷)。最小演示不使用这两个字段。
  6. 占位符渲染:同文件的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/v2CopilotKit+CopilotChat,Runtime 使用@copilotkit/runtime/v2CopilotRuntime并显式声明openGenerativeUI.agents白名单,后端任意能暴露 AG-UIMapAGUI端点的 Agent 框架(本演示为 Microsoft Agent Framework .NET + OpenAIgpt-4o-mini);生成物运行在仅允许脚本的沙盒 iframe 中,无同源网络与存储访问,initialHeightplaceholderMessagescsshtml的输出顺序由 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),仅供参考

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

ToolJet 如何在 RunJS 中故意抛出错误来调试查询失败事件处理?

ToolJet 如何在 RunJS 中故意抛出错误来调试查询失败事件处理&#xff1f; 【免费下载链接】ToolJet Open-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Buil…

作者头像 李华
网站建设 2026/9/14 13:55:49

Keyme Pass通过坚果云WebDAV实现安全自动同步

1. 项目背景与核心需求 作为一名长期使用密码管理工具的老用户&#xff0c;我一直在寻找一种安全可靠的自动同步方案。Keyme Pass&#xff08;KeePass兼容客户端&#xff09;作为开源密码管理工具&#xff0c;其数据库文件通常需要手动复制到不同设备&#xff0c;这种操作既繁琐…

作者头像 李华
网站建设 2026/9/14 13:55:47

SSD/U盘数据恢复核心技术解析与实战指南

1. 项目概述&#xff1a;免费数据恢复工具的核心价值去年帮朋友抢救一块突然罢工的固态硬盘时&#xff0c;我试遍了市面上十几款数据恢复软件。大多数免费工具要么对SSD支持有限&#xff0c;要么预览功能形同虚设——直到发现这款支持固态硬盘/U盘类型预览的免费方案。不同于传…

作者头像 李华
网站建设 2026/9/14 13:55:22

三阶RC模型下的无迹卡尔曼滤波电池SOC估算实践

简介&#xff1a;面向锂电池SOC估算与BMS算法开发的MATLAB/Simulink资源包&#xff0c;适合从事电池状态估计研究的工程师与学生。内容覆盖改进扩展卡尔曼滤波&#xff08;EKF&#xff09;估算SOC、基于卡尔曼滤波的电池参数辨识、三阶RC等效电路模型&#xff0c;以及无迹卡尔曼…

作者头像 李华
网站建设 2026/9/14 13:54:56

海康道闸LED屏Windows本地控制SDK详解

简介&#xff1a;本资源是海康威视HCEhomeSDK V2.1.7.1&#xff08;2019年3月26日发布&#xff09;的Windows 64位中文开发包&#xff0c;专为嵌入式及安防系统开发者设计&#xff0c;用于快速集成海康道闸、LED显示屏与抓拍机等硬件&#xff0c;构建智慧停车、社区门禁等物联网…

作者头像 李华
网站建设 2026/9/14 13:52:38

零成本视频创作:从剪辑到发布的开源资源全攻略

零成本视频创作&#xff1a;从剪辑到发布的开源资源全攻略 作为一名视频创作者&#xff0c;你是否曾因昂贵的专业软件望而却步&#xff1f;是否在寻找免费却功能强大的剪辑工具时迷失在杂乱的资源中&#xff1f;本文将系统梳理适合新手的免费视频剪辑软件、素材获取渠道和实用…

作者头像 李华