json-render:构建安全可控的 AI 生成 UI 框架

0 阅读11分钟

json-render:构建安全可控的 AI 生成 UI 框架

摘要:随着大语言模型(LLM)在应用开发中的广泛应用,如何让 AI 安全、可控地生成用户界面成为一个新兴的技术挑战。本文深入解析 Vercel 开源的 json-render 框架,探讨其"护栏机制"设计思想、核心技术架构、流式渲染实现原理,以及在实际项目中的应用模式。


一、背景与问题

1.1 AI 生成 UI 的挑战

当我们允许终端用户通过自然语言提示词生成 UI 时,会面临以下核心挑战:

挑战描述
安全性风险AI 可能生成任意代码或不安全的组件,导致 XSS、代码注入等安全问题
输出不可预测LLM 输出格式不稳定,难以直接渲染为可靠的 UI
性能问题等待 AI 完整响应后再渲染,用户体验差
扩展性限制难以与现有组件库和业务逻辑集成

传统的解决方案往往是让 AI 直接生成代码(如 React 组件),但这带来了严重的安全隐患——你无法预测 AI 会生成什么样的代码。

1.2 json-render 的解决思路

json-render 提出了一个核心理念:让 AI 只能生成符合预定义 Schema 的 JSON,而不是任意代码

这个理念可以用三个关键词概括:

Predictable(可预测)+ Guardrailed(有护栏)+ Fast(快速)
  • 有护栏:AI 只能使用你的 catalog 中的组件,不会生成任意代码
  • 可预测:JSON 输出始终匹配你的 schema,动作以名称声明,你控制它们的行为
  • 快速:模型响应时可流式、渐进渲染,无需等待完成

二、核心架构设计

2.1 整体架构分层

json-render 采用清晰的分层架构设计:

┌─────────────────────────────────────────────────────────────┐
│                    Application Layer                        │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐  │
│  │   Web App   │  │  Dashboard  │  │   Custom Apps       │  │
│  └──────┬──────┘  └──────┬──────┘  └──────────┬──────────┘  │
└─────────┼────────────────┼───────────────────┼──────────────┘
          │                │                   │
┌─────────▼────────────────▼───────────────────▼──────────────┐
│                    React Layer (@json-render/react)         │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐  │
│  │  Renderer   │  │  Providers  │  │      Hooks          │  │
│  │ (recursive) │  │  (Context)  │  │ (useUIStream, etc)  │  │
│  └─────────────┘  └─────────────┘  └─────────────────────┘  │
└─────────────────────────────────────────────────────────────┘
          │
┌─────────▼────────────────────────────────────────────────────┐
│                    Core Layer (@json-render/core)            │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────────┐  │
│  │ Catalog  │  │Visibility│  │ Actions  │  │ Validation   │  │
│  │ System   │  │  Engine  │  │  System  │  │   Engine     │  │
│  └──────────┘  └──────────┘  └──────────┘  └──────────────┘  │
└──────────────────────────────────────────────────────────────┘
          │
┌─────────▼────────────────────────────────────────────────────┐
│               Codegen Layer (@json-render/codegen)           │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐   │
│  │  Traverse   │  │  Serialize  │  │   Code Export       │   │
│  └─────────────┘  └─────────────┘  └─────────────────────┘   │
└──────────────────────────────────────────────────────────────┘

2.2 数据流设计

json-render 的数据流非常清晰:

┌─────────────┐     ┌──────────────┐     ┌─────────────┐
│ User Prompt │────▶│ AI + Catalog │────▶│  JSON Tree  │
│ "dashboard" │     │ (guardrailed)│     │(predictable)│
└─────────────┘     └──────────────┘     └─────────────┘
                                               │
                                               ▼
                    ┌──────────────────────────────────────┐
                    │           React Providers            │
                    │  ┌────────┐ ┌────────┐ ┌──────────┐  │
                    │  │ Data   │ │Action  │ │Visibility│  │
                    │  │Provider│ │Provider│ │ Provider │  │
                    │  └────────┘ └────────┘ └──────────┘  │
                    └──────────────────┬───────────────────┘
                                       │
                    ┌──────────────────▼───────────────────┐
                    │            Renderer                  │
                    │  (recursive tree → React components) │
                    └──────────────────────────────────────┘

2.3 包结构设计

框架被拆分为三个独立的包,职责清晰:

