给 AI 生成 UI 上“护栏“:json-render 白名单配置从零到生产
给 AI 生成 UI 上护栏json-render 白名单配置从零到生产【免费下载链接】json-renderThe Generative UI framework项目地址: https://gitcode.com/GitHub_Trending/js/json-render2026 年初Vercel Labs 开源的 json-render 在短短几天内拿下数千 Star、十天内突破一万一千几乎在一夜之间把生成式 UIGenerative UI这个概念从 PPT 变成了生产级工具。社区讨论的高频词既不是AI 多聪明而是guardrails护栏与可控。这恰恰切中了过去两年 AI 生成界面最深的痛点让大模型裸写 HTML、JSX 或 CSS输出既不稳定也充满安全与工程隐患。本文结合 json-render 源码从为什么护栏是刚需讲到白名单机制的每一层实现最后给出一份可直接落地的生产环境最小护栏清单。为什么 LLM 裸输出 HTML 不可控让模型直接生成 HTML 或组件代码是 AI 生成 UI 最直观的思路但社区实践反复证明这条路的代价输出结构不稳定。同一个 prompt模型可能给出三种不同的 DOM 结构样式类名随机漂移前端只能把它当黑盒注入页面无法复用、无法维护、无法做 SSR。组件与业务割裂。模型不认识你的设计系统生成的按钮不会调用你的提交接口图表不认识你的数据源最终产物只能看起来像 UI不能真正工作。安全边界无法收敛。模型生成的内联脚本、任意img src、危险 URL、不受控的交互逻辑都会成为 XSS 与数据泄露的入口一旦AI 能写任意 HTML等于把攻击面交给了黑盒。json-render 的解法是把链路从AI → HTML改成AI → JSON Spec → 受控渲染器AI 只负责在预定义的组件白名单内声明意图intent你的应用负责提供实现。用仓库文档的原话——You set the guardrails, AI generates within themREADME.md而实现这一承诺的是三层递进的白名单机制。第一层护栏组件白名单Catalogjson-render 的核心抽象是Catalog目录。官方文档对它的定位非常直白The catalog defines what AI can generate. Its your guardrail.catalog 文档/docs/catalog/page.mdx)。目录里列了哪些组件AI 就只能在哪些组件里选。这层约束不是靠提示词劝告而是被写进了类型系统与校验逻辑。在 React 的 schema 定义中元素的type字段被显式声明为对目录组件名的引用packages/react/src/schema.tsspec: s.object({ root: s.string(), elements: s.record( s.object({ /** Component type from catalog */ type: s.ref(catalog.components), /** Component props */ props: s.propsOf(catalog.components), ...ref(catalog.components)在编译成 Zod schema 时会从你的 catalog 数据里取出全部组件名生成一个enum 枚举见 packages/core/src/schema.ts 中buildZodType对ref分支的处理。也就是说白名单之外的组件名在catalog.validate()校验阶段就会直接判失败根本走不到渲染。实际工程中的白名单定义长这样来自真实示例 examples/chat/lib/render/catalog.tsexport const explorerCatalog defineCatalog(schema, { components: { Stack: shadcnComponentDefinitions.Stack, Card: shadcnComponentDefinitions.Card, Grid: shadcnComponentDefinitions.Grid, Heading: shadcnComponentDefinitions.Heading, // ... Text: { props: z.object({ content: z.string(), muted: z.boolean().nullable(), }), description: Text content, }, Button: { props: z.object({ label: z.string(), variant: z.enum([default, secondary, destructive, outline, ghost]).nullable(), // ... }), description: Clickable button. Use with on.press to trigger actions..., }, }, actions: {}, });项目还内置了 36 个预置的 shadcn/ui 组件定义Card、Stack、Grid、Tabs、Dialog、Drawer 等见 packages/shadcn/src/catalog.ts 与 packages/shadcn/src/ui开箱即可作为白名单的起点。第二层护栏props 与槽位的配置项白名单组件名被锁死后AI 能往组件里塞什么参数同样不能失控。json-render 为每个组件用 Zod 声明props schema类型、取值范围、是否可空全都提前钉死。一个很典型的设计可选值一律用z.enum或.nullable()禁止模型自由发挥。例如 shadcn 目录里的Stack组件packages/shadcn/src/catalog.tsStack: { props: z.object({ direction: z.enum([horizontal, vertical]).nullable(), gap: z.enum([none, sm, md, lg, xl]).nullable(), align: z.enum([start, center, end, stretch]).nullable(), justify: z.enum([start, center, end, between, around]).nullable(), className: z.string().nullable().describe(Additional CSS classes), }), slots: [default], description: Flex container for layouts, },这层约束至少带来三个收益可渲染性模型永远无法传出一个渲染器不认识的 prop从根上消灭类名魔法字符串。安全性href、src这类敏感字段依然可以出现在白名单里但由你决定它是否开放、如何开放。文档即护栏description和example不只是给人看的注释它们会被注入到系统提示词中作为模型何时使用该组件、怎么传参的行为规范。同时组件还声明了自己的slots 白名单slots: [default, header, footer]。渲染器在运行时会对 spec 中的槽位名做校验遇到未知槽位会打出告警packages/react/src/renderer.tsxconst metadata registryMetadata.get(registry)?.[resolvedElement.type]; if (resolvedElement.slots metadata?.slots) { const availableSlots new Set(metadata.slots); for (const slotName of Object.keys(resolvedElement.slots)) { if (slotName default) { console.warn([json-render] Component ${resolvedElement.type} uses slots.default. Use children...); } else if (!availableSlots.has(slotName)) { console.warn([json-render] Unknown slot ${slotName} on component ${resolvedElement.type}...); } } }交互事件的命名空间同样被约束组件通过events字段声明自己能发出的事件如Tabs声明events: [change]spec 中的on字段只能绑定这些事件。第三层护栏行为白名单ActionsUI 只是表象AI 生成的界面真正危险的是它能干什么。json-render 的第二张白名单就是ActionsAI 触发的每一个行为都必须先在 catalog 里声明运行时才会给模型对应的事件处理函数。目录中声明了哪些 action提示词里就只会列出哪些 actionAVAILABLE ACTIONS段落见 packages/core/src/schema.ts 的 prompt 生成逻辑运行时defineRegistry只把 catalog 中声明的 action 注册进 handlersexecuteAction遇到未声明的 action 名称会直接告警Unknown actionpackages/react/src/renderer.tsx 的defineRegistry实现。- setState: Update a value in the state model at the given statePath... [built-in] - pushState: Append an item to an array in state... [built-in] - removeState: Remove an item from an array in state by index... [built-in] - validateForm: Validate all registered form fields... [built-in] - export_report: Export dashboard to PDF - refresh_data: Refresh all metrics注意这里的分层设计packages/react/src/schema.tssetState、pushState、removeState、validateForm是built-in actions由运行时直接实现、始终可用而export_report这类业务动作必须由你编写处理函数AI 只能指名道姓地引用永远接触不到背后的实现细节。此外ActionBindingpackages/core/src/actions.ts还支持confirm执行前的确认对话框、onSuccess成功后导航 / 写状态 / 链式触发动作、onError失败回写错误信息到状态等声明式配置。对于删除、提交等危险动作可以要求 AI 生成confirm声明由运行时统一弹出确认框——行为边界又多了一层。数据边界状态模型与动态绑定白名单体系覆盖组件和行为之后还有一个容易忽略的维度数据。json-render 用显式的state model JSON Pointer 路径管理所有动态数据AI 生成的数据读取{ $state: /path }、双向绑定{ $bindState: /path }、列表渲染repeat: { statePath: /todos }都建立在状态模型之上而不是让 AI 把数据硬编码进 propspackages/core/src/types.ts 中$state/$bindState/$item的解析实现。这对护栏的意义在于UI 长什么样和数据从哪来被彻底分离。AI 只能引用你提供的状态路径无法凭空发明数据源表单值、筛选条件、弹窗开关全部经由状态模型收敛也就天然拥有了审计与治理的抓手。运行时兜底白名单之外的静默降级工程上的护栏不能只靠前置校验——AI 的输出在流式传输过程中随时可能出错。json-render 的渲染器为此做了一整套降级策略packages/react/src/renderer.tsx// Get the component renderer const Component registry[resolvedElement.type] ?? fallback; if (!Component) { console.warn(No renderer for component type: ${resolvedElement.type}); return null; }未知组件白名单里没有的type直接回退到fallback组件或什么都不渲染而不是把dangerouslySetInnerHTML塞给页面元素级错误边界每个元素都被ElementErrorBoundary包裹单个组件渲染崩溃只导致该元素静默消失绝不拖垮整个应用缺失子元素spec 中引用了不存在的 child key 时只打告警并跳过界面其余部分照常渲染流式中间态SpecStream 以 RFC 6902 JSON Patch 逐行输出packages/core/src/types.tscreateSpecStreamCompiler边收边构建UI 渐进填充护栏校验也逐补丁生效。换句话说白名单既是准入证也是安全网模型输出越界最坏结果是某个元素不渲染而不是整页崩溃或被注入任意代码。生产环境最小可行护栏清单把以上机制组合成一份可以直接抄进生产项目的检查清单大约有七项1. 白名单只放需要的组件Catalog 不是组件库快照而是你的 UI 能力声明。生产环境建议从一个较小的起点开始用预置的 packages/shadcn/src/catalog.ts 挑出业务必需的十几个组件按需逐步放开而不是一次性全量开放。2. 每个 props 都写严格 Zod schema类型收窄、可选值用z.enum、敏感字段URL、超链接文本单独约束。参考 examples/chat/lib/render/catalog.ts 中Link组件的写法——href只接受字符串且渲染时强制target_blankrelnoopener noreferrer。3. 给 AI 写 customRules白名单之外用catalog.prompt({ customRules })注入行为规则例如仪表盘最多 6 个 widget时间序列数据必须用 LineChart。这些规则与AVAILABLE COMPONENTS列表一起进入系统提示词packages/core/src/schema.ts 的 prompt 生成器是成本最低的一层护栏。4. 结构化输出 严格校验双保险catalog.jsonSchema({ strict: true })会导出兼容 OpenAI / Gemini / Anthropic 结构化输出 API 的 JSON SchemaadditionalProperties: false、全部属性进required拿到输出后再用catalog.validate(spec)基于 Zod 二次校验双保险拦截越界输出见 packages/core/src/schema.ts 与 自定义 schema 文档/docs/custom-schema/page.mdx)。5. 备好 fallback 组件给Renderer传入一个fallback让未知类型有可视化的降级呈现而不是悄无声息地消失。示例项目中就提供了这种兜底examples/chat/lib/render/registry.tsx 中的Fallback组件。6. 动作权限最小化catalog 的actions只声明确实需要 AI 触发的业务动作删除、覆盖等危险动作要求confirm确认涉及跳转/写回的一律通过onSuccess/onError显式声明。7. 锁定状态路径所有动态数据走$state/$bindState不在 props 里硬编码业务数据上线前可以人为注入恶意 spec未知 type、未知 action、危险 props跑一遍降级路径确认全部被护栏拦截。examples/dashboard正是这套清单的完整样例——README 中写道AI-generated dashboard widgets with guardrails. Each widget is streamed from an LLM, constrained by a json-render catalog, and rendered with shadcn components and Recharts.examples/dashboard/README.md。LLM 负责画catalog 负责管渲染器负责兜底三者各司其职。小结回顾 json-render 的白名单体系它的高明之处在于把护栏从提示词层面的软约束升级成了类型系统 运行时校验 降级兜底的硬约束组件名是枚举、props 是 Schema、行为是声明式 Action、数据被状态模型收敛、越界输出被 ErrorBoundary 兜住。四个维度叠加才让AI 生成 UI从不可控的黑盒实验变成了可以上线、可以审计、可以交给非前端同事使用的工程能力。这或许也是它在社区迅速走红之后留给工程界的真正启示生成式 UI 的竞争点从来不是模型生得多像而是护栏设得多稳。【免费下载链接】json-renderThe Generative UI framework项目地址: https://gitcode.com/GitHub_Trending/js/json-render创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

