json-render:构建安全可控的 AI 生成 UI 框架
摘要:随着大语言模型(LLM)在应用开发中的广泛应用,如何让 AI 安全、可控地生成用户界面成为一个新兴的技术挑战。本文深入解析 Vercel 开源的 json-render 框架,探讨其"护栏机制"设计思想、核心技术架构、流式渲染实现原理,以及在实际项目中的应用模式。
- 项目地址: github.com/vercel-labs…
- 短短5天,Stars数量已经涨了7.6K
一、背景与问题
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/react | React 集成、UI 渲染 | 依赖 core 和 react |
@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-render | Vercel AI SDK | React Server Components |
|---|---|---|---|
| AI 输出约束 | ✅ Schema 强制 | ❌ 无约束 | ❌ 无约束 |
| 流式渲染 | ✅ JSONL Patch | ✅ 流式文本 | ✅ Suspense |
| 组件注册 | ✅ 显式 registry | N/A | N/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 可能的改进方向
- 多框架支持:抽象渲染层接口,支持 Vue、Svelte 等框架
- Schema 导出:支持导出 JSON Schema,可直接用于 OpenAI function calling
- 树差异对比:添加 diff 工具,用于撤销/重做或协作编辑
- 性能优化:添加元素级 memo 支持
结语
json-render 是一个设计精良的 AI UI 生成框架,其核心创新在于:
- 安全第一:通过 Catalog 机制实现 AI 输出的强类型约束
- 渐进体验:基于 JSONL 的流式协议实现低延迟渲染
- 声明式架构:动作、可见性、验证均采用声明式设计,易于序列化和 AI 生成
- 类型驱动:深度利用 TypeScript 和 Zod 实现端到端类型安全
该项目特别适合需要将 AI 能力安全地暴露给终端用户的 SaaS 产品,为"AI 生成 UI"这一新兴场景提供了可靠的工程化解决方案。
在 AI 能力日益强大的今天,如何在释放 AI 潜力的同时保持应用的安全性和可控性,是每个开发者都需要思考的问题。json-render 提供了一个优雅的答案:让 AI 做它擅长的事(理解用户意图并生成结构化数据),让开发者掌控它应该掌控的事(组件实现、动作执行、安全边界)。