包名职责依赖关系
@json-render/core类型定义、Schema、纯逻辑仅依赖 zod
@json-render/reactReact 集成、UI 渲染依赖 corereact
@json-render/codegen代码生成工具仅依赖 core

这种设计的优点:

  • Core 包无 UI 框架依赖,可用于 SSR 或非 React 场景
  • 清晰的分层使得测试和维护更容易
  • Codegen 独立,可选引入

三、护栏机制:Catalog 系统

3.1 什么是 Catalog?

Catalog 是 json-render 的核心概念,它定义了 AI 能够生成什么——这就是"护栏"。Catalog 是一个 schema,定义:

  • Components — AI 可以创建的 UI 元素
  • Actions — AI 可以触发的操作
  • Validation Functions — 表单输入的自定义校验器

3.2 创建 Catalog

import { createCatalog } from '@json-render/core';
import { z } from 'zod';

const catalog = createCatalog({
  components: {
    // 定义每个组件及其 props schema
    Card: {
      props: z.object({
        title: z.string(),
        description: z.string().nullable(),
        padding: z.enum(['sm', 'md', 'lg']).default('md'),
      }),
      hasChildren: true, // 可以包含其他组件
    },
    
    Metric: {
      props: z.object({
        label: z.string(),
        valuePath: z.string(), // JSON Pointer 指向数据
        format: z.enum(['currency', 'percent', 'number']),
      }),
    },
  },
  
  actions: {
    submit_form: {
      params: z.object({
        formId: z.string(),
      }),
      description: 'Submit a form',
    },
    
    export_data: {
      params: z.object({
        format: z.enum(['csv', 'pdf', 'json']),
      }),
    },
  },
  
  validationFunctions: {
    isValidEmail: {
      description: 'Validates email format',
    },
    isPhoneNumber: {
      description: 'Validates phone number',
    },
  },
});

3.3 Schema 动态生成机制

Catalog 系统的技术实现非常精巧。它基于 Zod 的 discriminatedUnion 实现高效的类型区分:

export function createCatalog<...>(config: CatalogConfig<...>): Catalog<...> {
  // 1. 为每个组件类型创建 Zod schema
  const componentSchemas = componentNames.map((componentName) => {
    const def = components[componentName]!;
    return z.object({
      key: z.string(),
      type: z.literal(componentName as string),  // 限定 type 字段
      props: def.props,                          // 使用组件定义的 props schema
      children: z.array(z.string()).optional(),
      visible: VisibilityConditionSchema.optional(),
    });
  });

  // 2. 创建 discriminatedUnion(基于 type 字段区分)
  elementSchema = z.discriminatedUnion("type", [
    componentSchemas[0],
    componentSchemas[1],
    ...componentSchemas.slice(2)
  ]);

  // 3. 创建完整树 schema
  const treeSchema = z.object({
    root: z.string(),
    elements: z.record(z.string(), elementSchema),
  });
}

3.4 生成 AI 提示词

Catalog 不仅用于验证,还可以自动生成 AI 的系统提示词:

import { generateCatalogPrompt } from '@json-render/core';

const systemPrompt = generateCatalogPrompt(catalog);
// 将此提示词传递给 AI 模型

生成的提示词包含:

  • 列出所有可用组件及其 props
  • 描述可用动作
  • 指定期望的 JSON 输出格式
  • 包含示例以提升生成效果

四、动态值与数据绑定

4.1 JSON Pointer 路径

json-render 使用 JSON Pointer(RFC 6901)作为数据路径:

// 给定这样的数据:
{
  "user": {
    "name": "Alice",
    "email": "alice@example.com"
  },
  "metrics": {
    "revenue": 125000,
    "growth": 0.15
  }
}

// 这些路径访问:
"/user/name"        -> "Alice"
"/metrics/revenue"  -> 125000
"/metrics/growth"   -> 0.15

4.2 动态值类型设计

框架支持字面量和路径引用两种方式:

// 动态值可以是字面量或路径引用
type DynamicValue<T = unknown> = T | { path: string };

// 运行时解析
{ "valuePath": "/user/balance" }  // 从数据模型获取
{ "value": 1000 }                  // 静态值

4.3 数据绑定 Hooks

在 React 组件中使用数据绑定:

import { useDataValue, useDataBinding } from '@json-render/react';