用NAS把收藏夹文章变成专属播客:搭建指南

用NAS把收藏夹文章变成专属播客:搭建指南

我猜你八成也有这么个毛病:看到一篇好文章先收藏,想着“回头认真读”,结果这个“回头”就是永远。收藏夹里堆了几百篇深度长文,从AI技术、投资分析到历史考据,什么都有,就是没有时间去读。直到有天我在通勤…

2026/10/10 20:47:31 阅读更多 →
把“留痕“当一等公民:金融智能体的审计设计为什么比模型能力更烧钱

把“留痕“当一等公民:金融智能体的审计设计为什么比模型能力更烧钱

把"留痕"当一等公民:金融智能体的审计设计为什么比模型能力更烧钱 【免费下载链接】financial-services 可将 Claude 转变为金融服务专家,适用于投资银行、股票研究等领域。提供核心及专项插件,支持端到端工作流,集成多…

2026/10/10 20:47:31 阅读更多 →
基于Java的校园二手智能交易平台APP开发全攻略

基于Java的校园二手智能交易平台APP开发全攻略

1. 项目到底在做什么:需求与定位拆解每年毕业设计季,“校园二手交易平台”这类题目都是常青树,但今年我带着学生把“基于Java的校园二手智能交易平台APP”完整做成可运行系统时,发现很多人对这个题目的理解还停留在十年前&#xf…

2026/10/10 20:46:30 阅读更多 →

最新新闻

用电量数据分享实战:从数据清洗到时序分析

用电量数据分享实战:从数据清洗到时序分析

简介:这份资源面向制造行业数据分析与时间序列预测的学习者,围绕用电量数据展开,重点演示如何用LSTM循环神经网络对电力消耗模式进行建模与预测。包内共106个文件,以59个csv数据与预测结果文件、24张jpg图表、7个py源码脚本为主&a…

2026/10/10 21:25:11 阅读更多 →
Python实现VRPTW遗传算法:物流调度实战指南

Python实现VRPTW遗传算法:物流调度实战指南

简介:本资源是一个面向物流优化与智能算法学习者的Python实践项目,聚焦带时间窗的车辆路径问题(VRPTW)求解,适合具备基础Python编程能力及运筹学背景的高校学生、算法工程师与科研初学者。项目采用遗传算法实现全局搜索…

2026/10/10 21:25:11 阅读更多 →
S7-1200编程实战:配料站与输送线自动化控制解析

S7-1200编程实战:配料站与输送线自动化控制解析

最近翻项目存档,把去年给建材厂做的两个S7-1200程序调出来看了一遍,感触还挺多。当时赶工期的时候觉得都是常规活儿,现在回头看,很多处理方式其实挺有代表性。正好有同行问我有没有适合参考的车间自动化程序案例,我就把…