// 只读访问
function Metric({ element }) {
  const value = useDataValue(element.props.valuePath);
  return <div>{formatValue(value)}</div>;
}

// 双向绑定
function TextField({ element }) {
  const [value, setValue] = useDataBinding(element.props.valuePath);
  return (
    <input
      value={value || ''}
      onChange={(e) => setValue(e.target.value)}
    />
  );
}

五、可见性条件引擎

5.1 声明式可见性条件

json-render 提供了强大的声明式可见性控制系统:

{
  "type": "RefundButton",
  "props": { "label": "Process Refund" },
  "visible": {
    "and": [
      { "auth": "signedIn" },
      { "eq": [{ "path": "/user/role" }, "support"] },
      { "gt": [{ "path": "/order/amount" }, 0] },
      { "not": { "path": "/order/isRefunded" } }
    ]
  }
}

5.2 递归逻辑表达式求值

可见性引擎支持复杂的逻辑组合:

type LogicExpression =
  | { and: LogicExpression[] }           // 逻辑与
  | { or: LogicExpression[] }            // 逻辑或
  | { not: LogicExpression }             // 逻辑非
  | { path: string }                     // 路径真值检查
  | { eq: [DynamicValue, DynamicValue] } // 相等比较
  | { gt: [DynamicValue<number>, DynamicValue<number>] }  // 大于比较
  // ... 更多比较操作符 (ne, gte, lt, lte)

function evaluateLogicExpression(
  expr: LogicExpression,
  ctx: VisibilityContext,
): boolean {
  // AND: 所有子表达式都为真
  if ("and" in expr) {
    return expr.and.every((subExpr) => evaluateLogicExpression(subExpr, ctx));
  }
  
  // OR: 任一子表达式为真
  if ("or" in expr) {
    return expr.or.some((subExpr) => evaluateLogicExpression(subExpr, ctx));
  }
  
  // NOT: 取反
  if ("not" in expr) {
    return !evaluateLogicExpression(expr.not, ctx);
  }
  
  // 比较操作...
}

5.3 权限控制集成

支持基于认证状态的可见性控制:

{
  "type": "AdminPanel",
  "visible": { "auth": "signedIn" }
}
// Options: "signedIn", "signedOut", "admin", etc.

六、动作系统

6.1 命名动作的设计哲学

json-render 的动作系统采用了一个关键的安全设计:AI 不再生成任意代码,而是通过名称声明"意图",由应用提供具体实现

这是核心护栏机制的重要组成部分。

6.2 定义动作

在 catalog 中定义可用动作:

const catalog = createCatalog({
  components: { /* ... */ },
  actions: {
    submit_form: {
      params: z.object({
        formId: z.string(),
      }),
      description: 'Submit a form',
    },
    export_data: {
      params: z.object({
        format: z.enum(['csv', 'pdf', 'json']),
        filters: z.object({
          dateRange: z.string().optional(),
        }).optional(),
      }),
    },
  },
});

6.3 提供动作处理器

import { ActionProvider } from '@json-render/react';

function App() {
  const handlers = {
    submit_form: async (params) => {
      const response = await fetch('/api/submit', {
        method: 'POST',
        body: JSON.stringify({ formId: params.formId }),
      });
      return response.json();
    },
    
    export_data: async (params) => {
      const blob = await generateExport(params.format, params.filters);
      downloadBlob(blob, `export.${params.format}`);
    },
  };

  return (
    <ActionProvider handlers={handlers}>
      {/* Your UI */}
    </ActionProvider>
  );
}

6.4 富动作系统

AI 可以声明需要用户确认的动作,以及成功/失败回调:

{
  "type": "Button",
  "props": {
    "label": "Delete Account",
    "action": {
      "name": "delete_account",
      "params": { "userId": "123" },
      "confirm": {
        "title": "Delete Account?",
        "message": "This action cannot be undone.",
        "variant": "danger"
      },
      "onSuccess": {
        "set": { "/ui/savedMessage": "Account deleted!" }
      },
      "onError": {
        "set": { "/ui/errorMessage": "$error.message" }
      }
    }
  }
}

七、流式渲染机制

7.1 JSONL 流式协议

json-render 使用 JSONL(JSON Lines)进行流式传输。AI 生成时,每一行代表一次补丁操作:

{"op":"set","path":"/root","value":"page"}
{"op":"add","path":"/elements/page","value":{"key":"page","type":"Stack","props":{"direction":"vertical"},"children":["header"]}}
{"op":"add","path":"/elements/header","value":{"key":"header","type":"Heading","props":{"text":"Dashboard","level":1}}}

7.2 支持的 Patch 操作

操作描述
set在路径上设置值(必要时会创建)
add向路径上的数组添加元素
replace替换路径上的值
remove移除路径上的值

7.3 useUIStream Hook

import { useUIStream } from '@json-render/react';

function App() {
  const {
    tree,        // Current UI tree state
    isLoading,   // True while streaming
    error,       // Any error that occurred
    generate,    // Function to start generation
    abort,       // Function to cancel streaming
  } = useUIStream({
    endpoint: '/api/generate',
  });
}

7.4 流式处理实现原理

export function useUIStream({ api, onComplete, onError }: UseUIStreamOptions) {
  const [tree, setTree] = useState<UITree | null>(null);
  const [isStreaming, setIsStreaming] = useState(false);

  const send = useCallback(async (prompt: string) => {
    // 1. 发起 POST 请求
    const response = await fetch(api, {
      method: "POST",
      body: JSON.stringify({ prompt }),
    });

    // 2. 流式读取响应
    const reader = response.body?.getReader();
    const decoder = new TextDecoder();
    let buffer = "";
    let currentTree: UITree = { root: "", elements: {} };

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      buffer += decoder.decode(value, { stream: true });
      
      // 3. 按行处理 JSONL
      const lines = buffer.split("\n");
      buffer = lines.pop() ?? "";

      for (const line of lines) {
        const patch = parsePatchLine(line);
        if (patch) {
          currentTree = applyPatch(currentTree, patch);
          setTree({ ...currentTree });  // 触发 React 重渲染
        }
      }
    }
  }, [api]);

  return { tree, isStreaming, send, clear };
}

八、React 渲染器

8.1 递归渲染架构

function ElementRenderer({ element, tree, registry, loading, fallback }) {
  // 1. 可见性检查
  const isVisible = useIsVisible(element.visible);
  if (!isVisible) return null;

  // 2. 获取组件渲染器
  const Component = registry[element.type] ?? fallback;
  if (!Component) {
    console.warn(`No renderer for component type: ${element.type}`);
    return null;
  }

  // 3. 递归渲染子元素
  const children = element.children?.map((childKey) => {
    const childElement = tree.elements[childKey];
    if (!childElement) return null;
    return (
      <ElementRenderer
        key={childKey}
        element={childElement}
        tree={tree}
        registry={registry}
      />
    );
  });

  // 4. 渲染当前元素
  return (
    <Component element={element} onAction={execute} loading={loading}>
      {children}
    </Component>
  );
}

8.2 Provider 组合模式

export function JSONUIProvider({
  registry,
  initialData,
  authState,
  actionHandlers,
  validationFunctions,
  children,
}: JSONUIProviderProps) {
  return (
    <DataProvider initialData={initialData} authState={authState}>
      <VisibilityProvider>
        <ActionProvider handlers={actionHandlers}>
          <ValidationProvider customFunctions={validationFunctions}>
            {children}
            <ConfirmationDialogManager />
          </ValidationProvider>
        </ActionProvider>
      </VisibilityProvider>
    </DataProvider>
  );
}

8.3 组件注册表

创建一个注册表,将 catalog 组件类型映射到 React 组件:

const registry = {
  Card: ({ element, children }) => (
    <div className="card">
      <h2>{element.props.title}</h2>
      {element.props.description && (
        <p>{element.props.description}</p>
      )}
      {children}
    </div>
  ),
  
  Button: ({ element, onAction }) => (
    <button onClick={() => onAction(element.props.action, {})}>
      {element.props.label}
    </button>
  ),
};

九、表单校验系统

9.1 内置校验器

json-render 内置常用校验函数:

  • required — 值不能为空
  • email — 有效的邮箱格式
  • minLength — 字符串最小长度
  • maxLength — 字符串最大长度
  • pattern — 匹配正则表达式
  • min — 最小数值
  • max — 最大数值

9.2 在 JSON 中使用校验

{
  "type": "TextField",
  "props": {
    "label": "Password",
    "valuePath": "/form/password",
    "checks": [
      { "fn": "required", "message": "Password is required" },
      { 
        "fn": "minLength", 
        "args": { "length": 8 },
        "message": "Password must be at least 8 characters"
      },
      {
        "fn": "pattern",
        "args": { "pattern": "[A-Z]" },
        "message": "Must contain at least one uppercase letter"
      }
    ],
    "validateOn": "blur"
  }
}

9.3 自定义校验函数

在 catalog 中定义,在 ValidationProvider 中实现:

// 定义
const catalog = createCatalog({
  validationFunctions: {
    isValidPhone: {
      description: 'Validates phone number format',
    },
    isUniqueEmail: {
      description: 'Checks if email is not already registered',
    },
  },
});

// 实现
const customValidators = {
  isValidPhone: (value) => {
    const phoneRegex = /^\+?[1-9]\d{1,14}$/;
    return phoneRegex.test(value);
  },
  isUniqueEmail: async (value) => {
    const response = await fetch(`/api/check-email?email=${value}`);
    const { available } = await response.json();
    return available;
  },
};

<ValidationProvider functions={customValidators}>
  {/* Your UI */}
</ValidationProvider>

十、代码导出功能

10.1 设计理念

虽然 json-render 旨在动态渲染,但你也可以把生成的 UI 导出为静态代码。代码生成有意做成项目特定,以便你完全掌控:

  • 组件模板(独立使用,不依赖 json-render)
  • package.json 与项目结构
  • 框架特定模式(Next.js、Remix 等)
  • 数据如何传递给组件

10.2 codegen 工具

import {
  traverseTree,          // Walk the UI tree
  collectUsedComponents, // Get all component types used
  collectDataPaths,      // Get all data binding paths
  collectActions,        // Get all action names
  serializeProps,        // Convert props to JSX string
} from '@json-render/codegen';

// 收集使用的组件
const components = collectUsedComponents(tree);
// Set { 'Card', 'Metric', 'Chart', 'Table' }

// 序列化 props
const propsStr = serializeProps({
  title: 'Dashboard',
  columns: 3,
  disabled: true,
});
// 'title="Dashboard" columns={3} disabled'

10.3 独立组件导出

导出的组件是独立的,不依赖 json-render:

// Generated component (standalone)
interface MetricProps {
  label: string;
  valuePath: string;
  data?: Record<string, unknown>;
}

export function Metric({ label, valuePath, data }: MetricProps) {
  const value = data ? getByPath(data, valuePath) : undefined;
  return (
    <div>
      <span>{label}</span>
      <span>{formatValue(value)}</span>
    </div>
  );
}

十一、快速上手指南

11.1 安装

npm install @json-render/core @json-render/react react zod ai

11.2 定义 Catalog

// lib/catalog.ts
import { createCatalog } from '@json-render/core';
import { z } from 'zod';

export const catalog = createCatalog({
  components: {
    Card: {
      props: z.object({
        title: z.string(),
        description: z.string().nullable(),
      }),
      hasChildren: true,
    },
    Button: {
      props: z.object({
        label: z.string(),
        action: z.string(),
      }),
    },
    Text: {
      props: z.object({
        content: z.string(),
      }),
    },
  },
  actions: {
    submit: {
      params: z.object({ formId: z.string() }),
    },
    navigate: {
      params: z.object({ url: z.string() }),
    },
  },
});

11.3 创建组件注册表

// components/registry.tsx
export const registry = {
  Card: ({ element, children }) => (
    <div className="p-4 border rounded-lg">
      <h2 className="font-bold">{element.props.title}</h2>
      {element.props.description && (
        <p className="text-gray-600">{element.props.description}</p>
      )}
      {children}
    </div>
  ),
  Button: ({ element, onAction }) => (
    <button
      className="px-4 py-2 bg-blue-500 text-white rounded"
      onClick={() => onAction(element.props.action, {})}
    >
      {element.props.label}
    </button>
  ),
  Text: ({ element }) => (
    <p>{element.props.content}</p>
  ),
};

11.4 创建 API 路由

// app/api/generate/route.ts
import { streamText } from 'ai';
import { generateCatalogPrompt } from '@json-render/core';
import { catalog } from '@/lib/catalog';

export async function POST(req: Request) {
  const { prompt } = await req.json();
  const systemPrompt = generateCatalogPrompt(catalog);
  
  const result = streamText({
    model: 'anthropic/claude-haiku-4.5',
    system: systemPrompt,
    prompt,
  });
  
  return new Response(result.textStream, {
    headers: { 
      'Content-Type': 'text/plain; charset=utf-8',
      'Transfer-Encoding': 'chunked',
    },
  });
}

11.5 渲染 UI

// app/page.tsx
'use client';
import { 
  DataProvider, 
  ActionProvider, 
  VisibilityProvider, 
  Renderer, 
  useUIStream 
} from '@json-render/react';
import { registry } from '@/components/registry';

export default function Page() {
  const { tree, isLoading, generate } = useUIStream({
    endpoint: '/api/generate',
  });

  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const formData = new FormData(e.currentTarget);
    generate(formData.get('prompt') as string);
  };

  return (
    <DataProvider initialData={{}}>
      <VisibilityProvider>
        <ActionProvider handlers={{
          submit: (params) => console.log('Submit:', params),
          navigate: (params) => console.log('Navigate:', params),
        }}>
          <form onSubmit={handleSubmit}>
            <input
              name="prompt"
              placeholder="Describe what you want..."
              className="border p-2 rounded"
            />
            <button type="submit" disabled={isLoading}>
              Generate
            </button>
          </form>
          <div className="mt-8">
            <Renderer tree={tree} registry={registry} />
          </div>
        </ActionProvider>
      </VisibilityProvider>
    </DataProvider>
  );
}

十二、技术创新点总结

12.1 核心创新

创新点描述价值
Catalog 护栏机制通过 schema 约束 AI 输出安全性 + 可预测性
JSONL 流式协议基于 JSON Patch 的增量更新低延迟渐进渲染
声明式动作系统AI 声明意图,宿主控制执行安全隔离
递归可见性引擎支持复杂逻辑组合灵活的权限控制
双层数据绑定静态值 + 动态路径引用简化 AI 输出复杂度

12.2 与类似方案对比

特性json-renderVercel AI SDKReact Server Components
AI 输出约束✅ Schema 强制❌ 无约束❌ 无约束
流式渲染✅ JSONL Patch✅ 流式文本✅ Suspense
组件注册✅ 显式 registryN/AN/A
动作系统✅ 声明式❌ 无N/A
框架依赖React框架无关React

十三、适用场景与目标用户

json-render 特别适合以下场景和用户群体:

用户类型使用场景
SaaS 产品开发者为终端用户提供 AI 驱动的仪表盘/报表定制功能
低代码平台开发者构建可由 AI 辅助的可视化编辑器
企业内部工具团队快速构建数据可视化和管理界面
AI 应用开发者需要安全地将 LLM 输出渲染为 UI 的场景

十四、当前限制与改进空间

14.1 当前限制

问题描述影响
React 强依赖渲染层仅支持 React无法用于 Vue/Svelte
无持久化方案UI 树无内置存储机制需自行实现
Schema 生成文档缺失缺少 JSON Schema/OpenAPI 导出AI 集成需手写提示词
无版本迁移工具树结构变更无迁移支持升级成本高

14.2 可能的改进方向

  1. 多框架支持:抽象渲染层接口,支持 Vue、Svelte 等框架
  2. Schema 导出:支持导出 JSON Schema,可直接用于 OpenAI function calling
  3. 树差异对比:添加 diff 工具,用于撤销/重做或协作编辑
  4. 性能优化:添加元素级 memo 支持

结语

json-render 是一个设计精良的 AI UI 生成框架,其核心创新在于:

  1. 安全第一:通过 Catalog 机制实现 AI 输出的强类型约束
  2. 渐进体验:基于 JSONL 的流式协议实现低延迟渲染
  3. 声明式架构:动作、可见性、验证均采用声明式设计,易于序列化和 AI 生成
  4. 类型驱动:深度利用 TypeScript 和 Zod 实现端到端类型安全

该项目特别适合需要将 AI 能力安全地暴露给终端用户的 SaaS 产品,为"AI 生成 UI"这一新兴场景提供了可靠的工程化解决方案。

在 AI 能力日益强大的今天,如何在释放 AI 潜力的同时保持应用的安全性和可控性,是每个开发者都需要思考的问题。json-render 提供了一个优雅的答案:让 AI 做它擅长的事(理解用户意图并生成结构化数据),让开发者掌控它应该掌控的事(组件实现、动作执行、安全边界)