2026/10/10 21:24:11 阅读更多 →
WebUploader切片机制:实现视频大文件秒传与稳定上传

WebUploader切片机制:实现视频大文件秒传与稳定上传

做企业内网视频库、媒体素材管理或者课程录播归档的时候,大家几乎都会撞上同一个痛点:视频文件动辄几个GB,直接用浏览器表单上传,传到一半网络闪断就得从头再来;同一个宣传片被同事反复导入,每次都要干等几…

2026/10/10 21:24:11 阅读更多 →
基于ESP32的智能家居温控系统设计与实现

基于ESP32的智能家居温控系统设计与实现

抱歉,这个项目标题涉及政治人物与经济政策的公开致辞解读,属于我无法安全处理的范围。我可以围绕技术、生活、职场、手工、创意等其他领域的项目标题来写深度拆解型博文,比如“基于ESP32的智能家居温控系统”“老式木桌翻新实录”这类方向。你…

2026/10/10 21:24:10 阅读更多 →
AnyPS5技术解析:跨平台串流与远程控制的架构设计与实现

AnyPS5技术解析:跨平台串流与远程控制的架构设计与实现

1. 从“AnyPS5”这个名字说起:它到底想解决什么问题第一次看到“AnyPS5”这个标题,我脑子里蹦出来的第一个念头是:这大概率又是一个围绕主机生态做“泛化能力”的项目。为什么这么说?因为“Any”这个前缀在技术圈里几乎已经成了一…

2026/10/10 21:24:10 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:25 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →